summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPatrick Turley <patrick.turley@freescale.com>2010-04-13 20:55:17 -0500
committerPatrick Turley <patrick.turley@freescale.com>2010-04-27 21:19:27 -0500
commit534d11ce861a1fb102327357e0823d99dd6f242a (patch)
tree6ef3c7c942ebe2fafbe68523ef2ec53ac7cef866 /drivers
parenta5421893d57a5937962f9ca7807f85da33acba9c (diff)
ENGR00122629 Unified i.MX23/i.MX28 NAND Flash Driver
This driver unifies the i.MX23 and i.MX28 NAND Flash drivers into a single driver that supports both SoC's. Signed-off-by: Patrick Turley <patrick.turley@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/Kconfig46
-rw-r--r--drivers/mtd/nand/Makefile4
-rw-r--r--drivers/mtd/nand/gpmi-nfc/Makefile1
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-bch-regs.h550
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-gpmi-regs.h416
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-bch-regs.h557
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-gpmi-regs.h420
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c6351
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h406
-rw-r--r--drivers/mtd/nand/lba/Makefile2
-rw-r--r--drivers/mtd/nand/lba/gpmi-transport.c832
-rw-r--r--drivers/mtd/nand/lba/gpmi.h103
-rw-r--r--drivers/mtd/nand/lba/lba-blk.c345
-rw-r--r--drivers/mtd/nand/lba/lba-core.c619
-rw-r--r--drivers/mtd/nand/lba/lba.h140
15 files changed, 8705 insertions, 2087 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 8f1eebf8d3b3..3fe91622b400 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -434,49 +434,9 @@ config MXC_NAND_LOW_LEVEL_ERASE
This enables the erase of whole NAND flash. By
default low level erase operation is disabled.
-config MTD_NAND_GPMI_LBA
- tristate "GPMI LBA NAND driver"
- depends on MTD_NAND && ARCH_STMP3XXX
- help
- Enables support of LBA devices on GPMI on 37xx/378x SigmaTel
- boards
-
-config MTD_NAND_GPMI
- tristate "GPMI NAND driver"
- depends on MTD_NAND && ARCH_STMP3XXX && !MTD_NAND_GPMI_LBA
- help
- Enables support of NAND devices on GPMI on 37xx/378x SigmaTel
- boards
-
-config MTD_NAND_GPMI_SYSFS_ENTRIES
- bool "Create /sys entries for GPMI device"
- depends on MTD_NAND_GPMI
- help
- Check this to enable /sys entries for GPMI devices
-
-config MTD_NAND_GPMI_BCH
- bool "Enable BCH HWECC"
- depends on MTD_NAND_GPMI
- depends on ARCH_STMP378X
- default y
- help
- Check this to enable /sys entries for GPMI devices
-
-config MTD_NAND_GPMI_TA1
- bool "Support for TA1 NCB format (Hamming code 22,16)"
- depends on MTD_NAND_GPMI
- depends on ARCH_STMP378X
- default y
-
-config MTD_NAND_GPMI_TA3
- bool "Support for TA3 NCB format (Hamming code 13,8)"
- depends on MTD_NAND_GPMI
- depends on ARCH_STMP378X
- default y
-
-config MTD_NAND_GPMI1
- tristate "GPMI NAND Flash driver"
- depends on MTD_NAND && ARCH_MX28
+config MTD_NAND_GPMI_NFC
+ tristate "GPMI NAND Flash Controller driver"
+ depends on MTD_NAND && (ARCH_MX23 || ARCH_MX28)
help
Enables NAND Flash support.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 730f5db16e1d..2245a8df441b 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -41,9 +41,7 @@ obj-$(CONFIG_MTD_NAND_IMX_NFC) += imx_nfc.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_MXC_V2) += mxc_nd2.o nand_device_info.o
obj-$(CONFIG_MTD_NAND_MXC_V3) += mxc_nd2.o nand_device_info.o
-obj-$(CONFIG_MTD_NAND_GPMI) += gpmi/ nand_device_info.o
-obj-$(CONFIG_MTD_NAND_GPMI1) += gpmi1/ nand_device_info.o
-obj-$(CONFIG_MTD_NAND_GPMI_LBA) += lba/
+obj-$(CONFIG_MTD_NAND_GPMI_NFC) += gpmi-nfc/ nand_device_info.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
diff --git a/drivers/mtd/nand/gpmi-nfc/Makefile b/drivers/mtd/nand/gpmi-nfc/Makefile
new file mode 100644
index 000000000000..6acc04fef117
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MTD_NAND_GPMI_NFC) += gpmi-nfc.o
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-bch-regs.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-bch-regs.h
new file mode 100644
index 000000000000..f5251ab6e77d
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-bch-regs.h
@@ -0,0 +1,550 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Copyright 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.
+ */
+
+#ifndef __V0_GPMI_NFC_V0_BCH_REGS_H
+#define __V0_GPMI_NFC_V0_BCH_REGS_H
+
+/*============================================================================*/
+
+#define V0_HW_BCH_CTRL (0x00000000)
+#define V0_HW_BCH_CTRL_SET (0x00000004)
+#define V0_HW_BCH_CTRL_CLR (0x00000008)
+#define V0_HW_BCH_CTRL_TOG (0x0000000c)
+
+#define V0_BM_BCH_CTRL_SFTRST 0x80000000
+#define V0_BV_BCH_CTRL_SFTRST__RUN 0x0
+#define V0_BV_BCH_CTRL_SFTRST__RESET 0x1
+#define V0_BM_BCH_CTRL_CLKGATE 0x40000000
+#define V0_BV_BCH_CTRL_CLKGATE__RUN 0x0
+#define V0_BV_BCH_CTRL_CLKGATE__NO_CLKS 0x1
+#define V0_BP_BCH_CTRL_RSVD5 23
+#define V0_BM_BCH_CTRL_RSVD5 0x3F800000
+#define V0_BF_BCH_CTRL_RSVD5(v) (((v) << 23) & V0_BM_BCH_CTRL_RSVD5)
+#define V0_BM_BCH_CTRL_DEBUGSYNDROME 0x00400000
+#define V0_BP_BCH_CTRL_RSVD4 20
+#define V0_BM_BCH_CTRL_RSVD4 0x00300000
+#define V0_BF_BCH_CTRL_RSVD4(v) (((v) << 20) & V0_BM_BCH_CTRL_RSVD4)
+#define V0_BP_BCH_CTRL_M2M_LAYOUT 18
+#define V0_BM_BCH_CTRL_M2M_LAYOUT 0x000C0000
+#define V0_BF_BCH_CTRL_M2M_LAYOUT(v) (((v) << 18) & V0_BM_BCH_CTRL_M2M_LAYOUT)
+#define V0_BM_BCH_CTRL_M2M_ENCODE 0x00020000
+#define V0_BM_BCH_CTRL_M2M_ENABLE 0x00010000
+#define V0_BP_BCH_CTRL_RSVD3 11
+#define V0_BM_BCH_CTRL_RSVD3 0x0000F800
+#define V0_BF_BCH_CTRL_RSVD3(v) (((v) << 11) & V0_BM_BCH_CTRL_RSVD3)
+#define V0_BM_BCH_CTRL_DEBUG_STALL_IRQ_EN 0x00000400
+#define V0_BM_BCH_CTRL_RSVD2 0x00000200
+#define V0_BM_BCH_CTRL_COMPLETE_IRQ_EN 0x00000100
+#define V0_BP_BCH_CTRL_RSVD1 4
+#define V0_BM_BCH_CTRL_RSVD1 0x000000F0
+#define V0_BF_BCH_CTRL_RSVD1(v) (((v) << 4) & V0_BM_BCH_CTRL_RSVD1)
+#define V0_BM_BCH_CTRL_BM_ERROR_IRQ 0x00000008
+#define V0_BM_BCH_CTRL_DEBUG_STALL_IRQ 0x00000004
+#define V0_BM_BCH_CTRL_RSVD0 0x00000002
+#define V0_BM_BCH_CTRL_COMPLETE_IRQ 0x00000001
+
+/*============================================================================*/
+
+#define V0_HW_BCH_STATUS0 (0x00000010)
+
+#define V0_BP_BCH_STATUS0_HANDLE 20
+#define V0_BM_BCH_STATUS0_HANDLE 0xFFF00000
+#define V0_BF_BCH_STATUS0_HANDLE(v) \
+ (((v) << 20) & V0_BM_BCH_STATUS0_HANDLE)
+#define V0_BP_BCH_STATUS0_COMPLETED_CE 16
+#define V0_BM_BCH_STATUS0_COMPLETED_CE 0x000F0000
+#define V0_BF_BCH_STATUS0_COMPLETED_CE(v) \
+ (((v) << 16) & V0_BM_BCH_STATUS0_COMPLETED_CE)
+#define V0_BP_BCH_STATUS0_STATUS_BLK0 8
+#define V0_BM_BCH_STATUS0_STATUS_BLK0 0x0000FF00
+#define V0_BF_BCH_STATUS0_STATUS_BLK0(v) \
+ (((v) << 8) & V0_BM_BCH_STATUS0_STATUS_BLK0)
+#define V0_BV_BCH_STATUS0_STATUS_BLK0__ZERO 0x00
+#define V0_BV_BCH_STATUS0_STATUS_BLK0__ERROR1 0x01
+#define V0_BV_BCH_STATUS0_STATUS_BLK0__ERROR2 0x02
+#define V0_BV_BCH_STATUS0_STATUS_BLK0__ERROR3 0x03
+#define V0_BV_BCH_STATUS0_STATUS_BLK0__ERROR4 0x04
+#define V0_BV_BCH_STATUS0_STATUS_BLK0__UNCORRECTABLE 0xFE
+#define V0_BV_BCH_STATUS0_STATUS_BLK0__ERASED 0xFF
+#define V0_BP_BCH_STATUS0_RSVD1 5
+#define V0_BM_BCH_STATUS0_RSVD1 0x000000E0
+#define V0_BF_BCH_STATUS0_RSVD1(v) \
+ (((v) << 5) & V0_BM_BCH_STATUS0_RSVD1)
+#define V0_BM_BCH_STATUS0_ALLONES 0x00000010
+#define V0_BM_BCH_STATUS0_CORRECTED 0x00000008
+#define V0_BM_BCH_STATUS0_UNCORRECTABLE 0x00000004
+#define V0_BP_BCH_STATUS0_RSVD0 0
+#define V0_BM_BCH_STATUS0_RSVD0 0x00000003
+#define V0_BF_BCH_STATUS0_RSVD0(v) \
+ (((v) << 0) & V0_BM_BCH_STATUS0_RSVD0)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_MODE (0x00000020)
+
+#define V0_BP_BCH_MODE_RSVD 8
+#define V0_BM_BCH_MODE_RSVD 0xFFFFFF00
+#define V0_BF_BCH_MODE_RSVD(v) \
+ (((v) << 8) & V0_BM_BCH_MODE_RSVD)
+#define V0_BP_BCH_MODE_ERASE_THRESHOLD 0
+#define V0_BM_BCH_MODE_ERASE_THRESHOLD 0x000000FF
+#define V0_BF_BCH_MODE_ERASE_THRESHOLD(v) \
+ (((v) << 0) & V0_BM_BCH_MODE_ERASE_THRESHOLD)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_ENCODEPTR (0x00000030)
+
+#define V0_BP_BCH_ENCODEPTR_ADDR 0
+#define V0_BM_BCH_ENCODEPTR_ADDR 0xFFFFFFFF
+#define V0_BF_BCH_ENCODEPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_DATAPTR (0x00000040)
+
+#define V0_BP_BCH_DATAPTR_ADDR 0
+#define V0_BM_BCH_DATAPTR_ADDR 0xFFFFFFFF
+#define V0_BF_BCH_DATAPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_METAPTR (0x00000050)
+
+#define V0_BP_BCH_METAPTR_ADDR 0
+#define V0_BM_BCH_METAPTR_ADDR 0xFFFFFFFF
+#define V0_BF_BCH_METAPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_LAYOUTSELECT (0x00000070)
+
+#define V0_BP_BCH_LAYOUTSELECT_CS15_SELECT 30
+#define V0_BM_BCH_LAYOUTSELECT_CS15_SELECT 0xC0000000
+#define V0_BF_BCH_LAYOUTSELECT_CS15_SELECT(v) \
+ (((v) << 30) & V0_BM_BCH_LAYOUTSELECT_CS15_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS14_SELECT 28
+#define V0_BM_BCH_LAYOUTSELECT_CS14_SELECT 0x30000000
+#define V0_BF_BCH_LAYOUTSELECT_CS14_SELECT(v) \
+ (((v) << 28) & V0_BM_BCH_LAYOUTSELECT_CS14_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS13_SELECT 26
+#define V0_BM_BCH_LAYOUTSELECT_CS13_SELECT 0x0C000000
+#define V0_BF_BCH_LAYOUTSELECT_CS13_SELECT(v) \
+ (((v) << 26) & V0_BM_BCH_LAYOUTSELECT_CS13_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS12_SELECT 24
+#define V0_BM_BCH_LAYOUTSELECT_CS12_SELECT 0x03000000
+#define V0_BF_BCH_LAYOUTSELECT_CS12_SELECT(v) \
+ (((v) << 24) & V0_BM_BCH_LAYOUTSELECT_CS12_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS11_SELECT 22
+#define V0_BM_BCH_LAYOUTSELECT_CS11_SELECT 0x00C00000
+#define V0_BF_BCH_LAYOUTSELECT_CS11_SELECT(v) \
+ (((v) << 22) & V0_BM_BCH_LAYOUTSELECT_CS11_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS10_SELECT 20
+#define V0_BM_BCH_LAYOUTSELECT_CS10_SELECT 0x00300000
+#define V0_BF_BCH_LAYOUTSELECT_CS10_SELECT(v) \
+ (((v) << 20) & V0_BM_BCH_LAYOUTSELECT_CS10_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS9_SELECT 18
+#define V0_BM_BCH_LAYOUTSELECT_CS9_SELECT 0x000C0000
+#define V0_BF_BCH_LAYOUTSELECT_CS9_SELECT(v) \
+ (((v) << 18) & V0_BM_BCH_LAYOUTSELECT_CS9_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS8_SELECT 16
+#define V0_BM_BCH_LAYOUTSELECT_CS8_SELECT 0x00030000
+#define V0_BF_BCH_LAYOUTSELECT_CS8_SELECT(v) \
+ (((v) << 16) & V0_BM_BCH_LAYOUTSELECT_CS8_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS7_SELECT 14
+#define V0_BM_BCH_LAYOUTSELECT_CS7_SELECT 0x0000C000
+#define V0_BF_BCH_LAYOUTSELECT_CS7_SELECT(v) \
+ (((v) << 14) & V0_BM_BCH_LAYOUTSELECT_CS7_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS6_SELECT 12
+#define V0_BM_BCH_LAYOUTSELECT_CS6_SELECT 0x00003000
+#define V0_BF_BCH_LAYOUTSELECT_CS6_SELECT(v) \
+ (((v) << 12) & V0_BM_BCH_LAYOUTSELECT_CS6_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS5_SELECT 10
+#define V0_BM_BCH_LAYOUTSELECT_CS5_SELECT 0x00000C00
+#define V0_BF_BCH_LAYOUTSELECT_CS5_SELECT(v) \
+ (((v) << 10) & V0_BM_BCH_LAYOUTSELECT_CS5_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS4_SELECT 8
+#define V0_BM_BCH_LAYOUTSELECT_CS4_SELECT 0x00000300
+#define V0_BF_BCH_LAYOUTSELECT_CS4_SELECT(v) \
+ (((v) << 8) & V0_BM_BCH_LAYOUTSELECT_CS4_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS3_SELECT 6
+#define V0_BM_BCH_LAYOUTSELECT_CS3_SELECT 0x000000C0
+#define V0_BF_BCH_LAYOUTSELECT_CS3_SELECT(v) \
+ (((v) << 6) & V0_BM_BCH_LAYOUTSELECT_CS3_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS2_SELECT 4
+#define V0_BM_BCH_LAYOUTSELECT_CS2_SELECT 0x00000030
+#define V0_BF_BCH_LAYOUTSELECT_CS2_SELECT(v) \
+ (((v) << 4) & V0_BM_BCH_LAYOUTSELECT_CS2_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS1_SELECT 2
+#define V0_BM_BCH_LAYOUTSELECT_CS1_SELECT 0x0000000C
+#define V0_BF_BCH_LAYOUTSELECT_CS1_SELECT(v) \
+ (((v) << 2) & V0_BM_BCH_LAYOUTSELECT_CS1_SELECT)
+#define V0_BP_BCH_LAYOUTSELECT_CS0_SELECT 0
+#define V0_BM_BCH_LAYOUTSELECT_CS0_SELECT 0x00000003
+#define V0_BF_BCH_LAYOUTSELECT_CS0_SELECT(v) \
+ (((v) << 0) & V0_BM_BCH_LAYOUTSELECT_CS0_SELECT)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_FLASH0LAYOUT0 (0x00000080)
+
+#define V0_BP_BCH_FLASH0LAYOUT0_NBLOCKS 24
+#define V0_BM_BCH_FLASH0LAYOUT0_NBLOCKS 0xFF000000
+#define V0_BF_BCH_FLASH0LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & V0_BM_BCH_FLASH0LAYOUT0_NBLOCKS)
+#define V0_BP_BCH_FLASH0LAYOUT0_META_SIZE 16
+#define V0_BM_BCH_FLASH0LAYOUT0_META_SIZE 0x00FF0000
+#define V0_BF_BCH_FLASH0LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & V0_BM_BCH_FLASH0LAYOUT0_META_SIZE)
+#define V0_BP_BCH_FLASH0LAYOUT0_ECC0 12
+#define V0_BM_BCH_FLASH0LAYOUT0_ECC0 0x0000F000
+#define V0_BF_BCH_FLASH0LAYOUT0_ECC0(v) \
+ (((v) << 12) & V0_BM_BCH_FLASH0LAYOUT0_ECC0)
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__NONE 0x0
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC2 0x1
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC4 0x2
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC6 0x3
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC8 0x4
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC10 0x5
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC12 0x6
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC14 0x7
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC16 0x8
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC18 0x9
+#define V0_BV_BCH_FLASH0LAYOUT0_ECC0__ECC20 0xA
+#define V0_BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0
+#define V0_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE 0x00000FFF
+#define V0_BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & V0_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_FLASH0LAYOUT1 (0x00000090)
+
+#define V0_BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16
+#define V0_BM_BCH_FLASH0LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define V0_BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & V0_BM_BCH_FLASH0LAYOUT1_PAGE_SIZE)
+#define V0_BP_BCH_FLASH0LAYOUT1_ECCN 12
+#define V0_BM_BCH_FLASH0LAYOUT1_ECCN 0x0000F000
+#define V0_BF_BCH_FLASH0LAYOUT1_ECCN(v) \
+ (((v) << 12) & V0_BM_BCH_FLASH0LAYOUT1_ECCN)
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__NONE 0x0
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC2 0x1
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC4 0x2
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC6 0x3
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC8 0x4
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC10 0x5
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC12 0x6
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC14 0x7
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC16 0x8
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC18 0x9
+#define V0_BV_BCH_FLASH0LAYOUT1_ECCN__ECC20 0xA
+#define V0_BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0
+#define V0_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE 0x00000FFF
+#define V0_BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & V0_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_FLASH1LAYOUT0 (0x000000a0)
+
+#define V0_BP_BCH_FLASH1LAYOUT0_NBLOCKS 24
+#define V0_BM_BCH_FLASH1LAYOUT0_NBLOCKS 0xFF000000
+#define V0_BF_BCH_FLASH1LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & V0_BM_BCH_FLASH1LAYOUT0_NBLOCKS)
+#define V0_BP_BCH_FLASH1LAYOUT0_META_SIZE 16
+#define V0_BM_BCH_FLASH1LAYOUT0_META_SIZE 0x00FF0000
+#define V0_BF_BCH_FLASH1LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & V0_BM_BCH_FLASH1LAYOUT0_META_SIZE)
+#define V0_BP_BCH_FLASH1LAYOUT0_ECC0 12
+#define V0_BM_BCH_FLASH1LAYOUT0_ECC0 0x0000F000
+#define V0_BF_BCH_FLASH1LAYOUT0_ECC0(v) \
+ (((v) << 12) & V0_BM_BCH_FLASH1LAYOUT0_ECC0)
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__NONE 0x0
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC2 0x1
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC4 0x2
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC6 0x3
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC8 0x4
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC10 0x5
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC12 0x6
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC14 0x7
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC16 0x8
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC18 0x9
+#define V0_BV_BCH_FLASH1LAYOUT0_ECC0__ECC20 0xA
+#define V0_BP_BCH_FLASH1LAYOUT0_DATA0_SIZE 0
+#define V0_BM_BCH_FLASH1LAYOUT0_DATA0_SIZE 0x00000FFF
+#define V0_BF_BCH_FLASH1LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & V0_BM_BCH_FLASH1LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_FLASH1LAYOUT1 (0x000000b0)
+
+#define V0_BP_BCH_FLASH1LAYOUT1_PAGE_SIZE 16
+#define V0_BM_BCH_FLASH1LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define V0_BF_BCH_FLASH1LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & V0_BM_BCH_FLASH1LAYOUT1_PAGE_SIZE)
+#define V0_BP_BCH_FLASH1LAYOUT1_ECCN 12
+#define V0_BM_BCH_FLASH1LAYOUT1_ECCN 0x0000F000
+#define V0_BF_BCH_FLASH1LAYOUT1_ECCN(v) \
+ (((v) << 12) & V0_BM_BCH_FLASH1LAYOUT1_ECCN)
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__NONE 0x0
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC2 0x1
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC4 0x2
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC6 0x3
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC8 0x4
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC10 0x5
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC12 0x6
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC14 0x7
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC16 0x8
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC18 0x9
+#define V0_BV_BCH_FLASH1LAYOUT1_ECCN__ECC20 0xA
+#define V0_BP_BCH_FLASH1LAYOUT1_DATAN_SIZE 0
+#define V0_BM_BCH_FLASH1LAYOUT1_DATAN_SIZE 0x00000FFF
+#define V0_BF_BCH_FLASH1LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & V0_BM_BCH_FLASH1LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_FLASH2LAYOUT0 (0x000000c0)
+
+#define V0_BP_BCH_FLASH2LAYOUT0_NBLOCKS 24
+#define V0_BM_BCH_FLASH2LAYOUT0_NBLOCKS 0xFF000000
+#define V0_BF_BCH_FLASH2LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & V0_BM_BCH_FLASH2LAYOUT0_NBLOCKS)
+#define V0_BP_BCH_FLASH2LAYOUT0_META_SIZE 16
+#define V0_BM_BCH_FLASH2LAYOUT0_META_SIZE 0x00FF0000
+#define V0_BF_BCH_FLASH2LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & V0_BM_BCH_FLASH2LAYOUT0_META_SIZE)
+#define V0_BP_BCH_FLASH2LAYOUT0_ECC0 12
+#define V0_BM_BCH_FLASH2LAYOUT0_ECC0 0x0000F000
+#define V0_BF_BCH_FLASH2LAYOUT0_ECC0(v) \
+ (((v) << 12) & V0_BM_BCH_FLASH2LAYOUT0_ECC0)
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__NONE 0x0
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC2 0x1
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC4 0x2
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC6 0x3
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC8 0x4
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC10 0x5
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC12 0x6
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC14 0x7
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC16 0x8
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC18 0x9
+#define V0_BV_BCH_FLASH2LAYOUT0_ECC0__ECC20 0xA
+#define V0_BP_BCH_FLASH2LAYOUT0_DATA0_SIZE 0
+#define V0_BM_BCH_FLASH2LAYOUT0_DATA0_SIZE 0x00000FFF
+#define V0_BF_BCH_FLASH2LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & V0_BM_BCH_FLASH2LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_FLASH2LAYOUT1 (0x000000d0)
+
+#define V0_BP_BCH_FLASH2LAYOUT1_PAGE_SIZE 16
+#define V0_BM_BCH_FLASH2LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define V0_BF_BCH_FLASH2LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & V0_BM_BCH_FLASH2LAYOUT1_PAGE_SIZE)
+#define V0_BP_BCH_FLASH2LAYOUT1_ECCN 12
+#define V0_BM_BCH_FLASH2LAYOUT1_ECCN 0x0000F000
+#define V0_BF_BCH_FLASH2LAYOUT1_ECCN(v) \
+ (((v) << 12) & V0_BM_BCH_FLASH2LAYOUT1_ECCN)
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__NONE 0x0
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC2 0x1
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC4 0x2
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC6 0x3
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC8 0x4
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC10 0x5
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC12 0x6
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC14 0x7
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC16 0x8
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC18 0x9
+#define V0_BV_BCH_FLASH2LAYOUT1_ECCN__ECC20 0xA
+#define V0_BP_BCH_FLASH2LAYOUT1_DATAN_SIZE 0
+#define V0_BM_BCH_FLASH2LAYOUT1_DATAN_SIZE 0x00000FFF
+#define V0_BF_BCH_FLASH2LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & V0_BM_BCH_FLASH2LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_FLASH3LAYOUT0 (0x000000e0)
+
+#define V0_BP_BCH_FLASH3LAYOUT0_NBLOCKS 24
+#define V0_BM_BCH_FLASH3LAYOUT0_NBLOCKS 0xFF000000
+#define V0_BF_BCH_FLASH3LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & V0_BM_BCH_FLASH3LAYOUT0_NBLOCKS)
+#define V0_BP_BCH_FLASH3LAYOUT0_META_SIZE 16
+#define V0_BM_BCH_FLASH3LAYOUT0_META_SIZE 0x00FF0000
+#define V0_BF_BCH_FLASH3LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & V0_BM_BCH_FLASH3LAYOUT0_META_SIZE)
+#define V0_BP_BCH_FLASH3LAYOUT0_ECC0 12
+#define V0_BM_BCH_FLASH3LAYOUT0_ECC0 0x0000F000
+#define V0_BF_BCH_FLASH3LAYOUT0_ECC0(v) \
+ (((v) << 12) & V0_BM_BCH_FLASH3LAYOUT0_ECC0)
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__NONE 0x0
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC2 0x1
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC4 0x2
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC6 0x3
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC8 0x4
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC10 0x5
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC12 0x6
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC14 0x7
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC16 0x8
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC18 0x9
+#define V0_BV_BCH_FLASH3LAYOUT0_ECC0__ECC20 0xA
+#define V0_BP_BCH_FLASH3LAYOUT0_DATA0_SIZE 0
+#define V0_BM_BCH_FLASH3LAYOUT0_DATA0_SIZE 0x00000FFF
+#define V0_BF_BCH_FLASH3LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & V0_BM_BCH_FLASH3LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_FLASH3LAYOUT1 (0x000000f0)
+
+#define V0_BP_BCH_FLASH3LAYOUT1_PAGE_SIZE 16
+#define V0_BM_BCH_FLASH3LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define V0_BF_BCH_FLASH3LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & V0_BM_BCH_FLASH3LAYOUT1_PAGE_SIZE)
+#define V0_BP_BCH_FLASH3LAYOUT1_ECCN 12
+#define V0_BM_BCH_FLASH3LAYOUT1_ECCN 0x0000F000
+#define V0_BF_BCH_FLASH3LAYOUT1_ECCN(v) \
+ (((v) << 12) & V0_BM_BCH_FLASH3LAYOUT1_ECCN)
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__NONE 0x0
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC2 0x1
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC4 0x2
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC6 0x3
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC8 0x4
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC10 0x5
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC12 0x6
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC14 0x7
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC16 0x8
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC18 0x9
+#define V0_BV_BCH_FLASH3LAYOUT1_ECCN__ECC20 0xA
+#define V0_BP_BCH_FLASH3LAYOUT1_DATAN_SIZE 0
+#define V0_BM_BCH_FLASH3LAYOUT1_DATAN_SIZE 0x00000FFF
+#define V0_BF_BCH_FLASH3LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & V0_BM_BCH_FLASH3LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_DEBUG0 (0x00000100)
+#define V0_HW_BCH_DEBUG0_SET (0x00000104)
+#define V0_HW_BCH_DEBUG0_CLR (0x00000108)
+#define V0_HW_BCH_DEBUG0_TOG (0x0000010c)
+
+#define V0_BP_BCH_DEBUG0_RSVD1 27
+#define V0_BM_BCH_DEBUG0_RSVD1 0xF8000000
+#define V0_BF_BCH_DEBUG0_RSVD1(v) \
+ (((v) << 27) & V0_BM_BCH_DEBUG0_RSVD1)
+#define V0_BM_BCH_DEBUG0_ROM_BIST_ENABLE 0x04000000
+#define V0_BM_BCH_DEBUG0_ROM_BIST_COMPLETE 0x02000000
+#define V0_BP_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 16
+#define V0_BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 0x01FF0000
+#define V0_BF_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL(v) \
+ (((v) << 16) & V0_BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL)
+#define V0_BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__NORMAL 0x0
+#define V0_BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__TEST_MODE 0x1
+#define V0_BM_BCH_DEBUG0_KES_DEBUG_SHIFT_SYND 0x00008000
+#define V0_BM_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG 0x00004000
+#define V0_BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__DATA 0x1
+#define V0_BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__AUX 0x1
+#define V0_BM_BCH_DEBUG0_KES_DEBUG_MODE4K 0x00002000
+#define V0_BV_BCH_DEBUG0_KES_DEBUG_MODE4K__4k 0x1
+#define V0_BV_BCH_DEBUG0_KES_DEBUG_MODE4K__2k 0x1
+#define V0_BM_BCH_DEBUG0_KES_DEBUG_KICK 0x00001000
+#define V0_BM_BCH_DEBUG0_KES_STANDALONE 0x00000800
+#define V0_BV_BCH_DEBUG0_KES_STANDALONE__NORMAL 0x0
+#define V0_BV_BCH_DEBUG0_KES_STANDALONE__TEST_MODE 0x1
+#define V0_BM_BCH_DEBUG0_KES_DEBUG_STEP 0x00000400
+#define V0_BM_BCH_DEBUG0_KES_DEBUG_STALL 0x00000200
+#define V0_BV_BCH_DEBUG0_KES_DEBUG_STALL__NORMAL 0x0
+#define V0_BV_BCH_DEBUG0_KES_DEBUG_STALL__WAIT 0x1
+#define V0_BM_BCH_DEBUG0_BM_KES_TEST_BYPASS 0x00000100
+#define V0_BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__NORMAL 0x0
+#define V0_BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__TEST_MODE 0x1
+#define V0_BP_BCH_DEBUG0_RSVD0 6
+#define V0_BM_BCH_DEBUG0_RSVD0 0x000000C0
+#define V0_BF_BCH_DEBUG0_RSVD0(v) \
+ (((v) << 6) & V0_BM_BCH_DEBUG0_RSVD0)
+#define V0_BP_BCH_DEBUG0_DEBUG_REG_SELECT 0
+#define V0_BM_BCH_DEBUG0_DEBUG_REG_SELECT 0x0000003F
+#define V0_BF_BCH_DEBUG0_DEBUG_REG_SELECT(v) \
+ (((v) << 0) & V0_BM_BCH_DEBUG0_DEBUG_REG_SELECT)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_DBGKESREAD (0x00000110)
+
+#define V0_BP_BCH_DBGKESREAD_VALUES 0
+#define V0_BM_BCH_DBGKESREAD_VALUES 0xFFFFFFFF
+#define V0_BF_BCH_DBGKESREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_DBGCSFEREAD (0x00000120)
+
+#define V0_BP_BCH_DBGCSFEREAD_VALUES 0
+#define V0_BM_BCH_DBGCSFEREAD_VALUES 0xFFFFFFFF
+#define V0_BF_BCH_DBGCSFEREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_DBGSYNDGENREAD (0x00000130)
+
+#define V0_BP_BCH_DBGSYNDGENREAD_VALUES 0
+#define V0_BM_BCH_DBGSYNDGENREAD_VALUES 0xFFFFFFFF
+#define V0_BF_BCH_DBGSYNDGENREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_DBGAHBMREAD (0x00000140)
+
+#define V0_BP_BCH_DBGAHBMREAD_VALUES 0
+#define V0_BM_BCH_DBGAHBMREAD_VALUES 0xFFFFFFFF
+#define V0_BF_BCH_DBGAHBMREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_BLOCKNAME (0x00000150)
+
+#define V0_BP_BCH_BLOCKNAME_NAME 0
+#define V0_BM_BCH_BLOCKNAME_NAME 0xFFFFFFFF
+#define V0_BF_BCH_BLOCKNAME_NAME(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_BCH_VERSION (0x00000160)
+
+#define V0_BP_BCH_VERSION_MAJOR 24
+#define V0_BM_BCH_VERSION_MAJOR 0xFF000000
+#define V0_BF_BCH_VERSION_MAJOR(v) \
+ (((v) << 24) & V0_BM_BCH_VERSION_MAJOR)
+#define V0_BP_BCH_VERSION_MINOR 16
+#define V0_BM_BCH_VERSION_MINOR 0x00FF0000
+#define V0_BF_BCH_VERSION_MINOR(v) \
+ (((v) << 16) & V0_BM_BCH_VERSION_MINOR)
+#define V0_BP_BCH_VERSION_STEP 0
+#define V0_BM_BCH_VERSION_STEP 0x0000FFFF
+#define V0_BF_BCH_VERSION_STEP(v) \
+ (((v) << 0) & V0_BM_BCH_VERSION_STEP)
+
+/*============================================================================*/
+
+#endif
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-gpmi-regs.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-gpmi-regs.h
new file mode 100644
index 000000000000..5d683d415006
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-gpmi-regs.h
@@ -0,0 +1,416 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Copyright 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.
+ */
+
+#ifndef __V0_GPMI_NFC_V0_GPMI_REGS_H
+#define __V0_GPMI_NFC_V0_GPMI_REGS_H
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_CTRL0 (0x00000000)
+#define V0_HW_GPMI_CTRL0_SET (0x00000004)
+#define V0_HW_GPMI_CTRL0_CLR (0x00000008)
+#define V0_HW_GPMI_CTRL0_TOG (0x0000000c)
+
+#define V0_BM_GPMI_CTRL0_SFTRST 0x80000000
+#define V0_BV_GPMI_CTRL0_SFTRST__RUN 0x0
+#define V0_BV_GPMI_CTRL0_SFTRST__RESET 0x1
+#define V0_BM_GPMI_CTRL0_CLKGATE 0x40000000
+#define V0_BV_GPMI_CTRL0_CLKGATE__RUN 0x0
+#define V0_BV_GPMI_CTRL0_CLKGATE__NO_CLKS 0x1
+#define V0_BM_GPMI_CTRL0_RUN 0x20000000
+#define V0_BV_GPMI_CTRL0_RUN__IDLE 0x0
+#define V0_BV_GPMI_CTRL0_RUN__BUSY 0x1
+#define V0_BM_GPMI_CTRL0_DEV_IRQ_EN 0x10000000
+#define V0_BM_GPMI_CTRL0_TIMEOUT_IRQ_EN 0x08000000
+#define V0_BM_GPMI_CTRL0_UDMA 0x04000000
+#define V0_BV_GPMI_CTRL0_UDMA__DISABLED 0x0
+#define V0_BV_GPMI_CTRL0_UDMA__ENABLED 0x1
+#define V0_BP_GPMI_CTRL0_COMMAND_MODE 24
+#define V0_BM_GPMI_CTRL0_COMMAND_MODE 0x03000000
+#define V0_BF_GPMI_CTRL0_COMMAND_MODE(v) \
+ (((v) << 24) & V0_BM_GPMI_CTRL0_COMMAND_MODE)
+#define V0_BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0
+#define V0_BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1
+#define V0_BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
+#define V0_BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3
+#define V0_BM_GPMI_CTRL0_WORD_LENGTH 0x00800000
+#define V0_BV_GPMI_CTRL0_WORD_LENGTH__16_BIT 0x0
+#define V0_BV_GPMI_CTRL0_WORD_LENGTH__8_BIT 0x1
+#define V0_BM_GPMI_CTRL0_LOCK_CS 0x00400000
+#define V0_BV_GPMI_CTRL0_LOCK_CS__DISABLED 0x0
+#define V0_BV_GPMI_CTRL0_LOCK_CS__ENABLED 0x1
+#define V0_BP_GPMI_CTRL0_CS 20
+#define V0_BM_GPMI_CTRL0_CS 0x00300000
+#define V0_BF_GPMI_CTRL0_CS(v) (((v) << 20) & V0_BM_GPMI_CTRL0_CS)
+#define V0_BP_GPMI_CTRL0_ADDRESS 17
+#define V0_BM_GPMI_CTRL0_ADDRESS 0x000E0000
+#define V0_BF_GPMI_CTRL0_ADDRESS(v) (((v) << 17) & V0_BM_GPMI_CTRL0_ADDRESS)
+#define V0_BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0
+#define V0_BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1
+#define V0_BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2
+#define V0_BM_GPMI_CTRL0_ADDRESS_INCREMENT 0x00010000
+#define V0_BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED 0x0
+#define V0_BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED 0x1
+#define V0_BP_GPMI_CTRL0_XFER_COUNT 0
+#define V0_BM_GPMI_CTRL0_XFER_COUNT 0x0000FFFF
+#define V0_BF_GPMI_CTRL0_XFER_COUNT(v) \
+ (((v) << 0) & V0_BM_GPMI_CTRL0_XFER_COUNT)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_COMPARE (0x00000010)
+
+#define V0_BP_GPMI_COMPARE_MASK 16
+#define V0_BM_GPMI_COMPARE_MASK 0xFFFF0000
+#define V0_BF_GPMI_COMPARE_MASK(v) (((v) << 16) & V0_BM_GPMI_COMPARE_MASK)
+#define V0_BP_GPMI_COMPARE_REFERENCE 0
+#define V0_BM_GPMI_COMPARE_REFERENCE 0x0000FFFF
+#define V0_BF_GPMI_COMPARE_REFERENCE(v) \
+ (((v) << 0) & V0_BM_GPMI_COMPARE_REFERENCE)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_ECCCTRL (0x00000020)
+#define V0_HW_GPMI_ECCCTRL_SET (0x00000024)
+#define V0_HW_GPMI_ECCCTRL_CLR (0x00000028)
+#define V0_HW_GPMI_ECCCTRL_TOG (0x0000002c)
+
+#define V0_BP_GPMI_ECCCTRL_HANDLE 16
+#define V0_BM_GPMI_ECCCTRL_HANDLE 0xFFFF0000
+#define V0_BF_GPMI_ECCCTRL_HANDLE(v) (((v) << 16) & V0_BM_GPMI_ECCCTRL_HANDLE)
+#define V0_BM_GPMI_ECCCTRL_RSVD2 0x00008000
+#define V0_BP_GPMI_ECCCTRL_ECC_CMD 13
+#define V0_BM_GPMI_ECCCTRL_ECC_CMD 0x00006000
+#define V0_BF_GPMI_ECCCTRL_ECC_CMD(v) (((v) << 13) & V0_BM_GPMI_ECCCTRL_ECC_CMD)
+#define V0_BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT 0x0
+#define V0_BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT 0x1
+#define V0_BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT 0x2
+#define V0_BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT 0x3
+#define V0_BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE 0x0
+#define V0_BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE 0x1
+#define V0_BM_GPMI_ECCCTRL_ENABLE_ECC 0x00001000
+#define V0_BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE 0x1
+#define V0_BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE 0x0
+#define V0_BP_GPMI_ECCCTRL_RSVD1 9
+#define V0_BM_GPMI_ECCCTRL_RSVD1 0x00000E00
+#define V0_BF_GPMI_ECCCTRL_RSVD1(v) (((v) << 9) & V0_BM_GPMI_ECCCTRL_RSVD1)
+#define V0_BP_GPMI_ECCCTRL_BUFFER_MASK 0
+#define V0_BM_GPMI_ECCCTRL_BUFFER_MASK 0x000001FF
+#define V0_BF_GPMI_ECCCTRL_BUFFER_MASK(v) \
+ (((v) << 0) & V0_BM_GPMI_ECCCTRL_BUFFER_MASK)
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__AUXILIARY 0x100
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER7 0x080
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER6 0x040
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER5 0x020
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER4 0x010
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER3 0x008
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER2 0x004
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER1 0x002
+#define V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER0 0x001
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_ECCCOUNT (0x00000030)
+
+#define V0_BP_GPMI_ECCCOUNT_RSVD2 16
+#define V0_BM_GPMI_ECCCOUNT_RSVD2 0xFFFF0000
+#define V0_BF_GPMI_ECCCOUNT_RSVD2(v) (((v) << 16) & V0_BM_GPMI_ECCCOUNT_RSVD2)
+#define V0_BP_GPMI_ECCCOUNT_COUNT 0
+#define V0_BM_GPMI_ECCCOUNT_COUNT 0x0000FFFF
+#define V0_BF_GPMI_ECCCOUNT_COUNT(v) (((v) << 0) & V0_BM_GPMI_ECCCOUNT_COUNT)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_PAYLOAD (0x00000040)
+
+#define V0_BP_GPMI_PAYLOAD_ADDRESS 2
+#define V0_BM_GPMI_PAYLOAD_ADDRESS 0xFFFFFFFC
+#define V0_BF_GPMI_PAYLOAD_ADDRESS(v) (((v) << 2) & V0_BM_GPMI_PAYLOAD_ADDRESS)
+#define V0_BP_GPMI_PAYLOAD_RSVD0 0
+#define V0_BM_GPMI_PAYLOAD_RSVD0 0x00000003
+#define V0_BF_GPMI_PAYLOAD_RSVD0(v) (((v) << 0) & V0_BM_GPMI_PAYLOAD_RSVD0)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_AUXILIARY (0x00000050)
+
+#define V0_BP_GPMI_AUXILIARY_ADDRESS 2
+#define V0_BM_GPMI_AUXILIARY_ADDRESS 0xFFFFFFFC
+#define V0_BF_GPMI_AUXILIARY_ADDRESS(v) \
+ (((v) << 2) & V0_BM_GPMI_AUXILIARY_ADDRESS)
+#define V0_BP_GPMI_AUXILIARY_RSVD0 0
+#define V0_BM_GPMI_AUXILIARY_RSVD0 0x00000003
+#define V0_BF_GPMI_AUXILIARY_RSVD0(v) (((v) << 0) & V0_BM_GPMI_AUXILIARY_RSVD0)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_CTRL1 (0x00000060)
+#define V0_HW_GPMI_CTRL1_SET (0x00000064)
+#define V0_HW_GPMI_CTRL1_CLR (0x00000068)
+#define V0_HW_GPMI_CTRL1_TOG (0x0000006c)
+
+#define V0_BP_GPMI_CTRL1_RSVD2 24
+#define V0_BM_GPMI_CTRL1_RSVD2 0xFF000000
+#define V0_BF_GPMI_CTRL1_RSVD2(v) \
+ (((v) << 24) & V0_BM_GPMI_CTRL1_RSVD2)
+#define V0_BM_GPMI_CTRL1_CE3_SEL 0x00800000
+#define V0_BM_GPMI_CTRL1_CE2_SEL 0x00400000
+#define V0_BM_GPMI_CTRL1_CE1_SEL 0x00200000
+#define V0_BM_GPMI_CTRL1_CE0_SEL 0x00100000
+#define V0_BM_GPMI_CTRL1_GANGED_RDYBUSY 0x00080000
+#define V0_BM_GPMI_CTRL1_GPMI_MODE 0x00000001
+#define V0_BP_GPMI_CTRL1_GPMI_MODE 0
+#define V0_BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
+#define V0_BM_GPMI_CTRL1_DEV_RESET 0x00000008
+#define V0_BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
+#define V0_BM_GPMI_CTRL1_DEV_IRQ 0x00000400
+#define V0_BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
+#define V0_BP_GPMI_CTRL1_RDN_DELAY 12
+#define V0_BM_GPMI_CTRL1_BCH_MODE 0x00040000
+#define V0_BP_GPMI_CTRL1_DLL_ENABLE 17
+#define V0_BM_GPMI_CTRL1_DLL_ENABLE 0x00020000
+#define V0_BP_GPMI_CTRL1_HALF_PERIOD 16
+#define V0_BM_GPMI_CTRL1_HALF_PERIOD 0x00010000
+#define V0_BP_GPMI_CTRL1_RDN_DELAY 12
+#define V0_BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
+#define V0_BF_GPMI_CTRL1_RDN_DELAY(v) \
+ (((v) << 12) & V0_BM_GPMI_CTRL1_RDN_DELAY)
+#define V0_BM_GPMI_CTRL1_DMA2ECC_MODE 0x00000800
+#define V0_BM_GPMI_CTRL1_DEV_IRQ 0x00000400
+#define V0_BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
+#define V0_BM_GPMI_CTRL1_BURST_EN 0x00000100
+#define V0_BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY3 0x00000080
+#define V0_BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY2 0x00000040
+#define V0_BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY1 0x00000020
+#define V0_BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY0 0x00000010
+#define V0_BM_GPMI_CTRL1_DEV_RESET 0x00000008
+#define V0_BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0
+#define V0_BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1
+#define V0_BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
+#define V0_BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0
+#define V0_BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1
+#define V0_BM_GPMI_CTRL1_CAMERA_MODE 0x00000002
+#define V0_BM_GPMI_CTRL1_GPMI_MODE 0x00000001
+#define V0_BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0
+#define V0_BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_TIMING0 (0x00000070)
+
+#define V0_BP_GPMI_TIMING0_RSVD1 24
+#define V0_BM_GPMI_TIMING0_RSVD1 0xFF000000
+#define V0_BF_GPMI_TIMING0_RSVD1(v) \
+ (((v) << 24) & V0_BM_GPMI_TIMING0_RSVD1)
+#define V0_BP_GPMI_TIMING0_ADDRESS_SETUP 16
+#define V0_BM_GPMI_TIMING0_ADDRESS_SETUP 0x00FF0000
+#define V0_BF_GPMI_TIMING0_ADDRESS_SETUP(v) \
+ (((v) << 16) & V0_BM_GPMI_TIMING0_ADDRESS_SETUP)
+#define V0_BP_GPMI_TIMING0_DATA_HOLD 8
+#define V0_BM_GPMI_TIMING0_DATA_HOLD 0x0000FF00
+#define V0_BF_GPMI_TIMING0_DATA_HOLD(v) \
+ (((v) << 8) & V0_BM_GPMI_TIMING0_DATA_HOLD)
+#define V0_BP_GPMI_TIMING0_DATA_SETUP 0
+#define V0_BM_GPMI_TIMING0_DATA_SETUP 0x000000FF
+#define V0_BF_GPMI_TIMING0_DATA_SETUP(v) \
+ (((v) << 0) & V0_BM_GPMI_TIMING0_DATA_SETUP)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_TIMING1 (0x00000080)
+
+#define V0_BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 16
+#define V0_BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 0xFFFF0000
+#define V0_BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(v) \
+ (((v) << 16) & V0_BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT)
+#define V0_BP_GPMI_TIMING1_RSVD1 0
+#define V0_BM_GPMI_TIMING1_RSVD1 0x0000FFFF
+#define V0_BF_GPMI_TIMING1_RSVD1(v) \
+ (((v) << 0) & V0_BM_GPMI_TIMING1_RSVD1)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_TIMING2 (0x00000090)
+
+#define V0_BP_GPMI_TIMING2_UDMA_TRP 24
+#define V0_BM_GPMI_TIMING2_UDMA_TRP 0xFF000000
+#define V0_BF_GPMI_TIMING2_UDMA_TRP(v) \
+ (((v) << 24) & V0_BM_GPMI_TIMING2_UDMA_TRP)
+#define V0_BP_GPMI_TIMING2_UDMA_ENV 16
+#define V0_BM_GPMI_TIMING2_UDMA_ENV 0x00FF0000
+#define V0_BF_GPMI_TIMING2_UDMA_ENV(v) \
+ (((v) << 16) & V0_BM_GPMI_TIMING2_UDMA_ENV)
+#define V0_BP_GPMI_TIMING2_UDMA_HOLD 8
+#define V0_BM_GPMI_TIMING2_UDMA_HOLD 0x0000FF00
+#define V0_BF_GPMI_TIMING2_UDMA_HOLD(v) \
+ (((v) << 8) & V0_BM_GPMI_TIMING2_UDMA_HOLD)
+#define V0_BP_GPMI_TIMING2_UDMA_SETUP 0
+#define V0_BM_GPMI_TIMING2_UDMA_SETUP 0x000000FF
+#define V0_BF_GPMI_TIMING2_UDMA_SETUP(v) \
+ (((v) << 0) & V0_BM_GPMI_TIMING2_UDMA_SETUP)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_DATA (0x000000a0)
+
+#define V0_BP_GPMI_DATA_DATA 0
+#define V0_BM_GPMI_DATA_DATA 0xFFFFFFFF
+#define V0_BF_GPMI_DATA_DATA(v) (v)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_STAT (0x000000b0)
+
+#define V0_BM_GPMI_STAT_PRESENT 0x80000000
+#define V0_BV_GPMI_STAT_PRESENT__UNAVAILABLE 0x0
+#define V0_BV_GPMI_STAT_PRESENT__AVAILABLE 0x1
+#define V0_BP_GPMI_STAT_RSVD1 12
+#define V0_BM_GPMI_STAT_RSVD1 0x7FFFF000
+#define V0_BF_GPMI_STAT_RSVD1(v) \
+ (((v) << 12) & V0_BM_GPMI_STAT_RSVD1)
+#define V0_BP_GPMI_STAT_RDY_TIMEOUT 8
+#define V0_BM_GPMI_STAT_RDY_TIMEOUT 0x00000F00
+#define V0_BF_GPMI_STAT_RDY_TIMEOUT(v) \
+ (((v) << 8) & V0_BM_GPMI_STAT_RDY_TIMEOUT)
+#define V0_BM_GPMI_STAT_ATA_IRQ 0x00000080
+#define V0_BM_GPMI_STAT_INVALID_BUFFER_MASK 0x00000040
+#define V0_BM_GPMI_STAT_FIFO_EMPTY 0x00000020
+#define V0_BV_GPMI_STAT_FIFO_EMPTY__NOT_EMPTY 0x0
+#define V0_BV_GPMI_STAT_FIFO_EMPTY__EMPTY 0x1
+#define V0_BM_GPMI_STAT_FIFO_FULL 0x00000010
+#define V0_BV_GPMI_STAT_FIFO_FULL__NOT_FULL 0x0
+#define V0_BV_GPMI_STAT_FIFO_FULL__FULL 0x1
+#define V0_BM_GPMI_STAT_DEV3_ERROR 0x00000008
+#define V0_BM_GPMI_STAT_DEV2_ERROR 0x00000004
+#define V0_BM_GPMI_STAT_DEV1_ERROR 0x00000002
+#define V0_BM_GPMI_STAT_DEV0_ERROR 0x00000001
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_DEBUG (0x000000c0)
+
+#define V0_BM_GPMI_DEBUG_READY3 0x80000000
+#define V0_BM_GPMI_DEBUG_READY2 0x40000000
+#define V0_BM_GPMI_DEBUG_READY1 0x20000000
+#define V0_BM_GPMI_DEBUG_READY0 0x10000000
+#define V0_BM_GPMI_DEBUG_WAIT_FOR_READY_END3 0x08000000
+#define V0_BM_GPMI_DEBUG_WAIT_FOR_READY_END2 0x04000000
+#define V0_BM_GPMI_DEBUG_WAIT_FOR_READY_END1 0x02000000
+#define V0_BM_GPMI_DEBUG_WAIT_FOR_READY_END0 0x01000000
+#define V0_BM_GPMI_DEBUG_SENSE3 0x00800000
+#define V0_BM_GPMI_DEBUG_SENSE2 0x00400000
+#define V0_BM_GPMI_DEBUG_SENSE1 0x00200000
+#define V0_BM_GPMI_DEBUG_SENSE0 0x00100000
+#define V0_BM_GPMI_DEBUG_DMAREQ3 0x00080000
+#define V0_BM_GPMI_DEBUG_DMAREQ2 0x00040000
+#define V0_BM_GPMI_DEBUG_DMAREQ1 0x00020000
+#define V0_BM_GPMI_DEBUG_DMAREQ0 0x00010000
+#define V0_BP_GPMI_DEBUG_CMD_END 12
+#define V0_BM_GPMI_DEBUG_CMD_END 0x0000F000
+#define V0_BF_GPMI_DEBUG_CMD_END(v) \
+ (((v) << 12) & V0_BM_GPMI_DEBUG_CMD_END)
+#define V0_BP_GPMI_DEBUG_UDMA_STATE 8
+#define V0_BM_GPMI_DEBUG_UDMA_STATE 0x00000F00
+#define V0_BF_GPMI_DEBUG_UDMA_STATE(v) \
+ (((v) << 8) & V0_BM_GPMI_DEBUG_UDMA_STATE)
+#define V0_BM_GPMI_DEBUG_BUSY 0x00000080
+#define V0_BV_GPMI_DEBUG_BUSY__DISABLED 0x0
+#define V0_BV_GPMI_DEBUG_BUSY__ENABLED 0x1
+#define V0_BP_GPMI_DEBUG_PIN_STATE 4
+#define V0_BM_GPMI_DEBUG_PIN_STATE 0x00000070
+#define V0_BF_GPMI_DEBUG_PIN_STATE(v) \
+ (((v) << 4) & V0_BM_GPMI_DEBUG_PIN_STATE)
+#define V0_BV_GPMI_DEBUG_PIN_STATE__PSM_IDLE 0x0
+#define V0_BV_GPMI_DEBUG_PIN_STATE__PSM_BYTCNT 0x1
+#define V0_BV_GPMI_DEBUG_PIN_STATE__PSM_ADDR 0x2
+#define V0_BV_GPMI_DEBUG_PIN_STATE__PSM_STALL 0x3
+#define V0_BV_GPMI_DEBUG_PIN_STATE__PSM_STROBE 0x4
+#define V0_BV_GPMI_DEBUG_PIN_STATE__PSM_ATARDY 0x5
+#define V0_BV_GPMI_DEBUG_PIN_STATE__PSM_DHOLD 0x6
+#define V0_BV_GPMI_DEBUG_PIN_STATE__PSM_DONE 0x7
+#define V0_BP_GPMI_DEBUG_MAIN_STATE 0
+#define V0_BM_GPMI_DEBUG_MAIN_STATE 0x0000000F
+#define V0_BF_GPMI_DEBUG_MAIN_STATE(v) \
+ (((v) << 0) & V0_BM_GPMI_DEBUG_MAIN_STATE)
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_IDLE 0x0
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_BYTCNT 0x1
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFE 0x2
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFR 0x3
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_DMAREQ 0x4
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_DMAACK 0x5
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFF 0x6
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_LDFIFO 0x7
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_LDDMAR 0x8
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_RDCMP 0x9
+#define V0_BV_GPMI_DEBUG_MAIN_STATE__MSM_DONE 0xA
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_VERSION (0x000000d0)
+
+#define V0_BP_GPMI_VERSION_MAJOR 24
+#define V0_BM_GPMI_VERSION_MAJOR 0xFF000000
+#define V0_BF_GPMI_VERSION_MAJOR(v) (((v) << 24) & V0_BM_GPMI_VERSION_MAJOR)
+#define V0_BP_GPMI_VERSION_MINOR 16
+#define V0_BM_GPMI_VERSION_MINOR 0x00FF0000
+#define V0_BF_GPMI_VERSION_MINOR(v) (((v) << 16) & V0_BM_GPMI_VERSION_MINOR)
+#define V0_BP_GPMI_VERSION_STEP 0
+#define V0_BM_GPMI_VERSION_STEP 0x0000FFFF
+#define V0_BF_GPMI_VERSION_STEP(v) (((v) << 0) & V0_BM_GPMI_VERSION_STEP)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_DEBUG2 (0x000000e0)
+
+#define V0_BP_GPMI_DEBUG2_RSVD1 16
+#define V0_BM_GPMI_DEBUG2_RSVD1 0xFFFF0000
+#define V0_BF_GPMI_DEBUG2_RSVD1(v) (((v) << 16) & V0_BM_GPMI_DEBUG2_RSVD1)
+#define V0_BP_GPMI_DEBUG2_SYND2GPMI_BE 12
+#define V0_BM_GPMI_DEBUG2_SYND2GPMI_BE 0x0000F000
+#define V0_BF_GPMI_DEBUG2_SYND2GPMI_BE(v) \
+ (((v) << 12) & V0_BM_GPMI_DEBUG2_SYND2GPMI_BE)
+#define V0_BM_GPMI_DEBUG2_GPMI2SYND_VALID 0x00000800
+#define V0_BM_GPMI_DEBUG2_GPMI2SYND_READY 0x00000400
+#define V0_BM_GPMI_DEBUG2_SYND2GPMI_VALID 0x00000200
+#define V0_BM_GPMI_DEBUG2_SYND2GPMI_READY 0x00000100
+#define V0_BM_GPMI_DEBUG2_VIEW_DELAYED_RDN 0x00000080
+#define V0_BM_GPMI_DEBUG2_UPDATE_WINDOW 0x00000040
+#define V0_BP_GPMI_DEBUG2_RDN_TAP 0
+#define V0_BM_GPMI_DEBUG2_RDN_TAP 0x0000003F
+#define V0_BF_GPMI_DEBUG2_RDN_TAP(v) (((v) << 0) & V0_BM_GPMI_DEBUG2_RDN_TAP)
+
+/*============================================================================*/
+
+#define V0_HW_GPMI_DEBUG3 (0x000000f0)
+
+#define V0_BP_GPMI_DEBUG3_APB_WORD_CNTR 16
+#define V0_BM_GPMI_DEBUG3_APB_WORD_CNTR 0xFFFF0000
+#define V0_BF_GPMI_DEBUG3_APB_WORD_CNTR(v) \
+ (((v) << 16) & V0_BM_GPMI_DEBUG3_APB_WORD_CNTR)
+#define V0_BP_GPMI_DEBUG3_DEV_WORD_CNTR 0
+#define V0_BM_GPMI_DEBUG3_DEV_WORD_CNTR 0x0000FFFF
+#define V0_BF_GPMI_DEBUG3_DEV_WORD_CNTR(v) \
+ (((v) << 0) & V0_BM_GPMI_DEBUG3_DEV_WORD_CNTR)
+
+/*============================================================================*/
+#endif
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-bch-regs.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-bch-regs.h
new file mode 100644
index 000000000000..df003742715b
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-bch-regs.h
@@ -0,0 +1,557 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * 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
+ *
+ * Xml Revision: 2.5
+ * Template revision: 26195
+ */
+
+#ifndef __V1_GPMI_NFC_V1_BCH_REGS_H
+#define __V1_GPMI_NFC_V1_BCH_REGS_H
+
+/*============================================================================*/
+
+#define V1_HW_BCH_CTRL (0x00000000)
+#define V1_HW_BCH_CTRL_SET (0x00000004)
+#define V1_HW_BCH_CTRL_CLR (0x00000008)
+#define V1_HW_BCH_CTRL_TOG (0x0000000c)
+
+#define V1_BM_BCH_CTRL_SFTRST 0x80000000
+#define V1_BV_BCH_CTRL_SFTRST__RUN 0x0
+#define V1_BV_BCH_CTRL_SFTRST__RESET 0x1
+#define V1_BM_BCH_CTRL_CLKGATE 0x40000000
+#define V1_BV_BCH_CTRL_CLKGATE__RUN 0x0
+#define V1_BV_BCH_CTRL_CLKGATE__NO_CLKS 0x1
+#define V1_BP_BCH_CTRL_RSVD5 23
+#define V1_BM_BCH_CTRL_RSVD5 0x3F800000
+#define V1_BF_BCH_CTRL_RSVD5(v) \
+ (((v) << 23) & V1_BM_BCH_CTRL_RSVD5)
+#define V1_BM_BCH_CTRL_DEBUGSYNDROME 0x00400000
+#define V1_BP_BCH_CTRL_RSVD4 20
+#define V1_BM_BCH_CTRL_RSVD4 0x00300000
+#define V1_BF_BCH_CTRL_RSVD4(v) \
+ (((v) << 20) & V1_BM_BCH_CTRL_RSVD4)
+#define V1_BP_BCH_CTRL_M2M_LAYOUT 18
+#define V1_BM_BCH_CTRL_M2M_LAYOUT 0x000C0000
+#define V1_BF_BCH_CTRL_M2M_LAYOUT(v) \
+ (((v) << 18) & V1_BM_BCH_CTRL_M2M_LAYOUT)
+#define V1_BM_BCH_CTRL_M2M_ENCODE 0x00020000
+#define V1_BM_BCH_CTRL_M2M_ENABLE 0x00010000
+#define V1_BP_BCH_CTRL_RSVD3 11
+#define V1_BM_BCH_CTRL_RSVD3 0x0000F800
+#define V1_BF_BCH_CTRL_RSVD3(v) \
+ (((v) << 11) & V1_BM_BCH_CTRL_RSVD3)
+#define V1_BM_BCH_CTRL_DEBUG_STALL_IRQ_EN 0x00000400
+#define V1_BM_BCH_CTRL_RSVD2 0x00000200
+#define V1_BM_BCH_CTRL_COMPLETE_IRQ_EN 0x00000100
+#define V1_BP_BCH_CTRL_RSVD1 4
+#define V1_BM_BCH_CTRL_RSVD1 0x000000F0
+#define V1_BF_BCH_CTRL_RSVD1(v) \
+ (((v) << 4) & V1_BM_BCH_CTRL_RSVD1)
+#define V1_BM_BCH_CTRL_BM_ERROR_IRQ 0x00000008
+#define V1_BM_BCH_CTRL_DEBUG_STALL_IRQ 0x00000004
+#define V1_BM_BCH_CTRL_RSVD0 0x00000002
+#define V1_BM_BCH_CTRL_COMPLETE_IRQ 0x00000001
+
+/*============================================================================*/
+
+#define V1_HW_BCH_STATUS0 (0x00000010)
+
+#define V1_BP_BCH_STATUS0_HANDLE 20
+#define V1_BM_BCH_STATUS0_HANDLE 0xFFF00000
+#define V1_BF_BCH_STATUS0_HANDLE(v) \
+ (((v) << 20) & V1_BM_BCH_STATUS0_HANDLE)
+#define V1_BP_BCH_STATUS0_COMPLETED_CE 16
+#define V1_BM_BCH_STATUS0_COMPLETED_CE 0x000F0000
+#define V1_BF_BCH_STATUS0_COMPLETED_CE(v) \
+ (((v) << 16) & V1_BM_BCH_STATUS0_COMPLETED_CE)
+#define V1_BP_BCH_STATUS0_STATUS_BLK0 8
+#define V1_BM_BCH_STATUS0_STATUS_BLK0 0x0000FF00
+#define V1_BF_BCH_STATUS0_STATUS_BLK0(v) \
+ (((v) << 8) & V1_BM_BCH_STATUS0_STATUS_BLK0)
+#define V1_BV_BCH_STATUS0_STATUS_BLK0__ZERO 0x00
+#define V1_BV_BCH_STATUS0_STATUS_BLK0__ERROR1 0x01
+#define V1_BV_BCH_STATUS0_STATUS_BLK0__ERROR2 0x02
+#define V1_BV_BCH_STATUS0_STATUS_BLK0__ERROR3 0x03
+#define V1_BV_BCH_STATUS0_STATUS_BLK0__ERROR4 0x04
+#define V1_BV_BCH_STATUS0_STATUS_BLK0__UNCORRECTABLE 0xFE
+#define V1_BV_BCH_STATUS0_STATUS_BLK0__ERASED 0xFF
+#define V1_BP_BCH_STATUS0_RSVD1 5
+#define V1_BM_BCH_STATUS0_RSVD1 0x000000E0
+#define V1_BF_BCH_STATUS0_RSVD1(v) \
+ (((v) << 5) & V1_BM_BCH_STATUS0_RSVD1)
+#define V1_BM_BCH_STATUS0_ALLONES 0x00000010
+#define V1_BM_BCH_STATUS0_CORRECTED 0x00000008
+#define V1_BM_BCH_STATUS0_UNCORRECTABLE 0x00000004
+#define V1_BP_BCH_STATUS0_RSVD0 0
+#define V1_BM_BCH_STATUS0_RSVD0 0x00000003
+#define V1_BF_BCH_STATUS0_RSVD0(v) \
+ (((v) << 0) & V1_BM_BCH_STATUS0_RSVD0)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_MODE (0x00000020)
+
+#define V1_BP_BCH_MODE_RSVD 8
+#define V1_BM_BCH_MODE_RSVD 0xFFFFFF00
+#define V1_BF_BCH_MODE_RSVD(v) \
+ (((v) << 8) & V1_BM_BCH_MODE_RSVD)
+#define V1_BP_BCH_MODE_ERASE_THRESHOLD 0
+#define V1_BM_BCH_MODE_ERASE_THRESHOLD 0x000000FF
+#define V1_BF_BCH_MODE_ERASE_THRESHOLD(v) \
+ (((v) << 0) & V1_BM_BCH_MODE_ERASE_THRESHOLD)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_ENCODEPTR (0x00000030)
+
+#define V1_BP_BCH_ENCODEPTR_ADDR 0
+#define V1_BM_BCH_ENCODEPTR_ADDR 0xFFFFFFFF
+#define V1_BF_BCH_ENCODEPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_DATAPTR (0x00000040)
+
+#define V1_BP_BCH_DATAPTR_ADDR 0
+#define V1_BM_BCH_DATAPTR_ADDR 0xFFFFFFFF
+#define V1_BF_BCH_DATAPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_METAPTR (0x00000050)
+
+#define V1_BP_BCH_METAPTR_ADDR 0
+#define V1_BM_BCH_METAPTR_ADDR 0xFFFFFFFF
+#define V1_BF_BCH_METAPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_LAYOUTSELECT (0x00000070)
+
+#define V1_BP_BCH_LAYOUTSELECT_CS15_SELECT 30
+#define V1_BM_BCH_LAYOUTSELECT_CS15_SELECT 0xC0000000
+#define V1_BF_BCH_LAYOUTSELECT_CS15_SELECT(v) \
+ (((v) << 30) & V1_BM_BCH_LAYOUTSELECT_CS15_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS14_SELECT 28
+#define V1_BM_BCH_LAYOUTSELECT_CS14_SELECT 0x30000000
+#define V1_BF_BCH_LAYOUTSELECT_CS14_SELECT(v) \
+ (((v) << 28) & V1_BM_BCH_LAYOUTSELECT_CS14_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS13_SELECT 26
+#define V1_BM_BCH_LAYOUTSELECT_CS13_SELECT 0x0C000000
+#define V1_BF_BCH_LAYOUTSELECT_CS13_SELECT(v) \
+ (((v) << 26) & V1_BM_BCH_LAYOUTSELECT_CS13_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS12_SELECT 24
+#define V1_BM_BCH_LAYOUTSELECT_CS12_SELECT 0x03000000
+#define V1_BF_BCH_LAYOUTSELECT_CS12_SELECT(v) \
+ (((v) << 24) & V1_BM_BCH_LAYOUTSELECT_CS12_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS11_SELECT 22
+#define V1_BM_BCH_LAYOUTSELECT_CS11_SELECT 0x00C00000
+#define V1_BF_BCH_LAYOUTSELECT_CS11_SELECT(v) \
+ (((v) << 22) & V1_BM_BCH_LAYOUTSELECT_CS11_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS10_SELECT 20
+#define V1_BM_BCH_LAYOUTSELECT_CS10_SELECT 0x00300000
+#define V1_BF_BCH_LAYOUTSELECT_CS10_SELECT(v) \
+ (((v) << 20) & V1_BM_BCH_LAYOUTSELECT_CS10_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS9_SELECT 18
+#define V1_BM_BCH_LAYOUTSELECT_CS9_SELECT 0x000C0000
+#define V1_BF_BCH_LAYOUTSELECT_CS9_SELECT(v) \
+ (((v) << 18) & V1_BM_BCH_LAYOUTSELECT_CS9_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS8_SELECT 16
+#define V1_BM_BCH_LAYOUTSELECT_CS8_SELECT 0x00030000
+#define V1_BF_BCH_LAYOUTSELECT_CS8_SELECT(v) \
+ (((v) << 16) & V1_BM_BCH_LAYOUTSELECT_CS8_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS7_SELECT 14
+#define V1_BM_BCH_LAYOUTSELECT_CS7_SELECT 0x0000C000
+#define V1_BF_BCH_LAYOUTSELECT_CS7_SELECT(v) \
+ (((v) << 14) & V1_BM_BCH_LAYOUTSELECT_CS7_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS6_SELECT 12
+#define V1_BM_BCH_LAYOUTSELECT_CS6_SELECT 0x00003000
+#define V1_BF_BCH_LAYOUTSELECT_CS6_SELECT(v) \
+ (((v) << 12) & V1_BM_BCH_LAYOUTSELECT_CS6_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS5_SELECT 10
+#define V1_BM_BCH_LAYOUTSELECT_CS5_SELECT 0x00000C00
+#define V1_BF_BCH_LAYOUTSELECT_CS5_SELECT(v) \
+ (((v) << 10) & V1_BM_BCH_LAYOUTSELECT_CS5_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS4_SELECT 8
+#define V1_BM_BCH_LAYOUTSELECT_CS4_SELECT 0x00000300
+#define V1_BF_BCH_LAYOUTSELECT_CS4_SELECT(v) \
+ (((v) << 8) & V1_BM_BCH_LAYOUTSELECT_CS4_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS3_SELECT 6
+#define V1_BM_BCH_LAYOUTSELECT_CS3_SELECT 0x000000C0
+#define V1_BF_BCH_LAYOUTSELECT_CS3_SELECT(v) \
+ (((v) << 6) & V1_BM_BCH_LAYOUTSELECT_CS3_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS2_SELECT 4
+#define V1_BM_BCH_LAYOUTSELECT_CS2_SELECT 0x00000030
+#define V1_BF_BCH_LAYOUTSELECT_CS2_SELECT(v) \
+ (((v) << 4) & V1_BM_BCH_LAYOUTSELECT_CS2_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS1_SELECT 2
+#define V1_BM_BCH_LAYOUTSELECT_CS1_SELECT 0x0000000C
+#define V1_BF_BCH_LAYOUTSELECT_CS1_SELECT(v) \
+ (((v) << 2) & V1_BM_BCH_LAYOUTSELECT_CS1_SELECT)
+#define V1_BP_BCH_LAYOUTSELECT_CS0_SELECT 0
+#define V1_BM_BCH_LAYOUTSELECT_CS0_SELECT 0x00000003
+#define V1_BF_BCH_LAYOUTSELECT_CS0_SELECT(v) \
+ (((v) << 0) & V1_BM_BCH_LAYOUTSELECT_CS0_SELECT)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_FLASH0LAYOUT0 (0x00000080)
+
+#define V1_BP_BCH_FLASH0LAYOUT0_NBLOCKS 24
+#define V1_BM_BCH_FLASH0LAYOUT0_NBLOCKS 0xFF000000
+#define V1_BF_BCH_FLASH0LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & V1_BM_BCH_FLASH0LAYOUT0_NBLOCKS)
+#define V1_BP_BCH_FLASH0LAYOUT0_META_SIZE 16
+#define V1_BM_BCH_FLASH0LAYOUT0_META_SIZE 0x00FF0000
+#define V1_BF_BCH_FLASH0LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & V1_BM_BCH_FLASH0LAYOUT0_META_SIZE)
+#define V1_BP_BCH_FLASH0LAYOUT0_ECC0 12
+#define V1_BM_BCH_FLASH0LAYOUT0_ECC0 0x0000F000
+#define V1_BF_BCH_FLASH0LAYOUT0_ECC0(v) \
+ (((v) << 12) & V1_BM_BCH_FLASH0LAYOUT0_ECC0)
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__NONE 0x0
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC2 0x1
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC4 0x2
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC6 0x3
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC8 0x4
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC10 0x5
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC12 0x6
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC14 0x7
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC16 0x8
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC18 0x9
+#define V1_BV_BCH_FLASH0LAYOUT0_ECC0__ECC20 0xA
+#define V1_BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0
+#define V1_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE 0x00000FFF
+#define V1_BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & V1_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_FLASH0LAYOUT1 (0x00000090)
+
+#define V1_BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16
+#define V1_BM_BCH_FLASH0LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define V1_BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & V1_BM_BCH_FLASH0LAYOUT1_PAGE_SIZE)
+#define V1_BP_BCH_FLASH0LAYOUT1_ECCN 12
+#define V1_BM_BCH_FLASH0LAYOUT1_ECCN 0x0000F000
+#define V1_BF_BCH_FLASH0LAYOUT1_ECCN(v) \
+ (((v) << 12) & V1_BM_BCH_FLASH0LAYOUT1_ECCN)
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__NONE 0x0
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC2 0x1
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC4 0x2
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC6 0x3
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC8 0x4
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC10 0x5
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC12 0x6
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC14 0x7
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC16 0x8
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC18 0x9
+#define V1_BV_BCH_FLASH0LAYOUT1_ECCN__ECC20 0xA
+#define V1_BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0
+#define V1_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE 0x00000FFF
+#define V1_BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & V1_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_FLASH1LAYOUT0 (0x000000a0)
+
+#define V1_BP_BCH_FLASH1LAYOUT0_NBLOCKS 24
+#define V1_BM_BCH_FLASH1LAYOUT0_NBLOCKS 0xFF000000
+#define V1_BF_BCH_FLASH1LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & V1_BM_BCH_FLASH1LAYOUT0_NBLOCKS)
+#define V1_BP_BCH_FLASH1LAYOUT0_META_SIZE 16
+#define V1_BM_BCH_FLASH1LAYOUT0_META_SIZE 0x00FF0000
+#define V1_BF_BCH_FLASH1LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & V1_BM_BCH_FLASH1LAYOUT0_META_SIZE)
+#define V1_BP_BCH_FLASH1LAYOUT0_ECC0 12
+#define V1_BM_BCH_FLASH1LAYOUT0_ECC0 0x0000F000
+#define V1_BF_BCH_FLASH1LAYOUT0_ECC0(v) \
+ (((v) << 12) & V1_BM_BCH_FLASH1LAYOUT0_ECC0)
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__NONE 0x0
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC2 0x1
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC4 0x2
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC6 0x3
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC8 0x4
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC10 0x5
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC12 0x6
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC14 0x7
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC16 0x8
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC18 0x9
+#define V1_BV_BCH_FLASH1LAYOUT0_ECC0__ECC20 0xA
+#define V1_BP_BCH_FLASH1LAYOUT0_DATA0_SIZE 0
+#define V1_BM_BCH_FLASH1LAYOUT0_DATA0_SIZE 0x00000FFF
+#define V1_BF_BCH_FLASH1LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & V1_BM_BCH_FLASH1LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_FLASH1LAYOUT1 (0x000000b0)
+
+#define V1_BP_BCH_FLASH1LAYOUT1_PAGE_SIZE 16
+#define V1_BM_BCH_FLASH1LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define V1_BF_BCH_FLASH1LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & V1_BM_BCH_FLASH1LAYOUT1_PAGE_SIZE)
+#define V1_BP_BCH_FLASH1LAYOUT1_ECCN 12
+#define V1_BM_BCH_FLASH1LAYOUT1_ECCN 0x0000F000
+#define V1_BF_BCH_FLASH1LAYOUT1_ECCN(v) \
+ (((v) << 12) & V1_BM_BCH_FLASH1LAYOUT1_ECCN)
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__NONE 0x0
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC2 0x1
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC4 0x2
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC6 0x3
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC8 0x4
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC10 0x5
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC12 0x6
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC14 0x7
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC16 0x8
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC18 0x9
+#define V1_BV_BCH_FLASH1LAYOUT1_ECCN__ECC20 0xA
+#define V1_BP_BCH_FLASH1LAYOUT1_DATAN_SIZE 0
+#define V1_BM_BCH_FLASH1LAYOUT1_DATAN_SIZE 0x00000FFF
+#define V1_BF_BCH_FLASH1LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & V1_BM_BCH_FLASH1LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_FLASH2LAYOUT0 (0x000000c0)
+
+#define V1_BP_BCH_FLASH2LAYOUT0_NBLOCKS 24
+#define V1_BM_BCH_FLASH2LAYOUT0_NBLOCKS 0xFF000000
+#define V1_BF_BCH_FLASH2LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & V1_BM_BCH_FLASH2LAYOUT0_NBLOCKS)
+#define V1_BP_BCH_FLASH2LAYOUT0_META_SIZE 16
+#define V1_BM_BCH_FLASH2LAYOUT0_META_SIZE 0x00FF0000
+#define V1_BF_BCH_FLASH2LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & V1_BM_BCH_FLASH2LAYOUT0_META_SIZE)
+#define V1_BP_BCH_FLASH2LAYOUT0_ECC0 12
+#define V1_BM_BCH_FLASH2LAYOUT0_ECC0 0x0000F000
+#define V1_BF_BCH_FLASH2LAYOUT0_ECC0(v) \
+ (((v) << 12) & V1_BM_BCH_FLASH2LAYOUT0_ECC0)
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__NONE 0x0
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC2 0x1
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC4 0x2
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC6 0x3
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC8 0x4
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC10 0x5
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC12 0x6
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC14 0x7
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC16 0x8
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC18 0x9
+#define V1_BV_BCH_FLASH2LAYOUT0_ECC0__ECC20 0xA
+#define V1_BP_BCH_FLASH2LAYOUT0_DATA0_SIZE 0
+#define V1_BM_BCH_FLASH2LAYOUT0_DATA0_SIZE 0x00000FFF
+#define V1_BF_BCH_FLASH2LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & V1_BM_BCH_FLASH2LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_FLASH2LAYOUT1 (0x000000d0)
+
+#define V1_BP_BCH_FLASH2LAYOUT1_PAGE_SIZE 16
+#define V1_BM_BCH_FLASH2LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define V1_BF_BCH_FLASH2LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & V1_BM_BCH_FLASH2LAYOUT1_PAGE_SIZE)
+#define V1_BP_BCH_FLASH2LAYOUT1_ECCN 12
+#define V1_BM_BCH_FLASH2LAYOUT1_ECCN 0x0000F000
+#define V1_BF_BCH_FLASH2LAYOUT1_ECCN(v) \
+ (((v) << 12) & V1_BM_BCH_FLASH2LAYOUT1_ECCN)
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__NONE 0x0
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC2 0x1
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC4 0x2
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC6 0x3
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC8 0x4
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC10 0x5
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC12 0x6
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC14 0x7
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC16 0x8
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC18 0x9
+#define V1_BV_BCH_FLASH2LAYOUT1_ECCN__ECC20 0xA
+#define V1_BP_BCH_FLASH2LAYOUT1_DATAN_SIZE 0
+#define V1_BM_BCH_FLASH2LAYOUT1_DATAN_SIZE 0x00000FFF
+#define V1_BF_BCH_FLASH2LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & V1_BM_BCH_FLASH2LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_FLASH3LAYOUT0 (0x000000e0)
+
+#define V1_BP_BCH_FLASH3LAYOUT0_NBLOCKS 24
+#define V1_BM_BCH_FLASH3LAYOUT0_NBLOCKS 0xFF000000
+#define V1_BF_BCH_FLASH3LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & V1_BM_BCH_FLASH3LAYOUT0_NBLOCKS)
+#define V1_BP_BCH_FLASH3LAYOUT0_META_SIZE 16
+#define V1_BM_BCH_FLASH3LAYOUT0_META_SIZE 0x00FF0000
+#define V1_BF_BCH_FLASH3LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & V1_BM_BCH_FLASH3LAYOUT0_META_SIZE)
+#define V1_BP_BCH_FLASH3LAYOUT0_ECC0 12
+#define V1_BM_BCH_FLASH3LAYOUT0_ECC0 0x0000F000
+#define V1_BF_BCH_FLASH3LAYOUT0_ECC0(v) \
+ (((v) << 12) & V1_BM_BCH_FLASH3LAYOUT0_ECC0)
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__NONE 0x0
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC2 0x1
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC4 0x2
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC6 0x3
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC8 0x4
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC10 0x5
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC12 0x6
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC14 0x7
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC16 0x8
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC18 0x9
+#define V1_BV_BCH_FLASH3LAYOUT0_ECC0__ECC20 0xA
+#define V1_BP_BCH_FLASH3LAYOUT0_DATA0_SIZE 0
+#define V1_BM_BCH_FLASH3LAYOUT0_DATA0_SIZE 0x00000FFF
+#define V1_BF_BCH_FLASH3LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & V1_BM_BCH_FLASH3LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_FLASH3LAYOUT1 (0x000000f0)
+
+#define V1_BP_BCH_FLASH3LAYOUT1_PAGE_SIZE 16
+#define V1_BM_BCH_FLASH3LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define V1_BF_BCH_FLASH3LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & V1_BM_BCH_FLASH3LAYOUT1_PAGE_SIZE)
+#define V1_BP_BCH_FLASH3LAYOUT1_ECCN 12
+#define V1_BM_BCH_FLASH3LAYOUT1_ECCN 0x0000F000
+#define V1_BF_BCH_FLASH3LAYOUT1_ECCN(v) \
+ (((v) << 12) & V1_BM_BCH_FLASH3LAYOUT1_ECCN)
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__NONE 0x0
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC2 0x1
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC4 0x2
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC6 0x3
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC8 0x4
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC10 0x5
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC12 0x6
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC14 0x7
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC16 0x8
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC18 0x9
+#define V1_BV_BCH_FLASH3LAYOUT1_ECCN__ECC20 0xA
+#define V1_BP_BCH_FLASH3LAYOUT1_DATAN_SIZE 0
+#define V1_BM_BCH_FLASH3LAYOUT1_DATAN_SIZE 0x00000FFF
+#define V1_BF_BCH_FLASH3LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & V1_BM_BCH_FLASH3LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_DEBUG0 (0x00000100)
+#define V1_HW_BCH_DEBUG0_SET (0x00000104)
+#define V1_HW_BCH_DEBUG0_CLR (0x00000108)
+#define V1_HW_BCH_DEBUG0_TOG (0x0000010c)
+
+#define V1_BP_BCH_DEBUG0_RSVD1 27
+#define V1_BM_BCH_DEBUG0_RSVD1 0xF8000000
+#define V1_BF_BCH_DEBUG0_RSVD1(v) \
+ (((v) << 27) & V1_BM_BCH_DEBUG0_RSVD1)
+#define V1_BM_BCH_DEBUG0_ROM_BIST_ENABLE 0x04000000
+#define V1_BM_BCH_DEBUG0_ROM_BIST_COMPLETE 0x02000000
+#define V1_BP_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 16
+#define V1_BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 0x01FF0000
+#define V1_BF_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL(v) \
+ (((v) << 16) & V1_BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL)
+#define V1_BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__NORMAL 0x0
+#define V1_BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__TEST_MODE 0x1
+#define V1_BM_BCH_DEBUG0_KES_DEBUG_SHIFT_SYND 0x00008000
+#define V1_BM_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG 0x00004000
+#define V1_BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__DATA 0x1
+#define V1_BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__AUX 0x1
+#define V1_BM_BCH_DEBUG0_KES_DEBUG_MODE4K 0x00002000
+#define V1_BV_BCH_DEBUG0_KES_DEBUG_MODE4K__4k 0x1
+#define V1_BV_BCH_DEBUG0_KES_DEBUG_MODE4K__2k 0x1
+#define V1_BM_BCH_DEBUG0_KES_DEBUG_KICK 0x00001000
+#define V1_BM_BCH_DEBUG0_KES_STANDALONE 0x00000800
+#define V1_BV_BCH_DEBUG0_KES_STANDALONE__NORMAL 0x0
+#define V1_BV_BCH_DEBUG0_KES_STANDALONE__TEST_MODE 0x1
+#define V1_BM_BCH_DEBUG0_KES_DEBUG_STEP 0x00000400
+#define V1_BM_BCH_DEBUG0_KES_DEBUG_STALL 0x00000200
+#define V1_BV_BCH_DEBUG0_KES_DEBUG_STALL__NORMAL 0x0
+#define V1_BV_BCH_DEBUG0_KES_DEBUG_STALL__WAIT 0x1
+#define V1_BM_BCH_DEBUG0_BM_KES_TEST_BYPASS 0x00000100
+#define V1_BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__NORMAL 0x0
+#define V1_BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__TEST_MODE 0x1
+#define V1_BP_BCH_DEBUG0_RSVD0 6
+#define V1_BM_BCH_DEBUG0_RSVD0 0x000000C0
+#define V1_BF_BCH_DEBUG0_RSVD0(v) \
+ (((v) << 6) & V1_BM_BCH_DEBUG0_RSVD0)
+#define V1_BP_BCH_DEBUG0_DEBUG_REG_SELECT 0
+#define V1_BM_BCH_DEBUG0_DEBUG_REG_SELECT 0x0000003F
+#define V1_BF_BCH_DEBUG0_DEBUG_REG_SELECT(v) \
+ (((v) << 0) & V1_BM_BCH_DEBUG0_DEBUG_REG_SELECT)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_DBGKESREAD (0x00000110)
+
+#define V1_BP_BCH_DBGKESREAD_VALUES 0
+#define V1_BM_BCH_DBGKESREAD_VALUES 0xFFFFFFFF
+#define V1_BF_BCH_DBGKESREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_DBGCSFEREAD (0x00000120)
+
+#define V1_BP_BCH_DBGCSFEREAD_VALUES 0
+#define V1_BM_BCH_DBGCSFEREAD_VALUES 0xFFFFFFFF
+#define V1_BF_BCH_DBGCSFEREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_DBGSYNDGENREAD (0x00000130)
+
+#define V1_BP_BCH_DBGSYNDGENREAD_VALUES 0
+#define V1_BM_BCH_DBGSYNDGENREAD_VALUES 0xFFFFFFFF
+#define V1_BF_BCH_DBGSYNDGENREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_DBGAHBMREAD (0x00000140)
+
+#define V1_BP_BCH_DBGAHBMREAD_VALUES 0
+#define V1_BM_BCH_DBGAHBMREAD_VALUES 0xFFFFFFFF
+#define V1_BF_BCH_DBGAHBMREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_BLOCKNAME (0x00000150)
+
+#define V1_BP_BCH_BLOCKNAME_NAME 0
+#define V1_BM_BCH_BLOCKNAME_NAME 0xFFFFFFFF
+#define V1_BF_BCH_BLOCKNAME_NAME(v) (v)
+
+/*============================================================================*/
+
+#define V1_HW_BCH_VERSION (0x00000160)
+
+#define V1_BP_BCH_VERSION_MAJOR 24
+#define V1_BM_BCH_VERSION_MAJOR 0xFF000000
+#define V1_BF_BCH_VERSION_MAJOR(v) \
+ (((v) << 24) & V1_BM_BCH_VERSION_MAJOR)
+#define V1_BP_BCH_VERSION_MINOR 16
+#define V1_BM_BCH_VERSION_MINOR 0x00FF0000
+#define V1_BF_BCH_VERSION_MINOR(v) \
+ (((v) << 16) & V1_BM_BCH_VERSION_MINOR)
+#define V1_BP_BCH_VERSION_STEP 0
+#define V1_BM_BCH_VERSION_STEP 0x0000FFFF
+#define V1_BF_BCH_VERSION_STEP(v) \
+ (((v) << 0) & V1_BM_BCH_VERSION_STEP)
+
+/*============================================================================*/
+
+#endif
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-gpmi-regs.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-gpmi-regs.h
new file mode 100644
index 000000000000..d31c5f23e66f
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-gpmi-regs.h
@@ -0,0 +1,420 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * 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
+ *
+ * Xml Revision: 2.2
+ * Template revision: 26195
+ */
+
+#ifndef __V1_GPMI_NFC_V1_GPMI_REGS_H
+#define __V1_GPMI_NFC_V1_GPMI_REGS_H
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_CTRL0 (0x00000000)
+#define V1_HW_GPMI_CTRL0_SET (0x00000004)
+#define V1_HW_GPMI_CTRL0_CLR (0x00000008)
+#define V1_HW_GPMI_CTRL0_TOG (0x0000000c)
+
+#define V1_BM_GPMI_CTRL0_SFTRST 0x80000000
+#define V1_BV_GPMI_CTRL0_SFTRST__RUN 0x0
+#define V1_BV_GPMI_CTRL0_SFTRST__RESET 0x1
+#define V1_BM_GPMI_CTRL0_CLKGATE 0x40000000
+#define V1_BV_GPMI_CTRL0_CLKGATE__RUN 0x0
+#define V1_BV_GPMI_CTRL0_CLKGATE__NO_CLKS 0x1
+#define V1_BM_GPMI_CTRL0_RUN 0x20000000
+#define V1_BV_GPMI_CTRL0_RUN__IDLE 0x0
+#define V1_BV_GPMI_CTRL0_RUN__BUSY 0x1
+#define V1_BM_GPMI_CTRL0_DEV_IRQ_EN 0x10000000
+#define V1_BM_GPMI_CTRL0_LOCK_CS 0x08000000
+#define V1_BV_GPMI_CTRL0_LOCK_CS__DISABLED 0x0
+#define V1_BV_GPMI_CTRL0_LOCK_CS__ENABLED 0x1
+#define V1_BM_GPMI_CTRL0_UDMA 0x04000000
+#define V1_BV_GPMI_CTRL0_UDMA__DISABLED 0x0
+#define V1_BV_GPMI_CTRL0_UDMA__ENABLED 0x1
+#define V1_BP_GPMI_CTRL0_COMMAND_MODE 24
+#define V1_BM_GPMI_CTRL0_COMMAND_MODE 0x03000000
+#define V1_BF_GPMI_CTRL0_COMMAND_MODE(v) \
+ (((v) << 24) & V1_BM_GPMI_CTRL0_COMMAND_MODE)
+#define V1_BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0
+#define V1_BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1
+#define V1_BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
+#define V1_BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3
+#define V1_BM_GPMI_CTRL0_WORD_LENGTH 0x00800000
+#define V1_BV_GPMI_CTRL0_WORD_LENGTH__16_BIT 0x0
+#define V1_BV_GPMI_CTRL0_WORD_LENGTH__8_BIT 0x1
+#define V1_BP_GPMI_CTRL0_CS 20
+#define V1_BM_GPMI_CTRL0_CS 0x00700000
+#define V1_BF_GPMI_CTRL0_CS(v) \
+ (((v) << 20) & V1_BM_GPMI_CTRL0_CS)
+#define V1_BP_GPMI_CTRL0_ADDRESS 17
+#define V1_BM_GPMI_CTRL0_ADDRESS 0x000E0000
+#define V1_BF_GPMI_CTRL0_ADDRESS(v) \
+ (((v) << 17) & V1_BM_GPMI_CTRL0_ADDRESS)
+#define V1_BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0
+#define V1_BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1
+#define V1_BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2
+#define V1_BM_GPMI_CTRL0_ADDRESS_INCREMENT 0x00010000
+#define V1_BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED 0x0
+#define V1_BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED 0x1
+#define V1_BP_GPMI_CTRL0_XFER_COUNT 0
+#define V1_BM_GPMI_CTRL0_XFER_COUNT 0x0000FFFF
+#define V1_BF_GPMI_CTRL0_XFER_COUNT(v) \
+ (((v) << 0) & V1_BM_GPMI_CTRL0_XFER_COUNT)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_COMPARE (0x00000010)
+
+#define V1_BP_GPMI_COMPARE_MASK 16
+#define V1_BM_GPMI_COMPARE_MASK 0xFFFF0000
+#define V1_BF_GPMI_COMPARE_MASK(v) \
+ (((v) << 16) & V1_BM_GPMI_COMPARE_MASK)
+#define V1_BP_GPMI_COMPARE_REFERENCE 0
+#define V1_BM_GPMI_COMPARE_REFERENCE 0x0000FFFF
+#define V1_BF_GPMI_COMPARE_REFERENCE(v) \
+ (((v) << 0) & V1_BM_GPMI_COMPARE_REFERENCE)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_ECCCTRL (0x00000020)
+#define V1_HW_GPMI_ECCCTRL_SET (0x00000024)
+#define V1_HW_GPMI_ECCCTRL_CLR (0x00000028)
+#define V1_HW_GPMI_ECCCTRL_TOG (0x0000002c)
+
+#define V1_BP_GPMI_ECCCTRL_HANDLE 16
+#define V1_BM_GPMI_ECCCTRL_HANDLE 0xFFFF0000
+#define V1_BF_GPMI_ECCCTRL_HANDLE(v) \
+ (((v) << 16) & V1_BM_GPMI_ECCCTRL_HANDLE)
+#define V1_BM_GPMI_ECCCTRL_RSVD2 0x00008000
+#define V1_BP_GPMI_ECCCTRL_ECC_CMD 13
+#define V1_BM_GPMI_ECCCTRL_ECC_CMD 0x00006000
+#define V1_BF_GPMI_ECCCTRL_ECC_CMD(v) \
+ (((v) << 13) & V1_BM_GPMI_ECCCTRL_ECC_CMD)
+#define V1_BV_GPMI_ECCCTRL_ECC_CMD__DECODE 0x0
+#define V1_BV_GPMI_ECCCTRL_ECC_CMD__ENCODE 0x1
+#define V1_BV_GPMI_ECCCTRL_ECC_CMD__RESERVE2 0x2
+#define V1_BV_GPMI_ECCCTRL_ECC_CMD__RESERVE3 0x3
+#define V1_BM_GPMI_ECCCTRL_ENABLE_ECC 0x00001000
+#define V1_BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE 0x1
+#define V1_BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE 0x0
+#define V1_BP_GPMI_ECCCTRL_RSVD1 9
+#define V1_BM_GPMI_ECCCTRL_RSVD1 0x00000E00
+#define V1_BF_GPMI_ECCCTRL_RSVD1(v) \
+ (((v) << 9) & V1_BM_GPMI_ECCCTRL_RSVD1)
+#define V1_BP_GPMI_ECCCTRL_BUFFER_MASK 0
+#define V1_BM_GPMI_ECCCTRL_BUFFER_MASK 0x000001FF
+#define V1_BF_GPMI_ECCCTRL_BUFFER_MASK(v) \
+ (((v) << 0) & V1_BM_GPMI_ECCCTRL_BUFFER_MASK)
+#define V1_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100
+#define V1_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_ECCCOUNT (0x00000030)
+
+#define V1_BP_GPMI_ECCCOUNT_RSVD2 16
+#define V1_BM_GPMI_ECCCOUNT_RSVD2 0xFFFF0000
+#define V1_BF_GPMI_ECCCOUNT_RSVD2(v) \
+ (((v) << 16) & V1_BM_GPMI_ECCCOUNT_RSVD2)
+#define V1_BP_GPMI_ECCCOUNT_COUNT 0
+#define V1_BM_GPMI_ECCCOUNT_COUNT 0x0000FFFF
+#define V1_BF_GPMI_ECCCOUNT_COUNT(v) \
+ (((v) << 0) & V1_BM_GPMI_ECCCOUNT_COUNT)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_PAYLOAD (0x00000040)
+
+#define V1_BP_GPMI_PAYLOAD_ADDRESS 2
+#define V1_BM_GPMI_PAYLOAD_ADDRESS 0xFFFFFFFC
+#define V1_BF_GPMI_PAYLOAD_ADDRESS(v) \
+ (((v) << 2) & V1_BM_GPMI_PAYLOAD_ADDRESS)
+#define V1_BP_GPMI_PAYLOAD_RSVD0 0
+#define V1_BM_GPMI_PAYLOAD_RSVD0 0x00000003
+#define V1_BF_GPMI_PAYLOAD_RSVD0(v) \
+ (((v) << 0) & V1_BM_GPMI_PAYLOAD_RSVD0)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_AUXILIARY (0x00000050)
+
+#define V1_BP_GPMI_AUXILIARY_ADDRESS 2
+#define V1_BM_GPMI_AUXILIARY_ADDRESS 0xFFFFFFFC
+#define V1_BF_GPMI_AUXILIARY_ADDRESS(v) \
+ (((v) << 2) & V1_BM_GPMI_AUXILIARY_ADDRESS)
+#define V1_BP_GPMI_AUXILIARY_RSVD0 0
+#define V1_BM_GPMI_AUXILIARY_RSVD0 0x00000003
+#define V1_BF_GPMI_AUXILIARY_RSVD0(v) \
+ (((v) << 0) & V1_BM_GPMI_AUXILIARY_RSVD0)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_CTRL1 (0x00000060)
+#define V1_HW_GPMI_CTRL1_SET (0x00000064)
+#define V1_HW_GPMI_CTRL1_CLR (0x00000068)
+#define V1_HW_GPMI_CTRL1_TOG (0x0000006c)
+
+#define V1_BP_GPMI_CTRL1_RSVD2 25
+#define V1_BM_GPMI_CTRL1_RSVD2 0xFE000000
+#define V1_BF_GPMI_CTRL1_RSVD2(v) \
+ (((v) << 25) & V1_BM_GPMI_CTRL1_RSVD2)
+#define V1_BM_GPMI_CTRL1_DECOUPLE_CS 0x01000000
+#define V1_BP_GPMI_CTRL1_WRN_DLY_SEL 22
+#define V1_BM_GPMI_CTRL1_WRN_DLY_SEL 0x00C00000
+#define V1_BF_GPMI_CTRL1_WRN_DLY_SEL(v) \
+ (((v) << 22) & V1_BM_GPMI_CTRL1_WRN_DLY_SEL)
+#define V1_BM_GPMI_CTRL1_RSVD1 0x00200000
+#define V1_BM_GPMI_CTRL1_TIMEOUT_IRQ_EN 0x00100000
+#define V1_BM_GPMI_CTRL1_GANGED_RDYBUSY 0x00080000
+#define V1_BM_GPMI_CTRL1_BCH_MODE 0x00040000
+#define V1_BM_GPMI_CTRL1_DLL_ENABLE 0x00020000
+#define V1_BP_GPMI_CTRL1_HALF_PERIOD 16
+#define V1_BM_GPMI_CTRL1_HALF_PERIOD 0x00010000
+#define V1_BP_GPMI_CTRL1_RDN_DELAY 12
+#define V1_BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
+#define V1_BF_GPMI_CTRL1_RDN_DELAY(v) \
+ (((v) << 12) & V1_BM_GPMI_CTRL1_RDN_DELAY)
+#define V1_BM_GPMI_CTRL1_DMA2ECC_MODE 0x00000800
+#define V1_BM_GPMI_CTRL1_DEV_IRQ 0x00000400
+#define V1_BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
+#define V1_BM_GPMI_CTRL1_BURST_EN 0x00000100
+#define V1_BM_GPMI_CTRL1_ABORT_WAIT_REQUEST 0x00000080
+#define V1_BP_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL 4
+#define V1_BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL 0x00000070
+#define V1_BF_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL(v) \
+ (((v) << 4) & V1_BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL)
+#define V1_BM_GPMI_CTRL1_DEV_RESET 0x00000008
+#define V1_BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0
+#define V1_BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1
+#define V1_BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
+#define V1_BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0
+#define V1_BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1
+#define V1_BM_GPMI_CTRL1_CAMERA_MODE 0x00000002
+#define V1_BM_GPMI_CTRL1_GPMI_MODE 0x00000001
+#define V1_BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0
+#define V1_BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_TIMING0 (0x00000070)
+
+#define V1_BP_GPMI_TIMING0_RSVD1 24
+#define V1_BM_GPMI_TIMING0_RSVD1 0xFF000000
+#define V1_BF_GPMI_TIMING0_RSVD1(v) \
+ (((v) << 24) & V1_BM_GPMI_TIMING0_RSVD1)
+#define V1_BP_GPMI_TIMING0_ADDRESS_SETUP 16
+#define V1_BM_GPMI_TIMING0_ADDRESS_SETUP 0x00FF0000
+#define V1_BF_GPMI_TIMING0_ADDRESS_SETUP(v) \
+ (((v) << 16) & V1_BM_GPMI_TIMING0_ADDRESS_SETUP)
+#define V1_BP_GPMI_TIMING0_DATA_HOLD 8
+#define V1_BM_GPMI_TIMING0_DATA_HOLD 0x0000FF00
+#define V1_BF_GPMI_TIMING0_DATA_HOLD(v) \
+ (((v) << 8) & V1_BM_GPMI_TIMING0_DATA_HOLD)
+#define V1_BP_GPMI_TIMING0_DATA_SETUP 0
+#define V1_BM_GPMI_TIMING0_DATA_SETUP 0x000000FF
+#define V1_BF_GPMI_TIMING0_DATA_SETUP(v) \
+ (((v) << 0) & V1_BM_GPMI_TIMING0_DATA_SETUP)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_TIMING1 (0x00000080)
+
+#define V1_BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 16
+#define V1_BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 0xFFFF0000
+#define V1_BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(v) \
+ (((v) << 16) & V1_BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT)
+#define V1_BP_GPMI_TIMING1_RSVD1 0
+#define V1_BM_GPMI_TIMING1_RSVD1 0x0000FFFF
+#define V1_BF_GPMI_TIMING1_RSVD1(v) \
+ (((v) << 0) & V1_BM_GPMI_TIMING1_RSVD1)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_TIMING2 (0x00000090)
+
+#define V1_BP_GPMI_TIMING2_UDMA_TRP 24
+#define V1_BM_GPMI_TIMING2_UDMA_TRP 0xFF000000
+#define V1_BF_GPMI_TIMING2_UDMA_TRP(v) \
+ (((v) << 24) & V1_BM_GPMI_TIMING2_UDMA_TRP)
+#define V1_BP_GPMI_TIMING2_UDMA_ENV 16
+#define V1_BM_GPMI_TIMING2_UDMA_ENV 0x00FF0000
+#define V1_BF_GPMI_TIMING2_UDMA_ENV(v) \
+ (((v) << 16) & V1_BM_GPMI_TIMING2_UDMA_ENV)
+#define V1_BP_GPMI_TIMING2_UDMA_HOLD 8
+#define V1_BM_GPMI_TIMING2_UDMA_HOLD 0x0000FF00
+#define V1_BF_GPMI_TIMING2_UDMA_HOLD(v) \
+ (((v) << 8) & V1_BM_GPMI_TIMING2_UDMA_HOLD)
+#define V1_BP_GPMI_TIMING2_UDMA_SETUP 0
+#define V1_BM_GPMI_TIMING2_UDMA_SETUP 0x000000FF
+#define V1_BF_GPMI_TIMING2_UDMA_SETUP(v) \
+ (((v) << 0) & V1_BM_GPMI_TIMING2_UDMA_SETUP)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_DATA (0x000000a0)
+
+#define V1_BP_GPMI_DATA_DATA 0
+#define V1_BM_GPMI_DATA_DATA 0xFFFFFFFF
+#define V1_BF_GPMI_DATA_DATA(v) (v)
+
+#define V1_HW_GPMI_STAT (0x000000b0)
+
+#define V1_BP_GPMI_STAT_READY_BUSY 24
+#define V1_BM_GPMI_STAT_READY_BUSY 0xFF000000
+#define V1_BF_GPMI_STAT_READY_BUSY(v) \
+ (((v) << 24) & V1_BM_GPMI_STAT_READY_BUSY)
+#define V1_BP_GPMI_STAT_RDY_TIMEOUT 16
+#define V1_BM_GPMI_STAT_RDY_TIMEOUT 0x00FF0000
+#define V1_BF_GPMI_STAT_RDY_TIMEOUT(v) \
+ (((v) << 16) & V1_BM_GPMI_STAT_RDY_TIMEOUT)
+#define V1_BM_GPMI_STAT_DEV7_ERROR 0x00008000
+#define V1_BM_GPMI_STAT_DEV6_ERROR 0x00004000
+#define V1_BM_GPMI_STAT_DEV5_ERROR 0x00002000
+#define V1_BM_GPMI_STAT_DEV4_ERROR 0x00001000
+#define V1_BM_GPMI_STAT_DEV3_ERROR 0x00000800
+#define V1_BM_GPMI_STAT_DEV2_ERROR 0x00000400
+#define V1_BM_GPMI_STAT_DEV1_ERROR 0x00000200
+#define V1_BM_GPMI_STAT_DEV0_ERROR 0x00000100
+#define V1_BP_GPMI_STAT_RSVD1 5
+#define V1_BM_GPMI_STAT_RSVD1 0x000000E0
+#define V1_BF_GPMI_STAT_RSVD1(v) \
+ (((v) << 5) & V1_BM_GPMI_STAT_RSVD1)
+#define V1_BM_GPMI_STAT_ATA_IRQ 0x00000010
+#define V1_BM_GPMI_STAT_INVALID_BUFFER_MASK 0x00000008
+#define V1_BM_GPMI_STAT_FIFO_EMPTY 0x00000004
+#define V1_BV_GPMI_STAT_FIFO_EMPTY__NOT_EMPTY 0x0
+#define V1_BV_GPMI_STAT_FIFO_EMPTY__EMPTY 0x1
+#define V1_BM_GPMI_STAT_FIFO_FULL 0x00000002
+#define V1_BV_GPMI_STAT_FIFO_FULL__NOT_FULL 0x0
+#define V1_BV_GPMI_STAT_FIFO_FULL__FULL 0x1
+#define V1_BM_GPMI_STAT_PRESENT 0x00000001
+#define V1_BV_GPMI_STAT_PRESENT__UNAVAILABLE 0x0
+#define V1_BV_GPMI_STAT_PRESENT__AVAILABLE 0x1
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_DEBUG (0x000000c0)
+
+#define V1_BP_GPMI_DEBUG_WAIT_FOR_READY_END 24
+#define V1_BM_GPMI_DEBUG_WAIT_FOR_READY_END 0xFF000000
+#define V1_BF_GPMI_DEBUG_WAIT_FOR_READY_END(v) \
+ (((v) << 24) & V1_BM_GPMI_DEBUG_WAIT_FOR_READY_END)
+#define V1_BP_GPMI_DEBUG_DMA_SENSE 16
+#define V1_BM_GPMI_DEBUG_DMA_SENSE 0x00FF0000
+#define V1_BF_GPMI_DEBUG_DMA_SENSE(v) \
+ (((v) << 16) & V1_BM_GPMI_DEBUG_DMA_SENSE)
+#define V1_BP_GPMI_DEBUG_DMAREQ 8
+#define V1_BM_GPMI_DEBUG_DMAREQ 0x0000FF00
+#define V1_BF_GPMI_DEBUG_DMAREQ(v) \
+ (((v) << 8) & V1_BM_GPMI_DEBUG_DMAREQ)
+#define V1_BP_GPMI_DEBUG_CMD_END 0
+#define V1_BM_GPMI_DEBUG_CMD_END 0x000000FF
+#define V1_BF_GPMI_DEBUG_CMD_END(v) \
+ (((v) << 0) & V1_BM_GPMI_DEBUG_CMD_END)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_VERSION (0x000000d0)
+
+#define V1_BP_GPMI_VERSION_MAJOR 24
+#define V1_BM_GPMI_VERSION_MAJOR 0xFF000000
+#define V1_BF_GPMI_VERSION_MAJOR(v) \
+ (((v) << 24) & V1_BM_GPMI_VERSION_MAJOR)
+#define V1_BP_GPMI_VERSION_MINOR 16
+#define V1_BM_GPMI_VERSION_MINOR 0x00FF0000
+#define V1_BF_GPMI_VERSION_MINOR(v) \
+ (((v) << 16) & V1_BM_GPMI_VERSION_MINOR)
+#define V1_BP_GPMI_VERSION_STEP 0
+#define V1_BM_GPMI_VERSION_STEP 0x0000FFFF
+#define V1_BF_GPMI_VERSION_STEP(v) \
+ (((v) << 0) & V1_BM_GPMI_VERSION_STEP)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_DEBUG2 (0x000000e0)
+
+#define V1_BP_GPMI_DEBUG2_RSVD1 28
+#define V1_BM_GPMI_DEBUG2_RSVD1 0xF0000000
+#define V1_BF_GPMI_DEBUG2_RSVD1(v) \
+ (((v) << 28) & V1_BM_GPMI_DEBUG2_RSVD1)
+#define V1_BP_GPMI_DEBUG2_UDMA_STATE 24
+#define V1_BM_GPMI_DEBUG2_UDMA_STATE 0x0F000000
+#define V1_BF_GPMI_DEBUG2_UDMA_STATE(v) \
+ (((v) << 24) & V1_BM_GPMI_DEBUG2_UDMA_STATE)
+#define V1_BM_GPMI_DEBUG2_BUSY 0x00800000
+#define V1_BV_GPMI_DEBUG2_BUSY__DISABLED 0x0
+#define V1_BV_GPMI_DEBUG2_BUSY__ENABLED 0x1
+#define V1_BP_GPMI_DEBUG2_PIN_STATE 20
+#define V1_BM_GPMI_DEBUG2_PIN_STATE 0x00700000
+#define V1_BF_GPMI_DEBUG2_PIN_STATE(v) \
+ (((v) << 20) & V1_BM_GPMI_DEBUG2_PIN_STATE)
+#define V1_BV_GPMI_DEBUG2_PIN_STATE__PSM_IDLE 0x0
+#define V1_BV_GPMI_DEBUG2_PIN_STATE__PSM_BYTCNT 0x1
+#define V1_BV_GPMI_DEBUG2_PIN_STATE__PSM_ADDR 0x2
+#define V1_BV_GPMI_DEBUG2_PIN_STATE__PSM_STALL 0x3
+#define V1_BV_GPMI_DEBUG2_PIN_STATE__PSM_STROBE 0x4
+#define V1_BV_GPMI_DEBUG2_PIN_STATE__PSM_ATARDY 0x5
+#define V1_BV_GPMI_DEBUG2_PIN_STATE__PSM_DHOLD 0x6
+#define V1_BV_GPMI_DEBUG2_PIN_STATE__PSM_DONE 0x7
+#define V1_BP_GPMI_DEBUG2_MAIN_STATE 16
+#define V1_BM_GPMI_DEBUG2_MAIN_STATE 0x000F0000
+#define V1_BF_GPMI_DEBUG2_MAIN_STATE(v) \
+ (((v) << 16) & V1_BM_GPMI_DEBUG2_MAIN_STATE)
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_IDLE 0x0
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_BYTCNT 0x1
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_WAITFE 0x2
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_WAITFR 0x3
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_DMAREQ 0x4
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_DMAACK 0x5
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_WAITFF 0x6
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_LDFIFO 0x7
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_LDDMAR 0x8
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_RDCMP 0x9
+#define V1_BV_GPMI_DEBUG2_MAIN_STATE__MSM_DONE 0xA
+#define V1_BP_GPMI_DEBUG2_SYND2GPMI_BE 12
+#define V1_BM_GPMI_DEBUG2_SYND2GPMI_BE 0x0000F000
+#define V1_BF_GPMI_DEBUG2_SYND2GPMI_BE(v) \
+ (((v) << 12) & V1_BM_GPMI_DEBUG2_SYND2GPMI_BE)
+#define V1_BM_GPMI_DEBUG2_GPMI2SYND_VALID 0x00000800
+#define V1_BM_GPMI_DEBUG2_GPMI2SYND_READY 0x00000400
+#define V1_BM_GPMI_DEBUG2_SYND2GPMI_VALID 0x00000200
+#define V1_BM_GPMI_DEBUG2_SYND2GPMI_READY 0x00000100
+#define V1_BM_GPMI_DEBUG2_VIEW_DELAYED_RDN 0x00000080
+#define V1_BM_GPMI_DEBUG2_UPDATE_WINDOW 0x00000040
+#define V1_BP_GPMI_DEBUG2_RDN_TAP 0
+#define V1_BM_GPMI_DEBUG2_RDN_TAP 0x0000003F
+#define V1_BF_GPMI_DEBUG2_RDN_TAP(v) \
+ (((v) << 0) & V1_BM_GPMI_DEBUG2_RDN_TAP)
+
+/*============================================================================*/
+
+#define V1_HW_GPMI_DEBUG3 (0x000000f0)
+
+#define V1_BP_GPMI_DEBUG3_APB_WORD_CNTR 16
+#define V1_BM_GPMI_DEBUG3_APB_WORD_CNTR 0xFFFF0000
+#define V1_BF_GPMI_DEBUG3_APB_WORD_CNTR(v) \
+ (((v) << 16) & V1_BM_GPMI_DEBUG3_APB_WORD_CNTR)
+#define V1_BP_GPMI_DEBUG3_DEV_WORD_CNTR 0
+#define V1_BM_GPMI_DEBUG3_DEV_WORD_CNTR 0x0000FFFF
+#define V1_BF_GPMI_DEBUG3_DEV_WORD_CNTR(v) \
+ (((v) << 0) & V1_BM_GPMI_DEBUG3_DEV_WORD_CNTR)
+
+/*============================================================================*/
+
+#endif
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c
new file mode 100644
index 000000000000..7fa729bdea5c
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c
@@ -0,0 +1,6351 @@
+/*
+ * 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.
+ */
+
+/* Linux header files. */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+#include <linux/gpmi-nfc.h>
+
+/* Platform header files. */
+
+#include <mach/system.h>
+#include <mach/dmaengine.h>
+#include <mach/device.h>
+
+/* Driver header files. */
+
+#include "gpmi-nfc.h"
+
+/* Define this macro to enable detailed information messages. */
+
+#define DETAILED_INFO
+
+/* Define this macro to enable event reporting. */
+
+/*#define EVENT_REPORTING*/
+
+/*
+ * Indicates the driver should register the MTD that represents the entire
+ * medium, thus making it visible.
+ */
+
+static int register_main_mtd;
+module_param(register_main_mtd, int, 0400);
+
+/*
+ * Indicates the driver should attempt to perform DMA directly to/from buffers
+ * passed into this driver. This is true by default. If false, the driver will
+ * *always* copy incoming/outgoing data to/from its own DMA buffers.
+ */
+
+static int map_io_buffers = true;
+module_param(map_io_buffers, int, 0600);
+
+#ifdef EVENT_REPORTING
+
+/*
+ * This variable and module parameter controls whether the driver reports event
+ * information by printing to the console.
+ */
+
+static int report_events;
+module_param(report_events, int, 0600);
+
+/**
+ * struct event - A single record in the event trace.
+ *
+ * @time: The time at which the event occurred.
+ * @nesting: Indicates function call nesting.
+ * @description: A description of the event.
+ */
+
+struct event {
+ ktime_t time;
+ unsigned int nesting;
+ char *description;
+};
+
+/**
+ * The event trace.
+ *
+ * @overhead: The delay to take a time stamp and nothing else.
+ * @nesting: The current nesting level.
+ * @overflow: Indicates the trace overflowed.
+ * @next: Index of the next event to write.
+ * @events: The array of events.
+ */
+
+#define MAX_EVENT_COUNT (200)
+
+static struct {
+ ktime_t overhead;
+ int nesting;
+ int overflow;
+ unsigned int next;
+ struct event events[MAX_EVENT_COUNT];
+} event_trace;
+
+/**
+ * reset_event_trace() - Resets the event trace.
+ */
+static void reset_event_trace(void)
+{
+ event_trace.nesting = 0;
+ event_trace.overflow = false;
+ event_trace.next = 0;
+}
+
+/**
+ * add_event() - Adds an event to the event trace.
+ *
+ * @description: A description of the event.
+ * @delta: A delta to the nesting level for this event [-1, 0, 1].
+ */
+static inline void add_event(char *description, int delta)
+{
+ struct event *event;
+
+ if (!report_events)
+ return;
+
+ if (event_trace.overflow)
+ return;
+
+ if (event_trace.next >= MAX_EVENT_COUNT) {
+ event_trace.overflow = true;
+ return;
+ }
+
+ event = event_trace.events + event_trace.next;
+
+ event->time = ktime_get();
+
+ event->description = description;
+
+ if (!delta)
+ event->nesting = event_trace.nesting;
+ else if (delta < 0) {
+ event->nesting = event_trace.nesting - 1;
+ event_trace.nesting -= 2;
+ } else {
+ event->nesting = event_trace.nesting + 1;
+ event_trace.nesting += 2;
+ }
+
+ if (event_trace.nesting < 0)
+ event_trace.nesting = 0;
+
+ event_trace.next++;
+
+}
+
+/**
+ * start_event_trace() - Starts an event trace and adds the first event.
+ *
+ * @description: A description of the first event.
+ */
+static void start_event_trace(char *description)
+{
+
+ ktime_t t0;
+ ktime_t t1;
+
+ if (!report_events)
+ return;
+
+ reset_event_trace();
+
+ t0 = ktime_get();
+ t1 = ktime_get();
+
+ event_trace.overhead = ktime_sub(t1, t0);
+
+ add_event(description, 1);
+
+}
+
+/**
+ * dump_event_trace() - Dumps the event trace.
+ */
+static void dump_event_trace(void)
+{
+ unsigned int i;
+ time_t seconds;
+ long nanoseconds;
+ char line[100];
+ int o;
+ struct event *first_event;
+ struct event *last_event;
+ struct event *matching_event;
+ struct event *event;
+ ktime_t delta;
+
+ /* Check if event reporting is turned off. */
+
+ if (!report_events)
+ return;
+
+ /* Print important facts about this event trace. */
+
+ printk(KERN_DEBUG "\n+--------------\n");
+
+ printk(KERN_DEBUG "| Overhead : [%d:%d]\n",
+ event_trace.overhead.tv.sec,
+ event_trace.overhead.tv.nsec);
+
+ if (!event_trace.next) {
+ printk(KERN_DEBUG "| No Events\n");
+ return;
+ }
+
+ first_event = event_trace.events;
+ last_event = event_trace.events + (event_trace.next - 1);
+
+ delta = ktime_sub(last_event->time, first_event->time);
+ printk(KERN_DEBUG "| Elapsed Time: [%d:%d]\n",
+ delta.tv.sec, delta.tv.nsec);
+
+ if (event_trace.overflow)
+ printk(KERN_DEBUG "| Overflow!\n");
+
+ /* Print the events in this history. */
+
+ for (i = 0, event = event_trace.events;
+ i < event_trace.next; i++, event++) {
+
+ /* Get the delta between this event and the previous event. */
+
+ if (!i) {
+ seconds = 0;
+ nanoseconds = 0;
+ } else {
+ delta = ktime_sub(event[0].time, event[-1].time);
+ seconds = delta.tv.sec;
+ nanoseconds = delta.tv.nsec;
+ }
+
+ /* Print the current event. */
+
+ o = 0;
+
+ o = snprintf(line, sizeof(line) - o, "| [%ld:% 10ld]%*s %s",
+ seconds, nanoseconds,
+ event->nesting, "",
+ event->description);
+ /* Check if this is the last event in a nested series. */
+
+ if (i && (event[0].nesting < event[-1].nesting)) {
+
+ for (matching_event = event - 1;; matching_event--) {
+
+ if (matching_event < event_trace.events) {
+ matching_event = 0;
+ break;
+ }
+
+ if (matching_event->nesting == event->nesting)
+ break;
+
+ }
+
+ if (matching_event) {
+ delta = ktime_sub(event->time,
+ matching_event->time);
+ o += snprintf(line + o, sizeof(line) - o,
+ " <%d:%d]", delta.tv.sec,
+ delta.tv.nsec);
+ }
+
+ }
+
+ /* Check if this is the first event in a nested series. */
+
+ if ((i < event_trace.next - 1) &&
+ (event[0].nesting < event[1].nesting)) {
+
+ for (matching_event = event + 1;; matching_event++) {
+
+ if (matching_event >=
+ (event_trace.events+event_trace.next)) {
+ matching_event = 0;
+ break;
+ }
+
+ if (matching_event->nesting == event->nesting)
+ break;
+
+ }
+
+ if (matching_event) {
+ delta = ktime_sub(matching_event->time,
+ event->time);
+ o += snprintf(line + o, sizeof(line) - o,
+ " [%d:%d>", delta.tv.sec,
+ delta.tv.nsec);
+ }
+
+ }
+
+ printk(KERN_DEBUG "%s\n", line);
+
+ }
+
+ printk(KERN_DEBUG "+--------------\n");
+
+}
+
+/**
+ * stop_event_trace() - Stops an event trace.
+ *
+ * @description: A description of the last event.
+ */
+static void stop_event_trace(char *description)
+{
+ struct event *event;
+
+ if (!report_events)
+ return;
+
+ /*
+ * We want the end of the trace, no matter what happens. If the trace
+ * has already overflowed, or is about to, just jam this event into the
+ * last spot. Otherwise, add this event like any other.
+ */
+
+ if (event_trace.overflow || (event_trace.next >= MAX_EVENT_COUNT)) {
+ event = event_trace.events + (MAX_EVENT_COUNT - 1);
+ event->time = ktime_get();
+ event->description = description;
+ event->nesting = 0;
+ } else {
+ add_event(description, -1);
+ }
+
+ dump_event_trace();
+ reset_event_trace();
+
+}
+
+#else /* EVENT_REPORTING */
+
+#define start_event_trace(description) do {} while (0)
+#define add_event(description, delta) do {} while (0)
+#define add_state_event_l(address, mask, zero, not_zero) do {} while (0)
+#define stop_event_trace(description) do {} while (0)
+#define dump_event_trace() do {} while (0)
+
+#endif /* EVENT_REPORTING */
+
+/*
+ *------------------------------------------------------------------------------
+ * NFC HAL
+ *
+ * The following functions implent the NFC HAL for various NFC hardware
+ * versions.
+ *------------------------------------------------------------------------------
+ */
+
+/**
+ * nfc_bch_isr - BCH interrupt service routine.
+ *
+ * @interrupt_number: The interrupt number.
+ * @cookie: A cookie that contains a pointer to the owning device
+ * data structure.
+ */
+static irqreturn_t nfc_bch_isr(int irq, void *cookie)
+{
+ struct gpmi_nfc_data *this = cookie;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+
+ /* Clear the interrupt. */
+
+ __raw_writel(V1_BM_BCH_CTRL_COMPLETE_IRQ,
+ resources->bch_regs + V1_HW_BCH_CTRL_CLR);
+
+ /* Release the base level. */
+
+ complete(&(nfc->bch_done));
+
+ /* Return success. */
+
+ return IRQ_HANDLED;
+
+}
+
+/**
+ * nfc_dma_isr - DMA interrupt service routine.
+ *
+ * @interrupt_number: The interrupt number.
+ * @cookie: A cookie that contains a pointer to the owning device
+ * data structure.
+ */
+static irqreturn_t nfc_dma_isr(int irq, void *cookie)
+{
+ struct gpmi_nfc_data *this = cookie;
+ struct nfc_hal *nfc = this->nfc;
+
+ add_event("=> nfc_dma_isr", 1);
+
+ /* Acknowledge the DMA channel's interrupt. */
+
+ mxs_dma_ack_irq(nfc->isr_dma_channel);
+
+ /* Release the base level. */
+
+ complete(&(nfc->dma_done));
+
+ /* Return success. */
+
+ add_event("<= nfc_dma_isr", -1);
+
+ return IRQ_HANDLED;
+
+}
+
+/**
+ * nfc_dma_init() - Initializes DMA.
+ *
+ * @this: Per-device data.
+ */
+static int nfc_dma_init(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct nfc_hal *nfc = this->nfc;
+ int i;
+ int error;
+
+ /* Allocate the DMA descriptors. */
+
+ for (i = 0; i < NFC_DMA_DESCRIPTOR_COUNT; i++) {
+ nfc->dma_descriptors[i] = mxs_dma_alloc_desc();
+ if (!nfc->dma_descriptors[i]) {
+ dev_err(dev, "Cannot allocate all DMA descriptors.\n");
+ error = -ENOMEM;
+ goto exit_descriptor_allocation;
+ }
+ }
+
+ /* If control arrives here, all is well. */
+
+ return 0;
+
+ /* Control arrives here when something has gone wrong. */
+
+exit_descriptor_allocation:
+ while (--i >= 0)
+ mxs_dma_free_desc(this->nfc->dma_descriptors[i]);
+
+ return error;
+
+}
+
+/**
+ * nfc_dma_exit() - Shuts down DMA.
+ *
+ * @this: Per-device data.
+ */
+static void nfc_dma_exit(struct gpmi_nfc_data *this)
+{
+ struct nfc_hal *nfc = this->nfc;
+ int i;
+
+ /* Free the DMA descriptors. */
+
+ for (i = 0; i < NFC_DMA_DESCRIPTOR_COUNT; i++)
+ mxs_dma_free_desc(nfc->dma_descriptors[i]);
+
+}
+
+/**
+ * nfc_set_geometry() - Shared NFC geometry configuration.
+ *
+ * In principle, computing the NFC geometry is version-specific. However, at
+ * this writing all, versions share the same page model, so this code can also
+ * be shared.
+ *
+ * @this: Per-device data.
+ */
+static int nfc_set_geometry(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct nfc_geometry *geometry = &this->nfc_geometry;
+ struct boot_rom_helper *rom = this->rom;
+ unsigned int metadata_size;
+ unsigned int status_size;
+ unsigned int chunk_data_size_in_bits;
+ unsigned int chunk_ecc_size_in_bits;
+ unsigned int chunk_total_size_in_bits;
+ unsigned int block_mark_chunk_number;
+ unsigned int block_mark_chunk_bit_offset;
+ unsigned int block_mark_bit_offset;
+
+ /* At this writing, we support only BCH. */
+
+ geometry->ecc_algorithm = "BCH";
+
+ /*
+ * We always choose a metadata size of 10. Don't try to make sense of
+ * it -- this is really only for historical compatibility.
+ */
+
+ geometry->metadata_size_in_bytes = 10;
+
+ /*
+ * At this writing, we always use 512-byte ECC chunks. Later hardware
+ * will be able to support larger chunks, which will cause this
+ * decision to move into version-specific code.
+ */
+
+ geometry->ecc_chunk_size_in_bytes = 512;
+
+ /* Compute the page size based on the physical geometry. */
+
+ geometry->page_size_in_bytes =
+ physical->page_data_size_in_bytes +
+ physical->page_oob_size_in_bytes ;
+
+ /*
+ * Compute the total number of ECC chunks in a page. This includes the
+ * slightly larger chunk at the beginning of the page, which contains
+ * both data and metadata.
+ */
+
+ geometry->ecc_chunk_count =
+ physical->page_data_size_in_bytes /
+ /*---------------------------------*/
+ geometry->ecc_chunk_size_in_bytes;
+
+ /*
+ * We use the same ECC strength for all chunks, including the first one.
+ * At this writing, we base our ECC strength choice entirely on the
+ * the physical page geometry. In the future, this should be changed to
+ * pay attention to the detailed device information we gathered earlier.
+ */
+
+ geometry->ecc_strength = 0;
+
+ switch (physical->page_data_size_in_bytes) {
+ case 2048:
+ geometry->ecc_strength = 8;
+ break;
+ case 4096:
+ switch (physical->page_oob_size_in_bytes) {
+ case 128:
+ geometry->ecc_strength = 8;
+ break;
+ case 218:
+ geometry->ecc_strength = 16;
+ break;
+ }
+ break;
+ }
+
+ /* Check if we were able to figure out the ECC strength. */
+
+ if (!geometry->ecc_strength) {
+ dev_err(dev, "Unsupported page geometry: %u:%u\n",
+ physical->page_data_size_in_bytes,
+ physical->page_oob_size_in_bytes);
+ return !0;
+ }
+
+ /*
+ * The payload buffer contains the data area of a page. The ECC engine
+ * only needs what's required to hold the data.
+ */
+
+ geometry->payload_size_in_bytes = physical->page_data_size_in_bytes;
+
+ /*
+ * In principle, computing the auxiliary buffer geometry is NFC
+ * version-specific. However, at this writing, all versions share the
+ * same model, so this code can also be shared.
+ *
+ * The auxiliary buffer contains the metadata and the ECC status. The
+ * metadata is padded to the nearest 32-bit boundary. The ECC status
+ * contains one byte for every ECC chunk, and is also padded to the
+ * nearest 32-bit boundary.
+ */
+
+ metadata_size = (geometry->metadata_size_in_bytes + 0x3) & ~0x3;
+ status_size = (geometry->ecc_chunk_count + 0x3) & ~0x3;
+
+ geometry->auxiliary_size_in_bytes = metadata_size + status_size;
+ geometry->auxiliary_status_offset = metadata_size;
+
+ /* Check if we're going to do block mark swapping. */
+
+ if (!rom->swap_block_mark)
+ return 0;
+
+ /*
+ * If control arrives here, we're doing block mark swapping, so we need
+ * to compute the byte and bit offsets of the physical block mark within
+ * the ECC-based view of the page data. In principle, this isn't a
+ * difficult computation -- but it's very important and it's easy to get
+ * it wrong, so we do it carefully.
+ *
+ * Note that this calculation is simpler because we use the same ECC
+ * strength for all chunks, including the zero'th one, which contains
+ * the metadata. The calculation would be slightly more complicated
+ * otherwise.
+ *
+ * We start by computing the physical bit offset of the block mark. We
+ * then subtract the number of metadata and ECC bits appearing before
+ * the mark to arrive at its bit offset within the data alone.
+ */
+
+ /* Compute some important facts about chunk geometry. */
+
+ chunk_data_size_in_bits = geometry->ecc_chunk_size_in_bytes * 8;
+ chunk_ecc_size_in_bits = geometry->ecc_strength * 13;
+
+ 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. */
+
+ block_mark_bit_offset = physical->page_data_size_in_bytes * 8;
+
+ /* Subtract the metadata bits. */
+
+ block_mark_bit_offset -= geometry->metadata_size_in_bytes * 8;
+
+ /*
+ * Compute the chunk number (starting at zero) in which the block mark
+ * appears.
+ */
+
+ 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.
+ */
+
+ 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) {
+
+ /*
+ * If control arrives here, the block mark actually appears in
+ * the ECC bits of this chunk. This wont' work.
+ */
+
+ dev_err(dev, "Unsupported page geometry "
+ "(block mark in ECC): %u:%u\n",
+ physical->page_data_size_in_bytes,
+ physical->page_oob_size_in_bytes);
+ return !0;
+
+ }
+
+ /*
+ * Now that we know the chunk number in which the block mark appears,
+ * we can subtract all the ECC bits that appear before it.
+ */
+
+ block_mark_bit_offset -=
+ block_mark_chunk_number * chunk_ecc_size_in_bits;
+
+ /*
+ * We now know the absolute bit offset of the block mark within the
+ * ECC-based data. We can now compute the byte offset and the bit
+ * offset within the byte.
+ */
+
+ geometry->block_mark_byte_offset = block_mark_bit_offset / 8;
+ geometry->block_mark_bit_offset = block_mark_bit_offset % 8;
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/*
+ * This code is useful for debugging.
+ */
+
+/*#define DUMP_DMA_CONTEXT*/
+
+#if (defined DUMP_DMA_CONTEXT)
+
+int dump_dma_context_flag;
+
+static void dump_dma_context(struct gpmi_nfc_data *this, char *title)
+{
+
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ void *q;
+ uint32_t *p;
+ unsigned int i;
+ unsigned int j;
+
+ if (!dump_dma_context_flag)
+ return;
+
+ pr_info("%s\n", title);
+ pr_info("======\n");
+ pr_info("\n");
+
+ /*--------------------------------------------------------------------*/
+
+ pr_info(" Descriptors\n");
+ pr_info(" -----------\n");
+ {
+
+ for (i = 0; i < NFC_DMA_DESCRIPTOR_COUNT; i++, d++) {
+ pr_info(" #%u\n", i);
+ pr_info(" --\n");
+ pr_info(" Physical Address: 0x%08x\n" , (*d)->address);
+ pr_info(" Next : 0x%08lx\n", (*d)->cmd.next);
+ pr_info(" Command : 0x%08lx\n", (*d)->cmd.cmd.data);
+ pr_info(" Buffer : 0x%08x\n" , (*d)->cmd.address);
+ for (j = 0; j < 6; j++)
+ pr_info(" PIO[%u] : 0x%08lx\n",
+ j, (*d)->cmd.pio_words[j]);
+ }
+
+ }
+ pr_info("\n");
+
+ /*--------------------------------------------------------------------*/
+
+ pr_info(" DMA\n");
+ pr_info(" ---\n");
+ {
+ void *DMA = IO_ADDRESS(APBH_DMA_PHYS_ADDR);
+
+ p = q = DMA + 0x200;
+
+ for (i = 0; i < 7; i++) {
+ pr_info(" [0x%03x] 0x%08x\n", q - DMA, *p);
+ q += 0x10;
+ p = q;
+ }
+
+ }
+ pr_info("\n");
+
+ /*--------------------------------------------------------------------*/
+
+ pr_info(" GPMI\n");
+ pr_info(" ----\n");
+ {
+ void *GPMI = resources->gpmi_regs;
+
+ p = q = GPMI;
+
+ for (i = 0; i < 33; i++) {
+ pr_info(" [0x%03x] 0x%08x\n", q - GPMI, *p);
+ q += 0x10;
+ p = q;
+ }
+
+ }
+ pr_info("\n");
+
+ /*--------------------------------------------------------------------*/
+
+ pr_info(" BCH\n");
+ pr_info(" ---\n");
+ {
+ void *BCH = resources->bch_regs;
+
+ p = q = BCH;
+
+ for (i = 0; i < 22; i++) {
+ pr_info(" [0x%03x] 0x%08x\n", q - BCH, *p);
+ q += 0x10;
+ p = q;
+ }
+
+ }
+ pr_info("\n");
+
+}
+
+#endif
+
+/**
+ * nfc_dma_go - Run a DMA channel.
+ *
+ * @this: Per-device data structure.
+ * @dma_channel: The DMA channel we're going to use.
+ */
+static int nfc_dma_go(struct gpmi_nfc_data *this, int dma_channel)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ unsigned long timeout;
+ int error;
+ LIST_HEAD(tmp_desc_list);
+
+ add_event("=> nfc_dma_go", 1);
+
+ /* Get ready... */
+
+ nfc->isr_dma_channel = dma_channel;
+ init_completion(&nfc->dma_done);
+ mxs_dma_enable_irq(dma_channel, 1);
+
+ /* Go! */
+
+ #if defined(DUMP_DMA_CONTEXT)
+ dump_dma_context(this, "BEFORE");
+ #endif
+
+ mxs_dma_enable(dma_channel);
+
+ /* Wait for it to finish. */
+
+ timeout = wait_for_completion_timeout(&nfc->dma_done,
+ msecs_to_jiffies(1000));
+
+ #if defined(DUMP_DMA_CONTEXT)
+ dump_dma_context(this, "AFTER");
+ #endif
+
+ error = (!timeout) ? -ETIMEDOUT : 0;
+
+ if (error) {
+ dev_err(dev, "[%s] Chip: %u, DMA Channel: %d, Error %d\n",
+ __func__, dma_channel - resources->dma_low_channel,
+ dma_channel, error);
+ add_event("...DMA timed out", 0);
+ } else
+ add_event("...Finished DMA successfully", 0);
+
+ /* Clear out the descriptors we just ran. */
+
+ mxs_dma_cooked(dma_channel, &tmp_desc_list);
+
+ /* Shut the DMA channel down. */
+
+ mxs_dma_reset(dma_channel);
+ mxs_dma_enable_irq(dma_channel, 0);
+ mxs_dma_disable(dma_channel);
+
+ /* Return. */
+
+ add_event("<= nfc_dma_go", -1);
+
+ return error;
+
+}
+
+/**
+ * nfc_v0_init() - Initializes the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static int nfc_v0_init(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+ int error;
+
+ /* Initialize DMA. */
+
+ error = nfc_dma_init(this);
+
+ if (error)
+ return error;
+
+ /* Enable the clock. */
+
+ clk_enable(resources->clock);
+
+ /* Reset the GPMI block. */
+
+ mxs_reset_block(resources->gpmi_regs + V0_HW_GPMI_CTRL0, true);
+
+ /* Choose NAND mode. */
+ __raw_writel(V0_BM_GPMI_CTRL1_GPMI_MODE,
+ resources->gpmi_regs + V0_HW_GPMI_CTRL1_CLR);
+
+ /* Set the IRQ polarity. */
+ __raw_writel(V0_BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
+ resources->gpmi_regs + V0_HW_GPMI_CTRL1_SET);
+
+ /* Disable write protection. */
+ __raw_writel(V0_BM_GPMI_CTRL1_DEV_RESET,
+ resources->gpmi_regs + V0_HW_GPMI_CTRL1_SET);
+
+ /* Select BCH ECC. */
+ __raw_writel(V0_BM_GPMI_CTRL1_BCH_MODE,
+ resources->gpmi_regs + V0_HW_GPMI_CTRL1_SET);
+
+ /* If control arrives here, all is well. */
+
+ return 0;
+
+}
+
+/**
+ * nfc_v0_set_geometry() - Configures the NFC geometry.
+ *
+ * @this: Per-device data.
+ */
+static int nfc_v0_set_geometry(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+ struct nfc_geometry *nfc = &this->nfc_geometry;
+ unsigned int block_count;
+ unsigned int block_size;
+ unsigned int metadata_size;
+ unsigned int ecc_strength;
+ unsigned int page_size;
+
+ /* We make the abstract choices in a common function. */
+
+ if (nfc_set_geometry(this))
+ return !0;
+
+ /* Translate the abstract choices into register fields. */
+
+ block_count = nfc->ecc_chunk_count - 1;
+ block_size = nfc->ecc_chunk_size_in_bytes;
+ metadata_size = nfc->metadata_size_in_bytes;
+ ecc_strength = nfc->ecc_strength >> 1;
+ page_size = nfc->page_size_in_bytes;
+
+ /*
+ * 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. If you try to soft reset the BCH block, it becomes
+ * unusable until the next hard reset.
+ */
+
+ mxs_reset_block(resources->bch_regs, true);
+
+ /* Configure layout 0. */
+
+ __raw_writel(
+ V0_BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) |
+ V0_BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) |
+ V0_BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) |
+ V0_BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size) ,
+ resources->bch_regs + V0_HW_BCH_FLASH0LAYOUT0);
+
+ __raw_writel(
+ V0_BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) |
+ V0_BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) |
+ V0_BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size) ,
+ resources->bch_regs + V0_HW_BCH_FLASH0LAYOUT1);
+
+ /* Set *all* chip selects to use layout 0. */
+
+ __raw_writel(0, resources->bch_regs + V0_HW_BCH_LAYOUTSELECT);
+
+ /* Enable interrupts. */
+
+ __raw_writel(V0_BM_BCH_CTRL_COMPLETE_IRQ_EN,
+ resources->bch_regs + V0_HW_BCH_CTRL_SET);
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * nfc_v0_exit() - Shuts down the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static void nfc_v0_exit(struct gpmi_nfc_data *this)
+{
+ nfc_dma_exit(this);
+}
+
+/**
+ * nfc_v0_is_ready() - Returns the ready/busy status of the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ */
+static int nfc_v0_is_ready(struct gpmi_nfc_data *this, unsigned chip)
+{
+ struct resources *resources = &this->resources;
+ uint32_t mask;
+ uint32_t register_image;
+
+ /* Extract and return the status. */
+
+ mask = V0_BM_GPMI_DEBUG_READY0 << chip;
+
+ register_image = __raw_readl(resources->gpmi_regs + V0_HW_GPMI_DEBUG);
+
+ return !!(register_image & mask);
+
+}
+
+/**
+ * nfc_v0_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 nfc_v0_send_command(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t buffer, unsigned int length)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error;
+ uint32_t command_mode;
+ uint32_t address;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* A DMA descriptor that sends out the command. */
+
+ command_mode = V0_BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = V0_BV_GPMI_CTRL0_ADDRESS__NAND_CLE;
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = DMA_READ;
+ (*d)->cmd.cmd.bits.chain = 1;
+ (*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 = 3;
+ (*d)->cmd.cmd.bits.bytes = length;
+
+ (*d)->cmd.address = buffer;
+
+ (*d)->cmd.pio_words[0] =
+ V0_BM_GPMI_CTRL0_LOCK_CS |
+ V0_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V0_BM_GPMI_CTRL0_WORD_LENGTH |
+ V0_BF_GPMI_CTRL0_CS(chip) |
+ V0_BF_GPMI_CTRL0_ADDRESS(address) |
+ V0_BM_GPMI_CTRL0_ADDRESS_INCREMENT |
+ V0_BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v0_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 nfc_v0_send_data(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t buffer, unsigned int length)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* A DMA descriptor that writes a buffer out. */
+
+ command_mode = V0_BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = V0_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*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;
+
+ (*d)->cmd.address = buffer;
+
+ (*d)->cmd.pio_words[0] =
+ V0_BM_GPMI_CTRL0_LOCK_CS |
+ V0_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V0_BM_GPMI_CTRL0_WORD_LENGTH |
+ V0_BF_GPMI_CTRL0_CS(chip) |
+ V0_BF_GPMI_CTRL0_ADDRESS(address) |
+ V0_BF_GPMI_CTRL0_XFER_COUNT(length) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v0_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 nfc_v0_read_data(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t buffer, unsigned int length)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* A DMA descriptor that reads the data. */
+
+ command_mode = V0_BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = V0_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = DMA_WRITE;
+ (*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;
+ (*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 = 1;
+ (*d)->cmd.cmd.bits.bytes = length;
+
+ (*d)->cmd.address = buffer;
+
+ (*d)->cmd.pio_words[0] =
+ V0_BM_GPMI_CTRL0_LOCK_CS |
+ V0_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V0_BM_GPMI_CTRL0_WORD_LENGTH |
+ V0_BF_GPMI_CTRL0_CS(chip) |
+ V0_BF_GPMI_CTRL0_ADDRESS(address) |
+ V0_BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /*
+ * 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 = V0_BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = V0_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*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] =
+ V0_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V0_BM_GPMI_CTRL0_LOCK_CS |
+ V0_BM_GPMI_CTRL0_WORD_LENGTH |
+ V0_BF_GPMI_CTRL0_CS(chip) |
+ V0_BF_GPMI_CTRL0_ADDRESS(address) |
+ V0_BF_GPMI_CTRL0_XFER_COUNT(0) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v0_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 nfc_v0_send_page(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+ uint32_t ecc_command;
+ uint32_t buffer_mask;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* A DMA descriptor that does an ECC page read. */
+
+ command_mode = V0_BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = V0_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+ ecc_command = V0_BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
+ buffer_mask = V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+
+ (*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] =
+ V0_BM_GPMI_CTRL0_LOCK_CS |
+ V0_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V0_BM_GPMI_CTRL0_WORD_LENGTH |
+ V0_BF_GPMI_CTRL0_CS(chip) |
+ V0_BF_GPMI_CTRL0_ADDRESS(address) |
+ V0_BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+
+ (*d)->cmd.pio_words[2] =
+ V0_BM_GPMI_ECCCTRL_ENABLE_ECC |
+ V0_BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ V0_BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+
+ (*d)->cmd.pio_words[3] = nfc_geo->page_size_in_bytes;
+ (*d)->cmd.pio_words[4] = payload;
+ (*d)->cmd.pio_words[5] = auxiliary;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Prepare to receive an interrupt from the BCH block. */
+
+ init_completion(&nfc->bch_done);
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Wait for the interrupt from the BCH block. */
+
+ wait_for_completion(&nfc->bch_done);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v0_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 nfc_v0_read_page(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+ uint32_t ecc_command;
+ uint32_t buffer_mask;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* Wait for the chip to report ready. */
+
+ command_mode = V0_BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = V0_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*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;
+ (*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 = 1;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ V0_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V0_BM_GPMI_CTRL0_LOCK_CS |
+ V0_BM_GPMI_CTRL0_WORD_LENGTH |
+ V0_BF_GPMI_CTRL0_CS(chip) |
+ V0_BF_GPMI_CTRL0_ADDRESS(address) |
+ V0_BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Enable the BCH block and read. */
+
+ command_mode = V0_BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = V0_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+ ecc_command = V0_BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
+ buffer_mask = V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ V0_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+
+ (*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;
+ (*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] =
+ V0_BM_GPMI_CTRL0_LOCK_CS |
+ V0_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V0_BM_GPMI_CTRL0_WORD_LENGTH |
+ V0_BF_GPMI_CTRL0_CS(chip) |
+ V0_BF_GPMI_CTRL0_ADDRESS(address) |
+ V0_BF_GPMI_CTRL0_XFER_COUNT(nfc_geo->page_size_in_bytes) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] =
+ V0_BM_GPMI_ECCCTRL_ENABLE_ECC |
+ V0_BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ V0_BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+ (*d)->cmd.pio_words[3] = nfc_geo->page_size_in_bytes;
+ (*d)->cmd.pio_words[4] = payload;
+ (*d)->cmd.pio_words[5] = auxiliary;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Disable the BCH block */
+
+ command_mode = V0_BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = V0_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*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;
+ (*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 = 3;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ V0_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V0_BM_GPMI_CTRL0_LOCK_CS |
+ V0_BM_GPMI_CTRL0_WORD_LENGTH |
+ V0_BF_GPMI_CTRL0_CS(chip) |
+ V0_BF_GPMI_CTRL0_ADDRESS(address) |
+ V0_BF_GPMI_CTRL0_XFER_COUNT(nfc_geo->page_size_in_bytes) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+
+ 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++;
+
+ /* Prepare to receive an interrupt from the BCH block. */
+
+ init_completion(&nfc->bch_done);
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Wait for the interrupt from the BCH block. */
+
+ wait_for_completion(&nfc->bch_done);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v1_init() - Initializes the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static int nfc_v1_init(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+ int error;
+
+ /* Initialize DMA. */
+
+ error = nfc_dma_init(this);
+
+ if (error)
+ return error;
+
+ /* Enable the clock. */
+
+ clk_enable(resources->clock);
+
+ /* Reset the GPMI block. */
+
+ mxs_reset_block(resources->gpmi_regs + V1_HW_GPMI_CTRL0, true);
+
+ /* Choose NAND mode. */
+ __raw_writel(V1_BM_GPMI_CTRL1_GPMI_MODE,
+ resources->gpmi_regs + V1_HW_GPMI_CTRL1_CLR);
+
+ /* Set the IRQ polarity. */
+ __raw_writel(V1_BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
+ resources->gpmi_regs + V1_HW_GPMI_CTRL1_SET);
+
+ /* Disable write protection. */
+ __raw_writel(V1_BM_GPMI_CTRL1_DEV_RESET,
+ resources->gpmi_regs + V1_HW_GPMI_CTRL1_SET);
+
+ /* Select BCH ECC. */
+ __raw_writel(V1_BM_GPMI_CTRL1_BCH_MODE,
+ resources->gpmi_regs + V1_HW_GPMI_CTRL1_SET);
+
+ /* If control arrives here, all is well. */
+
+ return 0;
+
+}
+
+/**
+ * nfc_v1_set_geometry() - Configures the NFC geometry.
+ *
+ * @this: Per-device data.
+ */
+static int nfc_v1_set_geometry(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+ struct nfc_geometry *nfc = &this->nfc_geometry;
+ unsigned int block_count;
+ unsigned int block_size;
+ unsigned int metadata_size;
+ unsigned int ecc_strength;
+ unsigned int page_size;
+
+ /* We make the abstract choices in a common function. */
+
+ if (nfc_set_geometry(this))
+ return !0;
+
+ /* Translate the abstract choices into register fields. */
+
+ block_count = nfc->ecc_chunk_count - 1;
+ block_size = nfc->ecc_chunk_size_in_bytes;
+ metadata_size = nfc->metadata_size_in_bytes;
+ ecc_strength = nfc->ecc_strength >> 1;
+ page_size = nfc->page_size_in_bytes;
+
+ /*
+ * 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.
+ */
+
+ mxs_reset_block(resources->bch_regs, true);
+
+ /* Configure layout 0. */
+
+ __raw_writel(
+ V1_BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) |
+ V1_BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) |
+ V1_BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) |
+ V1_BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size) ,
+ resources->bch_regs + V1_HW_BCH_FLASH0LAYOUT0);
+
+ __raw_writel(
+ V1_BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) |
+ V1_BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) |
+ V1_BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size) ,
+ resources->bch_regs + V1_HW_BCH_FLASH0LAYOUT1);
+
+ /* Set *all* chip selects to use layout 0. */
+
+ __raw_writel(0, resources->bch_regs + V1_HW_BCH_LAYOUTSELECT);
+
+ /* Enable interrupts. */
+
+ __raw_writel(V1_BM_BCH_CTRL_COMPLETE_IRQ_EN,
+ resources->bch_regs + V1_HW_BCH_CTRL_SET);
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * nfc_v1_exit() - Shuts down the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static void nfc_v1_exit(struct gpmi_nfc_data *this)
+{
+ nfc_dma_exit(this);
+}
+
+/**
+ * nfc_v1_is_ready() - Returns the ready/busy status of the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ */
+static int nfc_v1_is_ready(struct gpmi_nfc_data *this, unsigned chip)
+{
+ struct resources *resources = &this->resources;
+ uint32_t mask;
+ uint32_t register_image;
+
+ /* Extract and return the status. */
+
+ mask = V1_BF_GPMI_STAT_READY_BUSY(1 << chip);
+
+ register_image = __raw_readl(resources->gpmi_regs + V1_HW_GPMI_STAT);
+
+ return !!(register_image & mask);
+
+}
+
+/**
+ * nfc_v1_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 nfc_v1_send_command(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t buffer, unsigned int length)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error;
+ uint32_t command_mode;
+ uint32_t address;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* A DMA descriptor that sends out the command. */
+
+ command_mode = V1_BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = V1_BV_GPMI_CTRL0_ADDRESS__NAND_CLE;
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = DMA_READ;
+ (*d)->cmd.cmd.bits.chain = 1;
+ (*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 = 3;
+ (*d)->cmd.cmd.bits.bytes = length;
+
+ (*d)->cmd.address = buffer;
+
+ (*d)->cmd.pio_words[0] =
+ V1_BM_GPMI_CTRL0_LOCK_CS |
+ V1_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V1_BM_GPMI_CTRL0_WORD_LENGTH |
+ V1_BF_GPMI_CTRL0_CS(chip) |
+ V1_BF_GPMI_CTRL0_ADDRESS(address) |
+ V1_BM_GPMI_CTRL0_ADDRESS_INCREMENT |
+ V1_BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v1_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 nfc_v1_send_data(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t buffer, unsigned int length)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* A DMA descriptor that writes a buffer out. */
+
+ command_mode = V1_BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = V1_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*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;
+
+ (*d)->cmd.address = buffer;
+
+ (*d)->cmd.pio_words[0] =
+ V1_BM_GPMI_CTRL0_LOCK_CS |
+ V1_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V1_BM_GPMI_CTRL0_WORD_LENGTH |
+ V1_BF_GPMI_CTRL0_CS(chip) |
+ V1_BF_GPMI_CTRL0_ADDRESS(address) |
+ V1_BF_GPMI_CTRL0_XFER_COUNT(length) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v1_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 nfc_v1_read_data(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t buffer, unsigned int length)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* A DMA descriptor that reads the data. */
+
+ command_mode = V1_BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = V1_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*d)->cmd.cmd.data = 0;
+ (*d)->cmd.cmd.bits.command = DMA_WRITE;
+ (*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;
+ (*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 = 1;
+ (*d)->cmd.cmd.bits.bytes = length;
+
+ (*d)->cmd.address = buffer;
+
+ (*d)->cmd.pio_words[0] =
+ V1_BM_GPMI_CTRL0_LOCK_CS |
+ V1_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V1_BM_GPMI_CTRL0_WORD_LENGTH |
+ V1_BF_GPMI_CTRL0_CS(chip) |
+ V1_BF_GPMI_CTRL0_ADDRESS(address) |
+ V1_BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /*
+ * 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 = V1_BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = V1_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*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] =
+ V1_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V1_BM_GPMI_CTRL0_LOCK_CS |
+ V1_BM_GPMI_CTRL0_WORD_LENGTH |
+ V1_BF_GPMI_CTRL0_CS(chip) |
+ V1_BF_GPMI_CTRL0_ADDRESS(address) |
+ V1_BF_GPMI_CTRL0_XFER_COUNT(0) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v1_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 nfc_v1_send_page(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+ uint32_t ecc_command;
+ uint32_t buffer_mask;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* A DMA descriptor that does an ECC page read. */
+
+ command_mode = V1_BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = V1_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+ ecc_command = V1_BV_GPMI_ECCCTRL_ECC_CMD__ENCODE;
+ buffer_mask = V1_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ V1_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+
+ (*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] =
+ V1_BM_GPMI_CTRL0_LOCK_CS |
+ V1_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V1_BM_GPMI_CTRL0_WORD_LENGTH |
+ V1_BF_GPMI_CTRL0_CS(chip) |
+ V1_BF_GPMI_CTRL0_ADDRESS(address) |
+ V1_BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+
+ (*d)->cmd.pio_words[2] =
+ V1_BM_GPMI_ECCCTRL_ENABLE_ECC |
+ V1_BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ V1_BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+
+ (*d)->cmd.pio_words[3] = nfc_geo->page_size_in_bytes;
+ (*d)->cmd.pio_words[4] = payload;
+ (*d)->cmd.pio_words[5] = auxiliary;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Prepare to receive an interrupt from the BCH block. */
+
+ init_completion(&nfc->bch_done);
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Wait for the interrupt from the BCH block. */
+
+ wait_for_completion(&nfc->bch_done);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * nfc_v1_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 nfc_v1_read_page(struct gpmi_nfc_data *this, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary)
+{
+ struct device *dev = this->dev;
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct mxs_dma_desc **d = nfc->dma_descriptors;
+ int dma_channel;
+ int error = 0;
+ uint32_t command_mode;
+ uint32_t address;
+ uint32_t ecc_command;
+ uint32_t buffer_mask;
+
+ /* Compute the DMA channel. */
+
+ dma_channel = resources->dma_low_channel + chip;
+
+ /* Wait for the chip to report ready. */
+
+ command_mode = V1_BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = V1_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*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;
+ (*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 = 1;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ V1_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V1_BM_GPMI_CTRL0_LOCK_CS |
+ V1_BM_GPMI_CTRL0_WORD_LENGTH |
+ V1_BF_GPMI_CTRL0_CS(chip) |
+ V1_BF_GPMI_CTRL0_ADDRESS(address) |
+ V1_BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Enable the BCH block and read. */
+
+ command_mode = V1_BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = V1_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+ ecc_command = V1_BV_GPMI_ECCCTRL_ECC_CMD__DECODE;
+ buffer_mask = V1_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ V1_BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+
+ (*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;
+ (*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] =
+ V1_BM_GPMI_CTRL0_LOCK_CS |
+ V1_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V1_BM_GPMI_CTRL0_WORD_LENGTH |
+ V1_BF_GPMI_CTRL0_CS(chip) |
+ V1_BF_GPMI_CTRL0_ADDRESS(address) |
+ V1_BF_GPMI_CTRL0_XFER_COUNT(nfc_geo->page_size_in_bytes) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] =
+ V1_BM_GPMI_ECCCTRL_ENABLE_ECC |
+ V1_BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ V1_BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+ (*d)->cmd.pio_words[3] = nfc_geo->page_size_in_bytes;
+ (*d)->cmd.pio_words[4] = payload;
+ (*d)->cmd.pio_words[5] = auxiliary;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Disable the BCH block */
+
+ command_mode = V1_BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = V1_BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+ (*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;
+ (*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 = 3;
+ (*d)->cmd.cmd.bits.bytes = 0;
+
+ (*d)->cmd.address = 0;
+
+ (*d)->cmd.pio_words[0] =
+ V1_BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ V1_BM_GPMI_CTRL0_LOCK_CS |
+ V1_BM_GPMI_CTRL0_WORD_LENGTH |
+ V1_BF_GPMI_CTRL0_CS(chip) |
+ V1_BF_GPMI_CTRL0_ADDRESS(address) |
+ V1_BF_GPMI_CTRL0_XFER_COUNT(nfc_geo->page_size_in_bytes) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+
+ 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++;
+
+ /* Prepare to receive an interrupt from the BCH block. */
+
+ init_completion(&nfc->bch_done);
+
+ /* Go! */
+
+ error = nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Wait for the interrupt from the BCH block. */
+
+ wait_for_completion(&nfc->bch_done);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/*
+ * At this point, we've defined all the version-specific primitives. We're now
+ * ready to construct the NFC HAL structures for every version.
+ */
+
+struct nfc_hal nfc_v0_hal = {
+ .version = 0,
+ .description = "4-chip GPMI and BCH",
+ .max_chip_count = 4,
+ .init = nfc_v0_init,
+ .set_geometry = nfc_v0_set_geometry,
+ .exit = nfc_v0_exit,
+ .is_ready = nfc_v0_is_ready,
+ .send_command = nfc_v0_send_command,
+ .send_data = nfc_v0_send_data,
+ .read_data = nfc_v0_read_data,
+ .send_page = nfc_v0_send_page,
+ .read_page = nfc_v0_read_page,
+};
+
+struct nfc_hal nfc_v1_hal = {
+ .version = 1,
+ .description = "8-chip GPMI and BCH",
+ .max_chip_count = 8,
+ .init = nfc_v1_init,
+ .set_geometry = nfc_v1_set_geometry,
+ .exit = nfc_v1_exit,
+ .is_ready = nfc_v1_is_ready,
+ .send_command = nfc_v1_send_command,
+ .send_data = nfc_v1_send_data,
+ .read_data = nfc_v1_read_data,
+ .send_page = nfc_v1_send_page,
+ .read_page = nfc_v1_read_page,
+};
+
+/*
+ * This array has a pointer to every NFC HAL structure. The probing process will
+ * find and install the one that matches the version given by the platform.
+ */
+
+struct nfc_hal *(nfc_hals[]) = {
+ &nfc_v0_hal,
+ &nfc_v1_hal,
+};
+
+/*
+ *------------------------------------------------------------------------------
+ * Boot ROM Helper
+ *
+ * The following functions implent Boot ROM helpers for various versions of the
+ * Boot ROM.
+ *------------------------------------------------------------------------------
+ */
+
+/**
+ * rom_helper_set_geometry() - Sets geometry for the Boot ROM Helper.
+ *
+ * @this: Per-device data.
+ */
+static int rom_helper_set_geometry(struct gpmi_nfc_data *this)
+{
+ struct boot_rom_geometry *geometry = &this->rom_geometry;
+
+ /*
+ * Set the boot block stride size.
+ *
+ * In principle, we should be reading this from the OTP bits, since
+ * that's where the ROM is going to get it. In fact, we don't have any
+ * way to read the OTP bits, so we go with the default and hope for the
+ * best.
+ */
+
+ geometry->stride_size_in_pages = 64;
+
+ /*
+ * Set the search area stride exponent.
+ *
+ * In principle, we should be reading this from the OTP bits, since
+ * that's where the ROM is going to get it. In fact, we don't have any
+ * way to read the OTP bits, so we go with the default and hope for the
+ * best.
+ */
+
+ geometry->search_area_stride_exponent = 2;
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/*
+ * Useful variables for Boot ROM Helper version 0.
+ */
+
+static const char *rom_helper_v0_fingerprint = "STMP";
+
+/**
+ * rom_helper_v0_set_geometry() - Sets geometry for the Boot ROM Helper.
+ *
+ * @this: Per-device data.
+ */
+static int rom_helper_v0_set_geometry(struct gpmi_nfc_data *this)
+{
+ struct gpmi_nfc_platform_data *pdata = this->pdata;
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct boot_rom_geometry *geometry = &this->rom_geometry;
+ int error;
+
+ /* Version-independent geometry. */
+
+ error = rom_helper_set_geometry(this);
+
+ if (error)
+ return error;
+
+ /*
+ * Check if the platform data indicates we are to protect the boot area.
+ */
+
+ if (!pdata->boot_area_size_in_bytes) {
+ geometry->boot_area_count = 0;
+ geometry->boot_area_size_in_bytes = 0;
+ return 0;
+ }
+
+ /*
+ * If control arrives here, we are supposed to set up partitions to
+ * protect the boot areas. In this version of the ROM, the number of
+ * boot areas and their size depends on the number of chips.
+ */
+
+ if (physical->chip_count == 1) {
+ geometry->boot_area_count = 1;
+ geometry->boot_area_size_in_bytes =
+ pdata->boot_area_size_in_bytes * 2;
+ } else {
+ geometry->boot_area_count = 2;
+ geometry->boot_area_size_in_bytes =
+ pdata->boot_area_size_in_bytes;
+ }
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * rom_helper_v0_check_transcription_stamp() - Checks for a transcription stamp.
+ *
+ * Returns 0 if a stamp is not found.
+ *
+ * @this: Per-device data.
+ */
+static int rom_helper_v0_check_transcription_stamp(struct gpmi_nfc_data *this)
+{
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct boot_rom_geometry *rom_geo = &this->rom_geometry;
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+ struct nand_chip *nand = &mil->nand;
+ unsigned int search_area_size_in_strides;
+ unsigned int stride;
+ unsigned int page;
+ loff_t byte;
+ uint8_t *buffer = nand->buffers->databuf;
+ int saved_chip_number;
+ int found_an_ncb_fingerprint = false;
+
+ /* Compute the number of strides in a search area. */
+
+ search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
+
+ /* Select chip 0. */
+
+ saved_chip_number = mil->current_chip;
+ nand->select_chip(mtd, 0);
+
+ /*
+ * Loop through the first search area, looking for the NCB fingerprint.
+ */
+
+ pr_info("Scanning for an NCB fingerprint...\n");
+
+ for (stride = 0; stride < search_area_size_in_strides; stride++) {
+
+ /* Compute the page and byte addresses. */
+
+ page = stride * rom_geo->stride_size_in_pages;
+ byte = page * physical->page_data_size_in_bytes;
+
+ pr_info(" Looking for a fingerprint in page 0x%x\n", page);
+
+ /*
+ * Read the NCB fingerprint. The fingerprint appears in the
+ * first four bytes of the page data, which is just past the
+ * metadata.
+ */
+
+ nand->cmdfunc(mtd, NAND_CMD_READ0,
+ nfc_geo->metadata_size_in_bytes, page);
+ nand->read_buf(mtd, buffer, strlen(rom_helper_v0_fingerprint));
+
+ /* Look for the fingerprint. */
+
+ if (!memcmp(buffer, rom_helper_v0_fingerprint,
+ strlen(rom_helper_v0_fingerprint))) {
+ found_an_ncb_fingerprint = true;
+ break;
+ }
+
+ }
+
+ /* Deselect chip 0. */
+
+ nand->select_chip(mtd, saved_chip_number);
+
+ /* Return. */
+
+ if (found_an_ncb_fingerprint)
+ pr_info(" Found a fingerprint\n");
+ else
+ pr_info(" No fingerprint found\n");
+
+ return found_an_ncb_fingerprint;
+
+}
+
+/**
+ * rom_helper_v0_write_transcription_stamp() - Writes a transcription stamp.
+ *
+ * @this: Per-device data.
+ */
+static int rom_helper_v0_write_transcription_stamp(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct boot_rom_geometry *rom_geo = &this->rom_geometry;
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+ struct nand_chip *nand = &mil->nand;
+ unsigned int block_size_in_pages;
+ unsigned int search_area_size_in_strides;
+ unsigned int search_area_size_in_pages;
+ unsigned int search_area_size_in_blocks;
+ unsigned int block;
+ unsigned int stride;
+ unsigned int page;
+ loff_t byte;
+ uint8_t *buffer = nand->buffers->databuf;
+ int saved_chip_number;
+ int status;
+
+ /* Compute the search area geometry. */
+
+ block_size_in_pages = physical->block_size_in_bytes >>
+ (ffs(physical->page_data_size_in_bytes) - 1);
+
+ search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
+
+ search_area_size_in_pages = search_area_size_in_strides *
+ rom_geo->stride_size_in_pages;
+
+ search_area_size_in_blocks =
+ (search_area_size_in_pages + (block_size_in_pages - 1)) /
+ /*-------------------------------------------------------*/
+ block_size_in_pages;
+
+ #if defined(DETAILED_INFO)
+
+ pr_info("--------------------\n");
+ pr_info("Search Area Geometry\n");
+ pr_info("--------------------\n");
+ pr_info("Search Area Size in Blocks : %u", search_area_size_in_blocks);
+ pr_info("Search Area Size in Strides: %u", search_area_size_in_strides);
+ pr_info("Search Area Size in Pages : %u", search_area_size_in_pages);
+
+ #endif
+
+ /* Select chip 0. */
+
+ saved_chip_number = mil->current_chip;
+ nand->select_chip(mtd, 0);
+
+ /* Loop over blocks in the first search area, erasing them. */
+
+ pr_info("Erasing the search area...\n");
+
+ for (block = 0; block < search_area_size_in_blocks; block++) {
+
+ /* Compute the page address. */
+
+ page = block * block_size_in_pages;
+
+ /* Erase this block. */
+
+ pr_info(" Erasing block 0x%x\n", block);
+
+ nand->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+ nand->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+
+ /* Wait for the erase to finish. */
+
+ status = nand->waitfunc(mtd, nand);
+
+ if (status & NAND_STATUS_FAIL)
+ dev_err(dev, "[%s] Erase failed.\n", __func__);
+
+ }
+
+ /* Write the NCB fingerprint into the page buffer. */
+
+ memset(buffer, ~0, mtd->writesize);
+ memset(nand->oob_poi, ~0, mtd->oobsize);
+
+ memcpy(buffer + nfc_geo->metadata_size_in_bytes,
+ rom_helper_v0_fingerprint, strlen(rom_helper_v0_fingerprint));
+
+ /* Loop through the first search area, writing NCB fingerprints. */
+
+ pr_info("Writing NCB fingerprints...\n");
+
+ for (stride = 0; stride < search_area_size_in_strides; stride++) {
+
+ /* Compute the page and byte addresses. */
+
+ page = stride * rom_geo->stride_size_in_pages;
+ byte = page * physical->page_data_size_in_bytes;
+
+ /* Write the first page of the current stride. */
+
+ pr_info(" Writing an NCB fingerprint in page 0x%x\n", page);
+
+ nand->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+ nand->ecc.write_page_raw(mtd, nand, buffer);
+ nand->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+ /* Wait for the write to finish. */
+
+ status = nand->waitfunc(mtd, nand);
+
+ if (status & NAND_STATUS_FAIL)
+ dev_err(dev, "[%s] Write failed.\n", __func__);
+
+ }
+
+ /* Deselect chip 0. */
+
+ nand->select_chip(mtd, saved_chip_number);
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * rom_helper_v1_set_geometry() - Sets geometry for the Boot ROM Helper.
+ *
+ * @this: Per-device data.
+ */
+static int rom_helper_v1_set_geometry(struct gpmi_nfc_data *this)
+{
+ struct gpmi_nfc_platform_data *pdata = this->pdata;
+ struct boot_rom_geometry *geometry = &this->rom_geometry;
+ int error;
+
+ /* Version-independent geometry. */
+
+ error = rom_helper_set_geometry(this);
+
+ if (error)
+ return error;
+
+ /*
+ * Check if the platform data indicates we are to protect the boot area.
+ */
+
+ if (!pdata->boot_area_size_in_bytes) {
+ geometry->boot_area_count = 0;
+ geometry->boot_area_size_in_bytes = 0;
+ return 0;
+ }
+
+ /*
+ * If control arrives here, we are supposed to set up partitions to
+ * protect the boot areas. In this version of the ROM, we support only
+ * one boot area.
+ */
+
+ geometry->boot_area_count = 1;
+
+ /*
+ * Use the platform's boot area size.
+ */
+
+ geometry->boot_area_size_in_bytes = pdata->boot_area_size_in_bytes;
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/*
+ * At this point, we've defined all the version-specific primitives. We're now
+ * ready to construct the Boot ROM Helper structures for every version.
+ */
+
+struct boot_rom_helper boot_rom_helper_0 = {
+ .version = 0,
+ .description = "Single/dual-chip boot area, "
+ "no block mark swapping",
+ .swap_block_mark = false,
+ .set_geometry = rom_helper_v0_set_geometry,
+ .check_transcription_stamp = rom_helper_v0_check_transcription_stamp,
+ .write_transcription_stamp = rom_helper_v0_write_transcription_stamp,
+};
+
+struct boot_rom_helper boot_rom_helper_1 = {
+ .version = 1,
+ .description = "Single-chip boot area, "
+ "block mark swapping supported",
+ .swap_block_mark = true,
+ .set_geometry = rom_helper_v1_set_geometry,
+ .check_transcription_stamp = 0,
+ .write_transcription_stamp = 0,
+};
+
+/*
+ * This array has a pointer to every Boot ROM Helper structure. The probing
+ * process will find and install the one that matches the version given by the
+ * platform.
+ */
+
+struct boot_rom_helper *(boot_rom_helpers[]) = {
+ &boot_rom_helper_0,
+ &boot_rom_helper_1,
+};
+
+/*
+ *------------------------------------------------------------------------------
+ * MTD Interface Layer
+ *
+ * The following functions interface this driver to the NAND Flash MTD system.
+ *------------------------------------------------------------------------------
+ */
+
+/**
+ * mil_outgoing_buffer_dma_begin() - Begins DMA on an outgoing buffer.
+ *
+ * @this: Per-device data.
+ * @source: The source buffer.
+ * @length: The length of the data in the source buffer.
+ * @alt_virt: The virtual address of an alternate buffer which is ready to be
+ * used for DMA.
+ * @alt_phys: The physical address of an alternate buffer which is ready to be
+ * used for DMA.
+ * @alt_size: The size of the alternate buffer.
+ * @use_virt: A pointer to a variable that will receive the virtual address to
+ * use.
+ * @use_phys: A pointer to a variable that will receive the physical address to
+ * use.
+ */
+static int mil_outgoing_buffer_dma_begin(struct gpmi_nfc_data *this,
+ const void *source, unsigned length,
+ void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+ const void **use_virt, dma_addr_t *use_phys)
+{
+ struct device *dev = this->dev;
+ dma_addr_t source_phys = ~0;
+
+ /*
+ * If we can, we want to use the caller's buffer directly for DMA. Check
+ * if the system will let us map them.
+ */
+
+ if (map_io_buffers && virt_addr_valid(source))
+ source_phys =
+ dma_map_single(dev,
+ (void *) source, length, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dev, source_phys)) {
+
+ /*
+ * If control arrives here, we're not mapping the source buffer.
+ * Make sure the alternate is large enough.
+ */
+
+ if (alt_size < length) {
+ dev_err(dev, "Alternate buffer is too small "
+ "for outgoing I/O\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Copy the contents of the source buffer into the alternate
+ * buffer and set up the return values accordingly.
+ */
+
+ memcpy(alt_virt, source, length);
+
+ *use_virt = alt_virt;
+ *use_phys = alt_phys;
+
+ } else {
+
+ /*
+ * If control arrives here, we're mapping the source buffer. Set
+ * up the return values accordingly.
+ */
+
+ *use_virt = source;
+ *use_phys = source_phys;
+
+ }
+
+ /* If control arrives here, all is well. */
+
+ return 0;
+
+}
+
+/**
+ * mil_outgoing_buffer_dma_end() - Ends DMA on an outgoing buffer.
+ *
+ * @this: Per-device data.
+ * @source: The source buffer.
+ * @length: The length of the data in the source buffer.
+ * @alt_virt: The virtual address of an alternate buffer which was ready to be
+ * used for DMA.
+ * @alt_phys: The physical address of an alternate buffer which was ready to
+ * be used for DMA.
+ * @alt_size: The size of the alternate buffer.
+ * @used_virt: The virtual address that was used.
+ * @used_phys: The physical address that was used.
+ */
+static void mil_outgoing_buffer_dma_end(struct gpmi_nfc_data *this,
+ const void *source, unsigned length,
+ void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+ const void *used_virt, dma_addr_t used_phys)
+{
+ struct device *dev = this->dev;
+
+ /*
+ * Check if we used the source buffer, and it's not one of our own DMA
+ * buffers. If so, we need to unmap it.
+ */
+
+ if (used_virt == source)
+ dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE);
+
+}
+
+/**
+ * mil_incoming_buffer_dma_begin() - Begins DMA on an incoming buffer.
+ *
+ * @this: Per-device data.
+ * @destination: The destination buffer.
+ * @length: The length of the data that will arrive.
+ * @alt_virt: The virtual address of an alternate buffer which is ready
+ * to be used for DMA.
+ * @alt_phys: The physical address of an alternate buffer which is ready
+ * to be used for DMA.
+ * @alt_size: The size of the alternate buffer.
+ * @use_virt: A pointer to a variable that will receive the virtual address
+ * to use.
+ * @use_phys: A pointer to a variable that will receive the physical address
+ * to use.
+ */
+static int mil_incoming_buffer_dma_begin(struct gpmi_nfc_data *this,
+ void *destination, unsigned length,
+ void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+ void **use_virt, dma_addr_t *use_phys)
+{
+ struct device *dev = this->dev;
+ dma_addr_t destination_phys = ~0;
+
+ /*
+ * If we can, we want to use the caller's buffer directly for DMA. Check
+ * if the system will let us map them.
+ */
+
+ if (map_io_buffers && virt_addr_valid(destination))
+ destination_phys =
+ dma_map_single(dev,
+ (void *) destination, length, DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(dev, destination_phys)) {
+
+ /*
+ * If control arrives here, we're not mapping the destination
+ * buffer. Make sure the alternate is large enough.
+ */
+
+ if (alt_size < length) {
+ dev_err(dev, "Alternate buffer is too small "
+ "for incoming I/O\n");
+ return -ENOMEM;
+ }
+
+ /* Set up the return values to use the alternate. */
+
+ *use_virt = alt_virt;
+ *use_phys = alt_phys;
+
+ } else {
+
+ /*
+ * If control arrives here, we're mapping the destination
+ * buffer. Set up the return values accordingly.
+ */
+
+ *use_virt = destination;
+ *use_phys = destination_phys;
+
+ }
+
+ /* If control arrives here, all is well. */
+
+ return 0;
+
+}
+
+/**
+ * mil_incoming_buffer_dma_end() - Ends DMA on an incoming buffer.
+ *
+ * @this: Per-device data.
+ * @destination: The destination buffer.
+ * @length: The length of the data that arrived.
+ * @alt_virt: The virtual address of an alternate buffer which was ready to
+ * be used for DMA.
+ * @alt_phys: The physical address of an alternate buffer which was ready to
+ * be used for DMA.
+ * @alt_size: The size of the alternate buffer.
+ * @used_virt: The virtual address that was used.
+ * @used_phys: The physical address that was used.
+ */
+static void mil_incoming_buffer_dma_end(struct gpmi_nfc_data *this,
+ void *destination, unsigned length,
+ void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+ void *used_virt, dma_addr_t used_phys)
+{
+ struct device *dev = this->dev;
+
+ /*
+ * Check if we used the destination buffer, and it's not one of our own
+ * DMA buffers. If so, we need to unmap it.
+ */
+
+ if (used_virt == destination)
+ dma_unmap_single(dev, used_phys, length, DMA_FROM_DEVICE);
+ else
+ memcpy(destination, alt_virt, length);
+
+}
+
+/**
+ * mil_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 mil_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct gpmi_nfc_data *this = nand->priv;
+ struct device *dev = this->dev;
+ struct mil *mil = &this->mil;
+ struct nfc_hal *nfc = this->nfc;
+ int error;
+#if defined(CONFIG_MTD_DEBUG)
+ unsigned int i;
+ char display[MIL_COMMAND_BUFFER_SIZE * 5];
+#endif
+
+ /*
+ * 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 deassert
+ * 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)
+ mil->cmd_virt[mil->command_length++] = 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 (!mil->command_length)
+ return;
+
+ /* Hand the command over to the NFC. */
+
+ add_event("mil_cmd_ctrl sending command...", 1);
+
+#if defined(CONFIG_MTD_DEBUG)
+ display[0] = 0;
+ for (i = 0; i < mil->command_length; i++)
+ sprintf(display + strlen(display), " 0x%02x",
+ mil->cmd_virt[i] & 0xff);
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc cmd_ctrl] command: %s\n", display);
+#endif
+
+ error = nfc->send_command(this,
+ mil->current_chip, mil->cmd_phys, mil->command_length);
+
+ if (error) {
+ dev_err(dev, "[%s] Chip: %u, Error %d\n",
+ __func__, mil->current_chip, error);
+ print_hex_dump(KERN_ERR,
+ " Command Bytes: ", DUMP_PREFIX_NONE, 16, 1,
+ mil->cmd_virt, mil->command_length, 0);
+ }
+
+ add_event("...Finished", -1);
+
+ /* Reset. */
+
+ mil->command_length = 0;
+
+}
+
+/**
+ * mil_dev_ready() - MTD Interface dev_ready()
+ *
+ * @mtd: A pointer to the owning MTD.
+ */
+static int mil_dev_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct gpmi_nfc_data *this = nand->priv;
+ struct nfc_hal *nfc = this->nfc;
+ struct mil *mil = &this->mil;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc dev_ready]\n");
+
+ add_event("=> mil_dev_ready", 1);
+
+ if (nfc->is_ready(this, mil->current_chip)) {
+ add_event("<= mil_dev_ready - Returning ready", -1);
+ return !0;
+ } else {
+ add_event("<= mil_dev_ready - Returning busy", -1);
+ return 0;
+ }
+
+}
+
+/**
+ * mil_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 mil_select_chip(struct mtd_info *mtd, int chip)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct gpmi_nfc_data *this = nand->priv;
+ struct mil *mil = &this->mil;
+ struct clk *clock = this->resources.clock;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc select_chip] chip: %d\n", chip);
+
+ /* Figure out what kind of transition this is. */
+
+ if ((mil->current_chip < 0) && (chip >= 0)) {
+ start_event_trace("=> mil_select_chip");
+ clk_enable(clock);
+ add_event("<= mil_select_chip", -1);
+ } else if ((mil->current_chip >= 0) && (chip < 0)) {
+ add_event("=> mil_select_chip", 1);
+ clk_disable(clock);
+ stop_event_trace("<= mil_select_chip");
+ } else {
+ add_event("=> mil_select_chip", 1);
+ add_event("<= mil_select_chip", -1);
+ }
+
+ mil->current_chip = chip;
+
+}
+
+/**
+ * mil_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 mil_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct gpmi_nfc_data *this = nand->priv;
+ struct device *dev = this->dev;
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct mil *mil = &this->mil;
+ void *use_virt = 0;
+ dma_addr_t use_phys = ~0;
+ int error;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc readbuf] len: %d\n", len);
+
+ add_event("=> mil_read_buf", 1);
+
+ /* Set up DMA. */
+
+ error = mil_incoming_buffer_dma_begin(this, buf, len,
+ mil->payload_virt, mil->payload_phys,
+ nfc_geo->payload_size_in_bytes,
+ &use_virt, &use_phys);
+
+ if (error) {
+ dev_err(dev, "[%s] Inadequate DMA buffer\n", __func__);
+ goto exit;
+ }
+
+ /* Ask the NFC. */
+
+ nfc->read_data(this, mil->current_chip, use_phys, len);
+
+ /* Finish with DMA. */
+
+ mil_incoming_buffer_dma_end(this, buf, len,
+ mil->payload_virt, mil->payload_phys,
+ nfc_geo->payload_size_in_bytes,
+ use_virt, use_phys);
+
+ /* Return. */
+
+exit:
+
+ add_event("<= mil_read_buf", -1);
+
+}
+
+/**
+ * mil_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 mil_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct gpmi_nfc_data *this = nand->priv;
+ struct device *dev = this->dev;
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct mil *mil = &this->mil;
+ const void *use_virt = 0;
+ dma_addr_t use_phys = ~0;
+ int error;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc writebuf] len: %d\n", len);
+
+ add_event("=> mil_write_buf", 1);
+
+ /* Set up DMA. */
+
+ error = mil_outgoing_buffer_dma_begin(this, buf, len,
+ mil->payload_virt, mil->payload_phys,
+ nfc_geo->payload_size_in_bytes,
+ &use_virt, &use_phys);
+
+ if (error) {
+ dev_err(dev, "[%s] Inadequate DMA buffer\n", __func__);
+ goto exit;
+ }
+
+ /* Ask the NFC. */
+
+ nfc->send_data(this, mil->current_chip, use_phys, len);
+
+ /* Finish with DMA. */
+
+ mil_outgoing_buffer_dma_end(this, buf, len,
+ mil->payload_virt, mil->payload_phys,
+ nfc_geo->payload_size_in_bytes,
+ use_virt, use_phys);
+
+ /* Return. */
+
+exit:
+
+ add_event("<= mil_write_buf", -1);
+
+}
+
+/**
+ * mil_read_byte() - MTD Interface read_byte().
+ *
+ * @mtd: A pointer to the owning MTD.
+ */
+static uint8_t mil_read_byte(struct mtd_info *mtd)
+{
+ uint8_t byte;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc read_byte]\n");
+
+ add_event("=> mil_read_byte", 1);
+
+ mil_read_buf(mtd, (uint8_t *) &byte, 1);
+
+ add_event("<= mil_read_byte", -1);
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc read_byte]: 0x%02x\n", byte);
+
+ return byte;
+
+}
+
+
+/**
+ * mil_handle_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 mil_handle_block_mark_swapping(struct gpmi_nfc_data *this,
+ void *payload, void *auxiliary)
+{
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct boot_rom_helper *rom = this->rom;
+ unsigned char *p;
+ unsigned char *a;
+ unsigned int bit;
+ unsigned char mask;
+ unsigned char from_data;
+ unsigned char from_oob;
+
+ /* Check if we're doing block mark swapping. */
+
+ if (!rom->swap_block_mark)
+ return;
+
+ /*
+ * If control arrives here, we're swapping. Make some convenience
+ * variables.
+ */
+
+ bit = nfc_geo->block_mark_bit_offset;
+ p = ((unsigned char *) payload) + nfc_geo->block_mark_byte_offset;
+ a = auxiliary;
+
+ /*
+ * 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));
+
+}
+
+/**
+ * mil_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 mil_ecc_read_page(struct mtd_info *mtd,
+ struct nand_chip *nand, uint8_t *buf)
+{
+ struct gpmi_nfc_data *this = nand->priv;
+ struct device *dev = this->dev;
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct mil *mil = &this->mil;
+ void *payload_virt = 0;
+ dma_addr_t payload_phys = ~0;
+ void *auxiliary_virt = 0;
+ dma_addr_t auxiliary_phys = ~0;
+ unsigned int i;
+ unsigned char *status;
+ unsigned int failed;
+ unsigned int corrected;
+ int error = 0;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc ecc_read_page]\n");
+
+ add_event("=> mil_ecc_read_page", 1);
+
+ /*
+ * Set up DMA.
+ *
+ * Notice that we don't try to use the caller's buffer as the auxiliary.
+ * We need to do a lot of fiddling to deliver the OOB, so there's no
+ * point.
+ */
+
+ error = mil_incoming_buffer_dma_begin(this, buf, mtd->writesize,
+ mil->payload_virt, mil->payload_phys,
+ nfc_geo->payload_size_in_bytes,
+ &payload_virt, &payload_phys);
+
+ if (error) {
+ dev_err(dev, "[%s] Inadequate DMA buffer\n", __func__);
+ error = -ENOMEM;
+ goto exit_payload;
+ }
+
+ auxiliary_virt = mil->auxiliary_virt;
+ auxiliary_phys = mil->auxiliary_phys;
+
+ /* Ask the NFC. */
+
+ error = nfc->read_page(this, mil->current_chip,
+ payload_phys, auxiliary_phys);
+
+ if (error) {
+ dev_err(dev, "[%s] Error in ECC-based read: %d\n",
+ __func__, error);
+ goto exit_nfc;
+ }
+
+ /* Handle block mark swapping. */
+
+ mil_handle_block_mark_swapping(this, payload_virt, auxiliary_virt);
+
+ /* Loop over status bytes, accumulating ECC status. */
+
+ failed = 0;
+ corrected = 0;
+
+ status = ((unsigned char *) auxiliary_virt) +
+ nfc_geo->auxiliary_status_offset;
+
+ for (i = 0; i < nfc_geo->ecc_chunk_count; 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 mil_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] = ((uint8_t *) auxiliary_virt)[0];
+
+ /* Return. */
+
+exit_nfc:
+ mil_incoming_buffer_dma_end(this, buf, mtd->writesize,
+ mil->payload_virt, mil->payload_phys,
+ nfc_geo->payload_size_in_bytes,
+ payload_virt, payload_phys);
+exit_payload:
+
+ add_event("<= mil_ecc_read_page", -1);
+
+ return error;
+
+}
+
+/**
+ * mil_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 mil_ecc_write_page(struct mtd_info *mtd,
+ struct nand_chip *nand, const uint8_t *buf)
+{
+ struct gpmi_nfc_data *this = nand->priv;
+ struct device *dev = this->dev;
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct boot_rom_helper *rom = this->rom;
+ struct mil *mil = &this->mil;
+ const void *payload_virt = 0;
+ dma_addr_t payload_phys = ~0;
+ const void *auxiliary_virt = 0;
+ dma_addr_t auxiliary_phys = ~0;
+ int error;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc ecc_write_page]\n");
+
+ add_event("=> mil_ecc_write_page", 1);
+
+ /*
+ * Set up DMA.
+ *
+ * If we're doing block mark swapping, we *must* use our own buffers
+ * because we need to modify the incoming data, and we can't touch the
+ * caller's buffers.
+ *
+ * If we're not doing block mark swapping, we can try to map the
+ * caller's buffers.
+ */
+
+ if (rom->swap_block_mark) {
+
+ memcpy(mil->payload_virt, buf, mtd->writesize);
+ payload_virt = mil->payload_virt;
+ payload_phys = mil->payload_phys;
+
+ memcpy(mil->auxiliary_virt, nand->oob_poi, mtd->oobsize);
+ auxiliary_virt = mil->auxiliary_virt;
+ auxiliary_phys = mil->auxiliary_phys;
+
+ } else {
+
+ error = mil_outgoing_buffer_dma_begin(this,
+ buf, mtd->writesize,
+ mil->payload_virt, mil->payload_phys,
+ nfc_geo->payload_size_in_bytes,
+ &payload_virt, &payload_phys);
+
+ if (error) {
+ dev_err(dev, "[%s] Inadequate payload DMA buffer\n",
+ __func__);
+ goto exit_payload;
+ }
+
+ error = mil_outgoing_buffer_dma_begin(this,
+ nand->oob_poi, mtd->oobsize,
+ mil->auxiliary_virt, mil->auxiliary_phys,
+ nfc_geo->auxiliary_size_in_bytes,
+ &auxiliary_virt, &auxiliary_phys);
+
+ if (error) {
+ dev_err(dev, "[%s] Inadequate auxiliary DMA buffer\n",
+ __func__);
+ goto exit_auxiliary;
+ }
+
+ }
+
+ /* Handle block mark swapping before writing. */
+
+ mil_handle_block_mark_swapping(this,
+ (void *) payload_virt, (void *) auxiliary_virt);
+
+ /* Ask the NFC. */
+
+ error = nfc->send_page(this, mil->current_chip,
+ payload_phys, auxiliary_phys);
+
+ if (error)
+ dev_err(dev, "[%s] Error in ECC-based write: %d\n",
+ __func__, error);
+
+ /* Return. */
+
+ if (!rom->swap_block_mark)
+ mil_outgoing_buffer_dma_end(this, nand->oob_poi, mtd->oobsize,
+ mil->auxiliary_virt, mil->auxiliary_phys,
+ nfc_geo->auxiliary_size_in_bytes,
+ auxiliary_virt, auxiliary_phys);
+exit_auxiliary:
+ if (!rom->swap_block_mark)
+ mil_outgoing_buffer_dma_end(this, buf, mtd->writesize,
+ mil->payload_virt, mil->payload_phys,
+ nfc_geo->payload_size_in_bytes,
+ payload_virt, payload_phys);
+exit_payload:
+
+ add_event("<= mil_ecc_write_page", -1);
+
+}
+
+/**
+ * mil_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 mil_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_data *this = chip->priv;
+ struct mil *mil = &this->mil;
+ int ret;
+
+ mil->raw_oob_mode = ops->mode == MTD_OOB_RAW;
+ ret = mil->hooked_read_oob(mtd, from, ops);
+ mil->raw_oob_mode = false;
+ return ret;
+}
+
+/**
+ * mil_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 mil_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_data *this = chip->priv;
+ struct mil *mil = &this->mil;
+ int ret;
+
+ mil->raw_oob_mode = ops->mode == MTD_OOB_RAW;
+ ret = mil->hooked_write_oob(mtd, to, ops);
+ mil->raw_oob_mode = false;
+ return ret;
+}
+
+/**
+ * mil_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 mil_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ register struct nand_chip *chip = mtd->priv;
+ struct gpmi_nfc_data *this = chip->priv;
+ struct mil *mil = &this->mil;
+ int ret;
+
+ mil->marking_a_bad_block = true;
+ ret = mil->hooked_block_markbad(mtd, ofs);
+ mil->marking_a_bad_block = false;
+ return ret;
+}
+
+/**
+ * mil_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 mil_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
+ int page, int sndcmd)
+{
+ struct gpmi_nfc_data *this = nand->priv;
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct mil *mil = &this->mil;
+ struct boot_rom_helper *rom = this->rom;
+ int block_mark_column;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc ecc_read_oob] "
+ "page: 0x%06x, sndcmd: %s\n", page, sndcmd ? "Yes" : "No");
+
+ add_event("=> mil_ecc_read_oob", 1);
+
+ /*
+ * 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 (mil->raw_oob_mode) {
+
+ /*
+ * If control arrives here, we're doing a "raw" read. Send the
+ * command to read the conventional OOB.
+ */
+
+ nand->cmdfunc(mtd, NAND_CMD_READ0,
+ physical->page_data_size_in_bytes, 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.
+ */
+
+ if (!(rom->swap_block_mark && mil->raw_oob_mode)) {
+
+ /* First, figure out where the block mark is. */
+
+ if (rom->swap_block_mark)
+ block_mark_column = physical->page_data_size_in_bytes;
+ else
+ block_mark_column = 0;
+
+ /* 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);
+
+ }
+
+ /*
+ * Return true, indicating that the next call to this function must send
+ * a command.
+ */
+
+ add_event("<= mil_ecc_read_oob", -1);
+
+ return true;
+
+}
+
+/**
+ * mil_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 mil_ecc_write_oob(struct mtd_info *mtd,
+ struct nand_chip *nand, int page)
+{
+ struct gpmi_nfc_data *this = nand->priv;
+ struct device *dev = this->dev;
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct mil *mil = &this->mil;
+ struct boot_rom_helper *rom = this->rom;
+ uint8_t block_mark = 0;
+ int block_mark_column;
+ int status;
+ int error = 0;
+
+ DEBUG(MTD_DEBUG_LEVEL2,
+ "[gpmi_nfc ecc_write_oob] page: 0x%06x\n", page);
+
+ add_event("=> mil_ecc_write_oob", -1);
+
+ /*
+ * 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 (!mil->marking_a_bad_block) {
+ dev_emerg(dev, "This driver doesn't support writing the OOB\n");
+ WARN_ON(1);
+ 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.
+ */
+
+ if (rom->swap_block_mark)
+ block_mark_column = physical->page_data_size_in_bytes;
+ else
+ block_mark_column = 0;
+
+ /* 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:
+
+ add_event("<= mil_ecc_write_oob", -1);
+
+ return error;
+
+}
+
+/**
+ * mil_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.
+ */
+int mil_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+{
+ return 0;
+}
+
+/**
+ * mil_set_physical_geometry() - Set up the physical medium geometry.
+ *
+ * This function retrieves the physical geometry information discovered by
+ * nand_scan(), corrects it, and records it in the per-device data structure.
+ *
+ * @this: Per-device data.
+ */
+static int mil_set_physical_geometry(struct gpmi_nfc_data *this)
+{
+ struct mil *mil = &this->mil;
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct mtd_info *mtd = &mil->mtd;
+ struct nand_chip *nand = &mil->nand;
+ struct nand_device_info *info;
+ int saved_chip_number;
+ uint8_t id_bytes[NAND_DEVICE_ID_BYTE_COUNT];
+ unsigned int block_size_in_pages;
+ unsigned int chip_size_in_blocks;
+ unsigned int chip_size_in_pages;
+ uint64_t medium_size_in_bytes;
+
+ /* Read ID bytes from the first NAND Flash chip. */
+
+ saved_chip_number = mil->current_chip;
+ nand->select_chip(mtd, 0);
+
+ nand->cmdfunc(mtd, NAND_CMD_READID, 0, -1);
+ nand->read_buf(mtd, id_bytes, NAND_DEVICE_ID_BYTE_COUNT);
+
+ nand->select_chip(mtd, saved_chip_number);
+
+ /* Look up information about this device, based on the ID bytes. */
+
+ info = nand_device_get_info(id_bytes);
+
+ /* Check if we understand this device. */
+
+ if (!info) {
+ printk(KERN_ERR "Unrecognized NAND Flash device.\n");
+ return !0;
+ }
+
+ /* Display the information we discovered. */
+
+ #if defined(DETAILED_INFO)
+ pr_info("-----------------------------\n");
+ pr_info("NAND Flash Device Information\n");
+ pr_info("-----------------------------\n");
+ nand_device_print_info(info);
+ #endif
+
+ /*
+ * Copy the device info into the per-device data. We can't just keep
+ * the pointer because that storage is reclaimed after initialization.
+ * Notice that we null out the pointer to the device description, which
+ * will also be reclaimed.
+ */
+
+ this->device_info = *info;
+ this->device_info.description = 0;
+
+ /*
+ * Record the number of physical chips that MTD found.
+ */
+
+ physical->chip_count = nand->numchips;
+
+ /*
+ * We know the total size of a page. We need to break that down into the
+ * data size and OOB size. The data size is the largest power of two
+ * that will fit in the given page size. The OOB size is what's left
+ * over.
+ */
+
+ physical->page_data_size_in_bytes =
+ 1 << (fls(info->page_total_size_in_bytes) - 1);
+
+ physical->page_oob_size_in_bytes =
+ info->page_total_size_in_bytes -
+ physical->page_data_size_in_bytes;
+
+ /*
+ * Now that we know the page data size, we can multiply this by the
+ * number of pages in a block to compute the block size.
+ */
+
+ physical->block_size_in_bytes =
+ physical->page_data_size_in_bytes * info->block_size_in_pages;
+
+ /* Get the chip size. */
+
+ physical->chip_size_in_bytes = info->chip_size_in_bytes;
+
+ /* Compute some interesting facts. */
+
+ block_size_in_pages =
+ physical->block_size_in_bytes >>
+ (fls(physical->page_data_size_in_bytes) - 1);
+ chip_size_in_pages =
+ physical->chip_size_in_bytes >>
+ (fls(physical->page_data_size_in_bytes) - 1);
+ chip_size_in_blocks =
+ physical->chip_size_in_bytes >>
+ (fls(physical->block_size_in_bytes) - 1);
+ medium_size_in_bytes =
+ physical->chip_size_in_bytes * physical->chip_count;
+
+ /* Report. */
+
+ #if defined(DETAILED_INFO)
+
+ pr_info("-----------------\n");
+ pr_info("Physical Geometry\n");
+ pr_info("-----------------\n");
+ pr_info("Chip Count : %d\n", physical->chip_count);
+ pr_info("Page Data Size in Bytes: %u (0x%x)\n",
+ physical->page_data_size_in_bytes,
+ physical->page_data_size_in_bytes);
+ pr_info("Page OOB Size in Bytes : %u\n",
+ physical->page_oob_size_in_bytes);
+ pr_info("Block Size in Bytes : %u (0x%x)\n",
+ physical->block_size_in_bytes,
+ physical->block_size_in_bytes);
+ pr_info("Block Size in Pages : %u (0x%x)\n",
+ block_size_in_pages,
+ block_size_in_pages);
+ pr_info("Chip Size in Bytes : %llu (0x%llx)\n",
+ physical->chip_size_in_bytes,
+ physical->chip_size_in_bytes);
+ pr_info("Chip Size in Pages : %u (0x%x)\n",
+ chip_size_in_pages, chip_size_in_pages);
+ pr_info("Chip Size in Blocks : %u (0x%x)\n",
+ chip_size_in_blocks, chip_size_in_blocks);
+ pr_info("Medium Size in Bytes : %llu (0x%llx)\n",
+ medium_size_in_bytes, medium_size_in_bytes);
+
+ #endif
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_set_nfc_geometry() - Set up the NFC geometry.
+ *
+ * This function calls the NFC HAL to select an NFC geometry that is compatible
+ * with the medium's physical geometry.
+ *
+ * @this: Per-device data.
+ */
+static int mil_set_nfc_geometry(struct gpmi_nfc_data *this)
+{
+ struct nfc_hal *nfc = this->nfc;
+ struct nfc_geometry *geo = &this->nfc_geometry;
+
+ /* Set the NFC geometry. */
+
+ if (nfc->set_geometry(this))
+ return !0;
+
+ /* Report. */
+
+ #if defined(DETAILED_INFO)
+
+ pr_info("------------\n");
+ pr_info("NFC Geometry\n");
+ pr_info("------------\n");
+ pr_info("ECC Algorithm : %s\n", geo->ecc_algorithm);
+ pr_info("ECC Strength : %u\n", geo->ecc_strength);
+ pr_info("Page Size in Bytes : %u\n", geo->page_size_in_bytes);
+ pr_info("Metadata Size in Bytes : %u\n", geo->metadata_size_in_bytes);
+ pr_info("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size_in_bytes);
+ pr_info("ECC Chunk Count : %u\n", geo->ecc_chunk_count);
+ pr_info("Payload Size in Bytes : %u\n", geo->payload_size_in_bytes);
+ pr_info("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size_in_bytes);
+ pr_info("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset);
+ pr_info("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset);
+ pr_info("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset);
+
+ #endif
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_set_boot_rom_helper_geometry() - Set up the Boot ROM Helper geometry.
+ *
+ * @this: Per-device data.
+ */
+static int mil_set_boot_rom_helper_geometry(struct gpmi_nfc_data *this)
+{
+ struct boot_rom_helper *rom = this->rom;
+ struct boot_rom_geometry *geo = &this->rom_geometry;
+
+ /* Set the Boot ROM Helper geometry. */
+
+ if (rom->set_geometry(this))
+ return !0;
+
+ /* Report. */
+
+ #if defined(DETAILED_INFO)
+
+ pr_info("-----------------\n");
+ pr_info("Boot ROM Geometry\n");
+ pr_info("-----------------\n");
+ pr_info("Boot Area Count : %u\n", geo->boot_area_count);
+ pr_info("Boot Area Size in Bytes : %u (0x%x)\n",
+ geo->boot_area_size_in_bytes, geo->boot_area_size_in_bytes);
+ pr_info("Stride Size in Pages : %u\n", geo->stride_size_in_pages);
+ pr_info("Search Area Stride Exponent: %u\n",
+ geo->search_area_stride_exponent);
+
+ #endif
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_set_mtd_geometry() - Set up the MTD geometry.
+ *
+ * This function adjusts the owning MTD data structures to match the logical
+ * geometry we've chosen.
+ *
+ * @this: Per-device data.
+ */
+static int mil_set_mtd_geometry(struct gpmi_nfc_data *this)
+{
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct mil *mil = &this->mil;
+ struct nand_ecclayout *layout = &mil->oob_layout;
+ struct nand_chip *nand = &mil->nand;
+ struct mtd_info *mtd = &mil->mtd;
+
+ /* Configure the struct nand_ecclayout. */
+
+ layout->eccbytes = 0;
+ layout->oobavail = physical->page_oob_size_in_bytes;
+ layout->oobfree[0].offset = 0;
+ layout->oobfree[0].length = physical->page_oob_size_in_bytes;
+
+ /* Configure the struct mtd_info. */
+
+ mtd->size = nand->numchips * physical->chip_size_in_bytes;
+ mtd->erasesize = physical->block_size_in_bytes;
+ mtd->writesize = physical->page_data_size_in_bytes;
+ mtd->ecclayout = layout;
+ mtd->oobavail = mtd->ecclayout->oobavail;
+ mtd->oobsize = mtd->ecclayout->oobavail + mtd->ecclayout->eccbytes;
+ mtd->subpage_sft = 0; /* We don't support sub-page writing. */
+
+ /* Configure the struct nand_chip. */
+
+ nand->chipsize = physical->chip_size_in_bytes;
+ 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->oob_poi = nand->buffers->databuf + mtd->writesize;
+ nand->ecc.layout = layout;
+ if (nand->chipsize & 0xffffffff)
+ nand->chip_shift = ffs((unsigned) nand->chipsize) - 1;
+ else
+ nand->chip_shift =
+ ffs((unsigned) (nand->chipsize >> 32)) + 32 - 1;
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_set_geometry() - Set up the medium geometry.
+ *
+ * @this: Per-device data.
+ */
+static int mil_set_geometry(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct nfc_geometry *nfc_geo = &this->nfc_geometry;
+ struct mil *mil = &this->mil;
+
+ /* Set up the various layers of geometry, in this specific order. */
+
+ if (mil_set_physical_geometry(this))
+ return -ENXIO;
+
+ if (mil_set_nfc_geometry(this))
+ return -ENXIO;
+
+ if (mil_set_boot_rom_helper_geometry(this))
+ return -ENXIO;
+
+ if (mil_set_mtd_geometry(this))
+ return -ENXIO;
+
+ /*
+ * Allocate the page buffer.
+ *
+ * Both the payload buffer and the auxiliary buffer must appear on
+ * 32-bit boundaries. We presume the size of the payload buffer is a
+ * power of two and is much larger than four, which guarantees the
+ * auxiliary buffer will appear on a 32-bit boundary.
+ */
+
+ mil->page_buffer_size = nfc_geo->payload_size_in_bytes +
+ nfc_geo->auxiliary_size_in_bytes;
+
+ mil->page_buffer_virt =
+ dma_alloc_coherent(dev, mil->page_buffer_size,
+ &mil->page_buffer_phys, GFP_DMA);
+
+ if (!mil->page_buffer_virt)
+ return -ENOMEM;
+
+ /* Slice up the page buffer. */
+
+ mil->payload_virt = mil->page_buffer_virt;
+ mil->payload_phys = mil->page_buffer_phys;
+
+ mil->auxiliary_virt = ((char *) mil->payload_virt) +
+ nfc_geo->payload_size_in_bytes;
+ mil->auxiliary_phys = mil->payload_phys +
+ nfc_geo->payload_size_in_bytes;
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_pre_bbt_scan() - Prepare for the BBT scan.
+ *
+ * @this: Per-device data.
+ */
+static int mil_pre_bbt_scan(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct boot_rom_helper *rom = this->rom;
+ struct mil *mil = &this->mil;
+ struct nand_chip *nand = &mil->nand;
+ struct mtd_info *mtd = &mil->mtd;
+ unsigned int block_count;
+ unsigned int block;
+ int chip;
+ int page;
+ loff_t byte;
+ uint8_t block_mark;
+ int error;
+
+ /*
+ * Check if we can use block mark swapping, which enables us to leave
+ * the block marks where they are. If so, we don't need to do anything
+ * at all.
+ */
+
+ if (rom->swap_block_mark)
+ return 0;
+
+ /*
+ * If control arrives here, we can't use block mark swapping, which
+ * means we're forced to use transcription. First, scan for the
+ * transcription stamp. If we find it, then we don't have to do
+ * anything -- the block marks are already transcribed.
+ */
+
+ if (rom->check_transcription_stamp(this))
+ return 0;
+
+ /*
+ * If control arrives here, we couldn't find a transcription stamp, so
+ * so we presume the block marks are in the conventional location.
+ */
+
+ pr_info("Transcribing bad block marks...\n");
+
+ /* Compute the number of blocks in the entire medium. */
+
+ block_count =
+ physical->chip_size_in_bytes >> nand->phys_erase_shift;
+
+ /*
+ * Loop over all the blocks in the medium, transcribing block marks as
+ * we go.
+ */
+
+ for (block = 0; block < block_count; block++) {
+
+ /*
+ * Compute the chip, page and byte addresses for this block's
+ * conventional mark.
+ */
+
+ chip = block >> (nand->chip_shift - nand->phys_erase_shift);
+ page = block << (nand->phys_erase_shift - nand->page_shift);
+ byte = block << nand->phys_erase_shift;
+
+ /* Select the chip. */
+
+ nand->select_chip(mtd, chip);
+
+ /* Send the command to read the conventional block mark. */
+
+ nand->cmdfunc(mtd, NAND_CMD_READ0,
+ physical->page_data_size_in_bytes, page);
+
+ /* Read the conventional block mark. */
+
+ block_mark = nand->read_byte(mtd);
+
+ /*
+ * Check if the block is marked bad. If so, we need to mark it
+ * again, but this time the result will be a mark in the
+ * location where we transcribe block marks.
+ *
+ * Notice that we have to explicitly set the marking_a_bad_block
+ * member before we call through the block_markbad function
+ * pointer in the owning struct nand_chip. If we could call
+ * though the block_markbad function pointer in the owning
+ * struct mtd_info, which we have hooked, then this would be
+ * taken care of for us. Unfortunately, we can't because that
+ * higher-level code path will do things like consulting the
+ * in-memory bad block table -- which doesn't even exist yet!
+ * So, we have to call at a lower level and handle some details
+ * ourselves.
+ */
+
+ if (block_mark != 0xff) {
+ pr_info("Transcribing block mark in block %u\n", block);
+ mil->marking_a_bad_block = true;
+ error = nand->block_markbad(mtd, byte);
+ mil->marking_a_bad_block = false;
+ if (error)
+ dev_err(dev, "Failed to mark block bad with "
+ "error %d\n", error);
+ }
+
+ /* Deselect the chip. */
+
+ nand->select_chip(mtd, -1);
+
+ }
+
+ /* Write the stamp that indicates we've transcribed the block marks. */
+
+ rom->write_transcription_stamp(this);
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_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 mil_scan_bbt(struct mtd_info *mtd)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct gpmi_nfc_data *this = nand->priv;
+ int error;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "[gpmi_nfc scan_bbt] \n");
+
+ /*
+ * 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;
+
+ /* Set up geometry. */
+
+ error = mil_set_geometry(this);
+
+ if (error)
+ return error;
+
+ /* Prepare for the BBT scan. */
+
+ error = mil_pre_bbt_scan(this);
+
+ if (error)
+ return error;
+
+ /* We use the reference implementation for bad block management. */
+
+ error = nand_default_bbt(mtd);
+
+ if (error)
+ return error;
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_boot_areas_init() - Initializes boot areas.
+ *
+ * @this: Per-device data.
+ */
+static int mil_boot_areas_init(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct physical_geometry *physical = &this->physical_geometry;
+ struct boot_rom_geometry *rom = &this->rom_geometry;
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+ struct nand_chip *nand = &mil->nand;
+ int mtd_support_is_adequate;
+ unsigned int i;
+ struct mtd_partition partitions[4];
+ struct mtd_info *search_mtd;
+ struct mtd_info *chip_0_remainder_mtd = 0;
+ struct mtd_info *medium_remainder_mtd = 0;
+ struct mtd_info *concatenate[2];
+
+ /*
+ * Here we declare the static strings we use to name partitions. We use
+ * static strings because, as of 2.6.31, the partitioning code *always*
+ * registers the partition MTDs it creates and leaves behind *no* other
+ * trace of its work. So, once we've created a partition, we must search
+ * the master MTD table to find the MTDs we created. Since we're using
+ * static strings, we can simply search the master table for an MTD with
+ * a name field pointing to a known address.
+ */
+
+ static char *chip_0_boot_name = "gpmi-nfc-0-boot";
+ static char *chip_0_remainder_name = "gpmi-nfc-0-remainder";
+ static char *chip_1_boot_name = "gpmi-nfc-1-boot";
+ static char *medium_remainder_name = "gpmi-nfc-remainder";
+ static char *general_use_name = "gpmi-nfc-general-use";
+
+ /* Check if we're protecting the boot areas.*/
+
+ if (!rom->boot_area_count) {
+
+ /*
+ * If control arrives here, we're not protecting the boot areas.
+ * In this case, there are not boot area partitons, and the main
+ * MTD is the general use MTD.
+ */
+
+ mil->general_use_mtd = &mil->mtd;
+
+ return 0;
+
+ }
+
+ /*
+ * If control arrives here, we're protecting the boot areas. Check if we
+ * have the MTD support we need.
+ */
+
+ pr_info("Boot area protection is enabled.\n");
+
+ if (rom->boot_area_count > 1) {
+
+ /*
+ * If the Boot ROM wants more than one boot area, then we'll
+ * need to create partitions *and* concatenate them.
+ */
+
+ #if defined(CONFIG_MTD_PARTITIONS) && defined(CONFIG_MTD_CONCAT)
+ mtd_support_is_adequate = true;
+ #else
+ mtd_support_is_adequate = false;
+ #endif
+
+ } else if (rom->boot_area_count == 1) {
+
+ /*
+ * If the Boot ROM wants only one boot area, then we only need
+ * to create partitions -- we don't need to concatenate them.
+ */
+
+ #if defined(CONFIG_MTD_PARTITIONS)
+ mtd_support_is_adequate = true;
+ #else
+ mtd_support_is_adequate = false;
+ #endif
+
+ } else {
+
+ /*
+ * If control arrives here, we're protecting the boot area, but
+ * somehow the boot area count was set to zero. This doesn't
+ * make any sense.
+ */
+
+ dev_err(dev, "Boot area count is incorrectly set to zero.");
+ return -ENXIO;
+
+ }
+
+ if (!mtd_support_is_adequate) {
+ dev_err(dev, "Configured MTD support is inadequate to "
+ "protect the boot area(s).");
+ return -ENXIO;
+ }
+
+ /*
+ * If control arrives here, we're protecting boot areas and we have
+ * everything we need to do so.
+ *
+ * We have special code to handle the case for one boot area.
+ *
+ * The code that handles "more than one" boot area actually only handles
+ * two. We *could* write the general case, but that would take a lot of
+ * time to both write and test -- and, at this writing, we don't have a
+ * chip that cares.
+ */
+
+ /* Check if a boot area is larger than a single chip. */
+
+ if (rom->boot_area_size_in_bytes > physical->chip_size_in_bytes) {
+ dev_emerg(dev, "Boot area size is larger than a single chip");
+ return -ENXIO;
+ }
+
+ if (rom->boot_area_count == 1) {
+
+ /*
+ * We partition the medium like so:
+ *
+ * +------+----------------------------------------------------+
+ * | Boot | General Use |
+ * +------+----------------------------------------------------+
+ */
+
+ /* Chip 0 Boot */
+
+ partitions[0].name = chip_0_boot_name;
+ partitions[0].offset = 0;
+ partitions[0].size = rom->boot_area_size_in_bytes;
+ partitions[0].mask_flags = 0;
+
+ /* General Use */
+
+ partitions[1].name = general_use_name;
+ partitions[1].offset = rom->boot_area_size_in_bytes;
+ partitions[1].size = MTDPART_SIZ_FULL;
+ partitions[1].mask_flags = 0;
+
+ /* Construct and register the partitions. */
+
+ add_mtd_partitions(mtd, partitions, 2);
+
+ /* Find the general use MTD. */
+
+ for (i = 0; i < MAX_MTD_DEVICES; i++) {
+ search_mtd = get_mtd_device(0, i);
+ if (!search_mtd)
+ continue;
+ if (search_mtd == ERR_PTR(-ENODEV))
+ continue;
+ if (search_mtd->name == general_use_name)
+ mil->general_use_mtd = search_mtd;
+ }
+
+ if (!mil->general_use_mtd) {
+ dev_emerg(dev, "Can't find general use MTD");
+ BUG();
+ }
+
+ } else if (rom->boot_area_count == 2) {
+
+ /*
+ * If control arrives here, there is more than one chip. We
+ * partition the medium and concatenate the remainders like so:
+ *
+ * --- Chip 0 --- --- Chip 1 --- ... ------- Chip N -------
+ * / \ / \
+ * +----+----------+----+--------------- ... ------------------+
+ * |Boot|Remainder |Boot| Remainder |
+ * +----+----------+----+--------------- ... ------------------+
+ * | | / /
+ * | | / /
+ * | | / /
+ * | |/ /
+ * +----------+----------- ... ----------------------+
+ * | General Use |
+ * +----------+----------- ... ----------------------+
+ *
+ * Notice that the results we leave in the master MTD table
+ * are a little bit goofy:
+ *
+ * * Chip 0 Boot Area
+ * * Chip 1 Boot Area
+ * * Chip 0 Remainder
+ * * Medium Remainder
+ *
+ * There are two reasons:
+ *
+ * 1) Since the remainder partitions aren't very useful, we'd
+ * actually prefer to "hide" (create them but not register
+ * them). This was possible before 2.6.31, but now the
+ * partitioning code automatically registers anything it
+ * creates (thanks :(). It might be possible to "unregister"
+ * these MTDs after the fact, but I don't have time to look
+ * into the other effects that might have.
+ *
+ * 2) Some user space programs expect the boot partitions to
+ * appear first. This is naive, but let's try not to cause
+ * any trouble, where we can avoid it.
+ */
+
+ /* Chip 0 Boot */
+
+ partitions[0].name = chip_0_boot_name;
+ partitions[0].offset = 0;
+ partitions[0].size = rom->boot_area_size_in_bytes;
+ partitions[0].mask_flags = 0;
+
+ /* Chip 1 Boot */
+
+ partitions[1].name = chip_1_boot_name;
+ partitions[1].offset = nand->chipsize;
+ partitions[1].size = rom->boot_area_size_in_bytes;
+ partitions[1].mask_flags = 0;
+
+ /* Chip 0 Remainder */
+
+ partitions[2].name = chip_0_remainder_name;
+ partitions[2].offset = rom->boot_area_size_in_bytes;
+ partitions[2].size = nand->chipsize -
+ rom->boot_area_size_in_bytes;
+ partitions[2].mask_flags = 0;
+
+ /* Medium Remainder */
+
+ partitions[3].name = medium_remainder_name;
+ partitions[3].offset = nand->chipsize +
+ rom->boot_area_size_in_bytes;
+ partitions[3].size = MTDPART_SIZ_FULL;
+ partitions[3].mask_flags = 0;
+
+ /* Construct and register the partitions. */
+
+ add_mtd_partitions(mtd, partitions, 4);
+
+ /* Find the remainder partitions. */
+
+ for (i = 0; i < MAX_MTD_DEVICES; i++) {
+ search_mtd = get_mtd_device(0, i);
+ if (!search_mtd)
+ continue;
+ if (search_mtd == ERR_PTR(-ENODEV))
+ continue;
+ if (search_mtd->name == chip_0_remainder_name)
+ chip_0_remainder_mtd = search_mtd;
+ if (search_mtd->name == medium_remainder_name)
+ medium_remainder_mtd = search_mtd;
+ }
+
+ if (!chip_0_remainder_mtd || !medium_remainder_mtd) {
+ dev_emerg(dev, "Can't find remainder partitions");
+ BUG();
+ }
+
+ /* Concatenate the remainders and register the result. */
+
+ concatenate[0] = chip_0_remainder_mtd;
+ concatenate[1] = medium_remainder_mtd;
+
+ mil->general_use_mtd = mtd_concat_create(concatenate,
+ 2, general_use_name);
+
+ add_mtd_device(mil->general_use_mtd);
+
+ } else {
+ dev_err(dev, "Boot area count greater than two is "
+ "unimplemented.\n");
+ return -ENXIO;
+ }
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_boot_areas_exit() - Shuts down boot areas.
+ *
+ * @this: Per-device data.
+ */
+static void mil_boot_areas_exit(struct gpmi_nfc_data *this)
+{
+ struct boot_rom_geometry *rom = &this->rom_geometry;
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+
+ /* Check if we're protecting the boot areas.*/
+
+ if (!rom->boot_area_count) {
+
+ /*
+ * If control arrives here, we're not protecting the boot areas.
+ * That means we never created any boot area partitions, and the
+ * general use MTD is just the main MTD.
+ */
+
+ mil->general_use_mtd = 0;
+
+ return;
+
+ }
+
+ /*
+ * If control arrives here, we're protecting the boot areas.
+ *
+ * Start by checking if there is more than one boot area. If so, then
+ * we both partitioned the medium and then concatenated some of the
+ * partitions to form the general use MTD. The first step is to get rid
+ * of the concatenation.
+ */
+
+ if (rom->boot_area_count > 1) {
+ del_mtd_device(mil->general_use_mtd);
+ mtd_concat_destroy(mil->general_use_mtd);
+ }
+
+ /*
+ * At this point, we're left only with the partitions of the main MTD.
+ * Delete them.
+ */
+
+ del_mtd_partitions(mtd);
+
+ /* The general use MTD no longer exists. */
+
+ mil->general_use_mtd = 0;
+
+}
+
+/**
+ * mil_partitions_init() - Initializes partitions.
+ *
+ * @this: Per-device data.
+ */
+static int mil_partitions_init(struct gpmi_nfc_data *this)
+{
+ struct gpmi_nfc_platform_data *pdata = this->pdata;
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+ int error;
+
+ /*
+ * Set up the boot areas. When this function returns, if there has been
+ * no error, the boot area partitions (if any) will have been created
+ * and registered. Also, the general_use_mtd field will point to an MTD
+ * we can use.
+ */
+
+ error = mil_boot_areas_init(this);
+
+ if (error)
+ return error;
+
+ /*
+ * If we've been told to, register the MTD that represents the entire
+ * medium. Normally, we don't register the main MTD because we only want
+ * to expose the medium through the boot area partitions and the general
+ * use partition.
+ *
+ * We do this *after* setting up the boot areas because, for historical
+ * reasons that don't make particular sense, we like the lowest-numbered
+ * MTDs to be the boot areas.
+ */
+
+ if (register_main_mtd) {
+ pr_info("Registering the main MTD.\n");
+ add_mtd_device(mtd);
+ }
+
+ /*
+ * If partitioning is available, we want to apply the user's partitions
+ * to the general use MTD. Recall that the general use MTD *can* be just
+ * a pointer to the main MTD.
+ */
+
+ #if defined(CONFIG_MTD_PARTITIONS)
+
+ /*
+ * Clear out the partition information.
+ */
+
+ mil->partition_count = 0;
+ mil->partitions = 0;
+
+ /*
+ * First, try to get partition information from the given
+ * partition sources.
+ */
+
+ if (pdata->partition_source_types)
+ mil->partition_count =
+ parse_mtd_partitions(mtd,
+ pdata->partition_source_types,
+ &mil->partitions, 0);
+
+ /*
+ * Check if we got anything from a partition source. If not,
+ * then accept whatever partitions are attached to the
+ * platform data.
+ */
+
+ if ((mil->partition_count <= 0) && (pdata->partitions)) {
+ mil->partition_count = mil->partition_count;
+ mil->partitions = mil->partitions;
+ }
+
+ /* If we came up with any partitions at all, apply them. */
+
+ if (mil->partition_count)
+ add_mtd_partitions(mil->general_use_mtd,
+ mil->partitions, mil->partition_count);
+
+ #endif
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * mil_partitions_exit() - Shuts down partitions.
+ *
+ * @this: Per-device data.
+ */
+static void mil_partitions_exit(struct gpmi_nfc_data *this)
+{
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+
+ /*
+ * Check if we applied any partitions from either a partition source or
+ * the platform data.
+ */
+
+ if (mil->partition_count)
+ del_mtd_partitions(mil->general_use_mtd);
+
+ /*
+ * If we were told to register the MTD that represents the entire
+ * medium, unregister it now. Note that this does *not* "destroy" the
+ * MTD - it merely unregisters it. That's important because all our
+ * other MTDs depend on this one.
+ */
+
+ if (register_main_mtd)
+ del_mtd_device(mtd);
+
+ /* Tear down the boot areas. */
+
+ mil_boot_areas_exit(this);
+
+}
+
+/**
+ * mil_init() - Initializes the MTD Interface Layer.
+ *
+ * @this: Per-device data.
+ */
+static int mil_init(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct gpmi_nfc_platform_data *pdata = this->pdata;
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+ struct nand_chip *nand = &mil->nand;
+ static struct nand_ecclayout fake_ecc_layout;
+ int error = 0;
+
+ /* Initialize MIL data. */
+
+ mil->current_chip = -1;
+ mil->command_length = 0;
+
+ mil->page_buffer_virt = 0;
+ mil->page_buffer_phys = ~0;
+ mil->page_buffer_size = 0;
+
+ /* Initialize the MTD data structures. */
+
+ mtd->priv = nand;
+ mtd->name = "gpmi-nfc-main";
+ mtd->owner = THIS_MODULE;
+ nand->priv = this;
+
+ /*
+ * Signal Control
+ */
+
+ nand->cmd_ctrl = mil_cmd_ctrl;
+
+ /*
+ * Chip Control
+ *
+ * We rely on the reference implementations of:
+ * - cmdfunc
+ * - waitfunc
+ */
+
+ nand->dev_ready = mil_dev_ready;
+ nand->select_chip = mil_select_chip;
+
+ /*
+ * 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.
+ */
+
+ nand->read_byte = mil_read_byte;
+ nand->read_buf = mil_read_buf;
+ nand->write_buf = mil_write_buf;
+
+ /*
+ * ECC Control
+ *
+ * None of these functions are necessary for us:
+ * - ecc.hwctl
+ * - ecc.calculate
+ * - ecc.correct
+ */
+
+ /*
+ * ECC-aware I/O
+ *
+ * We rely on the reference implementations of:
+ * - ecc.read_page_raw
+ * - ecc.write_page_raw
+ */
+
+ nand->ecc.read_page = mil_ecc_read_page;
+ nand->ecc.write_page = mil_ecc_write_page;
+
+ /*
+ * High-level I/O
+ *
+ * We rely on the reference implementations of:
+ * - write_page
+ * - erase_cmd
+ */
+
+ nand->ecc.read_oob = mil_ecc_read_oob;
+ nand->ecc.write_oob = mil_ecc_write_oob;
+
+ /*
+ * Bad Block Management
+ *
+ * We rely on the reference implementations of:
+ * - block_bad
+ * - block_markbad
+ */
+
+ nand->block_bad = mil_block_bad;
+ nand->scan_bbt = mil_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.
+ */
+
+ /*
+ * Set up NAND Flash options. Specifically:
+ *
+ * - Disallow partial page writes.
+ */
+
+ nand->options |= NAND_NO_SUBPAGE_WRITE;
+
+ /*
+ * Tell the NAND Flash MTD system that we'll be handling ECC with our
+ * own hardware. It turns out that we still have to fill in the ECC size
+ * because the MTD code will divide by it -- even though it doesn't
+ * actually care.
+ */
+
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->ecc.size = 1;
+
+ /*
+ * Install a "fake" ECC layout.
+ *
+ * We'll be calling nand_scan() to do the final MTD setup. If we haven't
+ * already chosen an ECC layout, then nand_scan() will choose one based
+ * on the part geometry it discovers. Unfortunately, it doesn't make
+ * good choices. It would be best if we could install the correct ECC
+ * layout now, before we call nand_scan(). We can't do that because we
+ * don't know the medium geometry yet. Here, we install a "fake" ECC
+ * layout just to stop nand_scan() from trying to pick one for itself.
+ * Later, when we know the medium geometry, we'll install the correct
+ * one.
+ *
+ * Of course, this tactic depends critically on the MTD code not doing
+ * an I/O operation that depends on the ECC layout being sensible. This
+ * is in fact the case.
+ */
+
+ memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout));
+
+ nand->ecc.layout = &fake_ecc_layout;
+
+ /* Allocate a command buffer. */
+
+ mil->cmd_virt =
+ dma_alloc_coherent(dev,
+ MIL_COMMAND_BUFFER_SIZE, &mil->cmd_phys, GFP_DMA);
+
+ if (!mil->cmd_virt)
+ goto exit_cmd_allocation;
+
+ /*
+ * Ask the NAND Flash system to scan for chips.
+ *
+ * This will fill in reference implementations for all the members of
+ * the MTD structures that we didn't set, and will make the medium fully
+ * usable.
+ */
+
+ pr_info("Scanning for NAND Flash chips...\n");
+
+ error = nand_scan(mtd, pdata->max_chip_count);
+
+ if (error) {
+ dev_err(dev, "Chip scan failed\n");
+ goto exit_nand_scan;
+ }
+
+ /*
+ * Hook some operations at the MTD level. See the descriptions of the
+ * saved function pointer fields for details about why we hook these.
+ */
+
+ mil->hooked_read_oob = mtd->read_oob;
+ mtd->read_oob = mil_hook_read_oob;
+
+ mil->hooked_write_oob = mtd->write_oob;
+ mtd->write_oob = mil_hook_write_oob;
+
+ mil->hooked_block_markbad = mtd->block_markbad;
+ mtd->block_markbad = mil_hook_block_markbad;
+
+ /* Construct partitions as necessary. */
+
+ error = mil_partitions_init(this);
+
+ if (error)
+ goto exit_partitions;
+
+ /* Return success. */
+
+ return 0;
+
+ /* Control arrives here if something went wrong. */
+
+exit_partitions:
+ nand_release(&mil->mtd);
+exit_nand_scan:
+ dma_free_coherent(dev, MIL_COMMAND_BUFFER_SIZE,
+ mil->cmd_virt, mil->cmd_phys);
+ mil->cmd_virt = 0;
+ mil->cmd_phys = ~0;
+exit_cmd_allocation:
+
+ return error;
+
+}
+
+/**
+ * mil_exit() - Shuts down the MTD Interface Layer.
+ *
+ * @this: Per-device data.
+ */
+static void mil_exit(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct mil *mil = &this->mil;
+
+ /* Shut down partitions as necessary. */
+
+ mil_partitions_exit(this);
+
+ /* Get MTD to let go of our MTD. */
+
+ nand_release(&mil->mtd);
+
+ /* Free the page buffer, if it's been allocated. */
+
+ if (mil->page_buffer_virt)
+ dma_free_coherent(dev, mil->page_buffer_size,
+ mil->page_buffer_virt, mil->page_buffer_phys);
+
+ mil->page_buffer_size = 0;
+ mil->page_buffer_virt = 0;
+ mil->page_buffer_phys = ~0;
+
+ /* Free the command buffer, if it's been allocated. */
+
+ if (mil->cmd_virt)
+ dma_free_coherent(dev, MIL_COMMAND_BUFFER_SIZE,
+ mil->cmd_virt, mil->cmd_phys);
+
+ mil->cmd_virt = 0;
+ mil->cmd_phys = ~0;
+
+}
+
+/*
+ *------------------------------------------------------------------------------
+ * System Interface
+ *
+ * The following functions interface this driver to the rest of the kernel.
+ *------------------------------------------------------------------------------
+ */
+
+/**
+ * show_device_numchips() - Shows the number of physical chips.
+ *
+ * This node is made obsolete by the physical_geometry node, but we keep it for
+ * backward compatibility (especially for kobs).
+ *
+ * @d: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_numchips(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct physical_geometry *physical = &this->physical_geometry;
+
+ return sprintf(buf, "%d\n", physical->chip_count);
+
+}
+
+/**
+ * show_device_physical_geometry() - Shows the physical Flash device geometry.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_physical_geometry(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct physical_geometry *physical = &this->physical_geometry;
+
+ return sprintf(buf,
+ "Chip Count : %u\n"
+ "Chip Size in Bytes : %llu\n"
+ "Block Size in Bytes : %u\n"
+ "Page Data Size in Bytes: %u\n"
+ "Page OOB Size in Bytes : %u\n"
+ ,
+ physical->chip_count,
+ physical->chip_size_in_bytes,
+ physical->block_size_in_bytes,
+ physical->page_data_size_in_bytes,
+ physical->page_oob_size_in_bytes
+ );
+
+}
+
+/**
+ * show_device_nfc_info() - Shows the NFC-specific information.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_nfc_info(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct resources *resources = &this->resources;
+ struct nfc_hal *nfc = this->nfc;
+ unsigned long parent_clock_rate_in_hz;
+ unsigned long clock_rate_in_hz;
+ struct clk *parent_clock;
+
+ parent_clock = clk_get_parent(resources->clock);
+ parent_clock_rate_in_hz = clk_get_rate(parent_clock);
+ clock_rate_in_hz = clk_get_rate(resources->clock);
+
+ return sprintf(buf,
+ "Version : %u\n"
+ "Description : %s\n"
+ "Max Chip Count : %u\n"
+ "Parent Clock Rate in Hz : %lu\n"
+ "Clock Rate in Hz : %lu\n"
+ ,
+ nfc->version,
+ nfc->description,
+ nfc->max_chip_count,
+ parent_clock_rate_in_hz,
+ clock_rate_in_hz
+ );
+
+}
+
+/**
+ * show_device_nfc_geometry() - Shows the NFC view of the device geometry.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_nfc_geometry(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct nfc_geometry *nfc = &this->nfc_geometry;
+
+ return sprintf(buf,
+ "ECC Algorithm : %s\n"
+ "ECC Strength : %u\n"
+ "Page Size in Bytes : %u\n"
+ "Metadata Size in Bytes : %u\n"
+ "ECC Chunk Size in Bytes: %u\n"
+ "ECC Chunk Count : %u\n"
+ "Payload Size in Bytes : %u\n"
+ "Auxiliary Size in Bytes: %u\n"
+ "Auxiliary Status Offset: %u\n"
+ "Block Mark Byte Offset : %u\n"
+ "Block Mark Bit Offset : %u\n"
+ ,
+ nfc->ecc_algorithm,
+ nfc->ecc_strength,
+ nfc->page_size_in_bytes,
+ nfc->metadata_size_in_bytes,
+ nfc->ecc_chunk_size_in_bytes,
+ nfc->ecc_chunk_count,
+ nfc->payload_size_in_bytes,
+ nfc->auxiliary_size_in_bytes,
+ nfc->auxiliary_status_offset,
+ nfc->block_mark_byte_offset,
+ nfc->block_mark_bit_offset
+ );
+
+}
+
+/**
+ * show_device_rom_geometry() - Shows the Boot ROM Helper's geometry.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_rom_geometry(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct boot_rom_geometry *rom = &this->rom_geometry;
+
+ return sprintf(buf,
+ "Boot Area Count : %u\n"
+ "Boot Area Size in Bytes : %u\n"
+ "Stride Size in Pages : %u\n"
+ "Seach Area Stride Exponent: %u\n"
+ ,
+ rom->boot_area_count,
+ rom->boot_area_size_in_bytes,
+ rom->stride_size_in_pages,
+ rom->search_area_stride_exponent
+ );
+
+}
+
+/**
+ * show_device_mtd_nand_info() - Shows the device's MTD NAND-specific info.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_mtd_nand_info(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int o = 0;
+ unsigned int i;
+ unsigned int j;
+ static const unsigned int columns = 8;
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct mil *mil = &this->mil;
+ struct nand_chip *nand = &mil->nand;
+
+ o += sprintf(buf + o,
+ "Options : 0x%08x\n"
+ "Chip Count : %u\n"
+ "Chip Size in Bytes : %llu\n"
+ "Minimum Writable Size in Bytes: %u\n"
+ "Page Shift : %u\n"
+ "Page Mask : 0x%x\n"
+ "Block Shift : %u\n"
+ "BBT Block Shift : %u\n"
+ "Chip Shift : %u\n"
+ "Block Mark Offset : %u\n"
+ "Cached Page Number : %d\n"
+ ,
+ nand->options,
+ nand->numchips,
+ nand->chipsize,
+ nand->subpagesize,
+ nand->page_shift,
+ nand->pagemask,
+ nand->phys_erase_shift,
+ nand->bbt_erase_shift,
+ nand->chip_shift,
+ nand->badblockpos,
+ nand->pagebuf
+ );
+
+ o += sprintf(buf + o,
+ "ECC Byte Count : %u\n"
+ ,
+ nand->ecc.layout->eccbytes
+ );
+
+ /* Loop over rows. */
+
+ for (i = 0; (i * columns) < nand->ecc.layout->eccbytes; i++) {
+
+ /* Loop over columns within rows. */
+
+ for (j = 0; j < columns; j++) {
+
+ if (((i * columns) + j) >= nand->ecc.layout->eccbytes)
+ break;
+
+ o += sprintf(buf + o, " %3u",
+ nand->ecc.layout->eccpos[(i * columns) + j]);
+
+ }
+
+ o += sprintf(buf + o, "\n");
+
+ }
+
+ o += sprintf(buf + o,
+ "OOB Available Bytes : %u\n"
+ ,
+ nand->ecc.layout->oobavail
+ );
+
+ j = 0;
+
+ for (i = 0; j < nand->ecc.layout->oobavail; i++) {
+
+ j += nand->ecc.layout->oobfree[i].length;
+
+ o += sprintf(buf + o,
+ " [%3u, %2u]\n"
+ ,
+ nand->ecc.layout->oobfree[i].offset,
+ nand->ecc.layout->oobfree[i].length
+ );
+
+ }
+
+ return o;
+
+}
+
+/**
+ * show_device_mtd_info() - Shows the device's MTD-specific information.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_mtd_info(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int o = 0;
+ unsigned int i;
+ unsigned int j;
+ static const unsigned int columns = 8;
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+
+ o += sprintf(buf + o,
+ "Name : %s\n"
+ "Type : %u\n"
+ "Flags : 0x%08x\n"
+ "Size in Bytes : %llu\n"
+ "Erase Region Count : %d\n"
+ "Erase Size in Bytes: %u\n"
+ "Write Size in Bytes: %u\n"
+ "OOB Size in Bytes : %u\n"
+ "Errors Corrected : %u\n"
+ "Failed Reads : %u\n"
+ "Bad Block Count : %u\n"
+ "BBT Block Count : %u\n"
+ ,
+ mtd->name,
+ mtd->type,
+ mtd->flags,
+ mtd->size,
+ mtd->numeraseregions,
+ mtd->erasesize,
+ mtd->writesize,
+ mtd->oobsize,
+ mtd->ecc_stats.corrected,
+ mtd->ecc_stats.failed,
+ mtd->ecc_stats.badblocks,
+ mtd->ecc_stats.bbtblocks
+ );
+
+ o += sprintf(buf + o,
+ "ECC Byte Count : %u\n"
+ ,
+ mtd->ecclayout->eccbytes
+ );
+
+ /* Loop over rows. */
+
+ for (i = 0; (i * columns) < mtd->ecclayout->eccbytes; i++) {
+
+ /* Loop over columns within rows. */
+
+ for (j = 0; j < columns; j++) {
+
+ if (((i * columns) + j) >= mtd->ecclayout->eccbytes)
+ break;
+
+ o += sprintf(buf + o, " %3u",
+ mtd->ecclayout->eccpos[(i * columns) + j]);
+
+ }
+
+ o += sprintf(buf + o, "\n");
+
+ }
+
+ o += sprintf(buf + o,
+ "OOB Available Bytes: %u\n"
+ ,
+ mtd->ecclayout->oobavail
+ );
+
+ j = 0;
+
+ for (i = 0; j < mtd->ecclayout->oobavail; i++) {
+
+ j += mtd->ecclayout->oobfree[i].length;
+
+ o += sprintf(buf + o,
+ " [%3u, %2u]\n"
+ ,
+ mtd->ecclayout->oobfree[i].offset,
+ mtd->ecclayout->oobfree[i].length
+ );
+
+ }
+
+ return o;
+
+}
+
+/**
+ * store_device_mark_block_bad() - Marks a block as bad.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer containing a new attribute value.
+ * @size: The size of the buffer.
+ */
+static ssize_t store_device_mark_block_bad(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct mil *mil = &this->mil;
+ struct mtd_info *mtd = &mil->mtd;
+ struct nand_chip *nand = &mil->nand;
+ unsigned long block_number;
+ loff_t byte_address;
+ int error;
+
+ /* Look for nonsense. */
+
+ if (!size)
+ return -EINVAL;
+
+ /* Try to understand the block number. */
+
+ if (strict_strtoul(buf, 0, &block_number))
+ return -EINVAL;
+
+ /* Compute the byte address of this block. */
+
+ byte_address = block_number << nand->phys_erase_shift;
+
+ /* Attempt to mark the block bad. */
+
+ error = mtd->block_markbad(mtd, byte_address);
+
+ if (error)
+ return error;
+
+ /* Return success. */
+
+ return size;
+
+}
+
+/**
+ * show_device_ignorebad() - Shows the value of the 'ignorebad' flag.
+ *
+ * @d: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_ignorebad(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct mil *mil = &this->mil;
+
+ return sprintf(buf, "%d\n", mil->ignore_bad_block_marks);
+}
+
+/**
+ * store_device_ignorebad() - Sets the value of the 'ignorebad' flag.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer containing a new attribute value.
+ * @size: The size of the buffer.
+ */
+static ssize_t store_device_ignorebad(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct mil *mil = &this->mil;
+ const char *p = buf;
+ unsigned long v;
+
+ /* Try to make sense of what arrived from user space. */
+
+ if (strict_strtoul(p, 0, &v) < 0)
+ return size;
+
+ if (v > 0)
+ v = 1;
+
+ /* Only do something if the value is changing. */
+
+ if (v != mil->ignore_bad_block_marks) {
+
+ if (v) {
+
+ /*
+ * If control arrives here, we want to begin ignoring
+ * bad block marks. Reach into the NAND Flash MTD data
+ * structures and set the in-memory BBT pointer to NULL.
+ * This will cause the NAND Flash MTD code to believe
+ * that it never created a BBT and force it to call our
+ * block_bad function.
+ *
+ * See mil_block_bad for more details.
+ */
+
+ mil->saved_bbt = mil->nand.bbt;
+ mil->nand.bbt = 0;
+
+ } else {
+
+ /*
+ * If control arrives here, we want to stop ignoring
+ * bad block marks. Restore the NAND Flash MTD's pointer
+ * to its in-memory BBT.
+ */
+
+ mil->nand.bbt = mil->saved_bbt;
+
+ }
+
+ mil->ignore_bad_block_marks = v;
+
+ }
+
+ return size;
+
+}
+
+/**
+ * show_device_inject_ecc_error() - Shows the device's error injection flag.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_inject_ecc_error(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct mil *mil = &this->mil;
+
+ return sprintf(buf, "%d\n", mil->inject_ecc_error);
+
+}
+
+/**
+ * store_device_inject_ecc_error() - Sets the device's error injection flag.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer containing a new attribute value.
+ * @size: The size of the buffer.
+ */
+static ssize_t store_device_inject_ecc_error(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+ struct mil *mil = &this->mil;
+ long new_inject_ecc_error;
+
+ /* Look for nonsense. */
+
+ if (!size)
+ return -EINVAL;
+
+ /* Try to understand the ECC error count. */
+
+ if (strict_strtol(buf, 0, &new_inject_ecc_error))
+ return -EINVAL;
+
+ /* Store the value. */
+
+ mil->inject_ecc_error = new_inject_ecc_error;
+
+ /* Return success. */
+
+ return size;
+
+}
+
+/**
+ * store_device_invalidate_page_cache() - Invalidates the device's page cache.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer containing a new attribute value.
+ * @size: The size of the buffer.
+ */
+static ssize_t store_device_invalidate_page_cache(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct gpmi_nfc_data *this = dev_get_drvdata(dev);
+
+ /* Invalidate the page cache. */
+
+ this->mil.nand.pagebuf = -1;
+
+ /* Return success. */
+
+ return size;
+
+}
+
+/* Device attributes that appear in sysfs. */
+
+static DEVICE_ATTR(numchips , 0444, show_device_numchips , 0);
+static DEVICE_ATTR(physical_geometry, 0444, show_device_physical_geometry, 0);
+static DEVICE_ATTR(nfc_info , 0444, show_device_nfc_info , 0);
+static DEVICE_ATTR(nfc_geometry , 0444, show_device_nfc_geometry , 0);
+static DEVICE_ATTR(rom_geometry , 0444, show_device_rom_geometry , 0);
+static DEVICE_ATTR(mtd_nand_info , 0444, show_device_mtd_nand_info , 0);
+static DEVICE_ATTR(mtd_info , 0444, show_device_mtd_info , 0);
+
+static DEVICE_ATTR(mark_block_bad, 0200,
+ 0, store_device_mark_block_bad);
+
+static DEVICE_ATTR(ignorebad, 0644,
+ show_device_ignorebad, store_device_ignorebad);
+
+static DEVICE_ATTR(inject_ecc_error, 0644,
+ show_device_inject_ecc_error, store_device_inject_ecc_error);
+
+static DEVICE_ATTR(invalidate_page_cache, 0644,
+ 0, store_device_invalidate_page_cache);
+
+static struct device_attribute *device_attributes[] = {
+ &dev_attr_numchips,
+ &dev_attr_physical_geometry,
+ &dev_attr_nfc_info,
+ &dev_attr_nfc_geometry,
+ &dev_attr_rom_geometry,
+ &dev_attr_mtd_nand_info,
+ &dev_attr_mtd_info,
+ &dev_attr_mark_block_bad,
+ &dev_attr_ignorebad,
+ &dev_attr_inject_ecc_error,
+ &dev_attr_invalidate_page_cache,
+};
+
+/**
+ * validate_the_platform() - Validates information about the platform.
+ *
+ * @pdev: A pointer to the platform device data structure.
+ */
+static int validate_the_platform(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpmi_nfc_platform_data *pdata = pdev->dev.platform_data;
+
+ /* Validate the clock name. */
+
+ if (!pdata->clock_name) {
+ dev_err(dev, "No clock name\n");
+ return -ENXIO;
+ }
+
+ /* Validate the partitions. */
+
+ if ((pdata->partitions && (!pdata->partition_count)) ||
+ (!pdata->partitions && (pdata->partition_count))) {
+ dev_err(dev, "Bad partition data\n");
+ return -ENXIO;
+ }
+
+ /* Return success */
+
+ return 0;
+
+}
+
+/**
+ * acquire_register_block() - Tries to acquire and map a register block.
+ *
+ * @this: Per-device data.
+ * @resource_name: The name of the resource.
+ * @reg_block_base: A pointer to a variable that will receive the address of
+ * the mapped register block.
+ */
+static int acquire_register_block(struct gpmi_nfc_data *this,
+ const char *resource_name, void **reg_block_base)
+{
+ struct platform_device *pdev = this->pdev;
+ struct device *dev = this->dev;
+ void *p;
+ struct resource *r;
+
+ /* Attempt to get information about the given resource. */
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, resource_name);
+
+ if (!r) {
+ dev_err(dev, "Can't get resource information for '%s'\n",
+ resource_name);
+ return -ENXIO;
+ }
+
+ /* Attempt to remap the register block. */
+
+ p = ioremap(r->start, r->end - r->start + 1);
+
+ if (!p) {
+ dev_err(dev, "Can't remap %s\n", resource_name);
+ return -EIO;
+ }
+
+ /* If control arrives here, everything went fine. */
+
+ *reg_block_base = p;
+
+ return 0;
+
+}
+
+/**
+ * release_register_block() - Releases a register block.
+ *
+ * @this: Per-device data.
+ * @reg_block_base: A pointer to the mapped register block.
+ */
+static void release_register_block(struct gpmi_nfc_data *this,
+ void *reg_block_base)
+{
+ iounmap(reg_block_base);
+}
+
+/**
+ * acquire_interrupt() - Tries to acquire an interrupt.
+ *
+ * @this: Per-device data.
+ * @resource_name: The name of the resource.
+ * @interrupt_handler: A pointer to the function that will handle interrupts
+ * from this interrupt number.
+ * @interrupt_number: A pointer to a variable that will receive the acquired
+ * interrupt number.
+ */
+static int acquire_interrupt(
+ struct gpmi_nfc_data *this, const char *resource_name,
+ irq_handler_t interrupt_handler, int *interrupt_number)
+{
+ struct platform_device *pdev = this->pdev;
+ struct device *dev = this->dev;
+ int error = 0;
+ int i;
+
+ /* Attempt to get information about the given resource. */
+
+ i = platform_get_irq_byname(pdev, resource_name);
+
+ if (i < 0) {
+ dev_err(dev, "Can't get resource information for '%s'\n",
+ resource_name);
+ return -ENXIO;
+ }
+
+ /* Attempt to own the interrupt. */
+
+ error = request_irq(i, interrupt_handler, 0, resource_name, this);
+
+ if (error) {
+ dev_err(dev, "Can't own %s\n", resource_name);
+ return -EIO;
+ }
+
+ /* If control arrives here, everything went fine. */
+
+ *interrupt_number = i;
+
+ return 0;
+
+}
+
+/**
+ * release_interrupt() - Releases an interrupt.
+ *
+ * @this: Per-device data.
+ * @interrupt_number: The interrupt number.
+ */
+static void release_interrupt(struct gpmi_nfc_data *this, int interrupt_number)
+{
+ free_irq(interrupt_number, this);
+}
+
+/**
+ * acquire_dma_channels() - Tries to acquire DMA channels.
+ *
+ * @this: Per-device data.
+ * @resource_name: The name of the resource.
+ * @low_channel: A pointer to a variable that will receive the acquired
+ * low DMA channel number.
+ * @high_channel: A pointer to a variable that will receive the acquired
+ * high DMA channel number.
+ */
+static int acquire_dma_channels(
+ struct gpmi_nfc_data *this, const char *resource_name,
+ unsigned *low_channel, unsigned *high_channel)
+{
+ struct platform_device *pdev = this->pdev;
+ struct device *dev = this->dev;
+ int error = 0;
+ struct resource *r;
+ unsigned int dma_channel;
+
+ /* Attempt to get information about the given resource. */
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_DMA, resource_name);
+
+ if (!r) {
+ dev_err(dev, "Can't get resource information for '%s'\n",
+ resource_name);
+ return -ENXIO;
+ }
+
+ /* Loop over DMA channels, attempting to own them. */
+
+ for (dma_channel = r->start; dma_channel <= r->end; dma_channel++) {
+
+ /* Attempt to own the current channel. */
+
+ error = mxs_dma_request(dma_channel, dev, resource_name);
+
+ /* Check if we successfully acquired the current channel. */
+
+ if (error) {
+
+ dev_err(dev, "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, dev);
+
+ return error;
+
+ }
+
+ /*
+ * If control arrives here, we successfully acquired the
+ * current channel. Continue initializing it.
+ */
+
+ mxs_dma_reset(dma_channel);
+ mxs_dma_ack_irq(dma_channel);
+
+ }
+
+ /* If control arrives here, all went well. */
+
+ *low_channel = r->start;
+ *high_channel = r->end;
+
+ return 0;
+
+}
+
+/**
+ * release_dma_channels() - Releases DMA channels.
+ *
+ * @this: Per-device data.
+ * @low_channel: The low DMA channel number.
+ * @high_channel: The high DMA channel number.
+ */
+static void release_dma_channels(struct gpmi_nfc_data *this,
+ unsigned low_channel, unsigned high_channel)
+{
+ struct device *dev = this->dev;
+ unsigned int i;
+
+ for (i = low_channel; i <= high_channel; i++)
+ mxs_dma_release(i, dev);
+}
+
+/**
+ * acquire_clock() - Tries to acquire a clock.
+ *
+ * @this: Per-device data.
+ * @resource_name: The name of the clock.
+ * @high_channel: A pointer to a variable that will receive the acquired
+ * clock address.
+ */
+static int acquire_clock(struct gpmi_nfc_data *this,
+ const char *clock_name, struct clk **clock)
+{
+ struct device *dev = this->dev;
+ int error = 0;
+ struct clk *c;
+
+ /* Try to get the clock. */
+
+ c = clk_get(dev, clock_name);
+
+ if (IS_ERR(c)) {
+ error = PTR_ERR(c);
+ dev_err(dev, "Can't own clock %s\n", clock_name);
+ return error;
+ }
+
+ /* If control arrives here, everything went fine. */
+
+ *clock = c;
+
+ return 0;
+
+}
+
+/**
+ * release_clock() - Releases a clock.
+ *
+ * @this: Per-device data.
+ * @clock: A pointer to the clock structure.
+ */
+static void release_clock(struct gpmi_nfc_data *this, struct clk *clock)
+{
+ clk_disable(clock);
+ clk_put(clock);
+}
+
+/**
+ * acquire_resources() - Tries to acquire resources.
+ *
+ * @this: Per-device data.
+ */
+static int acquire_resources(struct gpmi_nfc_data *this)
+{
+ struct gpmi_nfc_platform_data *pdata = this->pdata;
+ struct resources *resources = &this->resources;
+ int error = 0;
+
+ /* Attempt to acquire the GPMI register block. */
+
+ error = acquire_register_block(this,
+ GPMI_NFC_GPMI_REGS_ADDR_RES_NAME, &(resources->gpmi_regs));
+
+ if (error)
+ goto exit_gpmi_regs;
+
+ /* Attempt to acquire the BCH register block. */
+
+ error = acquire_register_block(this,
+ GPMI_NFC_BCH_REGS_ADDR_RES_NAME, &(resources->bch_regs));
+
+ if (error)
+ goto exit_bch_regs;
+
+ /* Attempt to acquire the BCH interrupt. */
+
+ error = acquire_interrupt(this,
+ GPMI_NFC_BCH_INTERRUPT_RES_NAME,
+ nfc_bch_isr, &(resources->bch_interrupt));
+
+ if (error)
+ goto exit_bch_interrupt;
+
+ /* Attempt to acquire the DMA channels. */
+
+ error = acquire_dma_channels(this,
+ GPMI_NFC_DMA_CHANNELS_RES_NAME,
+ &(resources->dma_low_channel), &(resources->dma_high_channel));
+
+ if (error)
+ goto exit_dma_channels;
+
+ /* Attempt to acquire the DMA interrupt. */
+
+ error = acquire_interrupt(this,
+ GPMI_NFC_DMA_INTERRUPT_RES_NAME,
+ nfc_dma_isr, &(resources->dma_interrupt));
+
+ if (error)
+ goto exit_dma_interrupt;
+
+ /* Attempt to acquire our clock. */
+
+ error = acquire_clock(this, pdata->clock_name, &(resources->clock));
+
+ if (error)
+ goto exit_clock;
+
+ /* If control arrives here, all went well. */
+
+ return 0;
+
+ /* Control arrives here if something went wrong. */
+
+exit_clock:
+ release_interrupt(this, resources->dma_interrupt);
+exit_dma_interrupt:
+ release_dma_channels(this,
+ resources->dma_low_channel, resources->dma_high_channel);
+exit_dma_channels:
+ release_interrupt(this, resources->bch_interrupt);
+exit_bch_interrupt:
+ release_register_block(this, resources->bch_regs);
+exit_bch_regs:
+ release_register_block(this, resources->gpmi_regs);
+exit_gpmi_regs:
+
+ return error;
+
+}
+
+/**
+ * release_resources() - Releases resources.
+ *
+ * @this: Per-device data.
+ */
+static void release_resources(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+
+ release_clock(this, resources->clock);
+ release_register_block(this, resources->gpmi_regs);
+ release_register_block(this, resources->bch_regs);
+ release_interrupt(this, resources->bch_interrupt);
+ release_dma_channels(this,
+ resources->dma_low_channel, resources->dma_high_channel);
+ release_interrupt(this, resources->dma_interrupt);
+}
+
+/**
+ * set_up_nfc_hal() - Sets up the NFC HAL.
+ *
+ * @this: Per-device data.
+ */
+static int set_up_nfc_hal(struct gpmi_nfc_data *this)
+{
+ struct gpmi_nfc_platform_data *pdata = this->pdata;
+ struct device *dev = this->dev;
+ struct nfc_hal *nfc;
+ int error = 0;
+ unsigned int i;
+
+ /* Attempt to find an NFC HAL that matches the given version. */
+
+ for (i = 0; i < ARRAY_SIZE(nfc_hals); i++) {
+
+ nfc = nfc_hals[i];
+
+ if (nfc->version == pdata->nfc_version) {
+ this->nfc = nfc;
+ break;
+ }
+
+ }
+
+ /* Check if we found a HAL. */
+
+ if (i >= ARRAY_SIZE(nfc_hals)) {
+ dev_err(dev, "Unkown NFC version %u\n", pdata->nfc_version);
+ return -ENXIO;
+ }
+
+ pr_info("NFC: Version %u, %s\n", nfc->version, nfc->description);
+
+ /*
+ * Check if we can handle the number of chips called for by the platform
+ * data.
+ */
+
+ if (pdata->max_chip_count > nfc->max_chip_count) {
+ dev_err(dev, "Platform data calls for %u chips "
+ "but NFC supports a max of %u.\n",
+ pdata->max_chip_count, nfc->max_chip_count);
+ return -ENXIO;
+ }
+
+ /* Initialize the NFC HAL. */
+
+ error = nfc->init(this);
+
+ if (error)
+ return error;
+
+ /*
+ * If control arrives here, all is well.
+ */
+
+ return 0;
+
+}
+
+/**
+ * set_up_boot_rom_helper() - Sets up the Boot ROM Helper.
+ *
+ * @this: Per-device data.
+ */
+static int set_up_boot_rom_helper(struct gpmi_nfc_data *this)
+{
+ struct gpmi_nfc_platform_data *pdata = this->pdata;
+ struct device *dev = this->dev;
+ unsigned int i;
+ struct boot_rom_helper *rom;
+
+ /* Attempt to find a Boot ROM Helper that matches the given version. */
+
+ for (i = 0; i < ARRAY_SIZE(boot_rom_helpers); i++) {
+
+ rom = boot_rom_helpers[i];
+
+ if (rom->version == pdata->boot_rom_version) {
+ this->rom = rom;
+ break;
+ }
+
+ }
+
+ /* Check if we found a Boot ROM Helper. */
+
+ if (i >= ARRAY_SIZE(boot_rom_helpers)) {
+ dev_err(dev, "Unkown Boot ROM version %u\n",
+ pdata->boot_rom_version);
+ return -ENXIO;
+ }
+
+ pr_info("Boot ROM: Version %u, %s\n", rom->version, rom->description);
+
+ /*
+ * If control arrives here, all is well.
+ */
+
+ return 0;
+
+}
+
+/**
+ * manage_sysfs_files() - Creates/removes sysfs files for this device.
+ *
+ * @this: Per-device data.
+ */
+static void manage_sysfs_files(struct gpmi_nfc_data *this, int create)
+{
+ struct device *dev = this->dev;
+ int error;
+ unsigned int i;
+ struct device_attribute **attr;
+
+ for (i = 0, attr = device_attributes;
+ i < ARRAY_SIZE(device_attributes); i++, attr++) {
+
+ if (create) {
+ error = device_create_file(dev, *attr);
+ if (error) {
+ while (--attr >= device_attributes)
+ device_remove_file(dev, *attr);
+ return;
+ }
+ } else {
+ device_remove_file(dev, *attr);
+ }
+
+ }
+
+}
+
+/**
+ * gpmi_nfc_probe() - Probes for a device and, if possible, takes ownership.
+ *
+ * @pdev: A pointer to the platform device data structure.
+ */
+static int gpmi_nfc_probe(struct platform_device *pdev)
+{
+ int error = 0;
+ struct device *dev = &pdev->dev;
+ struct gpmi_nfc_platform_data *pdata = pdev->dev.platform_data;
+ struct gpmi_nfc_data *this = 0;
+
+ /* Validate the platform device data. */
+
+ error = validate_the_platform(pdev);
+
+ if (error)
+ goto exit_validate_platform;
+
+ /* Allocate memory for the per-device data. */
+
+ this = kzalloc(sizeof(*this), GFP_KERNEL);
+
+ if (!this) {
+ dev_err(dev, "Failed to allocate per-device memory\n");
+ error = -ENOMEM;
+ goto exit_allocate_this;
+ }
+
+ /* Set up our data structures. */
+
+ platform_set_drvdata(pdev, this);
+
+ this->pdev = pdev;
+ this->dev = &pdev->dev;
+ this->pdata = pdata;
+
+ /* Acquire the resources we need. */
+
+ error = acquire_resources(this);
+
+ if (error)
+ goto exit_acquire_resources;
+
+ /* Set up the NFC. */
+
+ error = set_up_nfc_hal(this);
+
+ if (error)
+ goto exit_nfc_init;
+
+ /* Set up the platform. */
+
+ if (pdata->platform_init)
+ error = pdata->platform_init(pdata->max_chip_count);
+
+ if (error)
+ goto exit_platform_init;
+
+ /* Set up the Boot ROM Helper. */
+
+ error = set_up_boot_rom_helper(this);
+
+ if (error)
+ goto exit_boot_rom_helper_init;
+
+ /* Initialize the MTD Interface Layer. */
+
+ error = mil_init(this);
+
+ if (error)
+ goto exit_mil_init;
+
+ /* Create sysfs entries for this device. */
+
+ manage_sysfs_files(this, true);
+
+ /* Return success. */
+
+ return 0;
+
+ /* Error return paths begin here. */
+
+exit_mil_init:
+exit_boot_rom_helper_init:
+ if (pdata->platform_exit)
+ pdata->platform_exit(pdata->max_chip_count);
+exit_platform_init:
+ this->nfc->exit(this);
+exit_nfc_init:
+ release_resources(this);
+exit_acquire_resources:
+ platform_set_drvdata(pdev, NULL);
+ kfree(this);
+exit_allocate_this:
+exit_validate_platform:
+ return error;
+
+}
+
+/**
+ * gpmi_nfc_remove() - Dissociates this driver from the given device.
+ *
+ * @pdev: A pointer to the platform device data structure.
+ */
+static int __exit gpmi_nfc_remove(struct platform_device *pdev)
+{
+ struct gpmi_nfc_data *this = platform_get_drvdata(pdev);
+ struct gpmi_nfc_platform_data *pdata = this->pdata;
+
+ manage_sysfs_files(this, false);
+ mil_exit(this);
+ if (pdata->platform_exit)
+ pdata->platform_exit(pdata->max_chip_count);
+ this->nfc->exit(this);
+ release_resources(this);
+ platform_set_drvdata(pdev, NULL);
+ kfree(this);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/**
+ * gpmi_nfc_suspend() - Puts the NFC into a low power state.
+ *
+ * @pdev: A pointer to the platform device data structure.
+ * @state: The new power state.
+ */
+static int gpmi_nfc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+/**
+ * gpmi_nfc_resume() - Brings the NFC back from a low power state.
+ *
+ * @pdev: A pointer to the platform device data structure.
+ */
+static int gpmi_nfc_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#else
+
+#define suspend NULL
+#define resume NULL
+
+#endif /* CONFIG_PM */
+
+/*
+ * This structure represents this driver to the platform management system.
+ */
+static struct platform_driver gpmi_nfc_driver = {
+ .driver = {
+ .name = GPMI_NFC_DRIVER_NAME,
+ },
+ .probe = gpmi_nfc_probe,
+ .remove = __exit_p(gpmi_nfc_remove),
+ .suspend = gpmi_nfc_suspend,
+ .resume = gpmi_nfc_resume,
+};
+
+/**
+ * gpmi_nfc_init() - Initializes this module.
+ */
+static int __init gpmi_nfc_init(void)
+{
+
+ pr_info("i.MX GPMI NFC\n");
+
+ /* Register this driver with the platform management system. */
+
+ if (platform_driver_register(&gpmi_nfc_driver) != 0) {
+ pr_err("i.MX GPMI NFC driver registration failed\n");
+ return -ENODEV;
+ }
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * gpmi_nfc_exit() - Deactivates this module.
+ */
+static void __exit gpmi_nfc_exit(void)
+{
+ platform_driver_unregister(&gpmi_nfc_driver);
+}
+
+module_init(gpmi_nfc_init);
+module_exit(gpmi_nfc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h
new file mode 100644
index 000000000000..6aaa323cdaf1
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ */
+
+#ifndef __DRIVERS_MTD_NAND_GPMI_NFC_H
+#define __DRIVERS_MTD_NAND_GPMI_NFC_H
+
+#include "../nand_device_info.h"
+#include "gpmi-nfc-v0-gpmi-regs.h"
+#include "gpmi-nfc-v1-gpmi-regs.h"
+#include "gpmi-nfc-v0-bch-regs.h"
+#include "gpmi-nfc-v1-bch-regs.h"
+
+/**
+ * struct resources - The collection of resources the driver needs.
+ *
+ * @gpmi_regs: A pointer to the GPMI registers.
+ * @bch_regs: A pointer to the BCH registers.
+ * @bch_interrupt: The BCH interrupt number.
+ * @dma_low_channel: The low DMA channel.
+ * @dma_high_channel: The high DMA channel.
+ * @dma_interrupt: The DMA interrupt number.
+ * @clock: A pointer to the struct clk for the NFC's clock.
+ */
+
+struct resources {
+ void *gpmi_regs;
+ void *bch_regs;
+ unsigned int bch_interrupt;
+ unsigned int dma_low_channel;
+ unsigned int dma_high_channel;
+ unsigned int dma_interrupt;
+ struct clk *clock;
+};
+
+/**
+ * struct mil - State for the MTD Interface Layer.
+ *
+ * @nand: The NAND Flash MTD data structure that represents
+ * the NAND Flash medium.
+ * @mtd: The MTD data structure that represents the NAND
+ * Flash medium.
+ * @oob_layout: A structure that describes how bytes are laid out
+ * in the OOB.
+ * @general_use_mtd: A pointer to an MTD we export for general use.
+ * This *may* simply be a pointer to the mtd field, if
+ * we've been instructed NOT to protect the boot
+ * areas.
+ * @partitions: A pointer to a set of partitions collected from
+ * information provided by the platform data. These
+ * partitions are applied to the general use MTD.
+ * @partition_count: The number of partitions.
+ * @current_chip: The chip currently selected by the NAND Fash MTD
+ * code. A negative value indicates that no chip is
+ * selected.
+ * @command_length: The length of the command that appears in the
+ * command buffer (see cmd_virt, below).
+ * @inject_ecc_error: Indicates the driver should inject a "fake" ECC
+ * error into the next read operation that uses ECC.
+ * User space programs can set this value through the
+ * sysfs node of the same name. If this value is less
+ * than zero, the driver will inject an uncorrectable
+ * ECC error. If this value is greater than zero, the
+ * driver will inject that number of correctable
+ * errors, capped by the maximum possible number of
+ * errors that could appear in a single read.
+ * @ignore_bad_block_marks: Indicates we are ignoring bad block marks.
+ * @saved_bbt: A saved pointer to the in-memory NAND Flash MTD bad
+ * block table. See show_device_ignorebad() for more
+ * details.
+ * @raw_oob_mode: Indicates the OOB is to be read/written in "raw"
+ * mode. See mil_ecc_read_oob() for details.
+ * @hooked_read_oob: A pointer to the ecc.read_oob() function we
+ * "hooked." See mil_ecc_read_oob() for details.
+ * @hooked_write_oob: A pointer to the ecc.write_oob() function pointer
+ * we "hooked." See mil_ecc_read_oob() for details.
+ * @marking_a_bad_block: Indicates the caller is marking a bad block. See
+ * mil_ecc_write_oob() for details.
+ * @hooked_block_markbad: A pointer to the block_markbad() function we
+ * we "hooked." See mil_ecc_write_oob() for details.
+ * @cmd_virt: A pointer to a DMA-coherent buffer in which we
+ * accumulate command bytes before we give them to the
+ * NFC layer. See mil_cmd_ctrl() for more details.
+ * @cmd_phys: The physical address for the cmd_virt buffer.
+ * @page_buffer_virt: A pointer to a DMA-coherent buffer we use for
+ * reading and writing pages. This buffer includes
+ * space for both the payload data and the auxiliary
+ * data (including status bytes, but not syndrome
+ * bytes).
+ * @page_buffer_phys: The physical address for the page_buffer_virt
+ * buffer.
+ * @page_buffer_size: The size of the page buffer.
+ * @payload_virt: A pointer to a location in the page buffer used
+ * for payload bytes. The size of this buffer is
+ * determined by struct nfc_geometry.
+ * @payload_phys: The physical address for payload_virt.
+ * @payload_size: The size of the payload area in the page buffer.
+ * @auxiliary_virt: A pointer to a location in the page buffer used
+ * for auxiliary bytes. The size of this buffer is
+ * determined by struct nfc_geometry.
+ * @auxiliary_phys: The physical address for auxiliary_virt.
+ * @auxiliary_size: The size of the auxiliary area in the page buffer.
+ */
+
+#define MIL_COMMAND_BUFFER_SIZE (10)
+
+struct mil {
+
+ /* MTD Data Structures */
+
+ struct nand_chip nand;
+ struct mtd_info mtd;
+ struct nand_ecclayout oob_layout;
+
+ /* Partitioning and Boot Area Protection */
+
+ struct mtd_info *general_use_mtd;
+ struct mtd_partition *partitions;
+ unsigned int partition_count;
+
+ /* General-use Variables */
+
+ int current_chip;
+ unsigned int command_length;
+ int inject_ecc_error;
+ int ignore_bad_block_marks;
+ void *saved_bbt;
+
+ /* MTD Function Pointer Hooks */
+
+ int raw_oob_mode;
+ 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 marking_a_bad_block;
+ int (*hooked_block_markbad)(struct mtd_info *mtd,
+ loff_t ofs);
+
+ /* DMA Buffers */
+
+ char *cmd_virt;
+ dma_addr_t cmd_phys;
+
+ void *page_buffer_virt;
+ dma_addr_t page_buffer_phys;
+ unsigned int page_buffer_size;
+
+ void *payload_virt;
+ dma_addr_t payload_phys;
+
+ void *auxiliary_virt;
+ dma_addr_t auxiliary_phys;
+
+};
+
+/**
+ * struct physical_geometry - Physical geometry description.
+ *
+ * This structure describes the physical geometry of the medium.
+ *
+ * @chip_count: The number of chips in the medium.
+ * @chip_size_in_bytes: The size, in bytes, of a single chip
+ * (excluding the out-of-band bytes).
+ * @block_size_in_bytes: The size, in bytes, of a single block
+ * (excluding the out-of-band bytes).
+ * @page_data_size_in_bytes: The size, in bytes, of the data area in a
+ * page (excluding the out-of-band bytes).
+ * @page_oob_size_in_bytes: The size, in bytes, of the out-of-band area
+ * in a page.
+ */
+
+struct physical_geometry {
+ unsigned int chip_count;
+ uint64_t chip_size_in_bytes;
+ unsigned int block_size_in_bytes;
+ unsigned int page_data_size_in_bytes;
+ unsigned int page_oob_size_in_bytes;
+};
+
+/**
+ * struct nfc_geometry - NFC geometry description.
+ *
+ * This structure describes the NFC's view of the medium geometry.
+ *
+ * @ecc_algorithm: The human-readable name of the ECC algorithm
+ * (e.g., "Reed-Solomon" or "BCH").
+ * @ecc_strength: A number that describes the strength of the ECC
+ * algorithm.
+ * @page_size_in_bytes: The size, in bytes, of a physical page, including
+ * both data and OOB.
+ * @metadata_size_in_bytes: The size, in bytes, of the metadata.
+ * @ecc_chunk_size_in_bytes: The size, in bytes, of a single ECC chunk. Note
+ * the first chunk in the page includes both data and
+ * metadata, so it's a bit larger than this value.
+ * @ecc_chunk_count: The number of ECC chunks in the page,
+ * @payload_size_in_bytes: The size, in bytes, of the payload buffer.
+ * @auxiliary_size_in_bytes: The size, in bytes, of the auxiliary buffer.
+ * @auxiliary_status_offset: The offset into the auxiliary buffer at which
+ * the ECC status appears.
+ * @block_mark_byte_offset: The byte offset in the ECC-based page view at
+ * which the underlying physical block mark appears.
+ * @block_mark_bit_offset: The bit offset into the ECC-based page view at
+ * which the underlying physical block mark appears.
+ */
+
+struct nfc_geometry {
+ char *ecc_algorithm;
+ unsigned int ecc_strength;
+ unsigned int page_size_in_bytes;
+ unsigned int metadata_size_in_bytes;
+ unsigned int ecc_chunk_size_in_bytes;
+ unsigned int ecc_chunk_count;
+ unsigned int payload_size_in_bytes;
+ unsigned int auxiliary_size_in_bytes;
+ unsigned int auxiliary_status_offset;
+ unsigned int block_mark_byte_offset;
+ unsigned int block_mark_bit_offset;
+};
+
+/**
+ * struct boot_rom_geometry - Boot ROM geometry description.
+ *
+ * This structure encapsulates decisions made by the Boot ROM Helper.
+ *
+ * @boot_area_count: The number of boot areas. The first boot area
+ * appears at the beginning of chip 0, the next
+ * at the beginning of chip 1, etc.
+ * @boot_area_size_in_bytes: The size, in bytes, of each boot area.
+ * @stride_size_in_pages: The size of a boot block stride, in pages.
+ * @search_area_stride_exponent: The logarithm to base 2 of the size of a
+ * search area in boot block strides.
+ */
+
+struct boot_rom_geometry {
+ unsigned int boot_area_count;
+ unsigned int boot_area_size_in_bytes;
+ unsigned int stride_size_in_pages;
+ unsigned int search_area_stride_exponent;
+};
+
+/**
+ * struct gpmi_nfc_data - 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_data {
+
+ /* System Interface */
+ struct device *dev;
+ struct platform_device *pdev;
+ struct gpmi_nfc_platform_data *pdata;
+
+ /* Resources */
+ struct resources resources;
+
+ /* Flash Hardware */
+ struct nand_device_info device_info;
+ struct physical_geometry physical_geometry;
+
+ /* NFC HAL */
+ struct nfc_hal *nfc;
+ struct nfc_geometry nfc_geometry;
+
+ /* Boot ROM Helper */
+ struct boot_rom_helper *rom;
+ struct boot_rom_geometry rom_geometry;
+
+ /* MTD Interface Layer */
+ struct mil mil;
+
+};
+
+/**
+ * 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.
+ * @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.
+ * @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.
+ * @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.
+ * @is_ready: Returns true if the given chip is ready.
+ * @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 {
+ const unsigned int version;
+ const char *description;
+ const unsigned int max_chip_count;
+ struct mxs_dma_desc *dma_descriptors[NFC_DMA_DESCRIPTOR_COUNT];
+ int isr_dma_channel;
+ struct completion dma_done;
+ struct completion bch_done;
+ int (*init) (struct gpmi_nfc_data *);
+ int (*set_geometry)(struct gpmi_nfc_data *);
+ void (*exit) (struct gpmi_nfc_data *);
+ int (*is_ready) (struct gpmi_nfc_data *, unsigned chip);
+ int (*send_command)(struct gpmi_nfc_data *, unsigned chip,
+ dma_addr_t buffer, unsigned length);
+ int (*send_data) (struct gpmi_nfc_data *, unsigned chip,
+ dma_addr_t buffer, unsigned length);
+ int (*read_data) (struct gpmi_nfc_data *, unsigned chip,
+ dma_addr_t buffer, unsigned length);
+ int (*send_page) (struct gpmi_nfc_data *, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary);
+ int (*read_page) (struct gpmi_nfc_data *, unsigned chip,
+ dma_addr_t payload, dma_addr_t auxiliary);
+};
+
+/**
+ * struct boot_rom_helper - Boot ROM Helper
+ *
+ * This structure embodies the interface to an object that assists the driver
+ * in making decisions that relate to the Boot ROM.
+ *
+ * @version: The Boot ROM version.
+ * @description: A pointer to a human-readable description of the
+ * Boot ROM.
+ * @swap_block_mark: Indicates that the Boot ROM will swap the block
+ * mark with the first byte of the OOB.
+ * @set_geometry: Configures the Boot ROM geometry.
+ * @check_transcription_stamp: Checks for a transcription stamp. This pointer
+ * is ignored if swap_block_mark is set.
+ * @write_transcription_stamp: Writes a transcription stamp. This pointer
+ * is ignored if swap_block_mark is set.
+ */
+
+struct boot_rom_helper {
+ const unsigned int version;
+ const char *description;
+ const int swap_block_mark;
+ int (*set_geometry) (struct gpmi_nfc_data *);
+ int (*check_transcription_stamp)(struct gpmi_nfc_data *);
+ int (*write_transcription_stamp)(struct gpmi_nfc_data *);
+};
+
+#endif
diff --git a/drivers/mtd/nand/lba/Makefile b/drivers/mtd/nand/lba/Makefile
deleted file mode 100644
index 0e576bfa856d..000000000000
--- a/drivers/mtd/nand/lba/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_MTD_NAND_GPMI_LBA) += gpmi_lba.o
-gpmi_lba-objs += gpmi-transport.o lba-core.o lba-blk.o
diff --git a/drivers/mtd/nand/lba/gpmi-transport.c b/drivers/mtd/nand/lba/gpmi-transport.c
deleted file mode 100644
index f3eecc06f653..000000000000
--- a/drivers/mtd/nand/lba/gpmi-transport.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPMI transport layer for LBA driver
- *
- * Author: Dmitrij Frasenyak <sed@embeddedalley.com>
- * Clock settings and hw init comes from
- * gpmi driver by Dmitry Pervushin.
- *
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
-#include <asm/div64.h>
-#include <mach/platform.h>
-#include <mach/regs-apbh.h>
-#include <mach/regs-gpmi.h>
-#include <mach/stmp3xxx.h>
-#include <mach/dma.h>
-#include "gpmi.h"
-#include "lba.h"
-
-struct lba_data *g_data;
-static int max_chips = 1;
-static long clk = -1;
-
-struct gpmi_nand_timing gpmi_safe_timing = {
- .address_setup = 25,
- .data_setup = 80,
- .data_hold = 60,
- .dsample_time = 6,
-};
-
-/******************************************************************************
- * HW init part
- ******************************************************************************/
-
-/**
- * gpmi_irq - IRQ handler
- *
- * @irq: irq no
- * @context: IRQ context, pointer to gpmi_nand_data
- */
-static irqreturn_t gpmi_irq(int irq, void *context)
-{
- struct lba_data *data = context;
- int i;
-
- for (i = 0; i < max_chips; i++) {
- if (stmp3xxx_dma_is_interrupt(data->nand[i].dma_ch)) {
- stmp3xxx_dma_clear_interrupt(data->nand[i].dma_ch);
- complete(&data->nand[i].done);
- }
-
- }
- __raw_writel(BM_GPMI_CTRL1_DEV_IRQ | BM_GPMI_CTRL1_TIMEOUT_IRQ,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_CLR);
- return IRQ_HANDLED;
-}
-
-static inline u32 gpmi_cycles_ceil(u32 ntime, u32 period)
-{
- int k;
-
- k = (ntime + period - 1) / period;
- if (k == 0)
- k++;
- return k ;
-}
-
-
-/**
- * gpmi_set_timings - set GPMI timings
- * @pdev: pointer to GPMI platform device
- * @tm: pointer to structure &gpmi_nand_timing with new timings
- *
- * During initialization, GPMI uses safe sub-optimal timings, which
- * can be changed after reading boot control blocks
- */
-void gpmi_set_timings(struct lba_data *data, struct gpmi_nand_timing *tm)
-{
- u32 period_ns = 1000000 / clk_get_rate(data->clk) + 1;
- u32 address_cycles, data_setup_cycles;
- u32 data_hold_cycles, data_sample_cycles;
- u32 busy_timeout;
- u32 t0, reg;
-
- address_cycles = gpmi_cycles_ceil(tm->address_setup, period_ns);
- data_setup_cycles = gpmi_cycles_ceil(tm->data_setup, period_ns);
- data_hold_cycles = gpmi_cycles_ceil(tm->data_hold, period_ns);
- data_sample_cycles = gpmi_cycles_ceil(tm->dsample_time + period_ns / 4,
- period_ns / 2);
- busy_timeout = gpmi_cycles_ceil(10000000 / 4096, period_ns);
-
- t0 = address_cycles << BP_GPMI_TIMING0_ADDRESS_SETUP;
- t0 |= data_setup_cycles << BP_GPMI_TIMING0_DATA_SETUP;
- t0 |= data_hold_cycles << BP_GPMI_TIMING0_DATA_HOLD;
- __raw_writel(t0, REGS_GPMI_BASE + HW_GPMI_TIMING0);
-
- __raw_writel(busy_timeout, REGS_GPMI_BASE + HW_GPMI_TIMING1);
-
- reg = __raw_readl(REGS_GPMI_BASE + HW_GPMI_CTRL1);
-#ifdef CONFIG_ARCH_STMP378X
- reg &= ~BM_GPMI_CTRL1_RDN_DELAY;
- reg |= data_sample_cycles << BP_GPMI_CTRL1_RDN_DELAY;
-#else
- reg &= ~BM_GPMI_CTRL1_DSAMPLE_TIME;
- reg |= data_sample_cycles << BP_GPMI_CTRL1_DSAMPLE_TIME;
-#endif
- __raw_writel(reg, REGS_GPMI_BASE + HW_GPMI_CTRL1);
-}
-
-void queue_plug(struct lba_data *data)
-{
- u32 ctrl1;
- clk_enable(data->clk);
- if (clk <= 0)
- clk = 24000; /* safe setting, some chips do not work on
- speeds >= 24kHz */
- clk_set_rate(data->clk, clk);
-
- clk = clk_get_rate(data->clk);
-
-
- stmp3xxx_reset_block(HW_GPMI_CTRL0 + REGS_GPMI_BASE, 1);
-
- ctrl1 = __raw_readl(REGS_GPMI_BASE + HW_GPMI_CTRL1);
-
- /* write protection OFF */
- ctrl1 |= BM_GPMI_CTRL1_DEV_RESET;
-
- /* IRQ polarity */
- ctrl1 |= BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY;
-
- /* ...and ECC module */
- /*HW_GPMI_CTRL1_SET(bch_mode());*/
-
- /* choose NAND mode (1 means ATA, 0 - NAND */
- ctrl1 &= ~BM_GPMI_CTRL1_GPMI_MODE;
-
- __raw_writel(ctrl1, REGS_GPMI_BASE + HW_GPMI_CTRL1);
-
- gpmi_set_timings(data, &gpmi_safe_timing);
-}
-
-void queue_release(struct lba_data *data)
-{
- __raw_writel(BM_GPMI_CTRL0_SFTRST, REGS_GPMI_BASE + HW_GPMI_CTRL0_SET);
-
- clk_disable(data->clk);
-}
-
-
-/**
- * gpmi_init_hw - initialize the hardware
- * @pdev: pointer to platform device
- *
- * Initialize GPMI hardware and set default (safe) timings for NAND access.
- * Returns error code or 0 on success
- */
-static int gpmi_init_hw(struct platform_device *pdev, int request_pins)
-{
- struct lba_data *data = platform_get_drvdata(pdev);
- struct gpmi_platform_data *gpd =
- (struct gpmi_platform_data *)pdev->dev.platform_data;
- int err = 0;
-
- data->clk = clk_get(NULL, "gpmi");
- if (IS_ERR(data->clk)) {
- err = PTR_ERR(data->clk);
- dev_err(&pdev->dev, "cannot set failsafe clockrate\n");
- goto out;
- }
- if (request_pins)
- gpd->pinmux(1);
-
- queue_plug(data);
-
-out:
- return err;
-}
-/**
- * gpmi_release_hw - free the hardware
- * @pdev: pointer to platform device
- *
- * In opposite to gpmi_init_hw, release all acquired resources
- */
-static void gpmi_release_hw(struct platform_device *pdev)
-{
- struct gpmi_platform_data *gpd =
- (struct gpmi_platform_data *)pdev->dev.platform_data;
- struct lba_data *data = platform_get_drvdata(pdev);
-
- queue_release(data);
- clk_put(data->clk);
- gpd->pinmux(0);
-}
-
-
-/**
- * gpmi_alloc_buffers - allocate DMA buffers for one chip
- *
- * @pdev: GPMI platform device
- * @g: pointer to structure associated with NAND chip
- *
- * Allocate buffer using dma_alloc_coherent
- */
-static int gpmi_alloc_buffers(struct platform_device *pdev,
- struct gpmi_perchip_data *g)
-{
- g->cmd_buffer = dma_alloc_coherent(&pdev->dev,
- g->cmd_buffer_size,
- &g->cmd_buffer_handle, GFP_DMA);
- if (!g->cmd_buffer)
- goto out1;
-
- g->write_buffer = dma_alloc_coherent(&pdev->dev,
- g->write_buffer_size,
- &g->write_buffer_handle, GFP_DMA);
- if (!g->write_buffer)
- goto out2;
-
- g->data_buffer = dma_alloc_coherent(&pdev->dev,
- g->data_buffer_size,
- &g->data_buffer_handle, GFP_DMA);
- if (!g->data_buffer)
- goto out3;
-
- g->oob_buffer = dma_alloc_coherent(&pdev->dev,
- g->oob_buffer_size,
- &g->oob_buffer_handle, GFP_DMA);
- if (!g->oob_buffer)
- goto out4;
-
- g->cmdtail_buffer = dma_alloc_coherent(&pdev->dev,
- g->cmdtail_buffer_size,
- &g->cmdtail_buffer_handle, GFP_DMA);
- if (!g->oob_buffer)
- goto out5;
-
- return 0;
-
-out5:
- dma_free_coherent(&pdev->dev, g->oob_buffer_size,
- g->oob_buffer, g->oob_buffer_handle);
-
-out4:
- dma_free_coherent(&pdev->dev, g->data_buffer_size,
- g->data_buffer, g->data_buffer_handle);
-out3:
- dma_free_coherent(&pdev->dev, g->write_buffer_size,
- g->write_buffer, g->write_buffer_handle);
-out2:
- dma_free_coherent(&pdev->dev, g->cmd_buffer_size,
- g->cmd_buffer, g->cmd_buffer_handle);
-out1:
- return -ENOMEM;
-}
-
-/**
- * gpmi_free_buffers - free buffers allocated by gpmi_alloc_buffers
- *
- * @pdev: platform device
- * @g: pointer to structure associated with NAND chip
- *
- * Deallocate buffers on exit
- */
-static void gpmi_free_buffers(struct platform_device *pdev,
- struct gpmi_perchip_data *g)
-{
- dma_free_coherent(&pdev->dev, g->oob_buffer_size,
- g->oob_buffer, g->oob_buffer_handle);
- dma_free_coherent(&pdev->dev, g->write_buffer_size,
- g->write_buffer, g->write_buffer_handle);
- dma_free_coherent(&pdev->dev, g->cmd_buffer_size,
- g->cmd_buffer, g->cmd_buffer_handle);
- dma_free_coherent(&pdev->dev, g->cmdtail_buffer_size,
- g->cmdtail_buffer, g->cmdtail_buffer_handle);
- dma_free_coherent(&pdev->dev, g->data_buffer_size,
- g->data_buffer, g->data_buffer_handle);
-}
-
-
-/******************************************************************************
- * Arch specific chain_* callbaks
- ******************************************************************************/
-
-/**
- * chain_w4r - Initialize descriptor to perform W4R operation
- *
- * @chain: Descriptor to use
- * @cs: CS for this operation
- *
- * Due to HW bug we have to put W4R into separate desc.
- */
-static void chain_w4r(struct stmp3xxx_dma_descriptor *chain, int cs)
-{
- chain->command->cmd =
- (4 << BP_APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDWAIT4READY |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- (BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER << BP_APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- (BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY << BP_GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- (BV_GPMI_CTRL0_ADDRESS__NAND_DATA << BP_GPMI_CTRL0_ADDRESS) |
- (cs << BP_GPMI_CTRL0_CS);
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] = 0;
- chain->command->pio_words[3] = 0;
- chain->command->buf_ptr = 0;
-}
-
-/**
- * chain_cmd - Initialize descriptor to push CMD to the bus
- *
- * @chain: Descriptor to use
- * @cmd_handle: dma_addr_t pointer that holds the command
- * @lba_cmd: flags and lenghth of this command.
- * @cs: CS for this operation
- *
- * CLE || CLE+ALE
- */
-static void chain_cmd(struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t cmd_handle,
- struct lba_cmd *lba_cmd,
- int cs)
-{
- /* output command */
- chain->command->cmd =
- (lba_cmd->len << BP_APBH_CHn_CMD_XFER_COUNT) |
- (3 << BP_APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- (BV_APBH_CHn_CMD_COMMAND__DMA_READ << BP_APBH_CHn_CMD_COMMAND);
- chain->command->cmd |= BM_APBH_CHn_CMD_CHAIN;
- chain->command->pio_words[0] =
- (BV_GPMI_CTRL0_COMMAND_MODE__WRITE << BP_GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BM_GPMI_CTRL0_LOCK_CS |
- (cs << BP_GPMI_CTRL0_CS) |
- (BV_GPMI_CTRL0_ADDRESS__NAND_CLE << BP_GPMI_CTRL0_ADDRESS) |
- (lba_cmd->len << BP_GPMI_CTRL0_XFER_COUNT);
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] = 0;
- chain->command->buf_ptr = cmd_handle;
-
- if (lba_cmd->flag & FE_CMD_INC)
- chain->command->pio_words[0] |= BM_GPMI_CTRL0_ADDRESS_INCREMENT;
-/*BUG if (lba_cmd->flag & FE_W4R) */
-/* chain->command->cmd |= BM_APBH_CHn_CMD_NANDWAIT4READY; */
-}
-
-/**
- * chain_cmd - Initialize descriptor to read data from the bus
- *
- * @chain: Descriptor to use
- * @data_handle: dma_addr_t pointer to buffer to store data
- * @data_len: the size of the data buffer to read
- * @cmd_handle: dma_addr_t pointer that holds the command
- * @lba_cmd: flags and lenghth of this command.
- * @cs: CS for this operation
- */
-static void chain_read_data(struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t data_handle,
- dma_addr_t data_len,
- struct lba_cmd *lba_cmd,
- int cs)
-{
- chain->command->cmd =
- (data_len << BP_APBH_CHn_CMD_XFER_COUNT) |
- (4 << BP_APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- (BV_APBH_CHn_CMD_COMMAND__DMA_WRITE << BP_APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- (BV_GPMI_CTRL0_COMMAND_MODE__READ << BP_GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BM_GPMI_CTRL0_LOCK_CS |
- (cs << BP_GPMI_CTRL0_CS) |
- (BV_GPMI_CTRL0_ADDRESS__NAND_DATA << BP_GPMI_CTRL0_ADDRESS) |
- (data_len << BP_GPMI_CTRL0_XFER_COUNT);
-
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] = 0;
- chain->command->pio_words[3] = 0;
- chain->command->buf_ptr = data_handle;
-
- if (lba_cmd->flag & FE_CMD_INC)
- chain->command->pio_words[0] |= BM_GPMI_CTRL0_ADDRESS_INCREMENT;
-/*BUG if (lba_cmd->flag & FE_W4R) */
-/* chain->command->cmd |= BM_APBH_CHn_CMD_NANDWAIT4READY; */
-
-}
-
-/**
- * chain_cmd - Initialize descriptor to read data from the bus
- *
- * @chain: Descriptor to use
- * @data_handle: dma_addr_t pointer to buffer to read data from
- * @data_len: the size of the data buffer to write
- * @cmd_handle: dma_addr_t pointer that holds the command
- * @lba_cmd: flags and lenghth of this command.
- * @cs: CS for this operation
- */
-static void chain_write_data(struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t data_handle,
- int data_len,
- struct lba_cmd *lba_cmd,
- int cs)
-{
-
- chain->command->cmd =
- (data_len << BP_APBH_CHn_CMD_XFER_COUNT) |
- (4 << BP_APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- (BV_APBH_CHn_CMD_COMMAND__DMA_READ << BP_APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- (BV_GPMI_CTRL0_COMMAND_MODE__WRITE << BP_GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BM_GPMI_CTRL0_LOCK_CS |
- (cs << BP_GPMI_CTRL0_CS) |
- (BV_GPMI_CTRL0_ADDRESS__NAND_DATA << BP_GPMI_CTRL0_ADDRESS) |
- (data_len << BP_GPMI_CTRL0_XFER_COUNT);
-
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] = 0;
- chain->command->pio_words[3] = 0;
- chain->command->buf_ptr = data_handle;
-
- if (lba_cmd->flag & FE_CMD_INC)
- chain->command->pio_words[0] |= BM_GPMI_CTRL0_ADDRESS_INCREMENT;
-/*BUG if (lba_cmd->flag & FE_W4R) */
-/* chain->command->cmd |= BM_APBH_CHn_CMD_NANDWAIT4READY; */
-
-}
-
-
-/******************************************************************************
- * Interface to arch independent part
- ******************************************************************************/
-/**
- * queue_cmd - Setup a chain of descriptors
- *
- * @priv: private data passed
- * @cmd_buf: pointer to command buffer (to be removed)
- * @cmd_handle: dma_addr_t pointer that holds the command
- * @cmd_len: the size of the command buffer (to be removed)
- * @data_handle: dma_addr_t pointer to a data buffer
- * @data_len: the size of the data buffer
- * @cmd_flags: commands flags
- */
-int queue_cmd(void *priv,
- uint8_t *cmd_buf, dma_addr_t cmd_handle, int cmd_len,
- dma_addr_t data, int data_len,
- struct lba_cmd *cmd_flags)
-{
-
- struct gpmi_perchip_data *g = priv;
- unsigned long flags;
- int idx;
- int ret = 0;
- struct stmp3xxx_dma_descriptor *chain ;
- int i;
-
- if (!g || !(cmd_buf || cmd_handle))
- BUG();
-
- spin_lock_irqsave(&g->lock, flags);
-
- /* Keep it for debug purpose */
- chain = g->d;
- for (i = g->d_tail; i < GPMI_DMA_MAX_CHAIN; i++) {
- chain[i].command->cmd = 0;
- chain[i].command->buf_ptr = 0;
- }
- /* End */
-
- if (!cmd_handle) {
- if (!cmd_buf)
- BUG();
- memcpy(g->cmd_buffer, cmd_buf, cmd_len);
- cmd_handle = g->cmd_buffer_handle;
- }
-
- idx = g->d_tail;
- chain = &g->d[idx];
-
- do {
- if (!cmd_flags)
- BUG();
-
- if (cmd_flags->flag & FE_W4R) {
- /* there seems to be HW BUG with W4R flag.
- * IRQ controller hangs forever when it's combined
- * with real operation.
- */
- chain_w4r(chain, g->cs);
- chain++; idx++;
- }
-
-
- switch (cmd_flags->flag & F_MASK) {
-
- case F_CMD:
- chain_cmd(chain, cmd_handle, cmd_flags, g->cs);
- break;
- case F_DATA_READ:
- chain_read_data(chain, data, data_len,
- cmd_flags, g->cs);
- break;
- case F_DATA_WRITE:
- chain_write_data(chain, data, data_len,
- cmd_flags, g->cs);
- break;
- default:{
- if (cmd_flags->flag & FE_END)
- goto out;
- else{
- printk(KERN_ERR "uknown cmd\n");
- BUG();
- }
- }
- }
-
-
- chain++; idx++;
- cmd_handle += cmd_flags->len;
-
- if (idx >= GPMI_DMA_MAX_CHAIN) {
- printk(KERN_ERR "to many chains; idx is 0x%x\n", idx);
- BUG();
- }
-
- } while (!((cmd_flags++)->flag & FE_END));
-
-out:
- if (idx < GPMI_DMA_MAX_CHAIN) {
- ret = idx;
- g->d_tail = idx;
- }
- spin_unlock_irqrestore(g->lock, flags);
-
- return ret;
-
-}
-
-dma_addr_t queue_get_cmd_handle(void *priv)
-{
- struct gpmi_perchip_data *g = priv;
- return g->cmd_buffer_handle;
-}
-
-uint8_t *queue_get_cmd_ptr(void *priv)
-{
- struct gpmi_perchip_data *g = priv;
- return g->cmd_buffer;
-}
-
-dma_addr_t queue_get_data_handle(void *priv)
-{
- struct gpmi_perchip_data *g = priv;
- return g->data_buffer_handle;
-}
-
-uint8_t *queue_get_data_ptr(void *priv)
-{
- struct gpmi_perchip_data *g = priv;
- return g->data_buffer;
-}
-
-
-/**
- * queue_run - run the chain
- *
- * @priv: private data.
- */
-int queue_run(void *priv)
-{
- struct gpmi_perchip_data *g = priv;
-
- if (!g->d_tail)
- return 0;
- stmp3xxx_dma_reset_channel(g->dma_ch);
- stmp3xxx_dma_clear_interrupt(g->dma_ch);
- stmp3xxx_dma_enable_interrupt(g->dma_ch);
-
- g->d[g->d_tail-1].command->cmd &= ~(BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN);
- g->d[g->d_tail-1].command->cmd |= BM_APBH_CHn_CMD_IRQONCMPLT ;
-
- g->d[g->d_tail-1].command->pio_words[0] &= ~BM_GPMI_CTRL0_LOCK_CS;
-
-#ifdef DEBUG
- /*stmp37cc_dma_print_chain(&g->chain);*/
-#endif
-
- init_completion(&g->done);
- stmp3xxx_dma_go(g->dma_ch, g->d, 1);
- wait_for_completion(&g->done);
-
- g->d_tail = 0;
-
- return 0;
-
-}
-
-/******************************************************************************
- * Platform specific part / chard driver and misc functions
- ******************************************************************************/
-
-
-
-static int __init lba_probe(struct platform_device *pdev)
-{
- struct lba_data *data;
- struct resource *r;
- struct gpmi_perchip_data *g;
- int err;
-
- /* Allocate memory for the device structure (and zero it) */
- data = kzalloc(sizeof(*data) + sizeof(struct gpmi_perchip_data),
- GFP_KERNEL);
- if (!data) {
- dev_err(&pdev->dev, "failed to allocate gpmi_nand_data\n");
- err = -ENOMEM;
- goto out1;
- }
- g_data = data;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "failed to get resource\n");
- err = -ENXIO;
- goto out2;
- }
- data->io_base = ioremap(r->start, r->end - r->start + 1);
- if (!data->io_base) {
- dev_err(&pdev->dev, "ioremap failed\n");
- err = -EIO;
- goto out2;
- }
-
- r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!r) {
- err = -EIO;
- dev_err(&pdev->dev, "can't get IRQ resource\n");
- goto out3;
- }
- data->irq = r->start;
-
- platform_set_drvdata(pdev, data);
- err = gpmi_init_hw(pdev, 1);
- if (err)
- goto out3;
-
-
- err = request_irq(data->irq,
- gpmi_irq, 0, dev_name(&pdev->dev), data);
- if (err) {
- dev_err(&pdev->dev, "can't request GPMI IRQ\n");
- goto out4;
- }
-
- g = data->nand;
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r) {
- dev_err(&pdev->dev, "can't get DMA resource\n");
- goto out_res;
- }
- g->cs = 0;
- g->dma_ch = r->start;
-
- err = stmp3xxx_dma_request(g->dma_ch, NULL, dev_name(&pdev->dev));
- if (err) {
- dev_err(&pdev->dev, "can't request DMA channel 0x%x\n",
- g->dma_ch);
- goto out_res;
- }
-
- err = stmp3xxx_dma_make_chain(g->dma_ch, &g->chain,
- g->d, ARRAY_SIZE(g->d));
- if (err) {
- dev_err(&pdev->dev, "can't setup DMA chain\n");
- stmp3xxx_dma_release(g->dma_ch);
- goto out_res;
- }
-
- g->cmd_buffer_size = GPMI_CMD_BUF_SZ;
- g->cmdtail_buffer_size = GPMI_CMD_BUF_SZ;
- g->write_buffer_size = GPMI_WRITE_BUF_SZ;
- g->data_buffer_size = GPMI_DATA_BUF_SZ;
- g->oob_buffer_size = GPMI_OOB_BUF_SZ;
-
- err = gpmi_alloc_buffers(pdev, g);
- if (err) {
- dev_err(&pdev->dev, "can't setup buffers\n");
- stmp3xxx_dma_free_chain(&g->chain);
- stmp3xxx_dma_release(g->dma_ch);
- goto out_res;
- }
-
- g->dev = pdev;
- g->chip.priv = g;
- g->index = 0;
- g->timing = gpmi_safe_timing;
-
- g->cmd_buffer_sz =
- g->write_buffer_sz =
- g->data_buffer_sz =
- 0;
- g->valid = !0; /* mark the data as valid */
-
-
- lba_core_init(data);
-
- return 0;
-
-out_res:
- free_irq(data->irq, data);
-out4:
- gpmi_release_hw(pdev);
-out3:
- platform_set_drvdata(pdev, NULL);
- iounmap(data->io_base);
-out2:
- kfree(data);
-out1:
- return err;
-}
-
-static int gpmi_suspend(struct platform_device *pdev, pm_message_t pm)
-{
- struct lba_data *data = platform_get_drvdata(pdev);
- int err;
-
- printk(KERN_INFO "%s: %d\n", __func__, __LINE__);
- err = lba_core_suspend(pdev, data);
- if (!err)
- gpmi_release_hw(pdev);
-
- return err;
-}
-
-static int gpmi_resume(struct platform_device *pdev)
-{
- struct lba_data *data = platform_get_drvdata(pdev);
- int r;
-
- printk(KERN_INFO "%s: %d\n", __func__, __LINE__);
- r = gpmi_init_hw(pdev, 1);
- lba_core_resume(pdev, data);
- return r;
-}
-
-/**
- * gpmi_nand_remove - remove a GPMI device
- *
- */
-static int __devexit lba_remove(struct platform_device *pdev)
-{
- struct lba_data *data = platform_get_drvdata(pdev);
- int i;
-
- lba_core_remove(data);
- gpmi_release_hw(pdev);
- free_irq(data->irq, data);
-
- for (i = 0; i < max_chips; i++) {
- if (!data->nand[i].valid)
- continue;
- gpmi_free_buffers(pdev, &data->nand[i]);
- stmp3xxx_dma_free_chain(&data->nand[i].chain);
- stmp3xxx_dma_release(data->nand[i].dma_ch);
- }
- iounmap(data->io_base);
- kfree(data);
-
- return 0;
-}
-
-static struct platform_driver lba_driver = {
- .probe = lba_probe,
- .remove = __devexit_p(lba_remove),
- .driver = {
- .name = "gpmi",
- .owner = THIS_MODULE,
- },
- .suspend = gpmi_suspend,
- .resume = gpmi_resume,
-
-};
-
-
-static int __init lba_init(void)
-{
- return platform_driver_register(&lba_driver);
-}
-
-static void lba_exit(void)
-{
- platform_driver_unregister(&lba_driver);
-}
-
-module_init(lba_init);
-module_exit(lba_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/lba/gpmi.h b/drivers/mtd/nand/lba/gpmi.h
deleted file mode 100644
index a647c948040f..000000000000
--- a/drivers/mtd/nand/lba/gpmi.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
- *
- * Author: dmitry pervushin <dimka@embeddedalley.com>
- *
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __DRIVERS_GPMI_H
-#define __DRIVERS_GPMI_H
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-#include <mach/stmp3xxx.h>
-#include <mach/dma.h>
-
-#include <mach/gpmi.h>
-#include <mach/regs-gpmi.h>
-#include <mach/regs-apbh.h>
-#ifdef CONFIG_MTD_NAND_GPMI_BCH
-#include <mach/regs-bch.h>
-#endif
-
-
-struct gpmi_nand_timing {
- u8 data_setup;
- u8 data_hold;
- u8 address_setup;
- u8 dsample_time;
-};
-
-#define GPMI_DMA_MAX_CHAIN 20 /* max DMA commands in chain */
-
-#define GPMI_CMD_BUF_SZ 10
-#define GPMI_DATA_BUF_SZ 4096
-#define GPMI_WRITE_BUF_SZ 4096
-#define GPMI_OOB_BUF_SZ 218
-
-
-struct gpmi_perchip_data {
- int valid;
- struct nand_chip chip;
- struct platform_device *dev;
- int index;
-
- spinlock_t lock; /* protect chain operations */
- struct stmp37xx_circ_dma_chain chain;
- struct stmp3xxx_dma_descriptor d[GPMI_DMA_MAX_CHAIN];
- int d_tail;
-
- struct completion done;
-
- u8 *cmd_buffer;
- dma_addr_t cmd_buffer_handle;
- int cmd_buffer_size, cmd_buffer_sz;
-
- u8 *cmdtail_buffer;
- dma_addr_t cmdtail_buffer_handle;
- int cmdtail_buffer_size, cmdtail_buffer_sz;
-
- u8 *write_buffer;
- dma_addr_t write_buffer_handle;
- int write_buffer_size, write_buffer_sz;
-
- u8 *data_buffer;
- dma_addr_t data_buffer_handle;
- u8 *data_buffer_cptr;
- int data_buffer_size, data_buffer_sz, bytes2read;
-
- u8 *oob_buffer;
- dma_addr_t oob_buffer_handle;
- int oob_buffer_size;
-
- int cs;
- unsigned dma_ch;
-
- int ecc_oob_bytes, oob_free;
-
- struct gpmi_nand_timing timing;
-
- void *p2w, *oob2w, *p2r, *oob2r;
- size_t p2w_size, oob2w_size, p2r_size, oob2r_size;
- dma_addr_t p2w_dma, oob2w_dma, p2r_dma, oob2r_dma;
- unsigned read_memcpy:1, write_memcpy:1,
- read_oob_memcpy:1, write_oob_memcpy:1;
-};
-
-
-extern struct gpmi_nand_timing gpmi_safe_timing;
-
-
-#endif
diff --git a/drivers/mtd/nand/lba/lba-blk.c b/drivers/mtd/nand/lba/lba-blk.c
deleted file mode 100644
index 228aa9d27760..000000000000
--- a/drivers/mtd/nand/lba/lba-blk.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X LBA/block driver
- *
- * Author: Dmitrij Frasenyak <sed@embeddedalley.com>
- *
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h> /* printk() */
-#include <linux/slab.h> /* kmalloc() */
-#include <linux/fs.h> /* everything... */
-#include <linux/errno.h> /* error codes */
-#include <linux/kthread.h>
-#include <linux/timer.h>
-#include <linux/types.h> /* size_t */
-#include <linux/fcntl.h> /* O_ACCMODE */
-#include <linux/hdreg.h> /* HDIO_GETGEO */
-#include <linux/kdev_t.h>
-#include <linux/vmalloc.h>
-#include <linux/genhd.h>
-#include <linux/blkdev.h>
-#include <linux/buffer_head.h> /* invalidate_bdev */
-#include <linux/bio.h>
-#include <linux/dma-mapping.h>
-#include <linux/hdreg.h>
-#include <linux/blkdev.h>
-#include "lba.h"
-
-static int lba_major;
-
-#define LBA_NAME "lba"
-
-#if 0
-#define TAG() printk(KERNE_ERR "%s: %d\n", __func__, __LINE__)
-#else
-#define TAG()
-#endif
-
-/*
- * The internal representation of our device.
- */
-struct lba_blk_dev {
- int size; /* Device size in sectors */
- spinlock_t lock; /* For mutual exclusion */
- int users;
- struct request_queue *queue; /* The device request queue */
- struct gendisk *gd; /* The gendisk structure */
- struct lba_data *data; /* pointer from lba core */
-
- struct task_struct *thread;
- struct bio *bio_head;
- struct bio *bio_tail;
- wait_queue_head_t wait_q;
- struct semaphore busy;
-
-};
-
-static struct lba_blk_dev *g_lba_blk;
-
-static void blk_add_bio(struct lba_blk_dev *dev, struct bio *bio);
-
-
-/*
- * Transfer a single BIO.
- */
-static int lba_blk_xfer_bio(struct lba_blk_dev *dev, struct bio *bio)
-{
- int i;
- struct bio_vec *bvec;
- sector_t sector = bio->bi_sector;
- enum dma_data_direction dir;
- int status = 0;
- int (*lba_xfer)(void *priv,
- unsigned int sector,
- unsigned int count,
- void *buffer,
- dma_addr_t handle);
-
- if (bio_data_dir(bio) == WRITE) {
- lba_xfer = lba_write_sectors;
- dir = DMA_TO_DEVICE;
- } else {
- lba_xfer = lba_read_sectors;
- dir = DMA_FROM_DEVICE;
- }
-
- /* Fixme: merge segments */
- bio_for_each_segment(bvec, bio, i) {
- void *buffer = page_address(bvec->bv_page);
- dma_addr_t handle ;
- if (!buffer)
- BUG();
- buffer += bvec->bv_offset;
- handle = dma_map_single(&dev->data->nand->dev->dev,
- buffer,
- bvec->bv_len,
- dir);
- status = lba_xfer(dev->data->nand, sector,
- bvec->bv_len >> 9,
- buffer,
- handle);
-
- dma_unmap_single(&dev->data->nand->dev->dev,
- handle,
- bvec->bv_len,
- dir);
- if (status)
- break;
-
- sector += bio_cur_bytes(bio) >> 9;
- }
-
- return status;
-}
-
-
-/*
- * The direct make request version.
- */
-static int lba_make_request(struct request_queue *q, struct bio *bio)
-{
- struct lba_blk_dev *dev = q->queuedata;
-
- blk_add_bio(dev, bio);
- return 0;
-}
-
-/*
- * Open and close.
- */
-
-static int lba_blk_open(struct block_device *bdev, fmode_t mode)
-{
- struct lba_blk_dev *dev = bdev->bd_disk->private_data;
-
- TAG();
-
- spin_lock_irq(&dev->lock);
- dev->users++;
- spin_unlock_irq(&dev->lock);
- return 0;
-}
-
-
-static int lba_blk_release(struct gendisk *gd, fmode_t mode)
-{
- struct lba_blk_dev *dev = gd->private_data;
-
- spin_lock(&dev->lock);
- dev->users--;
- spin_unlock(&dev->lock);
-
- return 0;
-}
-
-static int lba_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- /*
- * get geometry: we have to fake one... trim the size to a
- * multiple of 2048 (1M): tell we have 32 sectors, 64 heads,
- * whatever cylinders.
- */
- geo->heads = 1 << 6;
- geo->sectors = 1 << 5;
- geo->cylinders = get_capacity(bdev->bd_disk) >> 11;
- return 0;
-}
-
-/*
- * Add bio to back of pending list
- */
-static void blk_add_bio(struct lba_blk_dev *dev, struct bio *bio)
-{
- unsigned long flags;
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->bio_tail) {
- dev->bio_tail->bi_next = bio;
- dev->bio_tail = bio;
- } else
- dev->bio_head = dev->bio_tail = bio;
- wake_up(&dev->wait_q);
- spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-/*
- * Grab first pending buffer
- */
-static struct bio *blk_get_bio(struct lba_blk_dev *dev)
-{
- struct bio *bio;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
- bio = dev->bio_head;
- if (bio) {
- if (bio == dev->bio_tail) {
- dev->bio_tail = NULL;
- dev->bio_head = NULL;
- }
- dev->bio_head = bio->bi_next;
- bio->bi_next = NULL;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return bio;
-}
-
-static int lba_thread(void *data)
-{
- struct lba_blk_dev *dev = data;
- struct bio *bio;
- int status;
-
- set_user_nice(current, -20);
-
- while (!kthread_should_stop() || dev->bio_head) {
-
- wait_event_interruptible(dev->wait_q,
- dev->bio_head || kthread_should_stop());
-
- if (!dev->bio_head)
- continue;
-
- if (lba_core_lock_mode(dev->data, LBA_MODE_MDP))
- continue;
-
- bio = blk_get_bio(dev);
- status = lba_blk_xfer_bio(dev, bio);
- bio_endio(bio, status);
-
- lba_core_unlock_mode(dev->data);
- }
-
- return 0;
-}
-
-
-
-/*
- * The device operations structure.
- */
-static struct block_device_operations lba_blk_ops = {
- .owner = THIS_MODULE,
- .open = lba_blk_open,
- .release = lba_blk_release,
- .getgeo = lba_getgeo,
-};
-
-
-int lba_blk_init(struct lba_data *data)
-{
-
- struct lba_blk_dev *dev;
- int err;
- if (!data)
- BUG();
-
- printk(KERN_INFO "LBA block driver v0.1\n");
- lba_major = LBA_MAJOR;
- dev = g_lba_blk = kzalloc(sizeof(struct lba_blk_dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- dev->data = data;
- register_blkdev(lba_major, "lba");
-
- spin_lock_init(&dev->lock);
- init_waitqueue_head(&dev->wait_q);
- sema_init(&dev->busy, 1);
-
- dev->queue = blk_alloc_queue(GFP_KERNEL);
- if (!dev->queue)
- goto out2;
- blk_queue_make_request(dev->queue, lba_make_request);
- /*dev->queue->unplug_fn = lba_unplug_device;*/
- blk_queue_logical_block_size(dev->queue, 512);
-
- dev->queue->queuedata = dev;
- dev->gd = alloc_disk(32);
- if (!dev->gd) {
- printk(KERN_ERR "failed to alloc disk\n");
- goto out3;
- }
- dev->size = data->mdp_size ;
- printk(KERN_INFO "%s: set capacity of the device to 0x%x\n",
- __func__, dev->size);
- dev->gd->major = lba_major;
- dev->gd->first_minor = 0;
- dev->gd->fops = &lba_blk_ops;
- dev->gd->queue = dev->queue;
- dev->gd->private_data = dev;
- snprintf(dev->gd->disk_name, 8, LBA_NAME);
- set_capacity(dev->gd, dev->size);
-
- dev->thread = kthread_create(lba_thread, dev, "lba-%d", 1);
- if (IS_ERR(dev->thread)) {
- err = PTR_ERR(dev->thread);
- goto out3;
- }
- wake_up_process(dev->thread);
-
- add_disk(dev->gd);
-
-
- TAG();
-
- return 0;
-out3:
-out2:
- unregister_blkdev(lba_major, "lba");
- return -ENOMEM;
-}
-
-int lba_blk_remove(struct lba_data *data)
-{
-
- struct lba_blk_dev *dev = g_lba_blk;
-
- del_gendisk(dev->gd);
- kthread_stop(dev->thread);
- blk_cleanup_queue(dev->queue);
- put_disk(dev->gd);
-
- unregister_blkdev(lba_major, LBA_NAME);
- kfree(dev);
- return 0;
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(254);
diff --git a/drivers/mtd/nand/lba/lba-core.c b/drivers/mtd/nand/lba/lba-core.c
deleted file mode 100644
index cdf28ca42b2a..000000000000
--- a/drivers/mtd/nand/lba/lba-core.c
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X LBA/core driver
- *
- * Author: Dmitrij Frasenyak <sed@embeddedalley.com>
- *
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
-#include <mach/stmp3xxx.h>
-#include <mach/dma.h>
-#include "gpmi.h"
-#include "lba.h"
-
-#define LBA_SELFPM_TIMEOUT 2000 /* msecs */
-dma_addr_t g_cmd_handle;
-dma_addr_t g_data_handle;
-uint8_t *g_data_buffer;
-uint8_t *g_cmd_buffer;
-
-uint8_t lba_get_status1(void *priv)
-{
- uint8_t cmd_buf[] = { 0x70 } ;
- struct lba_cmd lba_flags[] = {
- {1 , F_CMD | FE_W4R},
- {0, F_DATA_READ | FE_END},
- };
- *g_data_buffer = 0;
- queue_cmd(priv, cmd_buf, 0, 1, g_data_handle, 1, lba_flags);
- queue_run(priv);
- return *g_data_buffer;
-}
-
-
-int lba_wait_for_ready(void *priv)
-{
- int stat;
- unsigned long j_start = jiffies;
-
- stat = lba_get_status1(priv);
- if ((stat & 0x60) != 0x60) {
- while (((stat & 0x60) != 0x60) &&
- (jiffies - j_start < msecs_to_jiffies(2000))) {
- schedule();
- stat = lba_get_status1(priv);
- }
- }
- if (stat != 0x60)
- return stat;
-
- return 0;
-}
-
-int lba_write_sectors(void *priv, unsigned int sector, unsigned int count,
- void *buffer, dma_addr_t handle)
-{
- uint8_t cmd_buf[] = {
- 0x80,
- count & 0xff, (count >> 8) & 0xff, /* Count */
- (sector & 0xff), (sector >> 8) & 0xff, /* Address */
- (sector >> 16) & 0xff, (sector >> 24) & 0xff, /* Addres */
- /* Data goes here */
- 0x10
- };
-
- struct lba_cmd flags_t1[] = { /* Transmition mode 1/A */
- {7 , F_CMD | FE_CMD_INC | FE_W4R},
- {0, F_DATA_WRITE},
- {1 , F_CMD | FE_END}
- };
-
- if (count > 8)
- return -EINVAL;
-
- if (lba_wait_for_ready(priv))
- return -EIO;
-
- while (count) {
- int cnt = (count < 8) ? count : 8;
- int data_len = cnt * 512;
-
- queue_cmd(priv, cmd_buf, 0, 8,
- handle, data_len, flags_t1);
-
- handle += data_len;
- count -= cnt;
-
- }
-
- queue_run(priv);
-
- return count;
-
-}
-
-int lba_read_sectors(void *priv, unsigned int sector, unsigned int count,
- void *buffer, dma_addr_t handle)
-{
-
- int data_len;
- int cnt;
- uint8_t cmd_buf[] = {
- 0x00,
- count & 0xff, (count >> 8) & 0xff, /* Count */
- (sector & 0xff), (sector >> 8) & 0xff, /* Addr */
- (sector >> 16) & 0xff, (sector >> 24) & 0xff, /* Addr */
- 0x30
- /* Data goes here <data> */
-
- };
-
- struct lba_cmd flags_r3[] = { /* Read mode 3/A */
- {7 , F_CMD | FE_CMD_INC | FE_W4R},
- {1 , F_CMD },
- {0 , F_DATA_READ | FE_W4R | FE_END },
- };
- struct lba_cmd flags_r3c[] = { /* Read mode 3/A */
- {0 , F_DATA_READ | FE_W4R | FE_END },
- };
- struct lba_cmd *flags = flags_r3;
- int flags_len = 8;
-
- if (count > 8)
- return -EINVAL;
-
- if (lba_wait_for_ready(priv))
- return -EIO;
-
- while (count) {
- cnt = (count < 8) ? count : 8;
- data_len = cnt * 512;
- queue_cmd(priv, cmd_buf, 0, flags_len, handle, data_len, flags);
- handle += data_len;
- count -= cnt;
- flags = flags_r3c;
- flags_len = 0;
- }
-
- queue_run(priv);
-
- return count;
-
-}
-
-
-uint8_t lba_get_id1(void *priv, uint8_t *ret_buffer)
-{
- uint8_t cmd_buf[] = { 0x90 , 0x00, /* Data read 5bytes*/ };
- struct lba_cmd lba_flags[] = {
- {2 , F_CMD | FE_CMD_INC | FE_W4R},
- {0, F_DATA_READ | FE_END},
- };
-
- queue_cmd(priv, cmd_buf, 0, 2, g_data_handle, 5, lba_flags);
- queue_run(priv);
- memcpy(ret_buffer, g_data_buffer, 5);
-
- return 0;
-}
-
-uint8_t lba_get_id2(void *priv, uint8_t *ret_buffer)
-{
- uint8_t cmd_buf[] = { 0x92 , 0x00, /* Data read 5bytes*/ };
- struct lba_cmd lba_flags[] = {
- {2 , F_CMD | FE_CMD_INC | FE_W4R},
- {0, F_DATA_READ | FE_END},
- };
-
- queue_cmd(priv, cmd_buf, 0, 2, g_data_handle, 5, lba_flags);
- queue_run(priv);
- memcpy(ret_buffer, g_data_buffer, 5);
- return 0;
-}
-
-uint8_t lba_get_status2(void *priv)
-{
- uint8_t cmd_buf[] = { 0x71 };
- struct lba_cmd lba_flags[] = {
- {1 , F_CMD | FE_CMD_INC | FE_W4R},
- {0 , F_DATA_READ | FE_END},
- };
- *g_data_buffer = 0;
- queue_cmd(priv, cmd_buf, 0, 1, g_data_handle, 1, lba_flags);
- queue_run(priv);
- return *g_data_buffer;
-}
-
-static uint8_t lba_parse_status2(void *priv)
-{
- uint8_t stat;
-
- stat = lba_get_status2(priv);
- printk(KERN_INFO "Status2:|");
- if (stat & 0x40)
- printk(" C.PAR.ERR |"); /* no KERN_ here */
- if (stat & 0x20)
- printk(" NO spare |");
- if (stat & 0x10)
- printk(" ADDR OoRange |");
- if (stat & 0x8)
- printk(" high speed |");
- if ((stat & 0x6) == 6)
- printk(" MDP |");
- if ((stat & 0x6) == 4)
- printk(" VFP |");
- if ((stat & 0x6) == 2)
- printk(" PNP |");
- if (stat & 1)
- printk(" PSW |");
-
- printk("\n");
- return 0;
-}
-
-
-int lba_2mdp(void *priv)
-{
- uint8_t cmd_buf[] = { 0xFC };
- struct lba_cmd lba_flags[] = {
- {1 , F_CMD | FE_W4R | FE_END}
- };
-
- queue_cmd(priv, cmd_buf, 0, 1, 0, 0, lba_flags);
- queue_run(priv);
- return 0;
-}
-
-void _lba_misc_cmd_set(void *priv, uint8_t *cmd_buf)
-{
- struct lba_cmd lba_flags[] = {
- {6 , F_CMD | FE_CMD_INC | FE_W4R },
- {1 , F_CMD | FE_END },
- };
-
- queue_cmd(priv, cmd_buf, 0, 7, 0, 0, lba_flags);
- queue_run(priv);
-}
-
-uint8_t _lba_misc_cmd_get(void *priv, uint8_t *cmd_buf)
-{
- struct lba_cmd lba_flags[] = {
- {6 , F_CMD | FE_CMD_INC | FE_W4R },
- {1 , F_CMD },
- {0 , F_DATA_READ | FE_W4R | FE_END}
- };
-
- queue_cmd(priv, cmd_buf, 0, 7, g_data_handle, 1, lba_flags);
- queue_run(priv);
- return *g_data_buffer;
-}
-void lba_mdp2vfp(void *priv, uint8_t pass[2])
-{
- uint8_t cmd_buf[] = { 0x0, 0xbe, pass[0], pass[1], 0, 0, 0x57 };
- _lba_misc_cmd_set(priv, cmd_buf);
-}
-
-void lba_bcm2vfp(void *priv, uint8_t pass[2])
-{
- lba_mdp2vfp(priv, pass);
-}
-
-void lba_powersave_enable(void *priv)
-{
- uint8_t cmd_buf[] = { 0x0, 0xba, 0, 0, 0, 0, 0x57 };
- _lba_misc_cmd_set(priv, cmd_buf);
-}
-void lba_powersave_disable(void *priv)
-{
- uint8_t cmd_buf[] = { 0x0, 0xbb, 0, 0, 0, 0, 0x57 };
- _lba_misc_cmd_set(priv, cmd_buf);
-}
-
-void lba_highspeed_enable(void *priv)
-{
- uint8_t cmd_buf[] = { 0x0, 0xbc, 0, 0, 0, 0, 0x57 };
- _lba_misc_cmd_set(priv, cmd_buf);
-}
-
-void lba_highspeed_disable(void *priv)
-{
- uint8_t cmd_buf[] = { 0x0, 0xbd, 0, 0, 0, 0, 0x57 };
- _lba_misc_cmd_set(priv, cmd_buf);
-}
-
-void lba_prot1_set(void *priv, uint8_t mode)
-{
- uint8_t cmd_buf[] = { 0x0, 0xa2, mode, 0, 0, 0, 0x57 };
- _lba_misc_cmd_set(priv, cmd_buf);
-}
-
-void lba_prot2_set(void *priv, uint8_t mode)
-{
- uint8_t cmd_buf[] = { 0x0, 0xa3, mode, 0, 0, 0, 0x57 };
- _lba_misc_cmd_set(priv, cmd_buf);
-}
-
-uint8_t lba_prot1_get(void *priv)
-{
- uint8_t cmd_buf[] = { 0x0, 0xb2, 0, 0, 0, 0, 0x57 };
- return _lba_misc_cmd_get(priv, cmd_buf);
-}
-
-uint8_t lba_prot2_get(void *priv)
-{
- uint8_t cmd_buf[] = { 0x0, 0xb3, 0, 0, 0, 0, 0x57 };
- return _lba_misc_cmd_get(priv, cmd_buf);
-}
-
-uint64_t lba_mdp_size_get(void *priv)
-{
- uint8_t cmd_buf[] = { 0x0, 0xb0, 0, 0, 0, 0, 0x57 };
- struct lba_cmd lba_flags[] = {
- {6 , F_CMD | FE_CMD_INC | FE_W4R },
- {1 , F_CMD },
- {0 , F_DATA_READ | FE_W4R | FE_END}
- };
-
- memset((void *)g_data_buffer, 0, 8);
- queue_cmd(priv, cmd_buf, 0, 7, g_data_handle, 5, lba_flags);
- queue_run(priv);
- return le64_to_cpu(*(long long *)g_data_buffer);
-}
-
-void lba_cache_flush(void *priv)
-{
- uint8_t cmd_buf[] = { 0xF9 };
- struct lba_cmd lba_flags[] = {
- {1 , F_CMD | FE_W4R },
- {0 , FE_W4R | FE_END}
- };
-
- queue_cmd(priv, cmd_buf, 0, 7, g_data_handle, 5, lba_flags);
- queue_run(priv);
-}
-
-void lba_reboot(void *priv)
-{
- uint8_t cmd_buf[] = { 0xFD };
- struct lba_cmd lba_flags[] = {
- {1 , F_CMD | FE_W4R },
- {0 , FE_W4R | FE_END}
- };
-
- queue_cmd(priv, cmd_buf, 0, 7, g_data_handle, 5, lba_flags);
- queue_run(priv);
-}
-
-void lba_def_state(void *priv)
-{
- lba_wait_for_ready(priv);
- lba_reboot(priv);
-
- lba_wait_for_ready(priv);
- lba_parse_status2(priv);
-
- lba_wait_for_ready(priv);
- lba_2mdp(priv);
-
- lba_wait_for_ready(priv);
- lba_prot1_set(priv, LBA_T_SIZE8); /* 512 * 8 */
-
- lba_wait_for_ready(priv);
-/* Type C read; Type A write; */
- lba_prot2_set(priv, LBA_P_WRITE_A | LBA_P_READ_C);
-}
-
-/*
- * Should be called with mode locked
- */
-void lba_core_setvfp_passwd(struct lba_data *data, uint8_t pass[2])
-{
- memcpy(data->pass, pass, 2);
-}
-
-int lba_core_lock_mode(struct lba_data *data, int mode)
-{
- void *priv = &data->nand;
-
- if (down_interruptible(&data->mode_lock))
- return -EAGAIN;
- /*
- * MDP and VFP are the only supported
- * modes for now.
- */
- if ((mode != LBA_MODE_MDP) &&
- (mode != LBA_MODE_VFP)) {
- up(&data->mode_lock);
- return -EINVAL;
- }
-
- while ((data->mode & LBA_MODE_MASK) == LBA_MODE_SUSP) {
- up(&data->mode_lock);
-
- if (wait_event_interruptible(
- data->suspend_q,
- (data->mode & LBA_MODE_MASK) != LBA_MODE_SUSP))
- return -EAGAIN;
-
- if (down_interruptible(&data->mode_lock))
- return -EAGAIN;
-
- data->last_access = jiffies;
- }
-
- if (data->mode & LBA_MODE_SELFPM) {
- queue_plug(data);
- data->mode &= ~LBA_MODE_SELFPM;
- }
-
- if (mode == data->mode)
- return 0;
-
- /*
- * mode = VFP || MDP only
- * Revisit when more modes are added
- */
- switch (data->mode) {
- case LBA_MODE_RST:
- case LBA_MODE_PNR:
- case LBA_MODE_BCM:
- lba_def_state(priv);
- if (mode == LBA_MODE_MDP) {
- data->mode = LBA_MODE_MDP;
- break;
- }
- /*no break -> fall down to set VFP mode*/
- case LBA_MODE_MDP:
- lba_wait_for_ready(priv);
- lba_mdp2vfp(priv, data->pass);
- data->mode = LBA_MODE_VFP;
- break;
- case LBA_MODE_VFP:
- lba_wait_for_ready(priv);
- lba_2mdp(priv);
- data->mode = LBA_MODE_MDP;
- break;
- default:
- up(&data->mode_lock);
- return -EINVAL;
- }
-
- return 0;
-}
-
-int lba_core_unlock_mode(struct lba_data *data)
-{
- data->last_access = jiffies;
- up(&data->mode_lock);
- wake_up(&data->selfpm_q);
- return 0;
-}
-
-static int selfpm_timeout_expired(struct lba_data *data)
-{
- return jiffies_to_msecs(jiffies - data->last_access) > 2000;
-}
-
-static int lba_selfpm_thread(void *d)
-{
- struct lba_data *data = d;
-
- set_user_nice(current, -5);
-
- while (!kthread_should_stop()) {
-
- if (wait_event_interruptible(data->selfpm_q,
- kthread_should_stop() ||
- !(data->mode & LBA_MODE_SELFPM)))
- continue;
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(LBA_SELFPM_TIMEOUT));
-
- if (down_trylock(&data->mode_lock))
- continue;
-
- if (!selfpm_timeout_expired(data)) {
- up(&data->mode_lock);
- continue;
- }
- data->mode |= LBA_MODE_SELFPM;
- lba_wait_for_ready((void *)data->nand);
- lba_cache_flush((void *)data->nand);
- queue_release(data);
- up(&data->mode_lock);
-
- }
-
- return 0;
-}
-
-int lba_core_init(struct lba_data *data)
-{
- uint8_t id_buf[5];
- uint8_t capacity;
- uint8_t id1_template[5] = {0x98, 0xDC, 0x00, 0x15, 0x00};
- uint8_t id2_template[5] = {0x98, 0x21, 0x00, 0x55, 0xAA};
- void *priv = (void *)data->nand;
-
-
- g_data = data;
- g_cmd_handle = queue_get_cmd_handle(priv);
- g_data_handle = queue_get_data_handle(priv);
- g_data_buffer = queue_get_data_ptr(priv);
- g_cmd_buffer = queue_get_cmd_ptr(priv);
-
- spin_lock_init(&data->lock);
- sema_init(&data->mode_lock, 1);
- init_waitqueue_head(&data->suspend_q);
- init_waitqueue_head(&data->selfpm_q);
-
-
- lba_get_id1(data->nand, id_buf);
- if (!memcmp(id_buf, id1_template, 5))
- printk(KERN_INFO
- "LBA: Found LBA/SLC NAND emulated ID\n");
- else
- return -ENODEV;
-
- lba_get_id2(data->nand, id_buf);
- capacity = id_buf[2];
- id_buf[2] = 0;
-
- if (memcmp(id_buf, id2_template, 5)) {
- printk(KERN_INFO
- "LBA: Uknown LBA device\n");
- return -ENODEV;
- }
- printk(KERN_INFO
- "LBA: Found %dGbytes LBA NAND device\n",
- 1 << capacity);
-
- lba_wait_for_ready(priv);
- lba_parse_status2(priv);
-
- lba_def_state(priv);
- data->mode = LBA_MODE_MDP;
-
- g_data->pnp_size = 0xff;
- g_data->vfp_size = 16384;
-
- lba_wait_for_ready(priv);
- g_data->mdp_size = lba_mdp_size_get(priv);
-
- lba_wait_for_ready(priv);
- /*lba_powersave_enable(priv);*/
- /*lba_highspeed_enable(priv);*/
-
- lba_wait_for_ready(priv);
- lba_parse_status2(priv);
-
- data->thread = kthread_create(lba_selfpm_thread,
- data, "lba-selfpm-%d", 1);
- if (IS_ERR(data->thread))
- return PTR_ERR(data->thread);
-
- lba_blk_init(g_data);
-
- wake_up_process(data->thread);
- return 0;
-
-};
-
-int lba_core_remove(struct lba_data *data)
-{
- kthread_stop(data->thread);
- lba_blk_remove(data);
- lba_wait_for_ready((void *)data->nand);
- lba_cache_flush((void *)data->nand);
- return 0;
-}
-
-int lba_core_suspend(struct platform_device *pdev, struct lba_data *data)
-{
- BUG_ON((data->mode & 0xffff) == LBA_MODE_SUSP);
- if (down_interruptible(&data->mode_lock))
- return -EAGAIN;
- if (data->mode & LBA_MODE_SELFPM)
- queue_plug(data);
-
- data->mode = LBA_MODE_SUSP | LBA_MODE_SELFPM;
- up(&data->mode_lock);
- lba_wait_for_ready((void *)data->nand);
- lba_cache_flush((void *)data->nand);
- return 0;
-}
-
-int lba_core_resume(struct platform_device *pdev, struct lba_data *data)
-{
- BUG_ON((data->mode & 0xffff) != LBA_MODE_SUSP);
- lba_def_state((void *)data->nand);
- data->last_access = jiffies;
- data->mode = LBA_MODE_MDP;
- wake_up(&data->suspend_q);
- return 0;
-}
diff --git a/drivers/mtd/nand/lba/lba.h b/drivers/mtd/nand/lba/lba.h
deleted file mode 100644
index 3466f96881eb..000000000000
--- a/drivers/mtd/nand/lba/lba.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X LBA interface
- *
- * Author: Dmitrij Frasenyak <sed@embeddedalley.com>
- *
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef __INCLUDE_LBA_H__
-#define __INCLUDE_LBA_H__
-
-
-#include <linux/spinlock.h>
-#include <linux/kthread.h>
-#include "gpmi.h"
-
-struct lba_cmd {
- uint8_t len;
-#define F_MASK 0x0f
-#define F_ALE 0x01
-#define F_CMD 0x02
-#define F_DATA_READ 0x04
-#define F_DATA_WRITE 0x08
-
-#define FE_W4R 0x10
-#define FE_CMD_INC 0x20
-#define FE_END 0x40
-
- uint8_t flag;
-};
-
-#define LBA_P_READ_A 0
-#define LBA_P_READ_B 2
-#define LBA_P_READ_C 3
-#define LBA_P_WRITE_A 0
-#define LBA_P_WRITE_B 4
-#define LBA_T_SIZE1 1
-#define LBA_T_SIZE4 2
-#define LBA_T_SIZE8 4
-#define LBA_T_CRC (1 << 6)
-#define LBA_T_ECC_CHECK (2 << 6)
-#define LBA_T_ECC_CORRECT (3 << 6)
-
-struct lba_data {
- void __iomem *io_base;
- struct clk *clk;
- int irq;
-
- spinlock_t lock;
- int use_count;
- int mode;
- struct semaphore mode_lock;
-#define LBA_MODE_MASK 0x0000ffff
-#define LBA_FLAG_MASK 0xffff0000
-#define LBA_MODE_RST 0
-#define LBA_MODE_PNR 1
-#define LBA_MODE_BCM 2
-#define LBA_MODE_MDP 3
-#define LBA_MODE_VFP 4
-#define LBA_MODE_SUSP 5
-#define LBA_MODE_SELFPM 0x80000000
- wait_queue_head_t suspend_q;
- wait_queue_head_t selfpm_q;
- struct task_struct *thread;
- long long last_access;
- /* PNR specific */
- /* BCM specific */
- /* VFP specific */
- uint8_t pass[2];
-
- /* Size of the partiotions: pages for PNP; sectors for others */
- unsigned int pnp_size;
- unsigned int vfp_size;
- long long mdp_size;
- void *priv;
- /*should be last*/
- struct gpmi_perchip_data nand[0];
-
-};
-
-extern struct lba_data *g_data;
-
-void stmp37cc_dma_print_chain(struct stmp37xx_circ_dma_chain *chain);
-
-int lba_blk_init(struct lba_data *data);
-int lba_blk_remove(struct lba_data *data);
-int lba_blk_suspend(struct platform_device *pdev, struct lba_data *data);
-int lba_blk_resume(struct platform_device *pdev, struct lba_data *data);
-
-
-int lba_core_init(struct lba_data *data);
-int lba_core_remove(struct lba_data *data);
-int lba_core_suspend(struct platform_device *pdev, struct lba_data *data);
-int lba_core_resume(struct platform_device *pdev, struct lba_data *data);
-int lba_core_lock_mode(struct lba_data *data, int mode);
-int lba_core_unlock_mode(struct lba_data *data);
-
-int lba_write_sectors(void *priv, unsigned int sector, unsigned int count,
- void *buffer, dma_addr_t handle);
-int lba_read_sectors(void *priv, unsigned int sector, unsigned int count,
- void *buffer, dma_addr_t handle);
-void lba_protocol1_set(void *priv, uint8_t param);
-uint8_t lba_protocol1_get(void *priv);
-uint8_t lba_get_status1(void *priv);
-uint8_t lba_get_status2(void *priv);
-
-uint8_t lba_get_id1(void *priv, uint8_t *ret_buffer);
-uint8_t lba_get_id2(void *priv, uint8_t *);
-
-
-int queue_cmd(void *priv,
- uint8_t *cmd_buf, dma_addr_t cmd_handle, int cmd_len,
- dma_addr_t data, int data_len,
- struct lba_cmd *cmd_flags);
-
-int queue_run(void *priv);
-
-dma_addr_t queue_get_cmd_handle(void *priv);
-
-uint8_t *queue_get_cmd_ptr(void *priv);
-
-dma_addr_t queue_get_data_handle(void *priv);
-
-uint8_t *queue_get_data_ptr(void *priv);
-
-void queue_plug(struct lba_data *data);
-void queue_release(struct lba_data *data);
-
-
-#endif