summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorPatrick Turley <patrick.turley@freescale.com>2010-04-27 21:39:33 -0500
committerPatrick Turley <patrick.turley@freescale.com>2010-05-05 13:39:02 -0500
commit8aaf851aad2fb212e798c09272af98a5748a4556 (patch)
tree6b6e453c7cc97f38a0b953cf762e6afed79d638e /drivers/mtd
parent9238e7fa94c664b3a673f53518b0b58190acc5a9 (diff)
ENGR00122964 Second pass at unified i.MX23/i.MX28 NAND Flash driver
Deleted the old drivers. Broke the driver into separate files, for readability and to isolate hardware dependencies. Fixed bad block problems in the boot area for the i.MX23. At this writing, UBI can't handle MTDs larger than 2GiB. If the general use partition is larger than 2GiB, the driver will create sub-partitions, none of which are larger than 2GiB. Updated the default configs for the i.MX23 and i.MX28. Other, miscellaneous changes. Signed-off-by: Patrick Turley <patrick.turley@freescale.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/gpmi-nfc/Makefile9
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-bch-regs-v0.h550
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-bch-regs-v1.h (renamed from drivers/mtd/nand/gpmi1/regs-bch.h)56
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-event-reporting.c307
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-gpmi-regs-v0.h416
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-gpmi-regs-v1.h (renamed from drivers/mtd/nand/gpmi1/regs-gpmi.h)44
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-common.c522
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v0.c795
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v1.c797
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-main.c1379
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-mil.c2599
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-common.c59
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-v0.c298
-rw-r--r--drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-v1.c82
-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.h279
-rw-r--r--drivers/mtd/nand/gpmi/Makefile6
-rw-r--r--drivers/mtd/nand/gpmi/gpmi-base.c3382
-rw-r--r--drivers/mtd/nand/gpmi/gpmi-bbt.c844
-rw-r--r--drivers/mtd/nand/gpmi/gpmi-bch.c453
-rw-r--r--drivers/mtd/nand/gpmi/gpmi-ecc8.c513
-rw-r--r--drivers/mtd/nand/gpmi/gpmi-hamming-13-8.c130
-rw-r--r--drivers/mtd/nand/gpmi/gpmi-hamming-22-16.c195
-rw-r--r--drivers/mtd/nand/gpmi/gpmi-hamming-22-16.h43
-rw-r--r--drivers/mtd/nand/gpmi/gpmi.h464
-rw-r--r--drivers/mtd/nand/gpmi1/Makefile2
-rw-r--r--drivers/mtd/nand/gpmi1/gpmi-base.c3233
-rw-r--r--drivers/mtd/nand/gpmi1/gpmi-bbt.c433
-rw-r--r--drivers/mtd/nand/gpmi1/gpmi-bch.c488
-rw-r--r--drivers/mtd/nand/gpmi1/gpmi.h458
34 files changed, 8133 insertions, 18997 deletions
diff --git a/drivers/mtd/nand/gpmi-nfc/Makefile b/drivers/mtd/nand/gpmi-nfc/Makefile
index 6acc04fef117..e3d5660735b6 100644
--- a/drivers/mtd/nand/gpmi-nfc/Makefile
+++ b/drivers/mtd/nand/gpmi-nfc/Makefile
@@ -1 +1,10 @@
obj-$(CONFIG_MTD_NAND_GPMI_NFC) += gpmi-nfc.o
+gpmi-nfc-objs += gpmi-nfc-main.o
+gpmi-nfc-objs += gpmi-nfc-event-reporting.o
+gpmi-nfc-objs += gpmi-nfc-hal-common.o
+gpmi-nfc-objs += gpmi-nfc-hal-v0.o
+gpmi-nfc-objs += gpmi-nfc-hal-v1.o
+gpmi-nfc-objs += gpmi-nfc-rom-common.o
+gpmi-nfc-objs += gpmi-nfc-rom-v0.o
+gpmi-nfc-objs += gpmi-nfc-rom-v1.o
+gpmi-nfc-objs += gpmi-nfc-mil.o
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-bch-regs-v0.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-bch-regs-v0.h
new file mode 100644
index 000000000000..9af4feb29021
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-bch-regs-v0.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 __GPMI_NFC_BCH_REGS_H
+#define __GPMI_NFC_BCH_REGS_H
+
+/*============================================================================*/
+
+#define HW_BCH_CTRL (0x00000000)
+#define HW_BCH_CTRL_SET (0x00000004)
+#define HW_BCH_CTRL_CLR (0x00000008)
+#define HW_BCH_CTRL_TOG (0x0000000c)
+
+#define BM_BCH_CTRL_SFTRST 0x80000000
+#define BV_BCH_CTRL_SFTRST__RUN 0x0
+#define BV_BCH_CTRL_SFTRST__RESET 0x1
+#define BM_BCH_CTRL_CLKGATE 0x40000000
+#define BV_BCH_CTRL_CLKGATE__RUN 0x0
+#define BV_BCH_CTRL_CLKGATE__NO_CLKS 0x1
+#define BP_BCH_CTRL_RSVD5 23
+#define BM_BCH_CTRL_RSVD5 0x3F800000
+#define BF_BCH_CTRL_RSVD5(v) (((v) << 23) & BM_BCH_CTRL_RSVD5)
+#define BM_BCH_CTRL_DEBUGSYNDROME 0x00400000
+#define BP_BCH_CTRL_RSVD4 20
+#define BM_BCH_CTRL_RSVD4 0x00300000
+#define BF_BCH_CTRL_RSVD4(v) (((v) << 20) & BM_BCH_CTRL_RSVD4)
+#define BP_BCH_CTRL_M2M_LAYOUT 18
+#define BM_BCH_CTRL_M2M_LAYOUT 0x000C0000
+#define BF_BCH_CTRL_M2M_LAYOUT(v) (((v) << 18) & BM_BCH_CTRL_M2M_LAYOUT)
+#define BM_BCH_CTRL_M2M_ENCODE 0x00020000
+#define BM_BCH_CTRL_M2M_ENABLE 0x00010000
+#define BP_BCH_CTRL_RSVD3 11
+#define BM_BCH_CTRL_RSVD3 0x0000F800
+#define BF_BCH_CTRL_RSVD3(v) (((v) << 11) & BM_BCH_CTRL_RSVD3)
+#define BM_BCH_CTRL_DEBUG_STALL_IRQ_EN 0x00000400
+#define BM_BCH_CTRL_RSVD2 0x00000200
+#define BM_BCH_CTRL_COMPLETE_IRQ_EN 0x00000100
+#define BP_BCH_CTRL_RSVD1 4
+#define BM_BCH_CTRL_RSVD1 0x000000F0
+#define BF_BCH_CTRL_RSVD1(v) (((v) << 4) & BM_BCH_CTRL_RSVD1)
+#define BM_BCH_CTRL_BM_ERROR_IRQ 0x00000008
+#define BM_BCH_CTRL_DEBUG_STALL_IRQ 0x00000004
+#define BM_BCH_CTRL_RSVD0 0x00000002
+#define BM_BCH_CTRL_COMPLETE_IRQ 0x00000001
+
+/*============================================================================*/
+
+#define HW_BCH_STATUS0 (0x00000010)
+
+#define BP_BCH_STATUS0_HANDLE 20
+#define BM_BCH_STATUS0_HANDLE 0xFFF00000
+#define BF_BCH_STATUS0_HANDLE(v) \
+ (((v) << 20) & BM_BCH_STATUS0_HANDLE)
+#define BP_BCH_STATUS0_COMPLETED_CE 16
+#define BM_BCH_STATUS0_COMPLETED_CE 0x000F0000
+#define BF_BCH_STATUS0_COMPLETED_CE(v) \
+ (((v) << 16) & BM_BCH_STATUS0_COMPLETED_CE)
+#define BP_BCH_STATUS0_STATUS_BLK0 8
+#define BM_BCH_STATUS0_STATUS_BLK0 0x0000FF00
+#define BF_BCH_STATUS0_STATUS_BLK0(v) \
+ (((v) << 8) & BM_BCH_STATUS0_STATUS_BLK0)
+#define BV_BCH_STATUS0_STATUS_BLK0__ZERO 0x00
+#define BV_BCH_STATUS0_STATUS_BLK0__ERROR1 0x01
+#define BV_BCH_STATUS0_STATUS_BLK0__ERROR2 0x02
+#define BV_BCH_STATUS0_STATUS_BLK0__ERROR3 0x03
+#define BV_BCH_STATUS0_STATUS_BLK0__ERROR4 0x04
+#define BV_BCH_STATUS0_STATUS_BLK0__UNCORRECTABLE 0xFE
+#define BV_BCH_STATUS0_STATUS_BLK0__ERASED 0xFF
+#define BP_BCH_STATUS0_RSVD1 5
+#define BM_BCH_STATUS0_RSVD1 0x000000E0
+#define BF_BCH_STATUS0_RSVD1(v) \
+ (((v) << 5) & BM_BCH_STATUS0_RSVD1)
+#define BM_BCH_STATUS0_ALLONES 0x00000010
+#define BM_BCH_STATUS0_CORRECTED 0x00000008
+#define BM_BCH_STATUS0_UNCORRECTABLE 0x00000004
+#define BP_BCH_STATUS0_RSVD0 0
+#define BM_BCH_STATUS0_RSVD0 0x00000003
+#define BF_BCH_STATUS0_RSVD0(v) \
+ (((v) << 0) & BM_BCH_STATUS0_RSVD0)
+
+/*============================================================================*/
+
+#define HW_BCH_MODE (0x00000020)
+
+#define BP_BCH_MODE_RSVD 8
+#define BM_BCH_MODE_RSVD 0xFFFFFF00
+#define BF_BCH_MODE_RSVD(v) \
+ (((v) << 8) & BM_BCH_MODE_RSVD)
+#define BP_BCH_MODE_ERASE_THRESHOLD 0
+#define BM_BCH_MODE_ERASE_THRESHOLD 0x000000FF
+#define BF_BCH_MODE_ERASE_THRESHOLD(v) \
+ (((v) << 0) & BM_BCH_MODE_ERASE_THRESHOLD)
+
+/*============================================================================*/
+
+#define HW_BCH_ENCODEPTR (0x00000030)
+
+#define BP_BCH_ENCODEPTR_ADDR 0
+#define BM_BCH_ENCODEPTR_ADDR 0xFFFFFFFF
+#define BF_BCH_ENCODEPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define HW_BCH_DATAPTR (0x00000040)
+
+#define BP_BCH_DATAPTR_ADDR 0
+#define BM_BCH_DATAPTR_ADDR 0xFFFFFFFF
+#define BF_BCH_DATAPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define HW_BCH_METAPTR (0x00000050)
+
+#define BP_BCH_METAPTR_ADDR 0
+#define BM_BCH_METAPTR_ADDR 0xFFFFFFFF
+#define BF_BCH_METAPTR_ADDR(v) (v)
+
+/*============================================================================*/
+
+#define HW_BCH_LAYOUTSELECT (0x00000070)
+
+#define BP_BCH_LAYOUTSELECT_CS15_SELECT 30
+#define BM_BCH_LAYOUTSELECT_CS15_SELECT 0xC0000000
+#define BF_BCH_LAYOUTSELECT_CS15_SELECT(v) \
+ (((v) << 30) & BM_BCH_LAYOUTSELECT_CS15_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS14_SELECT 28
+#define BM_BCH_LAYOUTSELECT_CS14_SELECT 0x30000000
+#define BF_BCH_LAYOUTSELECT_CS14_SELECT(v) \
+ (((v) << 28) & BM_BCH_LAYOUTSELECT_CS14_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS13_SELECT 26
+#define BM_BCH_LAYOUTSELECT_CS13_SELECT 0x0C000000
+#define BF_BCH_LAYOUTSELECT_CS13_SELECT(v) \
+ (((v) << 26) & BM_BCH_LAYOUTSELECT_CS13_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS12_SELECT 24
+#define BM_BCH_LAYOUTSELECT_CS12_SELECT 0x03000000
+#define BF_BCH_LAYOUTSELECT_CS12_SELECT(v) \
+ (((v) << 24) & BM_BCH_LAYOUTSELECT_CS12_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS11_SELECT 22
+#define BM_BCH_LAYOUTSELECT_CS11_SELECT 0x00C00000
+#define BF_BCH_LAYOUTSELECT_CS11_SELECT(v) \
+ (((v) << 22) & BM_BCH_LAYOUTSELECT_CS11_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS10_SELECT 20
+#define BM_BCH_LAYOUTSELECT_CS10_SELECT 0x00300000
+#define BF_BCH_LAYOUTSELECT_CS10_SELECT(v) \
+ (((v) << 20) & BM_BCH_LAYOUTSELECT_CS10_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS9_SELECT 18
+#define BM_BCH_LAYOUTSELECT_CS9_SELECT 0x000C0000
+#define BF_BCH_LAYOUTSELECT_CS9_SELECT(v) \
+ (((v) << 18) & BM_BCH_LAYOUTSELECT_CS9_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS8_SELECT 16
+#define BM_BCH_LAYOUTSELECT_CS8_SELECT 0x00030000
+#define BF_BCH_LAYOUTSELECT_CS8_SELECT(v) \
+ (((v) << 16) & BM_BCH_LAYOUTSELECT_CS8_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS7_SELECT 14
+#define BM_BCH_LAYOUTSELECT_CS7_SELECT 0x0000C000
+#define BF_BCH_LAYOUTSELECT_CS7_SELECT(v) \
+ (((v) << 14) & BM_BCH_LAYOUTSELECT_CS7_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS6_SELECT 12
+#define BM_BCH_LAYOUTSELECT_CS6_SELECT 0x00003000
+#define BF_BCH_LAYOUTSELECT_CS6_SELECT(v) \
+ (((v) << 12) & BM_BCH_LAYOUTSELECT_CS6_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS5_SELECT 10
+#define BM_BCH_LAYOUTSELECT_CS5_SELECT 0x00000C00
+#define BF_BCH_LAYOUTSELECT_CS5_SELECT(v) \
+ (((v) << 10) & BM_BCH_LAYOUTSELECT_CS5_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS4_SELECT 8
+#define BM_BCH_LAYOUTSELECT_CS4_SELECT 0x00000300
+#define BF_BCH_LAYOUTSELECT_CS4_SELECT(v) \
+ (((v) << 8) & BM_BCH_LAYOUTSELECT_CS4_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS3_SELECT 6
+#define BM_BCH_LAYOUTSELECT_CS3_SELECT 0x000000C0
+#define BF_BCH_LAYOUTSELECT_CS3_SELECT(v) \
+ (((v) << 6) & BM_BCH_LAYOUTSELECT_CS3_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS2_SELECT 4
+#define BM_BCH_LAYOUTSELECT_CS2_SELECT 0x00000030
+#define BF_BCH_LAYOUTSELECT_CS2_SELECT(v) \
+ (((v) << 4) & BM_BCH_LAYOUTSELECT_CS2_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS1_SELECT 2
+#define BM_BCH_LAYOUTSELECT_CS1_SELECT 0x0000000C
+#define BF_BCH_LAYOUTSELECT_CS1_SELECT(v) \
+ (((v) << 2) & BM_BCH_LAYOUTSELECT_CS1_SELECT)
+#define BP_BCH_LAYOUTSELECT_CS0_SELECT 0
+#define BM_BCH_LAYOUTSELECT_CS0_SELECT 0x00000003
+#define BF_BCH_LAYOUTSELECT_CS0_SELECT(v) \
+ (((v) << 0) & BM_BCH_LAYOUTSELECT_CS0_SELECT)
+
+/*============================================================================*/
+
+#define HW_BCH_FLASH0LAYOUT0 (0x00000080)
+
+#define BP_BCH_FLASH0LAYOUT0_NBLOCKS 24
+#define BM_BCH_FLASH0LAYOUT0_NBLOCKS 0xFF000000
+#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & BM_BCH_FLASH0LAYOUT0_NBLOCKS)
+#define BP_BCH_FLASH0LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH0LAYOUT0_META_SIZE 0x00FF0000
+#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH0LAYOUT0_META_SIZE)
+#define BP_BCH_FLASH0LAYOUT0_ECC0 12
+#define BM_BCH_FLASH0LAYOUT0_ECC0 0x0000F000
+#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \
+ (((v) << 12) & BM_BCH_FLASH0LAYOUT0_ECC0)
+#define BV_BCH_FLASH0LAYOUT0_ECC0__NONE 0x0
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC2 0x1
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC4 0x2
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC6 0x3
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC8 0x4
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC10 0x5
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC12 0x6
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC14 0x7
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC16 0x8
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC18 0x9
+#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC20 0xA
+#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0
+#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE 0x00000FFF
+#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define HW_BCH_FLASH0LAYOUT1 (0x00000090)
+
+#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16
+#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE)
+#define BP_BCH_FLASH0LAYOUT1_ECCN 12
+#define BM_BCH_FLASH0LAYOUT1_ECCN 0x0000F000
+#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \
+ (((v) << 12) & BM_BCH_FLASH0LAYOUT1_ECCN)
+#define BV_BCH_FLASH0LAYOUT1_ECCN__NONE 0x0
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC2 0x1
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC4 0x2
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC6 0x3
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC8 0x4
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC10 0x5
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC12 0x6
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC14 0x7
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC16 0x8
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC18 0x9
+#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC20 0xA
+#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0
+#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE 0x00000FFF
+#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define HW_BCH_FLASH1LAYOUT0 (0x000000a0)
+
+#define BP_BCH_FLASH1LAYOUT0_NBLOCKS 24
+#define BM_BCH_FLASH1LAYOUT0_NBLOCKS 0xFF000000
+#define BF_BCH_FLASH1LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & BM_BCH_FLASH1LAYOUT0_NBLOCKS)
+#define BP_BCH_FLASH1LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH1LAYOUT0_META_SIZE 0x00FF0000
+#define BF_BCH_FLASH1LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH1LAYOUT0_META_SIZE)
+#define BP_BCH_FLASH1LAYOUT0_ECC0 12
+#define BM_BCH_FLASH1LAYOUT0_ECC0 0x0000F000
+#define BF_BCH_FLASH1LAYOUT0_ECC0(v) \
+ (((v) << 12) & BM_BCH_FLASH1LAYOUT0_ECC0)
+#define BV_BCH_FLASH1LAYOUT0_ECC0__NONE 0x0
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC2 0x1
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC4 0x2
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC6 0x3
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC8 0x4
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC10 0x5
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC12 0x6
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC14 0x7
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC16 0x8
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC18 0x9
+#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC20 0xA
+#define BP_BCH_FLASH1LAYOUT0_DATA0_SIZE 0
+#define BM_BCH_FLASH1LAYOUT0_DATA0_SIZE 0x00000FFF
+#define BF_BCH_FLASH1LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH1LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define HW_BCH_FLASH1LAYOUT1 (0x000000b0)
+
+#define BP_BCH_FLASH1LAYOUT1_PAGE_SIZE 16
+#define BM_BCH_FLASH1LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BF_BCH_FLASH1LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH1LAYOUT1_PAGE_SIZE)
+#define BP_BCH_FLASH1LAYOUT1_ECCN 12
+#define BM_BCH_FLASH1LAYOUT1_ECCN 0x0000F000
+#define BF_BCH_FLASH1LAYOUT1_ECCN(v) \
+ (((v) << 12) & BM_BCH_FLASH1LAYOUT1_ECCN)
+#define BV_BCH_FLASH1LAYOUT1_ECCN__NONE 0x0
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC2 0x1
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC4 0x2
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC6 0x3
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC8 0x4
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC10 0x5
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC12 0x6
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC14 0x7
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC16 0x8
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC18 0x9
+#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC20 0xA
+#define BP_BCH_FLASH1LAYOUT1_DATAN_SIZE 0
+#define BM_BCH_FLASH1LAYOUT1_DATAN_SIZE 0x00000FFF
+#define BF_BCH_FLASH1LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH1LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define HW_BCH_FLASH2LAYOUT0 (0x000000c0)
+
+#define BP_BCH_FLASH2LAYOUT0_NBLOCKS 24
+#define BM_BCH_FLASH2LAYOUT0_NBLOCKS 0xFF000000
+#define BF_BCH_FLASH2LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & BM_BCH_FLASH2LAYOUT0_NBLOCKS)
+#define BP_BCH_FLASH2LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH2LAYOUT0_META_SIZE 0x00FF0000
+#define BF_BCH_FLASH2LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH2LAYOUT0_META_SIZE)
+#define BP_BCH_FLASH2LAYOUT0_ECC0 12
+#define BM_BCH_FLASH2LAYOUT0_ECC0 0x0000F000
+#define BF_BCH_FLASH2LAYOUT0_ECC0(v) \
+ (((v) << 12) & BM_BCH_FLASH2LAYOUT0_ECC0)
+#define BV_BCH_FLASH2LAYOUT0_ECC0__NONE 0x0
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC2 0x1
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC4 0x2
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC6 0x3
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC8 0x4
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC10 0x5
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC12 0x6
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC14 0x7
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC16 0x8
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC18 0x9
+#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC20 0xA
+#define BP_BCH_FLASH2LAYOUT0_DATA0_SIZE 0
+#define BM_BCH_FLASH2LAYOUT0_DATA0_SIZE 0x00000FFF
+#define BF_BCH_FLASH2LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH2LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define HW_BCH_FLASH2LAYOUT1 (0x000000d0)
+
+#define BP_BCH_FLASH2LAYOUT1_PAGE_SIZE 16
+#define BM_BCH_FLASH2LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BF_BCH_FLASH2LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH2LAYOUT1_PAGE_SIZE)
+#define BP_BCH_FLASH2LAYOUT1_ECCN 12
+#define BM_BCH_FLASH2LAYOUT1_ECCN 0x0000F000
+#define BF_BCH_FLASH2LAYOUT1_ECCN(v) \
+ (((v) << 12) & BM_BCH_FLASH2LAYOUT1_ECCN)
+#define BV_BCH_FLASH2LAYOUT1_ECCN__NONE 0x0
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC2 0x1
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC4 0x2
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC6 0x3
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC8 0x4
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC10 0x5
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC12 0x6
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC14 0x7
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC16 0x8
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC18 0x9
+#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC20 0xA
+#define BP_BCH_FLASH2LAYOUT1_DATAN_SIZE 0
+#define BM_BCH_FLASH2LAYOUT1_DATAN_SIZE 0x00000FFF
+#define BF_BCH_FLASH2LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH2LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define HW_BCH_FLASH3LAYOUT0 (0x000000e0)
+
+#define BP_BCH_FLASH3LAYOUT0_NBLOCKS 24
+#define BM_BCH_FLASH3LAYOUT0_NBLOCKS 0xFF000000
+#define BF_BCH_FLASH3LAYOUT0_NBLOCKS(v) \
+ (((v) << 24) & BM_BCH_FLASH3LAYOUT0_NBLOCKS)
+#define BP_BCH_FLASH3LAYOUT0_META_SIZE 16
+#define BM_BCH_FLASH3LAYOUT0_META_SIZE 0x00FF0000
+#define BF_BCH_FLASH3LAYOUT0_META_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH3LAYOUT0_META_SIZE)
+#define BP_BCH_FLASH3LAYOUT0_ECC0 12
+#define BM_BCH_FLASH3LAYOUT0_ECC0 0x0000F000
+#define BF_BCH_FLASH3LAYOUT0_ECC0(v) \
+ (((v) << 12) & BM_BCH_FLASH3LAYOUT0_ECC0)
+#define BV_BCH_FLASH3LAYOUT0_ECC0__NONE 0x0
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC2 0x1
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC4 0x2
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC6 0x3
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC8 0x4
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC10 0x5
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC12 0x6
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC14 0x7
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC16 0x8
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC18 0x9
+#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC20 0xA
+#define BP_BCH_FLASH3LAYOUT0_DATA0_SIZE 0
+#define BM_BCH_FLASH3LAYOUT0_DATA0_SIZE 0x00000FFF
+#define BF_BCH_FLASH3LAYOUT0_DATA0_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH3LAYOUT0_DATA0_SIZE)
+
+/*============================================================================*/
+
+#define HW_BCH_FLASH3LAYOUT1 (0x000000f0)
+
+#define BP_BCH_FLASH3LAYOUT1_PAGE_SIZE 16
+#define BM_BCH_FLASH3LAYOUT1_PAGE_SIZE 0xFFFF0000
+#define BF_BCH_FLASH3LAYOUT1_PAGE_SIZE(v) \
+ (((v) << 16) & BM_BCH_FLASH3LAYOUT1_PAGE_SIZE)
+#define BP_BCH_FLASH3LAYOUT1_ECCN 12
+#define BM_BCH_FLASH3LAYOUT1_ECCN 0x0000F000
+#define BF_BCH_FLASH3LAYOUT1_ECCN(v) \
+ (((v) << 12) & BM_BCH_FLASH3LAYOUT1_ECCN)
+#define BV_BCH_FLASH3LAYOUT1_ECCN__NONE 0x0
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC2 0x1
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC4 0x2
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC6 0x3
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC8 0x4
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC10 0x5
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC12 0x6
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC14 0x7
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC16 0x8
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC18 0x9
+#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC20 0xA
+#define BP_BCH_FLASH3LAYOUT1_DATAN_SIZE 0
+#define BM_BCH_FLASH3LAYOUT1_DATAN_SIZE 0x00000FFF
+#define BF_BCH_FLASH3LAYOUT1_DATAN_SIZE(v) \
+ (((v) << 0) & BM_BCH_FLASH3LAYOUT1_DATAN_SIZE)
+
+/*============================================================================*/
+
+#define HW_BCH_DEBUG0 (0x00000100)
+#define HW_BCH_DEBUG0_SET (0x00000104)
+#define HW_BCH_DEBUG0_CLR (0x00000108)
+#define HW_BCH_DEBUG0_TOG (0x0000010c)
+
+#define BP_BCH_DEBUG0_RSVD1 27
+#define BM_BCH_DEBUG0_RSVD1 0xF8000000
+#define BF_BCH_DEBUG0_RSVD1(v) \
+ (((v) << 27) & BM_BCH_DEBUG0_RSVD1)
+#define BM_BCH_DEBUG0_ROM_BIST_ENABLE 0x04000000
+#define BM_BCH_DEBUG0_ROM_BIST_COMPLETE 0x02000000
+#define BP_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 16
+#define BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 0x01FF0000
+#define BF_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL(v) \
+ (((v) << 16) & BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL)
+#define BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__NORMAL 0x0
+#define BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__TEST_MODE 0x1
+#define BM_BCH_DEBUG0_KES_DEBUG_SHIFT_SYND 0x00008000
+#define BM_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG 0x00004000
+#define BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__DATA 0x1
+#define BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__AUX 0x1
+#define BM_BCH_DEBUG0_KES_DEBUG_MODE4K 0x00002000
+#define BV_BCH_DEBUG0_KES_DEBUG_MODE4K__4k 0x1
+#define BV_BCH_DEBUG0_KES_DEBUG_MODE4K__2k 0x1
+#define BM_BCH_DEBUG0_KES_DEBUG_KICK 0x00001000
+#define BM_BCH_DEBUG0_KES_STANDALONE 0x00000800
+#define BV_BCH_DEBUG0_KES_STANDALONE__NORMAL 0x0
+#define BV_BCH_DEBUG0_KES_STANDALONE__TEST_MODE 0x1
+#define BM_BCH_DEBUG0_KES_DEBUG_STEP 0x00000400
+#define BM_BCH_DEBUG0_KES_DEBUG_STALL 0x00000200
+#define BV_BCH_DEBUG0_KES_DEBUG_STALL__NORMAL 0x0
+#define BV_BCH_DEBUG0_KES_DEBUG_STALL__WAIT 0x1
+#define BM_BCH_DEBUG0_BM_KES_TEST_BYPASS 0x00000100
+#define BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__NORMAL 0x0
+#define BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__TEST_MODE 0x1
+#define BP_BCH_DEBUG0_RSVD0 6
+#define BM_BCH_DEBUG0_RSVD0 0x000000C0
+#define BF_BCH_DEBUG0_RSVD0(v) \
+ (((v) << 6) & BM_BCH_DEBUG0_RSVD0)
+#define BP_BCH_DEBUG0_DEBUG_REG_SELECT 0
+#define BM_BCH_DEBUG0_DEBUG_REG_SELECT 0x0000003F
+#define BF_BCH_DEBUG0_DEBUG_REG_SELECT(v) \
+ (((v) << 0) & BM_BCH_DEBUG0_DEBUG_REG_SELECT)
+
+/*============================================================================*/
+
+#define HW_BCH_DBGKESREAD (0x00000110)
+
+#define BP_BCH_DBGKESREAD_VALUES 0
+#define BM_BCH_DBGKESREAD_VALUES 0xFFFFFFFF
+#define BF_BCH_DBGKESREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define HW_BCH_DBGCSFEREAD (0x00000120)
+
+#define BP_BCH_DBGCSFEREAD_VALUES 0
+#define BM_BCH_DBGCSFEREAD_VALUES 0xFFFFFFFF
+#define BF_BCH_DBGCSFEREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define HW_BCH_DBGSYNDGENREAD (0x00000130)
+
+#define BP_BCH_DBGSYNDGENREAD_VALUES 0
+#define BM_BCH_DBGSYNDGENREAD_VALUES 0xFFFFFFFF
+#define BF_BCH_DBGSYNDGENREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define HW_BCH_DBGAHBMREAD (0x00000140)
+
+#define BP_BCH_DBGAHBMREAD_VALUES 0
+#define BM_BCH_DBGAHBMREAD_VALUES 0xFFFFFFFF
+#define BF_BCH_DBGAHBMREAD_VALUES(v) (v)
+
+/*============================================================================*/
+
+#define HW_BCH_BLOCKNAME (0x00000150)
+
+#define BP_BCH_BLOCKNAME_NAME 0
+#define BM_BCH_BLOCKNAME_NAME 0xFFFFFFFF
+#define BF_BCH_BLOCKNAME_NAME(v) (v)
+
+/*============================================================================*/
+
+#define HW_BCH_VERSION (0x00000160)
+
+#define BP_BCH_VERSION_MAJOR 24
+#define BM_BCH_VERSION_MAJOR 0xFF000000
+#define BF_BCH_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_BCH_VERSION_MAJOR)
+#define BP_BCH_VERSION_MINOR 16
+#define BM_BCH_VERSION_MINOR 0x00FF0000
+#define BF_BCH_VERSION_MINOR(v) \
+ (((v) << 16) & BM_BCH_VERSION_MINOR)
+#define BP_BCH_VERSION_STEP 0
+#define BM_BCH_VERSION_STEP 0x0000FFFF
+#define BF_BCH_VERSION_STEP(v) \
+ (((v) << 0) & BM_BCH_VERSION_STEP)
+
+/*============================================================================*/
+
+#endif
diff --git a/drivers/mtd/nand/gpmi1/regs-bch.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-bch-regs-v1.h
index 008fdd731e12..692db086de4d 100644
--- a/drivers/mtd/nand/gpmi1/regs-bch.h
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-bch-regs-v1.h
@@ -1,5 +1,5 @@
/*
- * Freescale BCH Register Definitions
+ * Freescale GPMI NFC NAND Flash Driver
*
* Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
@@ -17,15 +17,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * This file is created by xml file. Don't Edit it.
- *
* Xml Revision: 2.5
* Template revision: 26195
*/
-#ifndef __ARCH_ARM___BCH_H
-#define __ARCH_ARM___BCH_H
+#ifndef __GPMI_NFC_BCH_REGS_H
+#define __GPMI_NFC_BCH_REGS_H
+/*============================================================================*/
#define HW_BCH_CTRL (0x00000000)
#define HW_BCH_CTRL_SET (0x00000004)
@@ -69,6 +68,8 @@
#define BM_BCH_CTRL_RSVD0 0x00000002
#define BM_BCH_CTRL_COMPLETE_IRQ 0x00000001
+/*============================================================================*/
+
#define HW_BCH_STATUS0 (0x00000010)
#define BP_BCH_STATUS0_HANDLE 20
@@ -102,6 +103,8 @@
#define BF_BCH_STATUS0_RSVD0(v) \
(((v) << 0) & BM_BCH_STATUS0_RSVD0)
+/*============================================================================*/
+
#define HW_BCH_MODE (0x00000020)
#define BP_BCH_MODE_RSVD 8
@@ -113,24 +116,32 @@
#define BF_BCH_MODE_ERASE_THRESHOLD(v) \
(((v) << 0) & BM_BCH_MODE_ERASE_THRESHOLD)
+/*============================================================================*/
+
#define HW_BCH_ENCODEPTR (0x00000030)
#define BP_BCH_ENCODEPTR_ADDR 0
#define BM_BCH_ENCODEPTR_ADDR 0xFFFFFFFF
#define BF_BCH_ENCODEPTR_ADDR(v) (v)
+/*============================================================================*/
+
#define HW_BCH_DATAPTR (0x00000040)
#define BP_BCH_DATAPTR_ADDR 0
#define BM_BCH_DATAPTR_ADDR 0xFFFFFFFF
#define BF_BCH_DATAPTR_ADDR(v) (v)
+/*============================================================================*/
+
#define HW_BCH_METAPTR (0x00000050)
#define BP_BCH_METAPTR_ADDR 0
#define BM_BCH_METAPTR_ADDR 0xFFFFFFFF
#define BF_BCH_METAPTR_ADDR(v) (v)
+/*============================================================================*/
+
#define HW_BCH_LAYOUTSELECT (0x00000070)
#define BP_BCH_LAYOUTSELECT_CS15_SELECT 30
@@ -198,6 +209,8 @@
#define BF_BCH_LAYOUTSELECT_CS0_SELECT(v) \
(((v) << 0) & BM_BCH_LAYOUTSELECT_CS0_SELECT)
+/*============================================================================*/
+
#define HW_BCH_FLASH0LAYOUT0 (0x00000080)
#define BP_BCH_FLASH0LAYOUT0_NBLOCKS 24
@@ -228,6 +241,8 @@
#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \
(((v) << 0) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+/*============================================================================*/
+
#define HW_BCH_FLASH0LAYOUT1 (0x00000090)
#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16
@@ -254,6 +269,8 @@
#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \
(((v) << 0) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+/*============================================================================*/
+
#define HW_BCH_FLASH1LAYOUT0 (0x000000a0)
#define BP_BCH_FLASH1LAYOUT0_NBLOCKS 24
@@ -284,6 +301,8 @@
#define BF_BCH_FLASH1LAYOUT0_DATA0_SIZE(v) \
(((v) << 0) & BM_BCH_FLASH1LAYOUT0_DATA0_SIZE)
+/*============================================================================*/
+
#define HW_BCH_FLASH1LAYOUT1 (0x000000b0)
#define BP_BCH_FLASH1LAYOUT1_PAGE_SIZE 16
@@ -310,6 +329,8 @@
#define BF_BCH_FLASH1LAYOUT1_DATAN_SIZE(v) \
(((v) << 0) & BM_BCH_FLASH1LAYOUT1_DATAN_SIZE)
+/*============================================================================*/
+
#define HW_BCH_FLASH2LAYOUT0 (0x000000c0)
#define BP_BCH_FLASH2LAYOUT0_NBLOCKS 24
@@ -340,6 +361,8 @@
#define BF_BCH_FLASH2LAYOUT0_DATA0_SIZE(v) \
(((v) << 0) & BM_BCH_FLASH2LAYOUT0_DATA0_SIZE)
+/*============================================================================*/
+
#define HW_BCH_FLASH2LAYOUT1 (0x000000d0)
#define BP_BCH_FLASH2LAYOUT1_PAGE_SIZE 16
@@ -366,6 +389,8 @@
#define BF_BCH_FLASH2LAYOUT1_DATAN_SIZE(v) \
(((v) << 0) & BM_BCH_FLASH2LAYOUT1_DATAN_SIZE)
+/*============================================================================*/
+
#define HW_BCH_FLASH3LAYOUT0 (0x000000e0)
#define BP_BCH_FLASH3LAYOUT0_NBLOCKS 24
@@ -396,6 +421,8 @@
#define BF_BCH_FLASH3LAYOUT0_DATA0_SIZE(v) \
(((v) << 0) & BM_BCH_FLASH3LAYOUT0_DATA0_SIZE)
+/*============================================================================*/
+
#define HW_BCH_FLASH3LAYOUT1 (0x000000f0)
#define BP_BCH_FLASH3LAYOUT1_PAGE_SIZE 16
@@ -422,6 +449,8 @@
#define BF_BCH_FLASH3LAYOUT1_DATAN_SIZE(v) \
(((v) << 0) & BM_BCH_FLASH3LAYOUT1_DATAN_SIZE)
+/*============================================================================*/
+
#define HW_BCH_DEBUG0 (0x00000100)
#define HW_BCH_DEBUG0_SET (0x00000104)
#define HW_BCH_DEBUG0_CLR (0x00000108)
@@ -466,36 +495,48 @@
#define BF_BCH_DEBUG0_DEBUG_REG_SELECT(v) \
(((v) << 0) & BM_BCH_DEBUG0_DEBUG_REG_SELECT)
+/*============================================================================*/
+
#define HW_BCH_DBGKESREAD (0x00000110)
#define BP_BCH_DBGKESREAD_VALUES 0
#define BM_BCH_DBGKESREAD_VALUES 0xFFFFFFFF
#define BF_BCH_DBGKESREAD_VALUES(v) (v)
+/*============================================================================*/
+
#define HW_BCH_DBGCSFEREAD (0x00000120)
#define BP_BCH_DBGCSFEREAD_VALUES 0
#define BM_BCH_DBGCSFEREAD_VALUES 0xFFFFFFFF
#define BF_BCH_DBGCSFEREAD_VALUES(v) (v)
+/*============================================================================*/
+
#define HW_BCH_DBGSYNDGENREAD (0x00000130)
#define BP_BCH_DBGSYNDGENREAD_VALUES 0
#define BM_BCH_DBGSYNDGENREAD_VALUES 0xFFFFFFFF
#define BF_BCH_DBGSYNDGENREAD_VALUES(v) (v)
+/*============================================================================*/
+
#define HW_BCH_DBGAHBMREAD (0x00000140)
#define BP_BCH_DBGAHBMREAD_VALUES 0
#define BM_BCH_DBGAHBMREAD_VALUES 0xFFFFFFFF
#define BF_BCH_DBGAHBMREAD_VALUES(v) (v)
+/*============================================================================*/
+
#define HW_BCH_BLOCKNAME (0x00000150)
#define BP_BCH_BLOCKNAME_NAME 0
#define BM_BCH_BLOCKNAME_NAME 0xFFFFFFFF
#define BF_BCH_BLOCKNAME_NAME(v) (v)
+/*============================================================================*/
+
#define HW_BCH_VERSION (0x00000160)
#define BP_BCH_VERSION_MAJOR 24
@@ -510,4 +551,7 @@
#define BM_BCH_VERSION_STEP 0x0000FFFF
#define BF_BCH_VERSION_STEP(v) \
(((v) << 0) & BM_BCH_VERSION_STEP)
-#endif /* __ARCH_ARM___BCH_H */
+
+/*============================================================================*/
+
+#endif
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-event-reporting.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-event-reporting.c
new file mode 100644
index 000000000000..45574391b0f0
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-event-reporting.c
@@ -0,0 +1,307 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+#if defined(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;
+
+/**
+ * gpmi_nfc_reset_event_trace() - Resets the event trace.
+ */
+void gpmi_nfc_reset_event_trace(void)
+{
+ event_trace.nesting = 0;
+ event_trace.overflow = false;
+ event_trace.next = 0;
+}
+
+/**
+ * gpmi_nfc_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].
+ */
+void gpmi_nfc_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++;
+
+}
+
+/**
+ * gpmi_nfc_start_event_trace() - Starts an event trace.
+ *
+ * @description: A description of the first event.
+ */
+void gpmi_nfc_start_event_trace(char *description)
+{
+
+ ktime_t t0;
+ ktime_t t1;
+
+ if (!report_events)
+ return;
+
+ gpmi_nfc_reset_event_trace();
+
+ t0 = ktime_get();
+ t1 = ktime_get();
+
+ event_trace.overhead = ktime_sub(t1, t0);
+
+ gpmi_nfc_add_event(description, 1);
+
+}
+
+/**
+ * gpmi_nfc_dump_event_trace() - Dumps the event trace.
+ */
+void gpmi_nfc_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. */
+
+ pr_info("\n+----------------\n");
+
+ pr_info("| Overhead : [%d:%d]\n", event_trace.overhead.tv.sec,
+ event_trace.overhead.tv.nsec);
+
+ if (!event_trace.next) {
+ pr_info("| 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);
+ pr_info("| Elapsed Time: [%d:%d]\n", delta.tv.sec, delta.tv.nsec);
+
+ if (event_trace.overflow)
+ pr_info("| 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);
+ }
+
+ }
+
+ pr_info("%s\n", line);
+
+ }
+
+ pr_info("+----------------\n");
+
+}
+
+/**
+ * gpmi_nfc_stop_event_trace() - Stops an event trace.
+ *
+ * @description: A description of the last event.
+ */
+void gpmi_nfc_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 {
+ gpmi_nfc_add_event(description, -1);
+ }
+
+ gpmi_nfc_dump_event_trace();
+ gpmi_nfc_reset_event_trace();
+
+}
+
+#endif /* EVENT_REPORTING */
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-gpmi-regs-v0.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-gpmi-regs-v0.h
new file mode 100644
index 000000000000..2f9fce609a34
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-gpmi-regs-v0.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 __GPMI_NFC_GPMI_REGS_H
+#define __GPMI_NFC_GPMI_REGS_H
+
+/*============================================================================*/
+
+#define HW_GPMI_CTRL0 (0x00000000)
+#define HW_GPMI_CTRL0_SET (0x00000004)
+#define HW_GPMI_CTRL0_CLR (0x00000008)
+#define HW_GPMI_CTRL0_TOG (0x0000000c)
+
+#define BM_GPMI_CTRL0_SFTRST 0x80000000
+#define BV_GPMI_CTRL0_SFTRST__RUN 0x0
+#define BV_GPMI_CTRL0_SFTRST__RESET 0x1
+#define BM_GPMI_CTRL0_CLKGATE 0x40000000
+#define BV_GPMI_CTRL0_CLKGATE__RUN 0x0
+#define BV_GPMI_CTRL0_CLKGATE__NO_CLKS 0x1
+#define BM_GPMI_CTRL0_RUN 0x20000000
+#define BV_GPMI_CTRL0_RUN__IDLE 0x0
+#define BV_GPMI_CTRL0_RUN__BUSY 0x1
+#define BM_GPMI_CTRL0_DEV_IRQ_EN 0x10000000
+#define BM_GPMI_CTRL0_TIMEOUT_IRQ_EN 0x08000000
+#define BM_GPMI_CTRL0_UDMA 0x04000000
+#define BV_GPMI_CTRL0_UDMA__DISABLED 0x0
+#define BV_GPMI_CTRL0_UDMA__ENABLED 0x1
+#define BP_GPMI_CTRL0_COMMAND_MODE 24
+#define BM_GPMI_CTRL0_COMMAND_MODE 0x03000000
+#define BF_GPMI_CTRL0_COMMAND_MODE(v) \
+ (((v) << 24) & BM_GPMI_CTRL0_COMMAND_MODE)
+#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
+#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3
+#define BM_GPMI_CTRL0_WORD_LENGTH 0x00800000
+#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT 0x0
+#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT 0x1
+#define BM_GPMI_CTRL0_LOCK_CS 0x00400000
+#define BV_GPMI_CTRL0_LOCK_CS__DISABLED 0x0
+#define BV_GPMI_CTRL0_LOCK_CS__ENABLED 0x1
+#define BP_GPMI_CTRL0_CS 20
+#define BM_GPMI_CTRL0_CS 0x00300000
+#define BF_GPMI_CTRL0_CS(v) (((v) << 20) & BM_GPMI_CTRL0_CS)
+#define BP_GPMI_CTRL0_ADDRESS 17
+#define BM_GPMI_CTRL0_ADDRESS 0x000E0000
+#define BF_GPMI_CTRL0_ADDRESS(v) (((v) << 17) & BM_GPMI_CTRL0_ADDRESS)
+#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0
+#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1
+#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2
+#define BM_GPMI_CTRL0_ADDRESS_INCREMENT 0x00010000
+#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED 0x0
+#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED 0x1
+#define BP_GPMI_CTRL0_XFER_COUNT 0
+#define BM_GPMI_CTRL0_XFER_COUNT 0x0000FFFF
+#define BF_GPMI_CTRL0_XFER_COUNT(v) \
+ (((v) << 0) & BM_GPMI_CTRL0_XFER_COUNT)
+
+/*============================================================================*/
+
+#define HW_GPMI_COMPARE (0x00000010)
+
+#define BP_GPMI_COMPARE_MASK 16
+#define BM_GPMI_COMPARE_MASK 0xFFFF0000
+#define BF_GPMI_COMPARE_MASK(v) (((v) << 16) & BM_GPMI_COMPARE_MASK)
+#define BP_GPMI_COMPARE_REFERENCE 0
+#define BM_GPMI_COMPARE_REFERENCE 0x0000FFFF
+#define BF_GPMI_COMPARE_REFERENCE(v) \
+ (((v) << 0) & BM_GPMI_COMPARE_REFERENCE)
+
+/*============================================================================*/
+
+#define HW_GPMI_ECCCTRL (0x00000020)
+#define HW_GPMI_ECCCTRL_SET (0x00000024)
+#define HW_GPMI_ECCCTRL_CLR (0x00000028)
+#define HW_GPMI_ECCCTRL_TOG (0x0000002c)
+
+#define BP_GPMI_ECCCTRL_HANDLE 16
+#define BM_GPMI_ECCCTRL_HANDLE 0xFFFF0000
+#define BF_GPMI_ECCCTRL_HANDLE(v) (((v) << 16) & BM_GPMI_ECCCTRL_HANDLE)
+#define BM_GPMI_ECCCTRL_RSVD2 0x00008000
+#define BP_GPMI_ECCCTRL_ECC_CMD 13
+#define BM_GPMI_ECCCTRL_ECC_CMD 0x00006000
+#define BF_GPMI_ECCCTRL_ECC_CMD(v) (((v) << 13) & BM_GPMI_ECCCTRL_ECC_CMD)
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT 0x0
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT 0x1
+#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT 0x2
+#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT 0x3
+#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE 0x0
+#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE 0x1
+#define BM_GPMI_ECCCTRL_ENABLE_ECC 0x00001000
+#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE 0x1
+#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE 0x0
+#define BP_GPMI_ECCCTRL_RSVD1 9
+#define BM_GPMI_ECCCTRL_RSVD1 0x00000E00
+#define BF_GPMI_ECCCTRL_RSVD1(v) (((v) << 9) & BM_GPMI_ECCCTRL_RSVD1)
+#define BP_GPMI_ECCCTRL_BUFFER_MASK 0
+#define BM_GPMI_ECCCTRL_BUFFER_MASK 0x000001FF
+#define BF_GPMI_ECCCTRL_BUFFER_MASK(v) \
+ (((v) << 0) & BM_GPMI_ECCCTRL_BUFFER_MASK)
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__AUXILIARY 0x100
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER7 0x080
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER6 0x040
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER5 0x020
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER4 0x010
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER3 0x008
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER2 0x004
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER1 0x002
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER0 0x001
+
+/*============================================================================*/
+
+#define HW_GPMI_ECCCOUNT (0x00000030)
+
+#define BP_GPMI_ECCCOUNT_RSVD2 16
+#define BM_GPMI_ECCCOUNT_RSVD2 0xFFFF0000
+#define BF_GPMI_ECCCOUNT_RSVD2(v) (((v) << 16) & BM_GPMI_ECCCOUNT_RSVD2)
+#define BP_GPMI_ECCCOUNT_COUNT 0
+#define BM_GPMI_ECCCOUNT_COUNT 0x0000FFFF
+#define BF_GPMI_ECCCOUNT_COUNT(v) (((v) << 0) & BM_GPMI_ECCCOUNT_COUNT)
+
+/*============================================================================*/
+
+#define HW_GPMI_PAYLOAD (0x00000040)
+
+#define BP_GPMI_PAYLOAD_ADDRESS 2
+#define BM_GPMI_PAYLOAD_ADDRESS 0xFFFFFFFC
+#define BF_GPMI_PAYLOAD_ADDRESS(v) (((v) << 2) & BM_GPMI_PAYLOAD_ADDRESS)
+#define BP_GPMI_PAYLOAD_RSVD0 0
+#define BM_GPMI_PAYLOAD_RSVD0 0x00000003
+#define BF_GPMI_PAYLOAD_RSVD0(v) (((v) << 0) & BM_GPMI_PAYLOAD_RSVD0)
+
+/*============================================================================*/
+
+#define HW_GPMI_AUXILIARY (0x00000050)
+
+#define BP_GPMI_AUXILIARY_ADDRESS 2
+#define BM_GPMI_AUXILIARY_ADDRESS 0xFFFFFFFC
+#define BF_GPMI_AUXILIARY_ADDRESS(v) \
+ (((v) << 2) & BM_GPMI_AUXILIARY_ADDRESS)
+#define BP_GPMI_AUXILIARY_RSVD0 0
+#define BM_GPMI_AUXILIARY_RSVD0 0x00000003
+#define BF_GPMI_AUXILIARY_RSVD0(v) (((v) << 0) & BM_GPMI_AUXILIARY_RSVD0)
+
+/*============================================================================*/
+
+#define HW_GPMI_CTRL1 (0x00000060)
+#define HW_GPMI_CTRL1_SET (0x00000064)
+#define HW_GPMI_CTRL1_CLR (0x00000068)
+#define HW_GPMI_CTRL1_TOG (0x0000006c)
+
+#define BP_GPMI_CTRL1_RSVD2 24
+#define BM_GPMI_CTRL1_RSVD2 0xFF000000
+#define BF_GPMI_CTRL1_RSVD2(v) \
+ (((v) << 24) & BM_GPMI_CTRL1_RSVD2)
+#define BM_GPMI_CTRL1_CE3_SEL 0x00800000
+#define BM_GPMI_CTRL1_CE2_SEL 0x00400000
+#define BM_GPMI_CTRL1_CE1_SEL 0x00200000
+#define BM_GPMI_CTRL1_CE0_SEL 0x00100000
+#define BM_GPMI_CTRL1_GANGED_RDYBUSY 0x00080000
+#define BM_GPMI_CTRL1_GPMI_MODE 0x00000001
+#define BP_GPMI_CTRL1_GPMI_MODE 0
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
+#define BM_GPMI_CTRL1_DEV_RESET 0x00000008
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
+#define BM_GPMI_CTRL1_DEV_IRQ 0x00000400
+#define BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
+#define BP_GPMI_CTRL1_RDN_DELAY 12
+#define BM_GPMI_CTRL1_BCH_MODE 0x00040000
+#define BP_GPMI_CTRL1_DLL_ENABLE 17
+#define BM_GPMI_CTRL1_DLL_ENABLE 0x00020000
+#define BP_GPMI_CTRL1_HALF_PERIOD 16
+#define BM_GPMI_CTRL1_HALF_PERIOD 0x00010000
+#define BP_GPMI_CTRL1_RDN_DELAY 12
+#define BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
+#define BF_GPMI_CTRL1_RDN_DELAY(v) \
+ (((v) << 12) & BM_GPMI_CTRL1_RDN_DELAY)
+#define BM_GPMI_CTRL1_DMA2ECC_MODE 0x00000800
+#define BM_GPMI_CTRL1_DEV_IRQ 0x00000400
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
+#define BM_GPMI_CTRL1_BURST_EN 0x00000100
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY3 0x00000080
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY2 0x00000040
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY1 0x00000020
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY0 0x00000010
+#define BM_GPMI_CTRL1_DEV_RESET 0x00000008
+#define BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0
+#define BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
+#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0
+#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1
+#define BM_GPMI_CTRL1_CAMERA_MODE 0x00000002
+#define BM_GPMI_CTRL1_GPMI_MODE 0x00000001
+#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0
+#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1
+
+/*============================================================================*/
+
+#define HW_GPMI_TIMING0 (0x00000070)
+
+#define BP_GPMI_TIMING0_RSVD1 24
+#define BM_GPMI_TIMING0_RSVD1 0xFF000000
+#define BF_GPMI_TIMING0_RSVD1(v) \
+ (((v) << 24) & BM_GPMI_TIMING0_RSVD1)
+#define BP_GPMI_TIMING0_ADDRESS_SETUP 16
+#define BM_GPMI_TIMING0_ADDRESS_SETUP 0x00FF0000
+#define BF_GPMI_TIMING0_ADDRESS_SETUP(v) \
+ (((v) << 16) & BM_GPMI_TIMING0_ADDRESS_SETUP)
+#define BP_GPMI_TIMING0_DATA_HOLD 8
+#define BM_GPMI_TIMING0_DATA_HOLD 0x0000FF00
+#define BF_GPMI_TIMING0_DATA_HOLD(v) \
+ (((v) << 8) & BM_GPMI_TIMING0_DATA_HOLD)
+#define BP_GPMI_TIMING0_DATA_SETUP 0
+#define BM_GPMI_TIMING0_DATA_SETUP 0x000000FF
+#define BF_GPMI_TIMING0_DATA_SETUP(v) \
+ (((v) << 0) & BM_GPMI_TIMING0_DATA_SETUP)
+
+/*============================================================================*/
+
+#define HW_GPMI_TIMING1 (0x00000080)
+
+#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 16
+#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 0xFFFF0000
+#define BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(v) \
+ (((v) << 16) & BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT)
+#define BP_GPMI_TIMING1_RSVD1 0
+#define BM_GPMI_TIMING1_RSVD1 0x0000FFFF
+#define BF_GPMI_TIMING1_RSVD1(v) \
+ (((v) << 0) & BM_GPMI_TIMING1_RSVD1)
+
+/*============================================================================*/
+
+#define HW_GPMI_TIMING2 (0x00000090)
+
+#define BP_GPMI_TIMING2_UDMA_TRP 24
+#define BM_GPMI_TIMING2_UDMA_TRP 0xFF000000
+#define BF_GPMI_TIMING2_UDMA_TRP(v) \
+ (((v) << 24) & BM_GPMI_TIMING2_UDMA_TRP)
+#define BP_GPMI_TIMING2_UDMA_ENV 16
+#define BM_GPMI_TIMING2_UDMA_ENV 0x00FF0000
+#define BF_GPMI_TIMING2_UDMA_ENV(v) \
+ (((v) << 16) & BM_GPMI_TIMING2_UDMA_ENV)
+#define BP_GPMI_TIMING2_UDMA_HOLD 8
+#define BM_GPMI_TIMING2_UDMA_HOLD 0x0000FF00
+#define BF_GPMI_TIMING2_UDMA_HOLD(v) \
+ (((v) << 8) & BM_GPMI_TIMING2_UDMA_HOLD)
+#define BP_GPMI_TIMING2_UDMA_SETUP 0
+#define BM_GPMI_TIMING2_UDMA_SETUP 0x000000FF
+#define BF_GPMI_TIMING2_UDMA_SETUP(v) \
+ (((v) << 0) & BM_GPMI_TIMING2_UDMA_SETUP)
+
+/*============================================================================*/
+
+#define HW_GPMI_DATA (0x000000a0)
+
+#define BP_GPMI_DATA_DATA 0
+#define BM_GPMI_DATA_DATA 0xFFFFFFFF
+#define BF_GPMI_DATA_DATA(v) (v)
+
+/*============================================================================*/
+
+#define HW_GPMI_STAT (0x000000b0)
+
+#define BM_GPMI_STAT_PRESENT 0x80000000
+#define BV_GPMI_STAT_PRESENT__UNAVAILABLE 0x0
+#define BV_GPMI_STAT_PRESENT__AVAILABLE 0x1
+#define BP_GPMI_STAT_RSVD1 12
+#define BM_GPMI_STAT_RSVD1 0x7FFFF000
+#define BF_GPMI_STAT_RSVD1(v) \
+ (((v) << 12) & BM_GPMI_STAT_RSVD1)
+#define BP_GPMI_STAT_RDY_TIMEOUT 8
+#define BM_GPMI_STAT_RDY_TIMEOUT 0x00000F00
+#define BF_GPMI_STAT_RDY_TIMEOUT(v) \
+ (((v) << 8) & BM_GPMI_STAT_RDY_TIMEOUT)
+#define BM_GPMI_STAT_ATA_IRQ 0x00000080
+#define BM_GPMI_STAT_INVALID_BUFFER_MASK 0x00000040
+#define BM_GPMI_STAT_FIFO_EMPTY 0x00000020
+#define BV_GPMI_STAT_FIFO_EMPTY__NOT_EMPTY 0x0
+#define BV_GPMI_STAT_FIFO_EMPTY__EMPTY 0x1
+#define BM_GPMI_STAT_FIFO_FULL 0x00000010
+#define BV_GPMI_STAT_FIFO_FULL__NOT_FULL 0x0
+#define BV_GPMI_STAT_FIFO_FULL__FULL 0x1
+#define BM_GPMI_STAT_DEV3_ERROR 0x00000008
+#define BM_GPMI_STAT_DEV2_ERROR 0x00000004
+#define BM_GPMI_STAT_DEV1_ERROR 0x00000002
+#define BM_GPMI_STAT_DEERROR 0x00000001
+
+/*============================================================================*/
+
+#define HW_GPMI_DEBUG (0x000000c0)
+
+#define BM_GPMI_DEBUG_READY3 0x80000000
+#define BM_GPMI_DEBUG_READY2 0x40000000
+#define BM_GPMI_DEBUG_READY1 0x20000000
+#define BM_GPMI_DEBUG_READY0 0x10000000
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END3 0x08000000
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END2 0x04000000
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END1 0x02000000
+#define BM_GPMI_DEBUG_WAIT_FOR_READY_END0 0x01000000
+#define BM_GPMI_DEBUG_SENSE3 0x00800000
+#define BM_GPMI_DEBUG_SENSE2 0x00400000
+#define BM_GPMI_DEBUG_SENSE1 0x00200000
+#define BM_GPMI_DEBUG_SENSE0 0x00100000
+#define BM_GPMI_DEBUG_DMAREQ3 0x00080000
+#define BM_GPMI_DEBUG_DMAREQ2 0x00040000
+#define BM_GPMI_DEBUG_DMAREQ1 0x00020000
+#define BM_GPMI_DEBUG_DMAREQ0 0x00010000
+#define BP_GPMI_DEBUG_CMD_END 12
+#define BM_GPMI_DEBUG_CMD_END 0x0000F000
+#define BF_GPMI_DEBUG_CMD_END(v) \
+ (((v) << 12) & BM_GPMI_DEBUG_CMD_END)
+#define BP_GPMI_DEBUG_UDMA_STATE 8
+#define BM_GPMI_DEBUG_UDMA_STATE 0x00000F00
+#define BF_GPMI_DEBUG_UDMA_STATE(v) \
+ (((v) << 8) & BM_GPMI_DEBUG_UDMA_STATE)
+#define BM_GPMI_DEBUG_BUSY 0x00000080
+#define BV_GPMI_DEBUG_BUSY__DISABLED 0x0
+#define BV_GPMI_DEBUG_BUSY__ENABLED 0x1
+#define BP_GPMI_DEBUG_PIN_STATE 4
+#define BM_GPMI_DEBUG_PIN_STATE 0x00000070
+#define BF_GPMI_DEBUG_PIN_STATE(v) \
+ (((v) << 4) & BM_GPMI_DEBUG_PIN_STATE)
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_IDLE 0x0
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_BYTCNT 0x1
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_ADDR 0x2
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_STALL 0x3
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_STROBE 0x4
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_ATARDY 0x5
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_DHOLD 0x6
+#define BV_GPMI_DEBUG_PIN_STATE__PSM_DONE 0x7
+#define BP_GPMI_DEBUG_MAIN_STATE 0
+#define BM_GPMI_DEBUG_MAIN_STATE 0x0000000F
+#define BF_GPMI_DEBUG_MAIN_STATE(v) \
+ (((v) << 0) & BM_GPMI_DEBUG_MAIN_STATE)
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_IDLE 0x0
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_BYTCNT 0x1
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFE 0x2
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFR 0x3
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DMAREQ 0x4
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DMAACK 0x5
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFF 0x6
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_LDFIFO 0x7
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_LDDMAR 0x8
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_RDCMP 0x9
+#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DONE 0xA
+
+/*============================================================================*/
+
+#define HW_GPMI_VERSION (0x000000d0)
+
+#define BP_GPMI_VERSION_MAJOR 24
+#define BM_GPMI_VERSION_MAJOR 0xFF000000
+#define BF_GPMI_VERSION_MAJOR(v) (((v) << 24) & BM_GPMI_VERSION_MAJOR)
+#define BP_GPMI_VERSION_MINOR 16
+#define BM_GPMI_VERSION_MINOR 0x00FF0000
+#define BF_GPMI_VERSION_MINOR(v) (((v) << 16) & BM_GPMI_VERSION_MINOR)
+#define BP_GPMI_VERSION_STEP 0
+#define BM_GPMI_VERSION_STEP 0x0000FFFF
+#define BF_GPMI_VERSION_STEP(v) (((v) << 0) & BM_GPMI_VERSION_STEP)
+
+/*============================================================================*/
+
+#define HW_GPMI_DEBUG2 (0x000000e0)
+
+#define BP_GPMI_DEBUG2_RSVD1 16
+#define BM_GPMI_DEBUG2_RSVD1 0xFFFF0000
+#define BF_GPMI_DEBUG2_RSVD1(v) (((v) << 16) & BM_GPMI_DEBUG2_RSVD1)
+#define BP_GPMI_DEBUG2_SYND2GPMI_BE 12
+#define BM_GPMI_DEBUG2_SYND2GPMI_BE 0x0000F000
+#define BF_GPMI_DEBUG2_SYND2GPMI_BE(v) \
+ (((v) << 12) & BM_GPMI_DEBUG2_SYND2GPMI_BE)
+#define BM_GPMI_DEBUG2_GPMI2SYND_VALID 0x00000800
+#define BM_GPMI_DEBUG2_GPMI2SYND_READY 0x00000400
+#define BM_GPMI_DEBUG2_SYND2GPMI_VALID 0x00000200
+#define BM_GPMI_DEBUG2_SYND2GPMI_READY 0x00000100
+#define BM_GPMI_DEBUG2_VIEW_DELAYED_RDN 0x00000080
+#define BM_GPMI_DEBUG2_UPDATE_WINDOW 0x00000040
+#define BP_GPMI_DEBUG2_RDN_TAP 0
+#define BM_GPMI_DEBUG2_RDN_TAP 0x0000003F
+#define BF_GPMI_DEBUG2_RDN_TAP(v) (((v) << 0) & BM_GPMI_DEBUG2_RDN_TAP)
+
+/*============================================================================*/
+
+#define HW_GPMI_DEBUG3 (0x000000f0)
+
+#define BP_GPMI_DEBUG3_APB_WORD_CNTR 16
+#define BM_GPMI_DEBUG3_APB_WORD_CNTR 0xFFFF0000
+#define BF_GPMI_DEBUG3_APB_WORD_CNTR(v) \
+ (((v) << 16) & BM_GPMI_DEBUG3_APB_WORD_CNTR)
+#define BP_GPMI_DEBUG3_DEV_WORD_CNTR 0
+#define BM_GPMI_DEBUG3_DEV_WORD_CNTR 0x0000FFFF
+#define BF_GPMI_DEBUG3_DEV_WORD_CNTR(v) \
+ (((v) << 0) & BM_GPMI_DEBUG3_DEV_WORD_CNTR)
+
+/*============================================================================*/
+#endif
diff --git a/drivers/mtd/nand/gpmi1/regs-gpmi.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-gpmi-regs-v1.h
index 950f336f0965..8c1bc7b2fb7a 100644
--- a/drivers/mtd/nand/gpmi1/regs-gpmi.h
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-gpmi-regs-v1.h
@@ -1,5 +1,5 @@
/*
- * Freescale GPMI Register Definitions
+ * Freescale GPMI NFC NAND Flash Driver
*
* Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
@@ -17,15 +17,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * This file is created by xml file. Don't Edit it.
- *
* Xml Revision: 2.2
* Template revision: 26195
*/
-#ifndef __ARCH_ARM___GPMI_H
-#define __ARCH_ARM___GPMI_H
+#ifndef __GPMI_NFC_GPMI_REGS_H
+#define __GPMI_NFC_GPMI_REGS_H
+/*============================================================================*/
#define HW_GPMI_CTRL0 (0x00000000)
#define HW_GPMI_CTRL0_SET (0x00000004)
@@ -78,6 +77,8 @@
#define BF_GPMI_CTRL0_XFER_COUNT(v) \
(((v) << 0) & BM_GPMI_CTRL0_XFER_COUNT)
+/*============================================================================*/
+
#define HW_GPMI_COMPARE (0x00000010)
#define BP_GPMI_COMPARE_MASK 16
@@ -89,6 +90,8 @@
#define BF_GPMI_COMPARE_REFERENCE(v) \
(((v) << 0) & BM_GPMI_COMPARE_REFERENCE)
+/*============================================================================*/
+
#define HW_GPMI_ECCCTRL (0x00000020)
#define HW_GPMI_ECCCTRL_SET (0x00000024)
#define HW_GPMI_ECCCTRL_CLR (0x00000028)
@@ -121,6 +124,8 @@
#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100
#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF
+/*============================================================================*/
+
#define HW_GPMI_ECCCOUNT (0x00000030)
#define BP_GPMI_ECCCOUNT_RSVD2 16
@@ -132,6 +137,8 @@
#define BF_GPMI_ECCCOUNT_COUNT(v) \
(((v) << 0) & BM_GPMI_ECCCOUNT_COUNT)
+/*============================================================================*/
+
#define HW_GPMI_PAYLOAD (0x00000040)
#define BP_GPMI_PAYLOAD_ADDRESS 2
@@ -143,6 +150,8 @@
#define BF_GPMI_PAYLOAD_RSVD0(v) \
(((v) << 0) & BM_GPMI_PAYLOAD_RSVD0)
+/*============================================================================*/
+
#define HW_GPMI_AUXILIARY (0x00000050)
#define BP_GPMI_AUXILIARY_ADDRESS 2
@@ -154,6 +163,8 @@
#define BF_GPMI_AUXILIARY_RSVD0(v) \
(((v) << 0) & BM_GPMI_AUXILIARY_RSVD0)
+/*============================================================================*/
+
#define HW_GPMI_CTRL1 (0x00000060)
#define HW_GPMI_CTRL1_SET (0x00000064)
#define HW_GPMI_CTRL1_CLR (0x00000068)
@@ -199,6 +210,8 @@
#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0
#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1
+/*============================================================================*/
+
#define HW_GPMI_TIMING0 (0x00000070)
#define BP_GPMI_TIMING0_RSVD1 24
@@ -218,6 +231,8 @@
#define BF_GPMI_TIMING0_DATA_SETUP(v) \
(((v) << 0) & BM_GPMI_TIMING0_DATA_SETUP)
+/*============================================================================*/
+
#define HW_GPMI_TIMING1 (0x00000080)
#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 16
@@ -229,6 +244,8 @@
#define BF_GPMI_TIMING1_RSVD1(v) \
(((v) << 0) & BM_GPMI_TIMING1_RSVD1)
+/*============================================================================*/
+
#define HW_GPMI_TIMING2 (0x00000090)
#define BP_GPMI_TIMING2_UDMA_TRP 24
@@ -248,6 +265,8 @@
#define BF_GPMI_TIMING2_UDMA_SETUP(v) \
(((v) << 0) & BM_GPMI_TIMING2_UDMA_SETUP)
+/*============================================================================*/
+
#define HW_GPMI_DATA (0x000000a0)
#define BP_GPMI_DATA_DATA 0
@@ -270,7 +289,7 @@
#define BM_GPMI_STAT_DEV4_ERROR 0x00001000
#define BM_GPMI_STAT_DEV3_ERROR 0x00000800
#define BM_GPMI_STAT_DEV2_ERROR 0x00000400
-#define BM_GPMI_STAT_DEV1_ERROR 0x00000200
+#define BM_GPMI_STAT_DEERROR 0x00000200
#define BM_GPMI_STAT_DEV0_ERROR 0x00000100
#define BP_GPMI_STAT_RSVD1 5
#define BM_GPMI_STAT_RSVD1 0x000000E0
@@ -288,6 +307,8 @@
#define BV_GPMI_STAT_PRESENT__UNAVAILABLE 0x0
#define BV_GPMI_STAT_PRESENT__AVAILABLE 0x1
+/*============================================================================*/
+
#define HW_GPMI_DEBUG (0x000000c0)
#define BP_GPMI_DEBUG_WAIT_FOR_READY_END 24
@@ -307,6 +328,8 @@
#define BF_GPMI_DEBUG_CMD_END(v) \
(((v) << 0) & BM_GPMI_DEBUG_CMD_END)
+/*============================================================================*/
+
#define HW_GPMI_VERSION (0x000000d0)
#define BP_GPMI_VERSION_MAJOR 24
@@ -322,6 +345,8 @@
#define BF_GPMI_VERSION_STEP(v) \
(((v) << 0) & BM_GPMI_VERSION_STEP)
+/*============================================================================*/
+
#define HW_GPMI_DEBUG2 (0x000000e0)
#define BP_GPMI_DEBUG2_RSVD1 28
@@ -377,6 +402,8 @@
#define BF_GPMI_DEBUG2_RDN_TAP(v) \
(((v) << 0) & BM_GPMI_DEBUG2_RDN_TAP)
+/*============================================================================*/
+
#define HW_GPMI_DEBUG3 (0x000000f0)
#define BP_GPMI_DEBUG3_APB_WORD_CNTR 16
@@ -387,4 +414,7 @@
#define BM_GPMI_DEBUG3_DEV_WORD_CNTR 0x0000FFFF
#define BF_GPMI_DEBUG3_DEV_WORD_CNTR(v) \
(((v) << 0) & BM_GPMI_DEBUG3_DEV_WORD_CNTR)
-#endif /* __ARCH_ARM___GPMI_H */
+
+/*============================================================================*/
+
+#endif
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-common.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-common.c
new file mode 100644
index 000000000000..c210203adfca
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-common.c
@@ -0,0 +1,522 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+/**
+ * gpmi_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.
+ */
+irqreturn_t gpmi_nfc_bch_isr(int irq, void *cookie)
+{
+ struct gpmi_nfc_data *this = cookie;
+ struct nfc_hal *nfc = this->nfc;
+
+ gpmi_nfc_add_event("> gpmi_nfc_bch_isr", 1);
+
+ /* Clear the interrupt. */
+
+ nfc->clear_bch(this);
+
+ /* Release the base level. */
+
+ complete(&(nfc->bch_done));
+
+ /* Return success. */
+
+ gpmi_nfc_add_event("< gpmi_nfc_bch_isr", -1);
+
+ return IRQ_HANDLED;
+
+}
+
+/**
+ * gpmi_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.
+ */
+irqreturn_t gpmi_nfc_dma_isr(int irq, void *cookie)
+{
+ struct gpmi_nfc_data *this = cookie;
+ struct nfc_hal *nfc = this->nfc;
+
+ gpmi_nfc_add_event("> gpmi_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. */
+
+ gpmi_nfc_add_event("< gpmi_nfc_dma_isr", -1);
+
+ return IRQ_HANDLED;
+
+}
+
+/**
+ * gpmi_nfc_dma_init() - Initializes DMA.
+ *
+ * @this: Per-device data.
+ */
+int gpmi_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;
+
+}
+
+/**
+ * gpmi_nfc_dma_exit() - Shuts down DMA.
+ *
+ * @this: Per-device data.
+ */
+void gpmi_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]);
+
+}
+
+/**
+ * gpmi_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.
+ */
+int gpmi_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;
+
+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
+
+/**
+ * gpmi_nfc_dma_go - Run a DMA channel.
+ *
+ * @this: Per-device data structure.
+ * @dma_channel: The DMA channel we're going to use.
+ */
+int gpmi_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);
+
+ gpmi_nfc_add_event("> gpmi_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);
+ gpmi_nfc_add_event("...DMA timed out", 0);
+ } else
+ gpmi_nfc_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. */
+
+ gpmi_nfc_add_event("< gpmi_nfc_dma_go", -1);
+
+ return error;
+
+}
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v0.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v0.c
new file mode 100644
index 000000000000..fddccafdf17a
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v0.c
@@ -0,0 +1,795 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+#include "gpmi-nfc-gpmi-regs-v0.h"
+#include "gpmi-nfc-bch-regs-v0.h"
+
+/**
+ * init() - Initializes the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static int init(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+ int error;
+
+ /* Initialize DMA. */
+
+ error = gpmi_nfc_dma_init(this);
+
+ if (error)
+ return error;
+
+ /* Enable the clock. It will stay on until the end of set_geometry(). */
+
+ clk_enable(resources->clock);
+
+ /* Reset the GPMI block. */
+
+ mxs_reset_block(resources->gpmi_regs + HW_GPMI_CTRL0, true);
+
+ /* Choose NAND mode. */
+ __raw_writel(BM_GPMI_CTRL1_GPMI_MODE,
+ resources->gpmi_regs + HW_GPMI_CTRL1_CLR);
+
+ /* Set the IRQ polarity. */
+ __raw_writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* Disable write protection. */
+ __raw_writel(BM_GPMI_CTRL1_DEV_RESET,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* Select BCH ECC. */
+ __raw_writel(BM_GPMI_CTRL1_BCH_MODE,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* Disable the clock. */
+
+ clk_disable(resources->clock);
+
+ /* If control arrives here, all is well. */
+
+ return 0;
+
+}
+
+/**
+ * set_geometry() - Configures the NFC geometry.
+ *
+ * @this: Per-device data.
+ */
+static int 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 (gpmi_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;
+
+ /* Enable the clock. */
+
+ clk_enable(resources->clock);
+
+ /*
+ * 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(
+ BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) |
+ BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) |
+ BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) |
+ BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size) ,
+ resources->bch_regs + HW_BCH_FLASH0LAYOUT0);
+
+ __raw_writel(
+ BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) |
+ BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) |
+ BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size) ,
+ resources->bch_regs + HW_BCH_FLASH0LAYOUT1);
+
+ /* Set *all* chip selects to use layout 0. */
+
+ __raw_writel(0, resources->bch_regs + HW_BCH_LAYOUTSELECT);
+
+ /* Enable interrupts. */
+
+ __raw_writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
+ resources->bch_regs + HW_BCH_CTRL_SET);
+
+ /* Disable the clock. */
+
+ clk_disable(resources->clock);
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * set_set_timing() - Configures the NFC timing.
+ *
+ * @this: Per-device data.
+ * @timing: The timing of interest.
+ */
+static int set_timing(struct gpmi_nfc_data *this,
+ const struct gpmi_nfc_timing *timing)
+{
+ struct nfc_hal *nfc = this->nfc;
+
+ /* Accept the new timing. */
+
+ nfc->timing = *timing;
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * exit() - Shuts down the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static void exit(struct gpmi_nfc_data *this)
+{
+ gpmi_nfc_dma_exit(this);
+}
+
+/**
+ * begin() - Begin NFC I/O.
+ *
+ * @this: Per-device data.
+ */
+static void begin(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+
+ /* Enable the clock. */
+
+ clk_enable(resources->clock);
+
+}
+
+/**
+ * end() - End NFC I/O.
+ *
+ * @this: Per-device data.
+ */
+static void end(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+
+ /* Disable the clock. */
+
+ clk_disable(resources->clock);
+
+}
+
+/**
+ * clear_bch() - Clears a BCH interrupt.
+ *
+ * @this: Per-device data.
+ */
+static void clear_bch(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+
+ __raw_writel(BM_BCH_CTRL_COMPLETE_IRQ,
+ resources->bch_regs + HW_BCH_CTRL_CLR);
+
+}
+
+/**
+ * is_ready() - Returns the ready/busy status of the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ */
+static int is_ready(struct gpmi_nfc_data *this, unsigned chip)
+{
+ struct resources *resources = &this->resources;
+ uint32_t mask;
+ uint32_t register_image;
+
+ /* Extract and return the status. */
+
+ mask = BM_GPMI_DEBUG_READY0 << chip;
+
+ register_image = __raw_readl(resources->gpmi_regs + HW_GPMI_DEBUG);
+
+ return !!(register_image & mask);
+
+}
+
+/**
+ * send_command() - Sends a command and associated addresses.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that contains the command bytes.
+ * @length: The number of bytes in the buffer.
+ */
+static int send_command(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BM_GPMI_CTRL0_ADDRESS_INCREMENT |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = gpmi_nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * send_data() - Sends data to the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that contains the data.
+ * @length: The number of bytes in the buffer.
+ */
+static int send_data(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = gpmi_nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * read_data() - Receives data from the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that will receive the data.
+ * @length: The number of bytes to read.
+ */
+static int read_data(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ 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 = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = 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] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_LOCK_CS |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = gpmi_nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * send_page() - Sends a page, using ECC.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @payload: The physical address of the payload buffer.
+ * @auxiliary: The physical address of the auxiliary buffer.
+ */
+static int send_page(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+ ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
+ buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+
+ (*d)->cmd.pio_words[2] =
+ BM_GPMI_ECCCTRL_ENABLE_ECC |
+ BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+
+ (*d)->cmd.pio_words[3] = 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 = gpmi_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;
+
+}
+
+/**
+ * read_page() - Reads a page, using ECC.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @payload: The physical address of the payload buffer.
+ * @auxiliary: The physical address of the auxiliary buffer.
+ */
+static int read_page(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = 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] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_LOCK_CS |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Enable the BCH block and read. */
+
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+ ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
+ buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(nfc_geo->page_size_in_bytes) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] =
+ BM_GPMI_ECCCTRL_ENABLE_ECC |
+ BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+ (*d)->cmd.pio_words[3] = 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 = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = 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] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_LOCK_CS |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ 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 = gpmi_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;
+
+}
+
+/* This structure represents the NFC HAL for this version of the hardware. */
+
+struct nfc_hal gpmi_nfc_hal_v0 = {
+ .version = 0,
+ .description = "4-chip GPMI and BCH",
+ .max_chip_count = 4,
+ .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
+ BP_GPMI_TIMING0_DATA_SETUP),
+ .max_data_sample_delay_cycles = (BM_GPMI_CTRL1_RDN_DELAY >>
+ BP_GPMI_CTRL1_RDN_DELAY),
+ .max_dll_clock_period_in_ns = 32,
+ .init = init,
+ .set_geometry = set_geometry,
+ .set_timing = set_timing,
+ .exit = exit,
+ .begin = begin,
+ .end = end,
+ .clear_bch = clear_bch,
+ .is_ready = is_ready,
+ .send_command = send_command,
+ .send_data = send_data,
+ .read_data = read_data,
+ .send_page = send_page,
+ .read_page = read_page,
+};
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v1.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v1.c
new file mode 100644
index 000000000000..545fbbc9ba4d
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-hal-v1.c
@@ -0,0 +1,797 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+#include "gpmi-nfc-gpmi-regs-v1.h"
+#include "gpmi-nfc-bch-regs-v1.h"
+
+/**
+ * init() - Initializes the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static int init(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+ int error;
+
+ /* Initialize DMA. */
+
+ error = gpmi_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 + HW_GPMI_CTRL0, true);
+
+ /* Choose NAND mode. */
+ __raw_writel(BM_GPMI_CTRL1_GPMI_MODE,
+ resources->gpmi_regs + HW_GPMI_CTRL1_CLR);
+
+ /* Set the IRQ polarity. */
+ __raw_writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* Disable write protection. */
+ __raw_writel(BM_GPMI_CTRL1_DEV_RESET,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* Select BCH ECC. */
+ __raw_writel(BM_GPMI_CTRL1_BCH_MODE,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* Disable the clock. */
+
+ clk_disable(resources->clock);
+
+ /* If control arrives here, all is well. */
+
+ return 0;
+
+}
+
+/**
+ * set_geometry() - Configures the NFC geometry.
+ *
+ * @this: Per-device data.
+ */
+static int 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 (gpmi_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;
+
+ /* Enable the clock. */
+
+ clk_enable(resources->clock);
+
+ /*
+ * 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(
+ BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) |
+ BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) |
+ BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) |
+ BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size) ,
+ resources->bch_regs + HW_BCH_FLASH0LAYOUT0);
+
+ __raw_writel(
+ BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) |
+ BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) |
+ BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size) ,
+ resources->bch_regs + HW_BCH_FLASH0LAYOUT1);
+
+ /* Set *all* chip selects to use layout 0. */
+
+ __raw_writel(0, resources->bch_regs + HW_BCH_LAYOUTSELECT);
+
+ /* Enable interrupts. */
+
+ __raw_writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
+ resources->bch_regs + HW_BCH_CTRL_SET);
+
+ /* Disable the clock. */
+
+ clk_disable(resources->clock);
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * set_set_timing() - Configures the NFC timing.
+ *
+ * @this: Per-device data.
+ * @timing: The timing of interest.
+ */
+static int set_timing(struct gpmi_nfc_data *this,
+ const struct gpmi_nfc_timing *timing)
+{
+ struct nfc_hal *nfc = this->nfc;
+
+ /* Accept the new timing. */
+
+ nfc->timing = *timing;
+
+ /* Return success. */
+
+ return 0;
+
+}
+
+/**
+ * exit() - Shuts down the NFC hardware.
+ *
+ * @this: Per-device data.
+ */
+static void exit(struct gpmi_nfc_data *this)
+{
+ gpmi_nfc_dma_exit(this);
+}
+
+/**
+ * begin() - Begin NFC I/O.
+ *
+ * @this: Per-device data.
+ */
+static void begin(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+
+ /* Enable the clock. */
+
+ clk_enable(resources->clock);
+
+}
+
+/**
+ * end() - End NFC I/O.
+ *
+ * @this: Per-device data.
+ */
+static void end(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+
+ /* Disable the clock. */
+
+ clk_disable(resources->clock);
+
+}
+
+/**
+ * clear_bch() - Clears a BCH interrupt.
+ *
+ * @this: Per-device data.
+ */
+static void clear_bch(struct gpmi_nfc_data *this)
+{
+ struct resources *resources = &this->resources;
+
+ __raw_writel(BM_BCH_CTRL_COMPLETE_IRQ,
+ resources->bch_regs + HW_BCH_CTRL_CLR);
+
+}
+
+/**
+ * is_ready() - Returns the ready/busy status of the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ */
+static int is_ready(struct gpmi_nfc_data *this, unsigned chip)
+{
+ struct resources *resources = &this->resources;
+ uint32_t mask;
+ uint32_t register_image;
+
+ /* Extract and return the status. */
+
+ mask = BF_GPMI_STAT_READY_BUSY(1 << chip);
+
+ register_image = __raw_readl(resources->gpmi_regs + HW_GPMI_STAT);
+
+ return !!(register_image & mask);
+
+}
+
+/**
+ * send_command() - Sends a command and associated addresses.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that contains the command bytes.
+ * @length: The number of bytes in the buffer.
+ */
+static int send_command(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BM_GPMI_CTRL0_ADDRESS_INCREMENT |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = gpmi_nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * send_data() - Sends data to the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that contains the data.
+ * @length: The number of bytes in the buffer.
+ */
+static int send_data(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = gpmi_nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * read_data() - Receives data from the given chip.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @buffer: The physical address of a buffer that will receive the data.
+ * @length: The number of bytes to read.
+ */
+static int read_data(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(length) ;
+
+ 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 = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = 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] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_LOCK_CS |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] = 0;
+ (*d)->cmd.pio_words[3] = 0;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Go! */
+
+ error = gpmi_nfc_dma_go(this, dma_channel);
+
+ if (error)
+ dev_err(dev, "[%s] DMA error\n", __func__);
+
+ /* Return success. */
+
+ return error;
+
+}
+
+/**
+ * send_page() - Sends a page, using ECC.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @payload: The physical address of the payload buffer.
+ * @auxiliary: The physical address of the auxiliary buffer.
+ */
+static int send_page(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+ ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__ENCODE;
+ buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+
+ (*d)->cmd.pio_words[2] =
+ BM_GPMI_ECCCTRL_ENABLE_ECC |
+ BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+
+ (*d)->cmd.pio_words[3] = 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 = gpmi_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;
+
+}
+
+/**
+ * read_page() - Reads a page, using ECC.
+ *
+ * @this: Per-device data.
+ * @chip: The chip of interest.
+ * @payload: The physical address of the payload buffer.
+ * @auxiliary: The physical address of the auxiliary buffer.
+ */
+static int read_page(struct 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 = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = 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] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_LOCK_CS |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(0) ;
+
+ mxs_dma_desc_append(dma_channel, (*d));
+ d++;
+
+ /* Enable the BCH block and read. */
+
+ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
+ address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+ ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__DECODE;
+ buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ 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] =
+ BM_GPMI_CTRL0_LOCK_CS |
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ BF_GPMI_CTRL0_XFER_COUNT(nfc_geo->page_size_in_bytes) ;
+
+ (*d)->cmd.pio_words[1] = 0;
+ (*d)->cmd.pio_words[2] =
+ BM_GPMI_ECCCTRL_ENABLE_ECC |
+ BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) |
+ BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask) ;
+ (*d)->cmd.pio_words[3] = 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 = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+ address = 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] =
+ BF_GPMI_CTRL0_COMMAND_MODE(command_mode) |
+ BM_GPMI_CTRL0_LOCK_CS |
+ BM_GPMI_CTRL0_WORD_LENGTH |
+ BF_GPMI_CTRL0_CS(chip) |
+ BF_GPMI_CTRL0_ADDRESS(address) |
+ 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 = gpmi_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;
+
+}
+
+/* This structure represents the NFC HAL for this version of the hardware. */
+
+struct nfc_hal gpmi_nfc_hal_v1 = {
+ .version = 1,
+ .description = "8-chip GPMI and BCH",
+ .max_chip_count = 8,
+ .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
+ BP_GPMI_TIMING0_DATA_SETUP),
+ .max_data_sample_delay_cycles = (BM_GPMI_CTRL1_RDN_DELAY >>
+ BP_GPMI_CTRL1_RDN_DELAY),
+ .max_dll_clock_period_in_ns = 32,
+ .init = init,
+ .set_geometry = set_geometry,
+ .set_timing = set_timing,
+ .exit = exit,
+ .begin = begin,
+ .end = end,
+ .clear_bch = clear_bch,
+ .is_ready = is_ready,
+ .send_command = send_command,
+ .send_data = send_data,
+ .read_data = read_data,
+ .send_page = send_page,
+ .read_page = read_page,
+};
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-main.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-main.c
new file mode 100644
index 000000000000..d88215246bab
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-main.c
@@ -0,0 +1,1379 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+/*
+ * This structure contains the "safe" GPMI timing that should succeed with any
+ * NAND Flash device (although, with less-than-optimal performance).
+ */
+
+static struct gpmi_nfc_timing safe_timing = {
+ .data_setup_in_ns = 80,
+ .data_hold_in_ns = 60,
+ .address_setup_in_ns = 25,
+ .gpmi_sample_delay_in_ns = 6,
+ .tREA_in_ns = -1,
+ .tRLOH_in_ns = -1,
+ .tRHOH_in_ns = -1,
+};
+
+/*
+ * 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.
+ */
+
+static struct nfc_hal *(nfc_hals[]) = {
+ &gpmi_nfc_hal_v0,
+ &gpmi_nfc_hal_v1,
+};
+
+/*
+ * 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.
+ */
+
+static struct boot_rom_helper *(boot_rom_helpers[]) = {
+ &gpmi_nfc_boot_rom_helper_v0,
+ &gpmi_nfc_boot_rom_helper_v1,
+};
+
+/**
+ * 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;
+ struct clk *parent_clock;
+ unsigned long parent_clock_rate_in_hz;
+ unsigned long clock_rate_in_hz;
+ int clock_use_count;
+
+ 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);
+ clock_use_count = clk_get_usecount(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"
+ "Clock Use Count : %u\n"
+ "Data Setup in ns : %d\n"
+ "Data Hold in ns : %d\n"
+ "Address Setup in ns : %d\n"
+ "Sample Delay in ns : %d\n"
+ "tREA in ns : %d\n"
+ "tRLOH in ns : %d\n"
+ "tRHOH in ns : %d\n"
+ ,
+ nfc->version,
+ nfc->description,
+ nfc->max_chip_count,
+ parent_clock_rate_in_hz,
+ clock_rate_in_hz,
+ clock_use_count,
+ nfc->timing.data_setup_in_ns,
+ nfc->timing.data_hold_in_ns,
+ nfc->timing.address_setup_in_ns,
+ nfc->timing.gpmi_sample_delay_in_ns,
+ nfc->timing.tREA_in_ns,
+ nfc->timing.tRLOH_in_ns,
+ nfc->timing.tRHOH_in_ns
+ );
+
+}
+
+/**
+ * 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,
+ gpmi_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,
+ gpmi_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;
+
+ /* Set up safe timing. */
+
+ nfc->set_timing(this, &safe_timing);
+
+ /*
+ * 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 = gpmi_nfc_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);
+ gpmi_nfc_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-mil.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-mil.c
new file mode 100644
index 000000000000..85d5a12ac59a
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-mil.c
@@ -0,0 +1,2599 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+/*
+ * 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);
+
+/**
+ * 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. */
+
+ gpmi_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);
+ }
+
+ gpmi_nfc_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");
+
+ gpmi_nfc_add_event("> mil_dev_ready", 1);
+
+ if (nfc->is_ready(this, mil->current_chip)) {
+ gpmi_nfc_add_event("< mil_dev_ready - Returning ready", -1);
+ return !0;
+ } else {
+ gpmi_nfc_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 nfc_hal *nfc = this->nfc;
+ 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)) {
+ gpmi_nfc_start_event_trace("> mil_select_chip");
+ clk_enable(clock);
+ nfc->begin(this);
+ gpmi_nfc_add_event("< mil_select_chip", -1);
+ } else if ((mil->current_chip >= 0) && (chip < 0)) {
+ gpmi_nfc_add_event("> mil_select_chip", 1);
+ clk_disable(clock);
+ nfc->end(this);
+ gpmi_nfc_stop_event_trace("< mil_select_chip");
+ } else {
+ gpmi_nfc_add_event("> mil_select_chip", 1);
+ gpmi_nfc_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);
+
+ gpmi_nfc_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:
+
+ gpmi_nfc_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);
+
+ gpmi_nfc_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:
+
+ gpmi_nfc_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");
+
+ gpmi_nfc_add_event("> mil_read_byte", 1);
+
+ mil_read_buf(mtd, (uint8_t *) &byte, 1);
+
+ gpmi_nfc_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");
+
+ gpmi_nfc_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:
+
+ gpmi_nfc_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");
+
+ gpmi_nfc_add_event("> mil_ecc_write_page", 1);
+
+ /* Set up DMA. */
+
+ if (rom->swap_block_mark) {
+
+ /*
+ * If control arrives here, we're doing block mark swapping.
+ * Since we can't modify the caller's buffers, we must copy them
+ * into our own.
+ */
+
+ 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;
+
+ /* Handle block mark swapping. */
+
+ mil_handle_block_mark_swapping(this,
+ (void *) payload_virt, (void *) auxiliary_virt);
+
+ } else {
+
+ /*
+ * If control arrives here, we're not doing block mark swapping,
+ * so we can to try and use the caller's buffers.
+ */
+
+ 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;
+ }
+
+ }
+
+ /* 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:
+
+ gpmi_nfc_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");
+
+ gpmi_nfc_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.
+ */
+
+ gpmi_nfc_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);
+
+ gpmi_nfc_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:
+
+ gpmi_nfc_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.
+ */
+static 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 nand_chip *nand = &mil->nand;
+ struct nand_device_info *info = &this->device_info;
+ unsigned int block_size_in_pages;
+ unsigned int chip_size_in_blocks;
+ unsigned int chip_size_in_pages;
+ uint64_t medium_size_in_bytes;
+
+ /*
+ * 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;
+#if defined(DETAILED_INFO)
+ struct nfc_geometry *geo = &this->nfc_geometry;
+#endif
+ /* 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;
+#if defined(DETAILED_INFO)
+ struct boot_rom_geometry *geo = &this->rom_geometry;
+#endif
+
+ /* 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 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;
+ struct nfc_hal *nfc = this->nfc;
+ struct mil *mil = &this->mil;
+ int saved_chip_number;
+ uint8_t id_bytes[NAND_DEVICE_ID_BYTE_COUNT];
+ struct nand_device_info *info;
+ struct gpmi_nfc_timing timing;
+ 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;
+
+ /*
+ * MTD identified the attached NAND Flash devices, but we have a much
+ * better database that we want to consult. First, we need to gather all
+ * the ID bytes from the first chip (MTD only read the first two).
+ */
+
+ saved_chip_number = 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 this device in our database. */
+
+ info = nand_device_get_info(id_bytes);
+
+ /* Check if we understand this device. */
+
+ if (!info) {
+ pr_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;
+
+ /* Set up geometry. */
+
+ error = mil_set_geometry(this);
+
+ if (error)
+ return error;
+
+ /* Set up timing. */
+
+ timing.data_setup_in_ns = info->data_setup_in_ns;
+ timing.data_hold_in_ns = info->data_hold_in_ns;
+ timing.address_setup_in_ns = info->address_setup_in_ns;
+ timing.gpmi_sample_delay_in_ns = info->gpmi_sample_delay_in_ns;
+ timing.tREA_in_ns = info->tREA_in_ns;
+ timing.tRLOH_in_ns = info->tRLOH_in_ns;
+ timing.tRHOH_in_ns = info->tRHOH_in_ns;
+
+ error = nfc->set_timing(this, &timing);
+
+ 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, "Internal error: 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 chip");
+ return -ENXIO;
+ }
+
+ if (rom->boot_area_count == 1) {
+
+#if defined(CONFIG_MTD_PARTITIONS)
+
+ /*
+ * 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();
+ }
+
+#endif
+
+ } else if (rom->boot_area_count == 2) {
+
+#if defined(CONFIG_MTD_PARTITIONS) && defined(CONFIG_MTD_CONCAT)
+
+ /*
+ * 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++) {
+
+ /* Get the current MTD so we can examine it. */
+
+ search_mtd = get_mtd_device(0, i);
+
+ /* Check if we got nonsense. */
+
+ if ((!search_mtd) || (search_mtd == ERR_PTR(-ENODEV)))
+ continue;
+
+ /* Check if the current MTD is one of our remainders. */
+
+ 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;
+
+ /* Put the MTD back. We only wanted a quick look. */
+
+ put_mtd_device(search_mtd);
+
+ }
+
+ if (!chip_0_remainder_mtd || !medium_remainder_mtd) {
+ dev_emerg(dev, "Can't find remainder partitions");
+ BUG();
+ }
+
+ /*
+ * Unregister the remainder MTDs. Note that we are *not*
+ * destroying these MTDs -- we're just removing from the
+ * globally-visible list. There's no need for anyone to see
+ * these.
+ */
+
+ del_mtd_device(chip_0_remainder_mtd);
+ del_mtd_device(medium_remainder_mtd);
+
+ /* 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);
+
+#endif
+
+ } 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 defined(CONFIG_MTD_PARTITIONS) && defined(CONFIG_MTD_CONCAT)
+ if (rom->boot_area_count > 1) {
+ del_mtd_device(mil->general_use_mtd);
+ mtd_concat_destroy(mil->general_use_mtd);
+ }
+ #endif
+
+ /*
+ * At this point, we're left only with the partitions of the main MTD.
+ * Delete them.
+ */
+
+ #if defined(CONFIG_MTD_PARTITIONS)
+ del_mtd_partitions(mtd);
+ #endif
+
+ /* The general use MTD no longer exists. */
+
+ mil->general_use_mtd = 0;
+
+}
+
+/**
+ * mil_construct_ubi_partitions() - Constructs partitions for UBI.
+ *
+ * MTD uses a 64-bit value to express the size of MTDs, but UBI is still using
+ * a 32-bit value. For this reason, UBI can't work on top of an MTD with size
+ * greater than 2GiB. In this function, we examine the general use MTD and, if
+ * it's larger than 2GiB, we construct a set of partitions for that MTD such
+ * that none are too large for UBI to comprehend.
+ *
+ * @this: Per-device data.
+ */
+static void mil_construct_ubi_partitions(struct gpmi_nfc_data *this)
+{
+#if defined(CONFIG_MTD_PARTITIONS)
+ struct device *dev = this->dev;
+ struct mil *mil = &this->mil;
+ unsigned int partition_count;
+ struct mtd_partition *partitions;
+ unsigned int name_size;
+ char *names;
+ unsigned int memory_block_size;
+ unsigned int i;
+
+ static const char *name_prefix = "gpmi-nfc-ubi-";
+
+ /*
+ * If the general use MTD isn't larger than 2GiB, we have nothing to do.
+ */
+
+ if (mil->general_use_mtd->size <= SZ_2G)
+ return;
+
+ /*
+ * If control arrives here, the general use MTD is larger than 2GiB. We
+ * need to split it up into some number of partitions. Find out how many
+ * 2GiB partitions we'll be creating.
+ */
+
+ partition_count = mil->general_use_mtd->size >> 31;
+
+ /*
+ * If the MTD size doesn't evenly divide by 2GiB, we'll need another
+ * partition to hold the extra.
+ */
+
+ if (mil->general_use_mtd->size & ((1 << 30) - 1))
+ partition_count++;
+
+ /*
+ * We're going to allocate a single memory block to contain all the
+ * partition structures and their names. Calculate how large it must be.
+ */
+
+ name_size = strlen(name_prefix) + 4;
+
+ memory_block_size = (sizeof(*partitions) + name_size) * partition_count;
+
+ /*
+ * Attempt to allocate the block.
+ */
+
+ partitions = kzalloc(memory_block_size, GFP_KERNEL);
+
+ if (!partitions) {
+ dev_err(dev, "Could not allocate memory for UBI partitions.\n");
+ return;
+ }
+
+ names = (char *)(partitions + partition_count);
+
+ /* Loop over partitions, filling in the details. */
+
+ for (i = 0; i < partition_count; i++) {
+
+ partitions[i].name = names;
+ partitions[i].size = SZ_2G;
+ partitions[i].offset = MTDPART_OFS_NXTBLK;
+
+ sprintf(names, "%s%u", name_prefix, i);
+ names += name_size;
+
+ }
+
+ /* Adjust the last partition to take up the remainder. */
+
+ partitions[i - 1].size = MTDPART_SIZ_FULL;
+
+ /* Record everything in the device data structure. */
+
+ mil->partitions = partitions;
+ mil->partition_count = partition_count;
+ mil->ubi_partition_memory = partitions;
+
+#endif
+}
+
+/**
+ * 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, 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 defined(CONFIG_MTD_PARTITIONS)
+
+ /*
+ * If control arrives here, partitioning is available.
+ *
+ * There are three possible sets of partitions we might apply, in order
+ * of decreasing priority:
+ *
+ * 1) Partitions dynamically discovered from sources defined by the
+ * platform. These can come from, for example, the command line or
+ * a partition table.
+ *
+ * 2) Partitions attached to the platform data.
+ *
+ * 3) Partitions we generate to deal with limitations in UBI.
+ *
+ * Recall that the pointer to the general use MTD *may* just point to
+ * the main MTD.
+ */
+
+ /*
+ * First, try to get partition information from the sources defined by
+ * the platform.
+ */
+
+ if (pdata->partition_source_types)
+ mil->partition_count =
+ parse_mtd_partitions(mil->general_use_mtd,
+ pdata->partition_source_types,
+ &mil->partitions, 0);
+
+ /*
+ * Check if we got anything. 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 still don't have any partitions to apply, then we might want to
+ * apply some of our own, to account for UBI's limitations.
+ */
+
+ if (!mil->partition_count)
+ mil_construct_ubi_partitions(this);
+
+ /* If we came up with any partitions, 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 to the general use MTD. */
+
+ #if defined(CONFIG_MTD_PARTITIONS)
+
+ if (mil->partition_count)
+ del_mtd_partitions(mil->general_use_mtd);
+
+ kfree(mil->ubi_partition_memory);
+
+ #endif
+
+ /*
+ * 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);
+
+}
+
+/**
+ * gpmi_nfc_mil_init() - Initializes the MTD Interface Layer.
+ *
+ * @this: Per-device data.
+ */
+int gpmi_nfc_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;
+
+}
+
+/**
+ * gpmi_nfc_mil_exit() - Shuts down the MTD Interface Layer.
+ *
+ * @this: Per-device data.
+ */
+void gpmi_nfc_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;
+
+}
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-common.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-common.c
new file mode 100644
index 000000000000..0cd0b39141fd
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-common.c
@@ -0,0 +1,59 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+/**
+ * gpmi_nfc_rom_helper_set_geometry() - Sets geometry for the Boot ROM Helper.
+ *
+ * @this: Per-device data.
+ */
+int gpmi_nfc_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;
+
+}
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-v0.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-v0.c
new file mode 100644
index 000000000000..a2a459835934
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-v0.c
@@ -0,0 +1,298 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+/*
+ * Useful variables for Boot ROM Helper version 0.
+ */
+
+static const char *fingerprint = "STMP";
+
+/**
+ * set_geometry() - Sets geometry for the Boot ROM Helper.
+ *
+ * @this: Per-device data.
+ */
+static int 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 = gpmi_nfc_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;
+
+}
+
+/**
+ * check_transcription_stamp() - Checks for a transcription stamp.
+ *
+ * Returns 0 if a stamp is not found.
+ *
+ * @this: Per-device data.
+ */
+static int 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 is four bytes long
+ * and starts in the 12th byte of the page.
+ */
+
+ nand->cmdfunc(mtd, NAND_CMD_READ0, 12, page);
+ nand->read_buf(mtd, buffer, strlen(fingerprint));
+
+ /* Look for the fingerprint. */
+
+ if (!memcmp(buffer, fingerprint,
+ strlen(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;
+
+}
+
+/**
+ * write_transcription_stamp() - Writes a transcription stamp.
+ *
+ * @this: Per-device data.
+ */
+static int write_transcription_stamp(struct gpmi_nfc_data *this)
+{
+ struct device *dev = this->dev;
+ struct physical_geometry *physical = &this->physical_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 + 12, fingerprint, strlen(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;
+
+}
+
+/* This structure represents the Boot ROM Helper for this version. */
+
+struct boot_rom_helper gpmi_nfc_boot_rom_helper_v0 = {
+ .version = 0,
+ .description = "Single/dual-chip boot area, "
+ "no block mark swapping",
+ .swap_block_mark = false,
+ .set_geometry = set_geometry,
+ .check_transcription_stamp = check_transcription_stamp,
+ .write_transcription_stamp = write_transcription_stamp,
+};
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-v1.c b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-v1.c
new file mode 100644
index 000000000000..49cb329ccdd4
--- /dev/null
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-rom-v1.c
@@ -0,0 +1,82 @@
+/*
+ * Freescale GPMI NFC NAND Flash Driver
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "gpmi-nfc.h"
+
+/**
+ * set_geometry() - Sets geometry for the Boot ROM Helper.
+ *
+ * @this: Per-device data.
+ */
+static int 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 = gpmi_nfc_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;
+
+}
+
+/* This structure represents the Boot ROM Helper for this version. */
+
+struct boot_rom_helper gpmi_nfc_boot_rom_helper_v1 = {
+ .version = 1,
+ .description = "Single-chip boot area, "
+ "block mark swapping supported",
+ .swap_block_mark = true,
+ .set_geometry = set_geometry,
+ .check_transcription_stamp = 0,
+ .write_transcription_stamp = 0,
+};
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
deleted file mode 100644
index f5251ab6e77d..000000000000
--- a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-bch-regs.h
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 5d683d415006..000000000000
--- a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v0-gpmi-regs.h
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * 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
deleted file mode 100644
index df003742715b..000000000000
--- a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-bch-regs.h
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * 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
deleted file mode 100644
index d31c5f23e66f..000000000000
--- a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc-v1-gpmi-regs.h
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 7fa729bdea5c..000000000000
--- a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.c
+++ /dev/null
@@ -1,6351 +0,0 @@
-/*
- * 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
index 6aaa323cdaf1..08afbcf2d943 100644
--- a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h
+++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h
@@ -22,11 +22,53 @@
#ifndef __DRIVERS_MTD_NAND_GPMI_NFC_H
#define __DRIVERS_MTD_NAND_GPMI_NFC_H
+/* 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>
+#include <asm/sizes.h>
+
+/* Platform header files. */
+
+#include <mach/system.h>
+#include <mach/dmaengine.h>
+#include <mach/device.h>
+#include <mach/clock.h>
+
+/* Driver header files. */
+
#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"
+
+/*
+ *------------------------------------------------------------------------------
+ * Fundamental Macros
+ *------------------------------------------------------------------------------
+ */
+
+/* Define this macro to enable detailed information messages. */
+
+#define DETAILED_INFO
+
+/* Define this macro to enable event reporting. */
+
+/*#define EVENT_REPORTING*/
+
+/*
+ *------------------------------------------------------------------------------
+ * Fundamental Data Structures
+ *------------------------------------------------------------------------------
+ */
/**
* struct resources - The collection of resources the driver needs.
@@ -63,10 +105,12 @@ struct resources {
* 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.
+ * @partitions: A pointer to a set of partitions applied to the
+ * general use MTD.
* @partition_count: The number of partitions.
+ * @ubi_partition_memory: If not NULL, a block of memory used to create a set
+ * of partitions that help with the problem that UBI
+ * can't handle an MTD larger than 2GiB.
* @current_chip: The chip currently selected by the NAND Fash MTD
* code. A negative value indicates that no chip is
* selected.
@@ -134,6 +178,7 @@ struct mil {
struct mtd_info *general_use_mtd;
struct mtd_partition *partitions;
unsigned int partition_count;
+ void *ubi_partition_memory;
/* General-use Variables */
@@ -312,57 +357,151 @@ struct gpmi_nfc_data {
};
/**
+ * struct gpmi_nfc_timing - GPMI NFC timing parameters.
+ *
+ * This structure contains the fundamental timing attributes for the NAND Flash
+ * bus and the GPMI NFC hardware.
+ *
+ * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the
+ * maximum of tDS and tWP. A negative value
+ * indicates this characteristic isn't known.
+ * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the
+ * maximum of tDH, tWH and tREH. A negative value
+ * indicates this characteristic isn't known.
+ * @address_setup_in_ns: The address setup time, in nanoseconds. Usually
+ * the maximum of tCLS, tCS and tALS. A negative
+ * value indicates this characteristic isn't known.
+ * @gpmi_sample_time_in_ns: A GPMI-specific timing parameter. A negative
+ * value indicates this characteristic isn't known.
+ * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A
+ * negative value indicates this characteristic
+ * isn't known.
+ * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A
+ * negative value indicates this characteristic
+ * isn't known.
+ * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A
+ * negative value indicates this characteristic
+ * isn't known.
+ */
+
+struct gpmi_nfc_timing {
+ int8_t data_setup_in_ns;
+ int8_t data_hold_in_ns;
+ int8_t address_setup_in_ns;
+ int8_t gpmi_sample_delay_in_ns;
+ int8_t tREA_in_ns;
+ int8_t tRLOH_in_ns;
+ int8_t tRHOH_in_ns;
+};
+
+/**
* 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.
+ * @version: The NFC hardware version.
+ * @description: A pointer to a human-readable description of
+ * the NFC hardware.
+ * @max_chip_count: The maximum number of chips the NFC can
+ * possibly support (this value is a constant
+ * for each NFC version). This may *not* be the
+ * actual number of chips connected.
+ * @max_data_setup_cycles: The maximum number of data setup cycles
+ * that can be expressed in the hardware.
+ * @max_data_sample_delay_cycles: The maximum number of data sample delay
+ * cycles that can be expressed in the hardware.
+ * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the
+ * sample delay DLL hardware can possibly work
+ * with (the DLL is unusable with longer
+ * periods). At HALF this value, the DLL must be
+ * configured to use half-periods.
+ * @dma_descriptors: A pool of DMA descriptors.
+ * @isr_dma_channel: The DMA channel with which the NFC HAL is
+ * working. We record this here so the ISR knows
+ * which DMA channel to acknowledge.
+ * @dma_done: The completion structure used for DMA
+ * interrupts.
+ * @bch_done: The completion structure used for BCH
+ * interrupts.
+ * @timing: The current timing configuration.
+ * @init: Initializes the NFC hardware and data
+ * structures. This function will be called
+ * after everything has been set up for
+ * communication with the NFC itself, but before
+ * the platform has set up off-chip
+ * communication. Thus, this function must not
+ * attempt to communicate with the NAND Flash
+ * hardware.
+ * @set_geometry: Configures the NFC hardware and data
+ * structures to match the physical NAND Flash
+ * geometry.
+ * @set_geometry: Configures the NFC hardware and data
+ * structures to match the physical NAND Flash
+ * geometry.
+ * @exit: Shuts down the NFC hardware and data
+ * structures. This function will be called
+ * after the platform has shut down off-chip
+ * communication but while communication with
+ * the NFC itself still works.
+ * @clear_bch: Clears a BCH interrupt (intended to be called
+ * by a more general interrupt handler to do
+ * device-specific clearing).
+ * @is_ready: Returns true if the given chip is ready.
+ * @begin: Begins an interaction with the NFC. This
+ * function must be called before *any* of the
+ * following functions so the NFC can prepare
+ * itself.
+ * @end: Ends interaction with the NFC. This function
+ * should be called to give the NFC a chance to,
+ * among other things, enter a lower-power
+ * state.
+ * @send_command: Sends the given buffer of command bytes.
+ * @send_data: Sends the given buffer of data bytes.
+ * @read_data: Reads data bytes into the given buffer.
+ * @send_page: Sends the given given data and OOB bytes,
+ * using the ECC engine.
+ * @read_page: Reads a page through the ECC engine and
+ * delivers the data and OOB bytes to the given
+ * buffers.
*/
#define NFC_DMA_DESCRIPTOR_COUNT (4)
struct nfc_hal {
- 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;
+
+ /* Hardware attributes. */
+
+ const unsigned int version;
+ const char *description;
+ const unsigned int max_chip_count;
+ const unsigned int max_data_setup_cycles;
+ const unsigned int max_data_sample_delay_cycles;
+ const unsigned int max_dll_clock_period_in_ns;
+
+ /* Working variables. */
+
+ struct mxs_dma_desc *dma_descriptors[NFC_DMA_DESCRIPTOR_COUNT];
+ int isr_dma_channel;
+ struct completion dma_done;
+ struct completion bch_done;
+ struct gpmi_nfc_timing timing;
+
+ /* Configuration functions. */
+
int (*init) (struct gpmi_nfc_data *);
int (*set_geometry)(struct gpmi_nfc_data *);
+ int (*set_timing) (struct gpmi_nfc_data *,
+ const struct gpmi_nfc_timing *);
void (*exit) (struct gpmi_nfc_data *);
+
+ /* Call these functions to begin and end I/O. */
+
+ void (*begin) (struct gpmi_nfc_data *);
+ void (*end) (struct gpmi_nfc_data *);
+
+ /* Call these I/O functions only between begin() and end(). */
+
+ void (*clear_bch) (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);
@@ -403,4 +542,52 @@ struct boot_rom_helper {
int (*write_transcription_stamp)(struct gpmi_nfc_data *);
};
+/*
+ *------------------------------------------------------------------------------
+ * External Symbols
+ *------------------------------------------------------------------------------
+ */
+
+/* Event Reporting */
+
+#if defined(EVENT_REPORTING)
+ extern void gpmi_nfc_start_event_trace(char *description);
+ extern void gpmi_nfc_add_event(char *description, int delta);
+ extern void gpmi_nfc_stop_event_trace(char *description);
+ extern void gpmi_nfc_dump_event_trace(void);
+#else
+ #define gpmi_nfc_start_event_trace(description) do {} while (0)
+ #define gpmi_nfc_add_event(description, delta) do {} while (0)
+ #define gpmi_nfc_stop_event_trace(description) do {} while (0)
+ #define gpmi_nfc_dump_event_trace() do {} while (0)
+#endif
+
+/* NFC HAL Common Services */
+
+extern irqreturn_t gpmi_nfc_bch_isr(int irq, void *cookie);
+extern irqreturn_t gpmi_nfc_dma_isr(int irq, void *cookie);
+extern int gpmi_nfc_dma_init(struct gpmi_nfc_data *this);
+extern void gpmi_nfc_dma_exit(struct gpmi_nfc_data *this);
+extern int gpmi_nfc_set_geometry(struct gpmi_nfc_data *this);
+extern int gpmi_nfc_dma_go(struct gpmi_nfc_data *this, int dma_channel);
+
+/* NFC HAL Structures */
+
+extern struct nfc_hal gpmi_nfc_hal_v0;
+extern struct nfc_hal gpmi_nfc_hal_v1;
+
+/* Boot ROM Helper Common Services */
+
+extern int gpmi_nfc_rom_helper_set_geometry(struct gpmi_nfc_data *this);
+
+/* Boot ROM Helper Structures */
+
+extern struct boot_rom_helper gpmi_nfc_boot_rom_helper_v0;
+extern struct boot_rom_helper gpmi_nfc_boot_rom_helper_v1;
+
+/* MTD Interface Layer */
+
+extern int gpmi_nfc_mil_init(struct gpmi_nfc_data *this);
+extern void gpmi_nfc_mil_exit(struct gpmi_nfc_data *this);
+
#endif
diff --git a/drivers/mtd/nand/gpmi/Makefile b/drivers/mtd/nand/gpmi/Makefile
deleted file mode 100644
index 4a4b50d294fa..000000000000
--- a/drivers/mtd/nand/gpmi/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-obj-$(CONFIG_MTD_NAND_GPMI) += gpmi.o
-gpmi-objs += gpmi-base.o gpmi-bbt.o
-gpmi-objs += gpmi-hamming-22-16.o
-gpmi-objs += gpmi-hamming-13-8.o
-gpmi-objs += gpmi-bch.o
-gpmi-objs += gpmi-ecc8.o
diff --git a/drivers/mtd/nand/gpmi/gpmi-base.c b/drivers/mtd/nand/gpmi/gpmi-base.c
deleted file mode 100644
index 570e3894edae..000000000000
--- a/drivers/mtd/nand/gpmi/gpmi-base.c
+++ /dev/null
@@ -1,3382 +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
- */
-
-#include <linux/kernel.h>
-#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/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/concat.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
-#include <asm/div64.h>
-#include <asm/sizes.h>
-
-#include <mach/stmp3xxx.h>
-#include <mach/platform.h>
-#include <mach/regs-ecc8.h>
-#include <mach/regs-gpmi.h>
-#include <mach/dma.h>
-#include "gpmi.h"
-#include "../nand_device_info.h"
-
-/* Macro definitions for the i.MX23. Some will be different for other SoC's. */
-
-#define MAX_DATA_SETUP_CYCLES \
- (BM_GPMI_TIMING0_DATA_SETUP >> BP_GPMI_TIMING0_DATA_SETUP)
-
-#define MAX_DATA_SAMPLE_DELAY_CYCLES \
- ((uint32_t)(BM_GPMI_CTRL1_RDN_DELAY >> BP_GPMI_CTRL1_RDN_DELAY))
-
-/* Right shift value to get the frational GPMI time for data delay. */
-#define GPMI_DELAY_SHIFT (3)
-
-/* Max GPMI clock period the GPMI DLL can tolerate. */
-#define GPMI_MAX_DLL_PERIOD_NS (32)
-
-/*
- * The threshold for the GPMI clock period above which the DLL requires a divide
- * by two.
- */
-#define GPMI_DLL_HALF_THRESHOLD_PERIOD_NS (16)
-
-/* The number of GPMI clock cycles to wait for use of GPMI after DLL enable. */
-#define GPMI_WAIT_CYCLES_AFTER_DLL_ENABLE (64)
-
-/* The time in nanoseconds required for GPMI data read internal setup. */
-#define GPMI_DATA_SETUP_NS (0)
-
-/* The time in nanoseconds required for GPMI data read internal setup */
-#define GPMI_MAX_HARDWARE_DELAY_NS ((uint32_t)(16))
-
-/*
- * Max data delay possible for the GPMI.
- *
- * Use the min of the time (16 nS) or what will fit in the register. If the GPMI
- * clock period is greater than GPMI_MAX_DLL_PERIOD_NS then can't use the delay.
- *
- * Where:
- *
- * c is the GPMI clock period in nanoseconds.
- * f is the GPMI data sample delay fraction.
- *
- */
-#define GPMI_GET_MAX_DELAY_NS(c, f) \
- (\
- (c >= GPMI_MAX_DLL_PERIOD_NS) ? 0 :\
- min(GPMI_MAX_HARDWARE_DELAY_NS, \
- ((MAX_DATA_SAMPLE_DELAY_CYCLES * c) / f)) \
- )
-
-/*
- * Set this variable to a value greater than zero to see varying levels of
- * debugging output.
- */
-
-static int debug;
-
-/*
- * This variable counts the total number of times the driver has copied either
- * page data or OOB data from/to a DMA buffer.
- */
-
-static int copies;
-
-/*
- * Indicates that this driver should attempt to perform DMA directly to/from
- * buffers passed into this driver. If false, this driver will use its own
- * buffer for DMA and copy data between this buffer and the buffers that are
- * passed in.
- */
-
-static int map_buffers = true;
-
-static int ff_writes;
-
-/*
- * Forces all OOB reads and writes to NOT use ECC.
- */
-
-static int raw_mode;
-
-/*
- * Indicates the driver should register an MTD that represents the entire
- * medium.
- */
-
-static int add_mtd_entire;
-
-/*
- * Indicates the driver should register a separate MTD for every physical chip.
- */
-
-static int add_mtd_chip;
-
-/*
- * Indicates the driver should report that *all* blocks are good.
- */
-
-static int ignorebad;
-
-/*
- * The maximum number of chips for which the NAND Flash MTD system is allowed to
- * scan.
- */
-
-static int max_chips = 4;
-
-/*
- *
- */
-
-static long clk = -1;
-
-/*
- * This variable is connected to the "bch" module parameter. If set, it
- * indicates the driver should use the BCH hardware block instead of the ECC8
- * hardware block for error correction.
- */
-
-static int bch = 1;
-
-/* Forward references. */
-
-static int gpmi_nand_init_hw(struct platform_device *pdev, int request_pins);
-static void gpmi_nand_release_hw(struct platform_device *pdev);
-static int gpmi_dma_exchange(struct gpmi_nand_data *g,
- struct stmp3xxx_dma_descriptor *dma);
-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t * buf, int len);
-
-/*
- * This structure contains the "safe" GPMI timings that should succeed with any
- * NAND Flash device (although, with less-than-optimal performance).
- */
-
-struct gpmi_nand_timing gpmi_safe_timing = {
- .data_setup_in_ns = 80,
- .data_hold_in_ns = 60,
- .address_setup_in_ns = 25,
- .gpmi_sample_delay_in_ns = 6,
- .tREA_in_ns = -1,
- .tRLOH_in_ns = -1,
- .tRHOH_in_ns = -1,
-};
-
-/*
- * ECC layout descriptions for various device geometries.
- */
-
-static struct nand_ecclayout gpmi_oob_128 = {
- .oobfree = {
- {
- .offset = 2,
- .length = 56,
- }, {
- .length = 0,
- },
- },
-};
-
-static struct nand_ecclayout gpmi_oob_64 = {
- .oobfree = {
- {
- .offset = 2,
- .length = 16,
- }, {
- .length = 0,
- },
- },
-};
-
-/**
- * gpmi_cycles_ceil - Translates timings in nanoseconds to GPMI clock cycles.
- *
- * @ntime: The time in nanoseconds.
- * @period: The GPMI clock period.
- * @min: The minimum allowable number of cycles.
- */
-static inline u32 gpmi_cycles_ceil(u32 ntime, u32 period, u32 min)
-{
- int k;
-
- /*
- * Compute the minimum number of clock periods that entirely contain the
- * given time.
- */
-
- k = (ntime + period - 1) / period;
-
- return max(k, (int)min);
-
-}
-
-/**
- * gpmi_timer_expiry - Inactivity timer expiration handler.
- */
-static void gpmi_timer_expiry(unsigned long d)
-{
-#ifdef CONFIG_PM
- struct gpmi_nand_data *g = (struct gpmi_nand_data *)d;
-
- pr_debug("%s: timer expired\n", __func__);
- del_timer_sync(&g->timer);
-
- if (g->use_count ||
- __raw_readl(REGS_GPMI_BASE + HW_GPMI_CTRL0) & BM_GPMI_CTRL0_RUN) {
- g->timer.expires = jiffies + 4 * HZ;
- add_timer(&g->timer);
- } else {
- __raw_writel(BM_GPMI_CTRL0_CLKGATE,
- REGS_GPMI_BASE + HW_GPMI_CTRL0_SET);
- clk_disable(g->clk);
- g->self_suspended = 1;
- }
-#endif
-}
-
-/**
- * gpmi_self_wakeup - wakeup from self-pm light suspend
- */
-static void gpmi_self_wakeup(struct gpmi_nand_data *g)
-{
-#ifdef CONFIG_PM
- int i = 1000;
- clk_enable(g->clk);
- __raw_writel(BM_GPMI_CTRL0_CLKGATE, REGS_GPMI_BASE + HW_GPMI_CTRL0_CLR);
- while (i--
- && __raw_readl(REGS_GPMI_BASE +
- HW_GPMI_CTRL0) & BM_GPMI_CTRL0_CLKGATE) ;
-
- pr_debug("%s: i stopped at %d, data %p\n", __func__, i, g);
- g->self_suspended = 0;
- g->timer.expires = jiffies + 4 * HZ;
- add_timer(&g->timer);
-#endif
-}
-
-/**
- * gpmi_set_timings - Set GPMI timings.
- *
- * This function adjusts the GPMI hardware timing registers. If the override
- * parameter is NULL, this function will use the timings specified in the per-
- * device data. Otherwise, it will apply the given timings.
- *
- * @g: Per-device data.
- * @override: If not NULL, override the timings in the per-device data.
- */
-void gpmi_set_timings(struct gpmi_nand_data *g,
- struct gpmi_nand_timing *override)
-{
- struct gpmi_platform_data *gpd = g->gpd;
- struct gpmi_nand_timing target;
-
- bool dynamic_timing_is_available;
- uint32_t gpmi_delay_fraction;
- uint32_t gpmi_max_delay_in_ns;
- uint32_t address_setup_in_cycles;
- uint32_t data_setup_in_ns;
- uint32_t data_setup_in_cycles;
- uint32_t data_hold_in_cycles;
- int32_t data_sample_delay_in_ns;
- uint32_t data_sample_delay_in_cycles;
- int32_t tEYE;
- uint32_t gpmi_clock_period_in_ns = 1000000 / clk_get_rate(g->clk) + 1;
- uint32_t min_prop_delay_in_ns = gpd->min_prop_delay_in_ns;
- uint32_t max_prop_delay_in_ns = gpd->max_prop_delay_in_ns;
- uint32_t busy_timeout_in_cycles;
- uint32_t register_image;
- uint32_t dll_wait_time_in_us;
-
- /* Wake up. */
-
- if (g->self_suspended)
- gpmi_self_wakeup(g);
-
- g->use_count++;
-
- /* Figure out where we're getting our new timing. */
-
- if (override)
- target = *override;
- else {
- target.data_setup_in_ns = g->device_info.data_setup_in_ns;
- target.data_hold_in_ns = g->device_info.data_hold_in_ns;
- target.address_setup_in_ns =
- g->device_info.address_setup_in_ns;
- target.gpmi_sample_delay_in_ns =
- g->device_info.gpmi_sample_delay_in_ns;
- target.tREA_in_ns = g->device_info.tREA_in_ns;
- target.tRLOH_in_ns = g->device_info.tRLOH_in_ns;
- target.tRHOH_in_ns = g->device_info.tRHOH_in_ns;
- }
-
- /* Check if dynamic timing information is available. */
-
- dynamic_timing_is_available = 0;
-
- if ((target.tREA_in_ns >= 0) &&
- (target.tRLOH_in_ns >= 0) &&
- (target.tRHOH_in_ns >= 0))
- dynamic_timing_is_available = !0;
-
- /* Reset the DLL and sample delay to known values. */
-
- __raw_writel(
- BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_DLL_ENABLE,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_CLR);
-
- /*
- * Check how fast the GPMI clock is running. If it's running very
- * slowly, we'll need to use half-periods.
- */
-
- if (gpmi_clock_period_in_ns > GPMI_DLL_HALF_THRESHOLD_PERIOD_NS) {
-
- /*
- * The GPMI clock period is high enough that the DLL
- * requires a divide by two.
- */
-
- register_image = __raw_readl(REGS_GPMI_BASE + HW_GPMI_CTRL1);
- register_image |= BM_GPMI_CTRL1_HALF_PERIOD;
- __raw_writel(register_image, REGS_GPMI_BASE + HW_GPMI_CTRL1);
-
- gpmi_delay_fraction = GPMI_DELAY_SHIFT + 1;
-
- } else {
-
- gpmi_delay_fraction = GPMI_DELAY_SHIFT;
-
- }
-
- gpmi_max_delay_in_ns =
- GPMI_GET_MAX_DELAY_NS(gpmi_clock_period_in_ns,
- gpmi_delay_fraction);
-
- busy_timeout_in_cycles = gpmi_cycles_ceil(10000000 / 4096,
- gpmi_clock_period_in_ns, 0);
-
- /*
- * The hardware quantizes the setup and hold parameters to intervals of
- * the GPMI clock period.
- *
- * Quantize the setup and hold parameters to the next-highest GPMI clock
- * period to make sure we use at least the requested times.
- *
- * For data setup and data hold, the chip interprets a value of zero as
- * the largest amount of delay supported. This is not what's intended by
- * a zero in the input parameter, so we modify the zero input parameter
- * to the smallest supported value.
- */
-
- address_setup_in_cycles = gpmi_cycles_ceil(target.address_setup_in_ns,
- gpmi_clock_period_in_ns, 0);
- data_setup_in_cycles = gpmi_cycles_ceil(target.data_setup_in_ns,
- gpmi_clock_period_in_ns, 1);
- data_hold_in_cycles = gpmi_cycles_ceil(target.data_hold_in_ns,
- gpmi_clock_period_in_ns, 1);
-
- /*
- * Check if dynamic timing is available. If not, we have to use a
- * simpler algorithm for computing the values we put in the hardware
- * registers.
- */
-
- if (!dynamic_timing_is_available) {
-
- /*
- * Get the delay time and include the required chip read setup
- * time.
- */
-
- data_sample_delay_in_ns =
- target.gpmi_sample_delay_in_ns + GPMI_DATA_SETUP_NS;
-
- /*
- * Extend the data setup time as needed to reduce delay time
- * below the max supported by hardware. Also keep it in the
- * allowable range
- */
-
- while ((data_sample_delay_in_ns > gpmi_max_delay_in_ns) &&
- (data_setup_in_cycles < MAX_DATA_SETUP_CYCLES)) {
-
- data_setup_in_cycles++;
- data_sample_delay_in_ns -= gpmi_clock_period_in_ns;
-
- if (data_sample_delay_in_ns < 0)
- data_sample_delay_in_ns = 0;
-
- }
-
- /*
- * Compute the number of cycles that corresponds to the data
- * sample delay.
- */
-
- data_sample_delay_in_cycles =
- gpmi_cycles_ceil(
- gpmi_delay_fraction * data_sample_delay_in_ns,
- gpmi_clock_period_in_ns, 0);
-
- if (data_sample_delay_in_cycles > MAX_DATA_SAMPLE_DELAY_CYCLES)
- data_sample_delay_in_cycles =
- MAX_DATA_SAMPLE_DELAY_CYCLES;
-
- /* Go set up the hadware. */
-
- goto set_up_the_hardware;
-
- }
-
- /*
- * If control arrives here, we can use a more dynamic algorithm for
- * computing the hardware register values.
- */
-
- /* Compute the data setup time for the given number of GPMI cycles. */
-
- data_setup_in_ns = gpmi_clock_period_in_ns * data_setup_in_cycles;
-
- /*
- * This accounts for chip specific GPMI read setup time on the
- * data sample circuit. See i.MX23 reference manual section
- * "14.3.4. High-Speed NAND Timing"
- */
-
- max_prop_delay_in_ns += GPMI_DATA_SETUP_NS;
-
- /*
- * Compute tEYE, the width of the data eye when reading from the
- * NAND Flash.
- *
- * Note that we use the quantized versions of setup and hold because the
- * hardware uses these quantized values, and these timings create the
- * eye.
- *
- * end of the eye = min_prop_delay_in_ns + target.tRHOH_in_ns +
- * data_setup_in_ns
- * start of the eye = max_prop_delay_in_ns + target.tREA_in_ns
- */
-
- tEYE = ((int)min_prop_delay_in_ns +
- (int)target.tRHOH_in_ns + (int)data_setup_in_ns) -
- ((int)max_prop_delay_in_ns + (int)target.tREA_in_ns);
-
- /*
- * The eye has to be open. Constrain tEYE to be greater than zero
- * and the number of data setup cycles to fit in the timing register.
- */
-
- while ((tEYE <= 0) && (data_setup_in_cycles < MAX_DATA_SETUP_CYCLES)) {
-
- /*
- * The eye is not open. An increase in data setup time causes a
- * coresponding increase to size of the eye.
- */
-
- /* Give an additional DataSetup cycle. */
- data_setup_in_cycles++;
- /* Keep the data setup time in step with the cycles. */
- data_setup_in_ns += gpmi_clock_period_in_ns;
- /* And adjust tEYE accordingly. */
- tEYE += gpmi_clock_period_in_ns;
-
- }
-
- /*
- * Compute the ideal point at which to sample the data at the center of
- * the eye.
- */
-
- /*
- * Find the delay to get to the center of the eye, in time units.
- *
- * Delay for center of the eye:
- *
- * ((end of the eye + start of the eye) / 2) - data_setup
- *
- * This simplifies to the following:
- */
-
- data_sample_delay_in_ns =
- ((int)max_prop_delay_in_ns +
- (int)target.tREA_in_ns +
- (int)min_prop_delay_in_ns +
- (int)target.tRHOH_in_ns -
- (int)data_setup_in_ns) >> 1;
-
- /* The chip can't handle a negative parameter for the sample point. */
-
- if (data_sample_delay_in_ns < 0)
- data_sample_delay_in_ns = 0;
-
- /*
- * Make sure the required delay time does not exceed the max allowed
- * value. Also make sure the quantized delay time (at
- * data_sample_delay_in_cycles) is within the eye.
- *
- * Increasing data setup decreases the delay time required to get to
- * into the eye. Increasing data setup also moves the rear of the eye
- * back, enlarging the eye (helpful in the case where quantized delay
- * time does not fall inside the initial eye).
- *
- * ____ _______________________________________
- * RDN \_______________/
- *
- * <----- tEYE ---->
- * /-------------------\
- * Read Data ----------------------------< >------
- * \-------------------/
- * ^ ^ ^ tEYE/2 ^
- * | | | |
- * |<--DataSetup-->|<----DelayTime----->| |
- * | | | |
- * | | |
- * | |<----Quantized DelayTime---------->|
- * | | |
- */
-
- /*
- * Extend the data setup time as needed to reduce delay time below the
- * max allowable value. Also keep data setup in the allowable range.
- */
-
- while ((data_sample_delay_in_ns > gpmi_max_delay_in_ns) &&
- (data_setup_in_cycles < MAX_DATA_SETUP_CYCLES)) {
-
- /* Give an additional data setup cycle. */
- data_setup_in_cycles++;
- /* Keep the data setup time in step with the cycles. */
- data_setup_in_ns += gpmi_clock_period_in_ns;
- /* And adjust tEYE accordingly. */
- tEYE += gpmi_clock_period_in_ns;
-
- /*
- * Decrease the delay time by one half data setup cycle worth,
- * to keep in the middle of the eye.
- */
- data_sample_delay_in_ns -= (gpmi_clock_period_in_ns >> 1);
-
- /* Do not allow a delay time less than zero. */
- if (data_sample_delay_in_ns < 0)
- data_sample_delay_in_ns = 0;
-
- }
-
- /*
- * The sample delay time is expressed in the chip in units of fractions
- * of GPMI clocks. Convert the delay time to an integer quantity of
- * fractional GPMI cycles.
- */
-
- data_sample_delay_in_cycles =
- gpmi_cycles_ceil(
- gpmi_delay_fraction * data_sample_delay_in_ns,
- gpmi_clock_period_in_ns, 0);
-
- if (data_sample_delay_in_cycles > MAX_DATA_SAMPLE_DELAY_CYCLES)
- data_sample_delay_in_cycles = MAX_DATA_SAMPLE_DELAY_CYCLES;
-
- #define DSAMPLE_IS_NOT_WITHIN_THE_DATA_EYE \
- (tEYE>>1 < abs((int32_t)((data_sample_delay_in_cycles * \
- gpmi_clock_period_in_ns) / gpmi_delay_fraction) - \
- data_sample_delay_in_ns))
-
- /*
- * While the quantized delay time is out of the eye, reduce the delay
- * time or extend the data setup time to get in the eye. Do not allow
- * the number of data setup cycles to exceed the max supported by
- * the hardware.
- */
-
- while (DSAMPLE_IS_NOT_WITHIN_THE_DATA_EYE
- && (data_setup_in_cycles < MAX_DATA_SETUP_CYCLES)) {
-
- if (((data_sample_delay_in_cycles * gpmi_clock_period_in_ns) /
- gpmi_delay_fraction) > data_sample_delay_in_ns){
-
- /*
- * If the quantized delay time is greater than the max
- * reach of the eye, decrease the quantized delay time
- * to get it into the eye or before the eye.
- */
-
- if (data_sample_delay_in_cycles != 0)
- data_sample_delay_in_cycles--;
-
- } else {
-
- /*
- * If the quantized delay time is less than the min
- * reach of the eye, shift up the sample point by
- * increasing data setup. This will also open the eye
- * (helping get the quantized delay time in the eye).
- */
-
- /* Give an additional data setup cycle. */
- data_setup_in_cycles++;
- /* Keep the data setup time in step with the cycles. */
- data_setup_in_ns += gpmi_clock_period_in_ns;
- /* And adjust tEYE accordingly. */
- tEYE += gpmi_clock_period_in_ns;
-
- /*
- * Decrease the delay time by one half data setup cycle
- * worth, to keep in the middle of the eye.
- */
- data_sample_delay_in_ns -= (gpmi_clock_period_in_ns>>1);
-
- /* ...and one less period for the delay time. */
- data_sample_delay_in_ns -= gpmi_clock_period_in_ns;
-
- /* Keep the delay time from going negative. */
- if (data_sample_delay_in_ns < 0)
- data_sample_delay_in_ns = 0;
-
- /*
- * Convert time to GPMI cycles and make sure the number
- * of cycles fits in the coresponding hardware register.
- */
-
- data_sample_delay_in_cycles =
- gpmi_cycles_ceil(gpmi_delay_fraction *
- data_sample_delay_in_ns,
- gpmi_clock_period_in_ns, 0);
-
- if (data_sample_delay_in_cycles >
- MAX_DATA_SAMPLE_DELAY_CYCLES)
- data_sample_delay_in_cycles =
- MAX_DATA_SAMPLE_DELAY_CYCLES;
-
-
- }
-
- }
-
- /*
- * Control arrives here when we've computed all the hardware register
- * values (using eithe the static or dynamic algorithm) and we're ready
- * to apply them.
- */
-
-set_up_the_hardware:
-
- /* Set the values in the registers. */
-
- dev_dbg(&g->dev->dev,
- "%s: tAS %u, tDS %u, tDH %u, tDSAMPLE %u, tBTO %u\n",
- __func__,
- address_setup_in_cycles,
- data_setup_in_cycles,
- data_hold_in_cycles,
- data_sample_delay_in_cycles,
- busy_timeout_in_cycles
- );
-
- /* Set up all the simple timing parameters. */
-
- register_image =
- BF(address_setup_in_cycles, GPMI_TIMING0_ADDRESS_SETUP) |
- BF(data_setup_in_cycles, GPMI_TIMING0_DATA_SETUP) |
- BF(data_hold_in_cycles, GPMI_TIMING0_DATA_HOLD) ;
-
- __raw_writel(register_image, REGS_GPMI_BASE + HW_GPMI_TIMING0);
-
- __raw_writel(BF(busy_timeout_in_cycles,
- GPMI_TIMING1_DEVICE_BUSY_TIMEOUT),
- REGS_GPMI_BASE + HW_GPMI_TIMING1);
-
- /*
- * Hey - pay attention!
- *
- * DLL_ENABLE must be set to zero when setting RDN_DELAY or
- * HALF_PERIOD.
- */
-
- /* BW_GPMI_CTRL1_DLL_ENABLE(0); */
- __raw_writel(BM_GPMI_CTRL1_DLL_ENABLE,
- REGS_GPMI_BASE+HW_GPMI_CTRL1_CLR);
-
- if ((data_sample_delay_in_cycles == 0) ||
- (gpmi_clock_period_in_ns > GPMI_MAX_DLL_PERIOD_NS)) {
-
- /*
- * If no delay is desired, or if the GPMI clock period is out of
- * supported range, then don't enable the delay.
- */
-
- /* BW_GPMI_CTRL1_RDN_DELAY(0); */
- __raw_writel(BM_GPMI_CTRL1_RDN_DELAY,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_CLR);
- /* BW_GPMI_CTRL1_HALF_PERIOD(0); */
- __raw_writel(BM_GPMI_CTRL1_HALF_PERIOD,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_CLR);
-
- } else {
-
- /*
- * Set the delay and enable the DLL. GPMI_CTRL1_HALF_PERIOD is
- * assumed to have already been set properly.
- */
-
- /* BW_GPMI_CTRL1_RDN_DELAY(data_sample_delay_in_cycles); */
- register_image = __raw_readl(REGS_GPMI_BASE + HW_GPMI_CTRL1);
- register_image &= ~BM_GPMI_CTRL1_RDN_DELAY;
- register_image |=
- (data_sample_delay_in_cycles << BP_GPMI_CTRL1_RDN_DELAY)
- & BM_GPMI_CTRL1_RDN_DELAY;
- __raw_writel(register_image, REGS_GPMI_BASE + HW_GPMI_CTRL1);
-
- /* BW_GPMI_CTRL1_DLL_ENABLE(1); */
- __raw_writel(BM_GPMI_CTRL1_DLL_ENABLE,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_SET);
-
- /*
- * After we enable the GPMI DLL, we have to wait
- * GPMI_WAIT_CYCLES_AFTER_DLL_ENABLE GPMI clock cycles before
- * we can use the GPMI interface.
- *
- * Calculate the amount of time we need to wait, in
- * microseconds.
- */
-
- /*
- * Calculate the wait time and convert from nanoseconds to
- * microseconds.
- */
-
- dll_wait_time_in_us =
- (gpmi_clock_period_in_ns *
- GPMI_WAIT_CYCLES_AFTER_DLL_ENABLE) / 1000;
-
- if (!dll_wait_time_in_us)
- dll_wait_time_in_us = 1;
-
- /*
- * Wait for the DLL to settle.
- */
-
- udelay(dll_wait_time_in_us);
-
- }
-
- /* Allow the driver to go back to sleep, if it wants to. */
-
- g->use_count--;
-
-}
-
-/**
- * bch_mode - Return a hardware register value that selects BCH.
- */
-static inline u32 bch_mode(void)
-{
- u32 c1 = 0;
-
-#ifdef CONFIG_MTD_NAND_GPMI_BCH
- if (bch)
- c1 |= BM_GPMI_CTRL1_BCH_MODE;
-#endif
- return c1;
-}
-
-/**
- * gpmi_nand_init_hw - Initialize the hardware.
- *
- * @pdev: A pointer to the owning platform device.
- * @request_pins: Indicates this function should request GPMI pins.
- *
- * Initialize GPMI hardware and set default (safe) timings for NAND access.
- * Returns error code or 0 on success
- */
-static int gpmi_nand_init_hw(struct platform_device *pdev, int request_pins)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
- struct gpmi_platform_data *gpd =
- (struct gpmi_platform_data *)pdev->dev.platform_data;
- int err = 0;
-
- /* Try to get the GPMI clock. */
-
- g->clk = clk_get(NULL, "gpmi");
- if (IS_ERR(g->clk)) {
- err = PTR_ERR(g->clk);
- dev_err(&pdev->dev, "Can't get GPMI clock\n");
- goto out;
- }
-
- /* Turn on the GPMI clock. */
-
- clk_enable(g->clk);
-
- /*
- * Check the clock rate setting. We don't allow this value to go below
- * 24KHz because some chips don't work in that regime.
- */
-
- if (clk <= 0)
- clk = 24000;
-
- /*
- * Set the GPMI clock rate and record the value that was actually
- * implemented.
- */
-
- clk_set_rate(g->clk, clk);
-
- clk = clk_get_rate(g->clk);
-
- /* Check if we're supposed to ask for our pins. */
-
- if (request_pins)
- gpd->pinmux_handler(1);
-
- /* Reset the GPMI block. */
-
- stmp3xxx_reset_block(HW_GPMI_CTRL0 + REGS_GPMI_BASE, 1);
-
- /* this CLEARS reset, despite of its name */
- __raw_writel(BM_GPMI_CTRL1_DEV_RESET,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_SET);
-
- /* IRQ polarity */
- __raw_writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_SET);
-
- /*
- * Select the ECC to use. The bch_mode() function returns a value that
- * selects whichever hardware is appropriate (q.v.).
- */
- __raw_writel(bch_mode(), REGS_GPMI_BASE + HW_GPMI_CTRL1_SET);
-
- /* Choose NAND mode (1 means ATA, 0 - NAND */
- __raw_writel(BM_GPMI_CTRL1_GPMI_MODE,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_CLR);
-
-out:
- return err;
-}
-
-/**
- * gpmi_nand_release_hw - free the hardware
- *
- * @pdev: pointer to platform device
- *
- * In opposite to gpmi_nand_init_hw, release all acquired resources.
- */
-static void gpmi_nand_release_hw(struct platform_device *pdev)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
- struct gpmi_platform_data *gpd =
- (struct gpmi_platform_data *)pdev->dev.platform_data;
-
- __raw_writel(BM_GPMI_CTRL0_SFTRST, REGS_GPMI_BASE + HW_GPMI_CTRL0_SET);
-
- clk_disable(g->clk);
- clk_put(g->clk);
- gpd->pinmux_handler(0);
-}
-
-/**
- * gpmi_dma_is_error -
- *
- * @g: Per-device data structure.
- */
-static int gpmi_dma_is_error(struct gpmi_nand_data *g)
-{
- /* u32 n = __raw_readl(g->dma_ch); */
-
- /* CURrent DMA command */
- u32 c = __raw_readl(REGS_APBH_BASE +
- HW_APBH_CHn_NXTCMDAR(g->cchip->dma_ch));
-
- if (c == g->cchip->error.handle) {
- pr_debug("%s: dma chain has reached error terminator\n",
- __func__);
- return -EIO;
- }
- return 0;
-}
-
-/**
- * gpmi_dma_exchange - Run DMA to exchange with NAND chip
- *
- * @g: Per-device data structure.
- * @d: DMA descriptor.
- *
- * Run DMA and wait for completion
- */
-static int gpmi_dma_exchange(struct gpmi_nand_data *g,
- struct stmp3xxx_dma_descriptor *d)
-{
- struct platform_device *pdev = g->dev;
- unsigned long timeout;
- int err;
-
- if (g->self_suspended)
- gpmi_self_wakeup(g);
- g->use_count++;
-
- if (!g->regulator) {
- g->regulator = regulator_get(&pdev->dev, "mmc_ssp-2");
- if (g->regulator && !IS_ERR(g->regulator))
- regulator_set_mode(g->regulator, REGULATOR_MODE_NORMAL);
- else
- g->regulator = NULL;
- }
-
- if (g->regulator)
- regulator_set_current_limit(g->regulator, g->reg_uA, g->reg_uA);
-
- init_completion(&g->done);
- stmp3xxx_dma_enable_interrupt(g->cchip->dma_ch);
- stmp3xxx_dma_go(g->cchip->dma_ch, d ? d : g->cchip->d, 1);
-
- timeout = wait_for_completion_timeout(&g->done, msecs_to_jiffies(1000));
- err = (timeout <= 0) ? -ETIMEDOUT : gpmi_dma_is_error(g);
-
- if (err)
- printk(KERN_ERR "%s: error %d, CS = %d, channel %d\n",
- __func__, err, g->cchip->cs, g->cchip->dma_ch);
-
- stmp3xxx_dma_reset_channel(g->cchip->dma_ch);
- stmp3xxx_dma_clear_interrupt(g->cchip->dma_ch);
-
- if (g->regulator)
- regulator_set_current_limit(g->regulator, 0, 0);
-
- mod_timer(&g->timer, jiffies + 4 * HZ);
- g->use_count--;
-
- return err;
-}
-
-/**
- * gpmi_ecc_read_page - Replacement for nand_read_page
- *
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- */
-static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t * buf)
-{
- struct gpmi_nand_data *g = chip->priv;
- struct mtd_ecc_stats stats;
- dma_addr_t bufphys, oobphys;
- int err;
-
- bufphys = oobphys = ~0;
-
- if (map_buffers && virt_addr_valid(buf))
- bufphys = dma_map_single(&g->dev->dev, buf,
- mtd->writesize, DMA_FROM_DEVICE);
- if (dma_mapping_error(&g->dev->dev, bufphys))
- bufphys = g->data_buffer_handle;
-
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_FROM_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys))
- oobphys = g->oob_buffer_handle;
-
- /* ECC read */
- (void)g->hc->read(g->hc, g->selected_chip, g->cchip->d,
- g->cchip->error.handle, bufphys, oobphys);
-
- err = gpmi_dma_exchange(g, NULL);
-
- g->hc->stat(g->hc, g->selected_chip, &stats);
-
- if (stats.failed || stats.corrected) {
-
- pr_debug("%s: ECC failed=%d, corrected=%d\n",
- __func__, stats.failed, stats.corrected);
-
- g->mtd.ecc_stats.failed += stats.failed;
- g->mtd.ecc_stats.corrected += stats.corrected;
- }
-
- if (!dma_mapping_error(&g->dev->dev, oobphys)) {
- if (oobphys != g->oob_buffer_handle)
- dma_unmap_single(&g->dev->dev, oobphys,
- mtd->oobsize, DMA_FROM_DEVICE);
- else {
- memcpy(chip->oob_poi, g->oob_buffer, mtd->oobsize);
- copies++;
- }
- }
-
- if (!dma_mapping_error(&g->dev->dev, bufphys)) {
- if (bufphys != g->data_buffer_handle)
- dma_unmap_single(&g->dev->dev, bufphys,
- mtd->writesize, DMA_FROM_DEVICE);
- else {
- memcpy(buf, g->data_buffer, mtd->writesize);
- copies++;
- }
- }
-
- /* always fill the (possible ECC bytes with FF) */
- memset(chip->oob_poi + g->oob_free, 0xff, mtd->oobsize - g->oob_free);
-
- return err;
-}
-
-/**
- * is_ff - Checks if all the bits in a buffer are set.
- *
- * @buffer: The buffer of interest.
- * @size: The size of the buffer.
- */
-static inline int is_ff(const u8 * buffer, size_t size)
-{
- while (size--) {
- if (*buffer++ != 0xff)
- return 0;
- }
- return 1;
-}
-
-/**
- * gpmi_ecc_write_page - replacement for nand_write_page
- *
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- */
-static void gpmi_ecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t * buf)
-{
- struct gpmi_nand_data *g = chip->priv;
- dma_addr_t bufphys, oobphys;
- int err;
-
- /* if we can't map it, copy it */
- bufphys = oobphys = ~0;
-
- if (map_buffers && virt_addr_valid(buf))
- bufphys = dma_map_single(&g->dev->dev,
- (void *)buf, mtd->writesize,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, bufphys)) {
- bufphys = g->data_buffer_handle;
- memcpy(g->data_buffer, buf, mtd->writesize);
- copies++;
- }
-
- /* if OOB is all FF, leave it as such */
- if (!is_ff(chip->oob_poi, mtd->oobsize) || bch_mode()) {
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys)) {
- oobphys = g->oob_buffer_handle;
- memcpy(g->oob_buffer, chip->oob_poi, mtd->oobsize);
- copies++;
- }
- } else
- ff_writes++;
-
- /* call ECC */
- g->hc->write(g->hc, g->selected_chip, g->cchip->d,
- g->cchip->error.handle, bufphys, oobphys);
-
- err = gpmi_dma_exchange(g, NULL);
- if (err < 0)
- printk(KERN_ERR "%s: dma error\n", __func__);
-
- if (!dma_mapping_error(&g->dev->dev, oobphys)) {
- if (oobphys != g->oob_buffer_handle)
- dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize,
- DMA_TO_DEVICE);
- }
-
- if (bufphys != g->data_buffer_handle)
- dma_unmap_single(&g->dev->dev, bufphys, mtd->writesize,
- DMA_TO_DEVICE);
-}
-
-/**
- * gpmi_write_buf - replacement for nand_write_buf
- *
- * @mtd: MTD device
- * @buf: data buffer
- * @len: length of the data buffer
- */
-static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t * buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct stmp3xxx_dma_descriptor *chain = g->cchip->d;
- dma_addr_t phys;
- int err;
-
- BUG_ON(len > mtd->writesize);
-
- phys = ~0;
-
- if (map_buffers && virt_addr_valid(buf))
- phys = dma_map_single(&g->dev->dev,
- (void *)buf, len, DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, phys)) {
- phys = g->write_buffer_handle;
- memcpy(g->write_buffer, buf, len);
- copies++;
- }
-
- /* Write plain data */
- chain->command->cmd =
- BF(len, APBH_CHn_CMD_XFER_COUNT) |
- BF(4, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(BV_APBH_CHn_CMD_COMMAND__DMA_READ, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WRITE, GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BM_GPMI_CTRL0_LOCK_CS |
- BF(g->selected_chip, GPMI_CTRL0_CS) |
- BF(BV_GPMI_CTRL0_ADDRESS__NAND_DATA, GPMI_CTRL0_ADDRESS) |
- BF(len, 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 = phys;
-
- err = gpmi_dma_exchange(g, NULL);
- if (err)
- printk(KERN_ERR "%s: dma error\n", __func__);
-
- if (phys != g->write_buffer_handle)
- dma_unmap_single(&g->dev->dev, phys, len, DMA_TO_DEVICE);
-
- if (debug >= 2)
- print_hex_dump_bytes("WBUF ", DUMP_PREFIX_OFFSET, buf, len);
-}
-
-/**
- * gpmi_read_buf - replacement for nand_read_buf
- *
- * @mtd: MTD device
- * @buf: pointer to the buffer
- * @len: size of the buffer
- */
-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t * buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct stmp3xxx_dma_descriptor *chain;
- dma_addr_t phys;
- int err;
-
- phys = ~0;
-
- if (map_buffers && virt_addr_valid(buf))
- phys = dma_map_single(&g->dev->dev, buf, len, DMA_FROM_DEVICE);
- if (dma_mapping_error(&g->dev->dev, phys))
- phys = g->read_buffer_handle;
-
- chain = g->cchip->d;
-
- /* read data */
- chain->command->cmd =
- BF(len, APBH_CHn_CMD_XFER_COUNT) |
- BF(1, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__DMA_WRITE, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__READ, GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BM_GPMI_CTRL0_LOCK_CS |
- BF(g->selected_chip, GPMI_CTRL0_CS) |
- BF(BV_GPMI_CTRL0_ADDRESS__NAND_DATA, GPMI_CTRL0_ADDRESS) |
- BF(len, GPMI_CTRL0_XFER_COUNT);
- chain->command->buf_ptr = phys;
- chain++;
-
- chain->command->cmd =
- BF(4, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDWAIT4READY |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY,
- GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(BV_GPMI_CTRL0_ADDRESS__NAND_DATA, GPMI_CTRL0_ADDRESS) |
- BM_GPMI_CTRL0_LOCK_CS | BF(g->selected_chip, GPMI_CTRL0_CS);
- chain->command->pio_words[1] =
- chain->command->pio_words[2] = chain->command->pio_words[3] = 0;
- chain->command->buf_ptr = 0;
-
- err = gpmi_dma_exchange(g, NULL);
- if (err)
- printk(KERN_ERR "%s: dma error\n", __func__);
-
- if (phys != g->read_buffer_handle)
- dma_unmap_single(&g->dev->dev, phys, len, DMA_FROM_DEVICE);
- else {
- memcpy(buf, g->read_buffer, len);
- copies++;
- }
-
- if (debug >= 2)
- print_hex_dump_bytes("RBUF ", DUMP_PREFIX_OFFSET, buf, len);
-}
-
-/**
- * gpmi_read_byte - replacement for nand_read_byte
- * @mtd: MTD device
- *
- * Uses gpmi_read_buf to read 1 byte from device
- */
-static u8 gpmi_read_byte(struct mtd_info *mtd)
-{
- u8 b;
-
- gpmi_read_buf(mtd, (uint8_t *) & b, 1);
- return b;
-}
-
-/**
- * gpmi_read_word - replacement for nand_read_word
- * @mtd: The owning MTD.
- *
- * Uses gpmi_read_buf to read 2 bytes from device
- */
-static u16 gpmi_read_word(struct mtd_info *mtd)
-{
- u16 w;
-
- gpmi_read_buf(mtd, (uint8_t *) & w, sizeof(u16));
- return w;
-}
-
-/**
- * gpmi_erase - Hook for erase operations at the MTD level.
- *
- * We install this function in the "erase" function pointer of the owning
- * struct mtd_info. Thus, this function will get called *instead* of the
- * function that the NAND Flash MTD system installed (see nand_erase()).
- *
- * We do this because, if an erase operation fails, then the block should be
- * marked bad. Unfortunately, the NAND Flash MTD code doesn't do this. Since
- * we've "hooked" the call, we can "override" the base NAND Flash MTD behavior
- * and make sure the proper marking gets done before we return to the
- * original caller.
- *
- * @mtd: MTD device
- * @instr: erase instruction
- */
-int gpmi_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
- int rc;
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct gpmi_nand_data *data = platform_get_drvdata(g->dev);
-
- if (g->self_suspended)
- gpmi_self_wakeup(data);
- g->use_count++;
-
- rc = nand_erase_nand(mtd, instr, 0);
-
- if (rc == -EIO) /* block cannot be erased */
- gpmi_block_mark_as(chip,
- (instr->addr >> chip->bbt_erase_shift),
- 0x01);
-
- mod_timer(&g->timer, jiffies + 4 * HZ);
- g->use_count--;
- return rc;
-}
-
-/**
- * gpmi_dev_ready - Wait until the medium is ready.
- *
- * This function is supposed to return the instantaneous state of the medium.
- * Instead, it actually waits for the medium to be ready. This is mostly
- * harmless, but isn't actually correct.
- *
- * @mtd: The owning MTD.
- */
-static int gpmi_dev_ready(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct stmp3xxx_dma_descriptor *chain = g->cchip->d;
- int ret;
-
- /* wait for ready */
- chain->command->cmd =
- BF(4, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDWAIT4READY |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY,
- GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(BV_GPMI_CTRL0_ADDRESS__NAND_DATA,
- GPMI_CTRL0_ADDRESS) | BF(g->selected_chip, 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++;
-
- ret = gpmi_dma_exchange(g, NULL);
- if (ret != 0)
- printk(KERN_ERR "gpmi: gpmi_dma_exchange() timeout!\n");
- return ret == 0;
-}
-
-/**
- * gpmi_hwcontrol - Send command/address byte to the NAND Flash.
- *
- * 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.
- * @cmd: The command byte.
- * @ctrl: Control flags.
- */
-static void gpmi_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct stmp3xxx_dma_descriptor *chain = g->cchip->d;
- int ret;
-
- /*
- * Every operation begins with a series of command and address bytes,
- * which are distinguished by either the Address Latch Enable (ALE) or
- * Command Latch Enable (CLE) being asserted. Finally, when the caller
- * is actually ready to execute the command, he 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 (cmd != NAND_CMD_NONE)
- g->cmd_buffer[g->cmd_buffer_sz++] = cmd;
- return;
- }
-
- /*
- * If control arrives here, the caller has deasserted both the ALE and
- * CLE, which means he's ready to run an operation. Check if we actually
- * have any bytes to send.
- */
-
- if (g->cmd_buffer_sz == 0)
- return;
-
- /* output command */
- chain->command->cmd =
- BF(g->cmd_buffer_sz, APBH_CHn_CMD_XFER_COUNT) |
- BF(3, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__DMA_READ, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WRITE, GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BM_GPMI_CTRL0_LOCK_CS |
- BF(g->selected_chip, GPMI_CTRL0_CS) |
- BF(BV_GPMI_CTRL0_ADDRESS__NAND_CLE, GPMI_CTRL0_ADDRESS) |
- BF(g->cmd_buffer_sz, GPMI_CTRL0_XFER_COUNT);
- if (g->cmd_buffer_sz > 0)
- chain->command->pio_words[0] |= BM_GPMI_CTRL0_ADDRESS_INCREMENT;
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] = 0;
- chain->command->buf_ptr = g->cmd_buffer_handle;
- chain++;
-
- /* emit IRQ */
- chain->command->cmd =
- BF(0, APBH_CHn_CMD_CMDWORDS) |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD;
- chain++;
-
- /* last in chain get the irq bit set */
- chain[-1].command->cmd |= BM_APBH_CHn_CMD_IRQONCMPLT;
-
- if (debug >= 3)
- print_hex_dump(KERN_INFO, "CMD ", DUMP_PREFIX_OFFSET, 16, 1,
- g->cmd_buffer, g->cmd_buffer_sz, 1);
-
- ret = gpmi_dma_exchange(g, NULL);
- if (ret != 0) {
- printk(KERN_ERR "%s: chip %d, dma error %d on the command:\n",
- __func__, g->selected_chip, ret);
- print_hex_dump(KERN_INFO, "CMD ", DUMP_PREFIX_OFFSET, 16, 1,
- g->cmd_buffer, g->cmd_buffer_sz, 1);
- }
-
- gpmi_dev_ready(mtd);
-
- g->cmd_buffer_sz = 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_nand_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 * 2,
- &g->write_buffer_handle, GFP_DMA);
- if (!g->write_buffer)
- goto out2;
-
- g->read_buffer = g->write_buffer + g->write_buffer_size;
- g->read_buffer_handle = g->write_buffer_handle + g->write_buffer_size;
-
- 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->verify_buffer = kzalloc(2 * (g->data_buffer_size +
- g->oob_buffer_size), GFP_KERNEL);
- if (!g->verify_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 * 2,
- 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_nand_data *g)
-{
- kfree(g->verify_buffer);
- 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 * 2,
- 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->data_buffer_size,
- g->data_buffer, g->data_buffer_handle);
-}
-
-/* only used in SW-ECC or NO-ECC cases */
-static int gpmi_verify_buf(struct mtd_info *mtd, const uint8_t * buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
-
- chip->read_buf(mtd, g->verify_buffer, len);
-
- if (memcmp(buf, g->verify_buffer, len))
- return -EFAULT;
-
- return 0;
-}
-
-/**
- * gpmi_ecc_read_oob - replacement for nand_read_oob
- *
- * @mtd: MTD device
- * @chip: mtd->priv
- * @page: page address
- * @sndcmd: flag indicates that command should be sent
- */
-int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page, int sndcmd)
-{
- struct gpmi_nand_data *g = chip->priv;
- loff_t oob_offset = 0;
- struct mtd_ecc_stats stats;
- dma_addr_t bufphys, oobphys;
- int ecc;
- int ret;
-
- ecc = g->raw_oob_mode == 0 && raw_mode == 0;
-
- if (sndcmd) {
- if (!bch_mode() || !ecc)
- oob_offset = mtd->writesize;
- if (likely(ecc) && !bch_mode())
- oob_offset += chip->ecc.bytes * chip->ecc.steps;
- chip->cmdfunc(mtd, NAND_CMD_READ0, oob_offset, page);
- sndcmd = 0;
- }
-
- if (unlikely(!ecc)) {
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- return 1;
- }
-
- oobphys = ~0;
-
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_FROM_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys))
- oobphys = g->oob_buffer_handle;
-
- bufphys = ~0;
-
- if (map_buffers && bch_mode())
- bufphys = dma_map_single(&g->dev->dev, chip->buffers->databuf,
- mtd->writesize, DMA_FROM_DEVICE);
- if (bch_mode() && dma_mapping_error(&g->dev->dev, bufphys))
- bufphys = g->data_buffer_handle;
-
- /* ECC read */
- (void)g->hc->read(g->hc, g->selected_chip, g->cchip->d,
- g->cchip->error.handle, bufphys, oobphys);
-
- ret = gpmi_dma_exchange(g, NULL);
-
- g->hc->stat(g->hc, g->selected_chip, &stats);
-
- if (stats.failed || stats.corrected) {
-
- printk(KERN_DEBUG "%s: ECC failed=%d, corrected=%d\n",
- __func__, stats.failed, stats.corrected);
-
- g->mtd.ecc_stats.failed += stats.failed;
- g->mtd.ecc_stats.corrected += stats.corrected;
- }
-
- if (oobphys != g->oob_buffer_handle)
- dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize,
- DMA_FROM_DEVICE);
- else {
- memcpy(chip->oob_poi, g->oob_buffer, mtd->oobsize);
- copies++;
- }
-
- if (bufphys != g->data_buffer_handle)
- dma_unmap_single(&g->dev->dev, bufphys, mtd->writesize,
- DMA_FROM_DEVICE);
-
-
- /* fill rest with ff */
- memset(chip->oob_poi + g->oob_free, 0xff, mtd->oobsize - g->oob_free);
-
- return ret ? ret : 1;
-}
-
-/**
- * gpmi_ecc_write_oob - replacement for nand_write_oob
- *
- * @mtd: MTD device
- * @chip: mtd->priv
- * @page: page address
- */
-static int gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
-{
- int status = 0;
- struct gpmi_nand_data *g = chip->priv;
- loff_t oob_offset = 0;
- dma_addr_t oobphys, bufphys;
- int ecc;
- int err = 0;
-
- /* if OOB is all FF, leave it as such */
- if (is_ff(chip->oob_poi, mtd->oobsize)) {
- ff_writes++;
-
- pr_debug("%s: Skipping an empty page 0x%x (0x%x)\n",
- __func__, page, page << chip->page_shift);
- return 0;
- }
-
- ecc = g->raw_oob_mode == 0 && raw_mode == 0;
-
- /* Send command to start input data */
- if (!bch_mode() || !ecc) {
- oob_offset = mtd->writesize;
- if (likely(ecc)) {
- oob_offset += chip->ecc.bytes * chip->ecc.steps;
- memset(chip->oob_poi + g->oob_free, 0xff,
- mtd->oobsize - g->oob_free);
- }
- }
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, oob_offset, page);
-
- /* call ECC */
- if (likely(ecc)) {
-
- oobphys = ~0;
-
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys)) {
- oobphys = g->oob_buffer_handle;
- memcpy(g->oob_buffer, chip->oob_poi, mtd->oobsize);
- copies++;
- }
-
- bufphys = ~0;
-
- if (bch_mode()) {
- bufphys = g->data_buffer_handle;
- memset(g->data_buffer, 0xff, mtd->writesize);
- }
-
- g->hc->write(g->hc, g->selected_chip, g->cchip->d,
- g->cchip->error.handle, bufphys, oobphys);
-
- err = gpmi_dma_exchange(g, NULL);
- } else
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
- /* Send command to program the OOB data */
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-
- /* ..and wait for result */
- status = chip->waitfunc(mtd, chip);
-
- if (likely(ecc)) {
- if (oobphys != g->oob_buffer_handle)
- dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize,
- DMA_TO_DEVICE);
- }
-
- if (status & NAND_STATUS_FAIL) {
- pr_debug("%s: NAND_STATUS_FAIL\n", __func__);
- return -EIO;
- }
-
- return err;
-}
-
-/**
- * gpmi_irq - IRQ handler
- *
- * @irq: Interrupt number.
- * @context: IRQ context, pointer to gpmi_nand_data
- */
-static irqreturn_t gpmi_irq(int irq, void *context)
-{
- struct gpmi_nand_data *g = context;
-
- if (stmp3xxx_dma_is_interrupt(g->cchip->dma_ch)) {
- stmp3xxx_dma_clear_interrupt(g->cchip->dma_ch);
- complete(&g->done);
- }
- __raw_writel(BM_GPMI_CTRL1_DEV_IRQ | BM_GPMI_CTRL1_TIMEOUT_IRQ,
- REGS_GPMI_BASE + HW_GPMI_CTRL1_CLR);
- return IRQ_HANDLED;
-}
-
-/**
- * gpmi_select_chip() - NAND Flash MTD Interface select_chip()
- *
- * @mtd: A pointer to the owning MTD.
- * @chipnr: The chip number to select, or -1 to select no chip.
- */
-static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
-
- if (chipnr == g->selected_chip)
- return;
-
- g->selected_chip = chipnr;
- g->cchip = NULL;
-
- if (chipnr == -1)
- return;
-
- g->cchip = g->chips + chipnr;
-}
-
-/**
- * gpmi_command() - NAND Flash MTD Interface cmdfunc()
- *
- * This function is a veneer that calls the function originally installed by the
- * NAND Flash MTD code.
- *
- * @mtd: A pointer to the owning MTD.
- * @command: The command code.
- * @column: The column address associated with this command code, or -1 if
- * no column address applies.
- * @page_addr: The page address associated with this command code, or -1 if no
- * page address applies.
- */
-static void gpmi_command(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr)
-{
- register struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
-
- g->saved_command(mtd, command, column, page_addr);
-}
-
-/**
- * gpmi_read_oob() - MTD Interface read_oob().
- *
- * This function is a veneer that replaces the function originally installed by
- * the NAND Flash MTD code.
- *
- * @mtd: A pointer to the MTD.
- * @from: The starting address to read.
- * @ops: Describes the operation.
- */
-static int gpmi_read_oob(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops)
-{
- register struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- int ret;
-
- g->raw_oob_mode = ops->mode == MTD_OOB_RAW;
- ret = g->saved_read_oob(mtd, from, ops);
- g->raw_oob_mode = 0;
- return ret;
-}
-
-/**
- * gpmi_read_oob() - MTD Interface write_oob().
- *
- * This function is a veneer that replaces the function originally installed by
- * the NAND Flash MTD code.
- *
- * @mtd: A pointer to the MTD.
- * @to: The starting address to write.
- * @ops: Describes the operation.
- */
-static int gpmi_write_oob(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops)
-{
- register struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- int ret;
-
- g->raw_oob_mode = ops->mode == MTD_OOB_RAW;
- ret = g->saved_write_oob(mtd, to, ops);
- g->raw_oob_mode = 0;
- return ret;
-}
-
-/**
- * gpmi_write_page - [REPLACEABLE] write one page
- * @mtd: MTD device structure
- * @chip: NAND chip descriptor
- * @buf: the data to write
- * @page: page number to write
- * @cached: cached programming
- * @raw: use _raw version of write_page
- */
-static int gpmi_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t * buf, int page, int cached, int raw)
-{
- struct gpmi_nand_data *g = chip->priv;
- int status, empty_data, empty_oob;
- int oobsz;
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- void *vbuf, *obuf;
-#if 0
- void *voob, *ooob;
-#endif
-#endif
-
- oobsz = likely(g->raw_oob_mode == 0 && raw_mode == 0) ?
- g->oob_free : mtd->oobsize;
-
- empty_data = is_ff(buf, mtd->writesize);
- empty_oob = is_ff(buf, oobsz);
-
- if (empty_data && empty_oob) {
- ff_writes++;
-
- pr_debug("%s: Skipping an empty page 0x%x (0x%x)\n",
- __func__, page, page << chip->page_shift);
- return 0;
- }
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-
- if (likely(raw == 0))
- chip->ecc.write_page(mtd, chip, buf);
- else
- chip->ecc.write_page_raw(mtd, chip, buf);
-
- /*
- * Cached progamming disabled for now, Not sure if its worth the
- * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
- */
- cached = 0;
-
- if (!cached || !(chip->options & NAND_CACHEPRG)) {
-
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-
- status = chip->waitfunc(mtd, chip);
-
- /*
- * See if operation failed and additional status checks are
- * available
- */
- if ((status & NAND_STATUS_FAIL) && (chip->errstat))
- status = chip->errstat(mtd, chip, FL_WRITING, status,
- page);
-
- if (status & NAND_STATUS_FAIL) {
- pr_debug("%s: NAND_STATUS_FAIL\n", __func__);
- return -EIO;
- }
- } else {
- chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
- }
-
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- if (empty_data)
- return 0;
-
- obuf = g->verify_buffer;
-#if 1 /* make vbuf aligned by mtd->writesize */
- vbuf = obuf + mtd->writesize;
-#else
- ooob = obuf + mtd->writesize;
- vbuf = ooob + mtd->oobsize;
- voob = vbuf + mtd->writesize;
-#endif
-
- /* keep data around */
- memcpy(obuf, buf, mtd->writesize);
-#if 0
- memcpy(ooob, chip->oob_poi, oobsz);
-#endif
- /* Send command to read back the data */
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- if (likely(raw == 0))
- chip->ecc.read_page(mtd, chip, vbuf);
- else
- chip->ecc.read_page_raw(mtd, chip, vbuf);
-
-#if 0
- memcpy(voob, chip->oob_poi, oobsz);
-#endif
-
- if (!empty_data && memcmp(obuf, vbuf, mtd->writesize) != 0)
- return -EIO;
-#endif
-
- return 0;
-}
-
-/**
- * gpmi_read_page_raw - [Intern] read raw page data without ecc
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- */
-static int gpmi_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t * buf)
-{
- chip->read_buf(mtd, buf, mtd->writesize);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- return 0;
-}
-
-/**
- * gpmi_write_page_raw - [Intern] raw page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- */
-static void gpmi_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t * buf)
-{
- chip->write_buf(mtd, buf, mtd->writesize);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-}
-
-/**
- * gpmi_init_chip - Sets up the driver to control the given chip.
- *
- * @pdev: A pointer to the owning struct platform_device.
- * @g: Per-device data.
- * @n: The chip number.
- * @dma_ch: The DMA channel to use with this chip.
- */
-static int gpmi_init_chip(struct platform_device *pdev,
- struct gpmi_nand_data *g, int n, unsigned dma_ch)
-{
- int err;
-
- g->chips[n].dma_ch = dma_ch;
- g->chips[n].cs = n;
-
- err = stmp3xxx_dma_request(dma_ch, NULL, dev_name(&pdev->dev));
- if (err) {
- dev_err(&pdev->dev, "can't request DMA channel 0x%x\n", dma_ch);
- goto out_all;
- }
-
- err = stmp3xxx_dma_make_chain(dma_ch,
- &g->chips[n].chain,
- g->chips[n].d, ARRAY_SIZE(g->chips[n].d));
- if (err) {
- dev_err(&pdev->dev, "can't setup DMA chain\n");
- goto out_all;
- }
-
- err = stmp3xxx_dma_allocate_command(dma_ch, &g->chips[n].error);
- if (err) {
- dev_err(&pdev->dev, "can't setup DMA chain\n");
- goto out_all;
- }
-
- g->chips[n].error.command->cmd =
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
-out_all:
- return err;
-}
-
-/**
- * gpmi_deinit_chip - Tears down this driver's control of the given chip.
- *
- * @pdev: A pointer to the owning struct platform_device.
- * @g: Per-device data.
- * @n: The chip number.
- */
-static void gpmi_deinit_chip(struct platform_device *pdev,
- struct gpmi_nand_data *g, int n)
-{
- int dma_ch;
-
- if (n < 0) {
- for (n = 0; n < ARRAY_SIZE(g->chips); n++)
- gpmi_deinit_chip(pdev, g, n);
- return;
- }
-
- if (g->chips[n].dma_ch <= 0)
- return;
-
- dma_ch = g->chips[n].dma_ch;
-
- stmp3xxx_dma_free_command(dma_ch, &g->chips[n].error);
- stmp3xxx_dma_free_chain(&g->chips[n].chain);
- stmp3xxx_dma_release(dma_ch);
-}
-
-/**
- * gpmi_get_device_info() - Get information about the NAND Flash devices.
- *
- * @g: Per-device data.
- */
-static int gpmi_get_device_info(struct gpmi_nand_data *g)
-{
- unsigned i;
- uint8_t id_bytes[NAND_DEVICE_ID_BYTE_COUNT];
- struct mtd_info *mtd = &g->mtd;
- struct nand_chip *nand = &g->nand;
- struct nand_device_info *info;
-
- /* Read ID bytes from the first NAND Flash chip. */
-
- nand->select_chip(mtd, 0);
-
- gpmi_command(mtd, NAND_CMD_READID, 0x00, -1);
-
- for (i = 0; i < NAND_DEVICE_ID_BYTE_COUNT; i++)
- id_bytes[i] = nand->read_byte(mtd);
-
- /* Get 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;
- }
-
- /*
- * Copy the device info into the per-device data. We can't just keep
- * the pointer because that storage is reclaimed after initialization.
- */
-
- g->device_info = *info;
-
- /* Display the information we got. */
-
- nand_device_print_info(&g->device_info);
-
- /* Return success. */
-
- return 0;
-
-}
-
-/**
- * gpmi_scan_middle - Intermediate initialization.
- *
- * @g: Per-device data structure.
- *
- * Rather than call nand_scan(), this function makes the same calls, but
- * inserts this function into the initialization pathway.
- */
-static int gpmi_scan_middle(struct gpmi_nand_data *g)
-{
- struct mtd_info *mtd = &g->mtd;
- struct nand_chip *nand = &g->nand;
- struct nand_device_info *info = &g->device_info;
- int index = 0;
- uint64_t physical_medium_size_in_bytes;
- uint64_t logical_medium_size_in_bytes;
- uint64_t logical_chip_size_in_bytes;
- uint32_t page_data_size_in_bytes;
- uint32_t page_oob_size_in_bytes;
-
- /*
- * Hook the command function provided by the reference implementation.
- * This has to be done here, rather than at initialization time, because
- * the NAND Flash MTD installed the reference implementation only just
- * now.
- */
-
- g->saved_command = nand->cmdfunc;
- nand->cmdfunc = gpmi_command;
-
- /* Identify the NAND Flash devices. */
-
- if (gpmi_get_device_info(g))
- return -ENXIO;
-
- /* Update timings. */
-
- gpmi_set_timings(g, 0);
-
- /*
- * Compute some important facts about the medium.
- *
- * Note that we don't yet support a medium of size larger than 2 GiB. If
- * we find the physical medium is too large, then we pretend it's
- * smaller.
- */
-
- physical_medium_size_in_bytes =
- nand->numchips * info->chip_size_in_bytes;
-
- if (physical_medium_size_in_bytes > (2LL*SZ_1G)) {
- logical_medium_size_in_bytes = 2LL*SZ_1G;
- logical_chip_size_in_bytes = 2LL*SZ_1G;
- do_div(logical_chip_size_in_bytes, nand->numchips);
-
- } else {
- logical_medium_size_in_bytes = physical_medium_size_in_bytes;
- logical_chip_size_in_bytes = info->chip_size_in_bytes;
- }
-
- page_data_size_in_bytes = 1 << (fls(info->page_total_size_in_bytes)-1);
- page_oob_size_in_bytes = info->page_total_size_in_bytes -
- page_data_size_in_bytes;
-
- /*
- * In all currently-supported geometries, the number of ECC bytes that
- * apply to the OOB bytes is the same.
- */
-
- g->ecc_oob_bytes = 9;
-
- /* Configure ECC. */
-
- switch (page_data_size_in_bytes) {
- case 2048:
- nand->ecc.layout = &gpmi_oob_64;
- nand->ecc.bytes = 9;
- g->oob_free = 19;
- g->hwecc_type_read = GPMI_ECC4_RD;
- g->hwecc_type_write = GPMI_ECC4_WR;
- break;
- case 4096:
- nand->ecc.layout = &gpmi_oob_128;
- nand->ecc.bytes = 18;
- g->oob_free = 65;
- g->hwecc_type_read = GPMI_ECC8_RD;
- g->hwecc_type_write = GPMI_ECC8_WR;
- break;
- default:
- printk(KERN_ERR "Unsupported page data size %d.",
- page_data_size_in_bytes);
- return -ENXIO;
- break;
- }
-
- mtd->ecclayout = nand->ecc.layout;
-
- /* Configure the MTD geometry. */
-
- mtd->size = logical_medium_size_in_bytes;
- mtd->erasesize = info->block_size_in_pages * page_data_size_in_bytes;
- mtd->writesize = page_data_size_in_bytes;
- mtd->oobavail = mtd->ecclayout->oobavail;
- mtd->oobsize = page_oob_size_in_bytes;
- mtd->subpage_sft = 0; /* We don't support sub-page writing. */
-
- /* Configure the struct nand_chip geometry. */
-
- nand->chipsize = logical_chip_size_in_bytes;
- nand->page_shift = ffs(page_data_size_in_bytes) - 1;
- nand->pagemask = (nand->chipsize >> nand->page_shift) - 1;
- nand->subpagesize = mtd->writesize >> mtd->subpage_sft;
- nand->phys_erase_shift = ffs(mtd->erasesize) - 1;
- nand->bbt_erase_shift = nand->phys_erase_shift;
- nand->chip_shift = ffs(nand->chipsize) - 1;
-
- /* Sanity check */
-
- if (mtd->oobsize > NAND_MAX_OOBSIZE ||
- mtd->writesize > NAND_MAX_PAGESIZE) {
- printk(KERN_ERR "Internal error. Either page size "
- "(%d) > max (%d) "
- "or oob size (%d) > max(%d). Sorry.\n",
- mtd->oobsize, NAND_MAX_OOBSIZE,
- mtd->writesize, NAND_MAX_PAGESIZE);
- return -ERANGE;
- }
-
- /* Install the ECC. */
-
- g->hc = gpmi_ecc_find("bch");
- for (index = 0; index < nand->numchips; index++)
- g->hc->setup(g->hc, index, mtd->writesize, mtd->oobsize);
-
- /* Return success. */
-
- return 0;
-
-}
-
-/**
- * gpmi_register_with_mtd - Registers devices with MTD.
- *
- * @g: Per-device data.
- */
-static int gpmi_register_with_mtd(struct gpmi_nand_data *g)
-{
-#if defined(CONFIG_MTD_PARTITIONS) && defined(CONFIG_MTD_CONCAT)
- int r;
- unsigned i;
- struct gpmi_platform_data *gpd = g->gpd;
- struct mtd_info *mtd = &g->mtd;
- struct nand_chip *nand = &g->nand;
- struct mtd_partition partitions[4];
- struct mtd_info *search_mtd;
- struct mtd_info *gpmi_0_remainder_mtd = 0;
- struct mtd_info *gpmi_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 table to find the MTDs we created. Since we're using
- * static strings, we can search the master table for an MTD with a name
- * field pointing to a known address.
- */
-
- static char *gpmi_0_boot_name = "gpmi-0-boot";
- static char *gpmi_0_remainder_name = "gpmi-0-remainder";
- static char *gpmi_1_boot_name = "gpmi-1-boot";
- static char *gpmi_remainder_name = "gpmi-remainder";
- static char *gpmi_general_use_name = "gpmi-general-use";
-#endif
-
- /* Initialize the MTD object. */
-
- mtd->priv = &g->nand;
- mtd->name = "gpmi-medium";
- mtd->owner = THIS_MODULE;
-
- /*
- * Signal Control
- */
-
- g->nand.cmd_ctrl = gpmi_hwcontrol;
-
- /*
- * Chip Control
- *
- * The cmdfunc pointer is assigned elsewhere.
- * We use the reference implementation of waitfunc.
- */
-
- g->nand.dev_ready = gpmi_dev_ready;
- g->nand.select_chip = gpmi_select_chip;
-
- /*
- * Low-level I/O
- */
-
- g->nand.read_byte = gpmi_read_byte;
- g->nand.read_word = gpmi_read_word;
- g->nand.read_buf = gpmi_read_buf;
- g->nand.write_buf = gpmi_write_buf;
- g->nand.verify_buf = gpmi_verify_buf;
-
- /*
- * ECC Control
- *
- * None of these functions are necessary:
- * - ecc.hwctl
- * - ecc.calculate
- * - ecc.correct
- */
-
- /*
- * ECC-aware I/O
- */
-
- g->nand.ecc.read_page = gpmi_ecc_read_page;
- g->nand.ecc.read_page_raw = gpmi_read_page_raw;
- g->nand.ecc.write_page = gpmi_ecc_write_page;
- g->nand.ecc.write_page_raw = gpmi_write_page_raw;
-
- /*
- * High-level I/O
- *
- * This driver doesn't assign the erase_cmd pointer at the NAND Flash
- * chip level. Instead, it intercepts the erase operation at the MTD
- * level (see the assignment to mtd.erase below).
- */
-
- g->nand.write_page = gpmi_write_page;
- g->nand.ecc.read_oob = gpmi_ecc_read_oob;
- g->nand.ecc.write_oob = gpmi_ecc_write_oob;
-
- /*
- * Bad Block Management
- *
- * We use the reference implementation of block_markbad.
- */
-
- g->nand.block_bad = gpmi_block_bad;
- g->nand.scan_bbt = gpmi_scan_bbt;
-
- g->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
- g->nand.ecc.size = 512;
-
- g->cmd_buffer_sz = 0;
-
- /*
- * We now want the NAND Flash MTD system to scan for chips and create
- * the MTD data structure that represents the medium.
- *
- * At this point, most drivers would call nand_scan(). Instead, this
- * driver directly performs most of the same operations nand_scan()
- * would, and introduces some additional initialization work in the
- * "middle."
- */
-
- pr_info("Scanning for NAND Flash chips...\n");
-
- if (nand_scan_ident(&g->mtd, max_chips)
- || gpmi_scan_middle(g)
- || nand_scan_tail(&g->mtd)) {
-
- /*
- * If control arrives here, something went wrong.
- */
-
- dev_err(&g->dev->dev, "No NAND Flash chips found\n");
- return !0;
-
- }
-
- /* Completely disallow partial page writes. */
-
- g->nand.options |= NAND_NO_SUBPAGE_WRITE;
- g->nand.subpagesize = g->mtd.writesize;
- g->mtd.subpage_sft = 0;
-
- /* Hook erase operations at the MTD level. */
-
- g->mtd.erase = gpmi_erase;
-
- /* Hook OOB read and write operations at the MTD level. */
-
- g->saved_read_oob = g->mtd.read_oob;
- g->saved_write_oob = g->mtd.write_oob;
- g->mtd.read_oob = gpmi_read_oob;
- g->mtd.write_oob = gpmi_write_oob;
-
-#if !defined(CONFIG_MTD_PARTITIONS) || !defined(CONFIG_MTD_CONCAT)
-
- /*
- * If control arrives here, we're missing support for either or both of
- * MTD partitioning and concatenation. Do the simple thing and register
- * the entire medium.
- */
-
- pr_info("MTD partitioning and/or concatenation are disabled.\n"
- "Registering the entire GPMI medium...\n");
-
- add_mtd_device(g->mtd);
-
-#else
-
- /*
- * Our goal here is to partition the medium in a way that protects the
- * boot area. First, check if the platform data says we need to
- * protect it.
- */
-
- if (!gpd->boot_area_size_in_bytes) {
-
- /*
- * If control arrives here, we don't need to protect the boot
- * area. Make the entire medium available for general use.
- */
-
- pr_info("Boot area protection disabled.\n"
- "Opening the entire medium for general use.\n");
-
- g->general_use_mtd = mtd;
-
- } else {
-
- pr_info("Boot area protection enabled: 0x%x bytes.\n",
- gpd->boot_area_size_in_bytes);
-
- /*
- * If control arrives here, we need to protect the boot area.
- * First, check if the area we're supposed to protect is larger
- * than a single chip.
- */
-
- if (gpd->boot_area_size_in_bytes > nand->chipsize) {
- dev_emerg(&g->dev->dev, "Protected boot area size is "
- "larger than a single chip");
- BUG();
- }
-
- /*
- * Recall that the boot ROM uses the first part of chip one and,
- * if it exists, also the first part of chip two. We check now
- * to see how many chips there are, and adjust our partitioning
- * accordingly.
- */
-
- g->chip0_boot_mtd = 0;
- g->chip1_boot_mtd = 0;
-
- if (nand->numchips == 1) {
-
- pr_info("Partitioning for one chip.\n");
-
- /*
- * If control arrives here, there's only one chip. We
- * partition the medium like so:
- *
- * +------+-------------------------------------------+
- * | Boot | General Use |
- * +------+-------------------------------------------+
- */
-
- /* Chip 0 Boot */
-
- partitions[0].name = gpmi_0_boot_name;
- partitions[0].offset = 0;
- partitions[0].size = gpd->boot_area_size_in_bytes;
- partitions[0].mask_flags = 0;
-
- /* General Use */
-
- partitions[1].name = gpmi_general_use_name;
- partitions[1].offset = gpd->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 == gpmi_general_use_name)
- g->general_use_mtd = search_mtd;
- }
-
- if (!g->general_use_mtd) {
- dev_emerg(&g->dev->dev, "Can't find general "
- "use MTD");
- BUG();
- }
-
- } else {
-
- pr_info("Partitioning for multiple chips.\n");
-
- /*
- * 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 we do something just a little goofy here.
- * Instead of numbering these partitions in the order
- * they appear in the medium, we have them in this
- * order:
- *
- * * Chip 0 Boot Area
- * * Chip 1 Boot Area
- * * Chip 0 Remainder
- * * Medium Remainder
- *
- * Before 2.6.31, it was possible to "hide" partitions
- * (to create them without registering them), which made
- * it possible to hide the remainders. In the future, it
- * may become possible to do so again. Also, 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 = gpmi_0_boot_name;
- partitions[0].offset = 0;
- partitions[0].size = gpd->boot_area_size_in_bytes;
- partitions[0].mask_flags = 0;
-
- /* Chip 1 Boot */
-
- partitions[1].name = gpmi_1_boot_name;
- partitions[1].offset = nand->chipsize;
- partitions[1].size = gpd->boot_area_size_in_bytes;
- partitions[1].mask_flags = 0;
-
- /* Chip 0 Remainder */
-
- partitions[2].name = gpmi_0_remainder_name;
- partitions[2].offset = gpd->boot_area_size_in_bytes;
- partitions[2].size = nand->chipsize -
- gpd->boot_area_size_in_bytes;
- partitions[2].mask_flags = 0;
-
- /* Medium Remainder */
-
- partitions[3].name = gpmi_remainder_name;
- partitions[3].offset = nand->chipsize +
- gpd->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 == gpmi_0_remainder_name)
- gpmi_0_remainder_mtd = search_mtd;
- if (search_mtd->name == gpmi_remainder_name)
- gpmi_remainder_mtd = search_mtd;
- }
-
- if (!gpmi_0_remainder_mtd || !gpmi_remainder_mtd) {
- dev_emerg(&g->dev->dev, "Can't find remainder "
- "partitions");
- BUG();
- }
-
- /* Concatenate the remainders and register. */
-
- concatenate[0] = gpmi_0_remainder_mtd;
- concatenate[1] = gpmi_remainder_mtd;
-
- g->general_use_mtd = mtd_concat_create(concatenate,
- 2, "gpmi-general-use");
-
- add_mtd_device(g->general_use_mtd);
-
- }
-
- }
-
- /*
- * When control arrives here, we've done whatever partitioning and
- * concatenation we needed to protect the boot area, and we have
- * identified a single MTD that represents the "general use" portion of
- * the medium. Check if the user wants to partition the general use MTD
- * further.
- */
-
- /* Check for dynamic partitioning information. */
-
- if (gpd->partition_source_types) {
- r = parse_mtd_partitions(mtd, gpd->partition_source_types,
- &g->partitions, 0);
- if (r > 0)
- g->partition_count = r;
- else {
- g->partitions = 0;
- g->partition_count = 0;
- }
- }
-
- /* Fall back to platform partitions? */
-
- if (!g->partition_count && gpd->partitions && gpd->partition_count) {
- g->partitions = gpd->partitions;
- g->partition_count = gpd->partition_count;
- }
-
- /* If we have partitions, implement them. */
-
- if (g->partitions) {
- pr_info("Applying partitions to the general use area.\n");
- add_mtd_partitions(g->general_use_mtd,
- g->partitions, g->partition_count);
- }
-
- /*
- * Check if we're supposed to register the MTD that represents
- * the entire medium.
- */
-
- if (add_mtd_entire) {
- pr_info("Registering the full NAND Flash medium MTD.\n");
- add_mtd_device(mtd);
- }
-
-#endif
-
- /* If control arrives here, everything went well. */
-
- return 0;
-
-}
-
-/**
- * gpmi_unregister_with_mtd - Unregisters devices with MTD.
- *
- * @g: Per-device data.
- */
-static void gpmi_unregister_with_mtd(struct gpmi_nand_data *g)
-{
-#if defined(CONFIG_MTD_PARTITIONS) && defined(CONFIG_MTD_CONCAT)
- struct gpmi_platform_data *gpd = g->gpd;
- struct mtd_info *mtd = &g->mtd;
- struct nand_chip *nand = &g->nand;
-#endif
-
- /*
- * This function mirrors, in reverse, the structure of
- * gpmi_register_with_mtd(). See that function for details about how we
- * partition the medium.
- */
-
-#if !defined(CONFIG_MTD_PARTITIONS) || !defined(CONFIG_MTD_CONCAT)
-
- del_mtd_device(mtd);
-
-#else
-
- /*
- * If we registered 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 (add_mtd_entire)
- del_mtd_device(mtd);
-
- /* If we partitioned the general use MTD, destroy the partitions. */
-
- if (g->partitions)
- del_mtd_partitions(g->general_use_mtd);
-
- /*
- * If we're protecting the boot area, we have some additional MTDs to
- * tear down.
- */
-
- if (gpd->boot_area_size_in_bytes) {
-
- /*
- * If we have more than one chip, then we concatenated two
- * "remainder" MTDs to produce the "general use" MTD.
- * Unregister the concatenation MTD, and then destroy it.
- */
-
- if (nand->numchips > 1) {
- del_mtd_device(g->general_use_mtd);
- mtd_concat_destroy(g->general_use_mtd);
- }
-
- /*
- * Destroy all the partition MTDs based directly on the medium
- * MTD.
- */
-
- del_mtd_partitions(mtd);
-
- }
-
-#endif
-
-}
-
-/**
- * gpmi_nand_probe - Probes for a GPMI device and, if possible, takes ownership.
- *
- * @pdev: A pointer to the platform device.
- */
-static int __init gpmi_nand_probe(struct platform_device *pdev)
-{
- struct gpmi_nand_data *g;
- struct gpmi_platform_data *gpd;
- int err = 0;
- struct resource *r;
- int dma;
-
- /* Allocate memory for the per-device structure (and zero it). */
- g = kzalloc(sizeof(*g), GFP_KERNEL);
- if (!g) {
- dev_err(&pdev->dev, "failed to allocate gpmi_nand_data\n");
- err = -ENOMEM;
- goto out1;
- }
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "failed to get resource\n");
- err = -ENXIO;
- goto out2;
- }
- g->io_base = ioremap(r->start, r->end - r->start + 1);
- if (!g->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;
- }
-
- gpd = (struct gpmi_platform_data *)pdev->dev.platform_data;
- g->gpd = gpd;
- platform_set_drvdata(pdev, g);
- err = gpmi_nand_init_hw(pdev, 1);
- if (err)
- goto out3;
-
- init_timer(&g->timer);
- g->timer.data = (unsigned long)g;
- g->timer.function = gpmi_timer_expiry;
- g->timer.expires = jiffies + 4 * HZ;
- add_timer(&g->timer);
- dev_dbg(&pdev->dev, "%s: timer set to %ld\n",
- __func__, jiffies + 4 * HZ);
-
- g->reg_uA = gpd->io_uA;
- g->regulator = regulator_get(&pdev->dev, "mmc_ssp-2");
- if (g->regulator && !IS_ERR(g->regulator)) {
- regulator_set_mode(g->regulator, REGULATOR_MODE_NORMAL);
- } else
- g->regulator = NULL;
-
- g->irq = r->start;
- err = request_irq(g->irq, gpmi_irq, 0, dev_name(&pdev->dev), g);
- if (err) {
- dev_err(&pdev->dev, "can't request GPMI IRQ\n");
- goto out4;
- }
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r) {
- dev_err(&pdev->dev, "can't get DMA resource\n");
- goto out5;
- }
-
- if (r->end - r->start > GPMI_MAX_CHIPS)
- dev_info(&pdev->dev, "too spread resource: max %d chips\n",
- GPMI_MAX_CHIPS);
-
- for (dma = r->start;
- dma < min_t(int, r->end, r->start + GPMI_MAX_CHIPS); dma++) {
- err = gpmi_init_chip(pdev, g, dma - r->start, dma);
- if (err)
- goto out6;
- }
-
- g->cmd_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");
- goto out6;
- }
-
- g->dev = pdev;
- g->nand.priv = g;
- g->timing = gpmi_safe_timing;
- g->selected_chip = -1;
- g->ignorebad = ignorebad; /* copy global setting */
-
- /* Set up timings. */
-
- gpmi_set_timings(g, &gpmi_safe_timing);
-
- /* Register with MTD. */
-
- if (gpmi_register_with_mtd(g))
- goto out7;
-
- /* Stay away from Unique ID -- It's going away soon. */
-
- /* Initialize the Unique ID facility. */
-
- gpmi_uid_init("nand", &g->mtd, gpd->uid_offset, gpd->uid_size);
-
- /*
- * Check if we should export sysfs entries.
- *
- * This configuration variable should be destroyed, and this driver
- * should *always* create the sysfs entries.
- */
-
-#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES
- gpmi_sysfs(pdev, true);
-#endif
-
- /* If control arrives here, everything worked. Return success. */
-
- return 0;
-
- ecc8_exit();
- bch_exit();
-out7:
- nand_release(&g->mtd);
- gpmi_free_buffers(pdev, g);
-out6:
- gpmi_deinit_chip(pdev, g, -1);
-out5:
- free_irq(g->irq, g);
-out4:
- del_timer_sync(&g->timer);
- gpmi_nand_release_hw(pdev);
-out3:
- platform_set_drvdata(pdev, NULL);
- iounmap(g->io_base);
-out2:
- kfree(g);
-out1:
- return err;
-}
-
-/**
- * gpmi_nand_remove - Dissociates this driver from the given device.
- *
- * @pdev: A pointer to the platform device.
- */
-static int __devexit gpmi_nand_remove(struct platform_device *pdev)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
-
- gpmi_unregister_with_mtd(g);
- del_timer_sync(&g->timer);
- gpmi_uid_remove("nand");
-
-#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES
- gpmi_sysfs(pdev, false);
-#endif
-
- nand_release(&g->mtd);
- gpmi_free_buffers(pdev, g);
- gpmi_deinit_chip(pdev, g, -1);
- gpmi_nand_release_hw(pdev);
- free_irq(g->irq, g);
- if (g->regulator)
- regulator_put(g->regulator);
- iounmap(g->io_base);
- kfree(g);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-
-/**
- * gpmi_nand_suspend() - Suspends this driver.
- *
- * @pdev: A pointer to the owning struct platform_device.
- * @pm: For future use, currently unused.
- */
-static int gpmi_nand_suspend(struct platform_device *pdev, pm_message_t pm)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
- int r = 0;
-
- /* If the driver suspended itself due to inactivity, wake it up. */
-
- if (g->self_suspended)
- gpmi_self_wakeup(g);
-
- /* Deactivate the inactivity timer. */
-
- del_timer_sync(&g->timer);
-
- /*
- * Suspend MTD's use of this device and, if that works, then shut down
- * the actual hardware.
- */
-
- r = g->mtd.suspend(&g->mtd);
- if (r == 0)
- gpmi_nand_release_hw(pdev);
-
- return r;
-
-}
-
-/**
- * gpmi_nand_resume() - Resumes this driver from suspend.
- *
- * @pdev: A pointer to the owning struct platform_device.
- */
-static int gpmi_nand_resume(struct platform_device *pdev)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
- int r;
-
- /*
- * Spin up the hardware.
- *
- * Unfortunately, this code ignores the result of hardware
- * initialization and spins up the driver unconditionally.
- */
-
- r = gpmi_nand_init_hw(pdev, 1);
- gpmi_set_timings(g, 0);
-
- /* Tell MTD it can use this device again. */
-
- g->mtd.resume(&g->mtd);
-
- /* Re-instate the inactivity timer. */
-
- g->timer.expires = jiffies + 4 * HZ;
- add_timer(&g->timer);
-
- return r;
-
-}
-
-#else
-#define gpmi_nand_suspend NULL
-#define gpmi_nand_resume NULL
-#endif
-
-#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES
-
-/**
- * show_timings() - Shows the current NAND Flash timing.
- *
- * @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_timings(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct gpmi_nand_data *g = dev_get_drvdata(d);
- uint32_t register_image;
- uint32_t data_setup_in_cycles;
- uint32_t effective_data_setup_in_ns;
- uint32_t data_hold_in_cycles;
- uint32_t effective_data_hold_in_ns;
- uint32_t address_setup_in_cycles;
- uint32_t effective_address_setup_in_ns;
- uint32_t sample_delay_in_cycles;
- uint32_t effective_sample_delay_in_ns;
- bool sample_delay_uses_half_period;
- uint32_t gpmi_clock_frequency_in_khz =
- clk_get_rate(g->clk);
- uint32_t gpmi_clock_period_in_ns =
- 1000000 / gpmi_clock_frequency_in_khz;
-
- /* Retrieve basic timing facts. */
-
- register_image = __raw_readl(REGS_GPMI_BASE + HW_GPMI_TIMING0);
-
- data_setup_in_cycles = (register_image & BM_GPMI_TIMING0_DATA_SETUP)
- >> BP_GPMI_TIMING0_DATA_SETUP;
- data_hold_in_cycles = (register_image & BM_GPMI_TIMING0_DATA_HOLD)
- >> BP_GPMI_TIMING0_DATA_HOLD;
- address_setup_in_cycles =
- (register_image & BM_GPMI_TIMING0_ADDRESS_SETUP)
- >> BP_GPMI_TIMING0_ADDRESS_SETUP;
-
- effective_data_setup_in_ns =
- data_setup_in_cycles * gpmi_clock_period_in_ns;
- effective_data_hold_in_ns =
- data_hold_in_cycles * gpmi_clock_period_in_ns;
- effective_address_setup_in_ns =
- address_setup_in_cycles * gpmi_clock_period_in_ns;
-
- /* Retrieve facts about the sample delay. */
-
- register_image = __raw_readl(REGS_GPMI_BASE + HW_GPMI_CTRL1);
-
- sample_delay_in_cycles = (register_image & BM_GPMI_CTRL1_RDN_DELAY)
- >> BP_GPMI_CTRL1_RDN_DELAY;
-
- sample_delay_uses_half_period =
- !!((register_image & BM_GPMI_CTRL1_HALF_PERIOD)
- >> BP_GPMI_CTRL1_HALF_PERIOD);
-
- effective_sample_delay_in_ns =
- sample_delay_in_cycles * gpmi_clock_period_in_ns;
-
- if (sample_delay_uses_half_period)
- effective_sample_delay_in_ns >>= 1;
-
- /* Show the results. */
-
- return sprintf(buf,
- "GPMI Clock Frequency : %u KHz\n"
- "GPMI Clock Period : %u ns\n"
- "Recorded Data Setup : %d ns\n"
- "Hardware Data Setup : %u cycles\n"
- "Effective Data Setup : %u ns\n"
- "Recorded Data Hold : %d ns\n"
- "Hardware Data Hold : %u cycles\n"
- "Effective Data Hold : %u ns\n"
- "Recorded Address Setup: %d ns\n"
- "Hardware Address Setup: %u cycles\n"
- "Effective Address Setup: %u ns\n"
- "Recorded Sample Delay : %d ns\n"
- "Hardware Sample Delay : %u cycles\n"
- "Using Half Period : %s\n"
- "Effective Sample Delay : %u ns\n"
- "Recorded tREA : %d ns\n"
- "Recorded tRLOH : %d ns\n"
- "Recorded tRHOH : %d ns\n"
- ,
- gpmi_clock_frequency_in_khz,
- gpmi_clock_period_in_ns,
- g->device_info.data_setup_in_ns,
- data_setup_in_cycles,
- effective_data_setup_in_ns,
- g->device_info.data_hold_in_ns,
- data_hold_in_cycles,
- effective_data_hold_in_ns,
- g->device_info.address_setup_in_ns,
- address_setup_in_cycles,
- effective_address_setup_in_ns,
- g->device_info.gpmi_sample_delay_in_ns,
- sample_delay_in_cycles,
- (sample_delay_uses_half_period ? "Yes" : "No"),
- effective_sample_delay_in_ns,
- g->device_info.tREA_in_ns,
- g->device_info.tRLOH_in_ns,
- g->device_info.tRHOH_in_ns);
-
-}
-
-/**
- * store_timings() - Sets the current NAND Flash timing.
- *
- * @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_timings(struct device *d, struct device_attribute *attr,
- const char *buf, size_t size)
-{
- const char *p, *end;
- struct gpmi_nand_timing t;
- struct gpmi_nand_data *g = dev_get_drvdata(d);
- char tmps[20];
- u8 *timings[] = {
- &t.data_setup_in_ns,
- &t.data_hold_in_ns,
- &t.address_setup_in_ns,
- &t.gpmi_sample_delay_in_ns,
- NULL,
- };
- u8 **timing = timings;
-
- p = buf;
-
- /* parse values */
- while (*timing != NULL) {
- unsigned long t_long;
-
- end = strchr(p, ',');
- memset(tmps, 0, sizeof(tmps));
- if (end)
- strncpy(tmps, p, min_t(int, sizeof(tmps) - 1, end - p));
- else
- strncpy(tmps, p, sizeof(tmps) - 1);
-
- if (strict_strtoul(tmps, 0, &t_long) < 0)
- return -EINVAL;
-
- if (t_long > 255)
- return -EINVAL;
-
- **timing = (u8) t_long;
- timing++;
-
- if (!end && *timing)
- return -EINVAL;
- p = end + 1;
- }
-
- gpmi_set_timings(g, &t);
-
- return size;
-}
-
-/**
- * show_stat() - Shows current statistics.
- *
- * @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_stat(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "copies\t\t%dff pages\t%d\n", copies, ff_writes);
-}
-
-/**
- * show_chips() - Shows the number of physical chips that were discovered.
- *
- * @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_chips(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct gpmi_nand_data *g = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", g->nand.numchips);
-}
-
-/**
- * show_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_ignorebad(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct gpmi_nand_data *g = dev_get_drvdata(d);
-
- return sprintf(buf, "%d\n", g->ignorebad);
-}
-
-/**
- * store_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_ignorebad(struct device *d, struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct gpmi_nand_data *g = dev_get_drvdata(d);
- const char *p = buf;
- unsigned long v;
-
- if (strict_strtoul(p, 0, &v) < 0)
- return size;
- if (v > 0)
- v = 1;
- if (v != g->ignorebad) {
- if (v) {
- g->bbt = g->nand.bbt;
- g->nand.bbt = NULL;
- g->ignorebad = 1;
- } else {
- g->nand.bbt = g->bbt;
- g->ignorebad = 0;
- }
- }
- return size;
-}
-
-static DEVICE_ATTR(timings, 0644, show_timings, store_timings);
-static DEVICE_ATTR(stat, 0444, show_stat, NULL);
-static DEVICE_ATTR(ignorebad, 0644, show_ignorebad, store_ignorebad);
-static DEVICE_ATTR(numchips, 0444, show_chips, NULL);
-
-static struct device_attribute *gpmi_attrs[] = {
- &dev_attr_timings,
- &dev_attr_stat,
- &dev_attr_ignorebad,
- &dev_attr_numchips,
- NULL,
-};
-
-/**
- * gpmi_sysfs() - Creates or removes sysfs nodes.
- *
- * @pdev: A pointer to the owning platform device.
- * @create: Indicates the nodes are to be created (otherwise, removed).
- */
-int gpmi_sysfs(struct platform_device *pdev, int create)
-{
- int err = 0;
- int i;
-
- if (create) {
- for (i = 0; gpmi_attrs[i]; i++) {
- err = device_create_file(&pdev->dev, gpmi_attrs[i]);
- if (err)
- break;
- }
- if (err)
- while (--i >= 0)
- device_remove_file(&pdev->dev, gpmi_attrs[i]);
- } else {
- for (i = 0; gpmi_attrs[i]; i++)
- device_remove_file(&pdev->dev, gpmi_attrs[i]);
- }
- return err;
-}
-
-#endif
-
-/*
- * The global list of ECC descriptors.
- *
- * Each descriptor represents an ECC option that's available to the driver.
- */
-
-static LIST_HEAD(gpmi_ecc_descriptor_list);
-
-/**
- * gpmi_ecc_add() - Adds the given ECC descriptor.
- *
- * @name: The name of interest.
- */
-void gpmi_ecc_add(struct gpmi_ecc_descriptor *chip)
-{
- list_add(&chip->list, &gpmi_ecc_descriptor_list);
-}
-EXPORT_SYMBOL_GPL(gpmi_ecc_add);
-
-/**
- * gpmi_ecc_remove() - Removes an ECC descriptor with the given name.
- *
- * @name: The name of interest.
- */
-void gpmi_ecc_remove(struct gpmi_ecc_descriptor *chip)
-{
- list_del(&chip->list);
-}
-EXPORT_SYMBOL_GPL(gpmi_ecc_remove);
-
-/**
- * gpmi_ecc_find() - Tries to find an ECC descriptor with the given name.
- *
- * @name: The name of interest.
- */
-struct gpmi_ecc_descriptor *gpmi_ecc_find(char *name)
-{
- struct gpmi_ecc_descriptor *c;
-
- list_for_each_entry(c, &gpmi_ecc_descriptor_list, list)
- if (strncmp(c->name, name, sizeof(c->name)) == 0)
- return c;
-
- return NULL;
-
-}
-EXPORT_SYMBOL_GPL(gpmi_ecc_find);
-
-/*
- * This structure represents this driver to the platform management system.
- */
-
-static struct platform_driver gpmi_nand_driver = {
- .probe = gpmi_nand_probe,
- .remove = __devexit_p(gpmi_nand_remove),
- .driver = {
- .name = "gpmi",
- .owner = THIS_MODULE,
- },
- .suspend = gpmi_nand_suspend,
- .resume = gpmi_nand_resume,
-};
-
-static int __init gpmi_nand_init(void)
-{
- int return_value;
-
- pr_info("GPMI NAND Flash driver\n");
-
- /* Initialize the BCH and ECC8 hardware blocks. */
-
- bch_init();
- ecc8_init();
-
- /* Attempt to register this driver with the platform. */
-
- return_value = platform_driver_register(&gpmi_nand_driver);
-
- if (return_value)
- pr_err("GPMI NAND Flash driver registration failed\n");
-
- return return_value;
-
-}
-
-static void __exit gpmi_nand_exit(void)
-{
- pr_info("GPMI NAND Flash driver exiting...\n");
- platform_driver_unregister(&gpmi_nand_driver);
-}
-
-module_init(gpmi_nand_init);
-module_exit(gpmi_nand_exit);
-MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("GPMI NAND Flash driver");
-module_param(max_chips, int, 0400);
-module_param(clk, long, 0400);
-module_param(bch, int, 0600);
-module_param(map_buffers, int, 0600);
-module_param(raw_mode, int, 0600);
-module_param(debug, int, 0600);
-module_param(add_mtd_entire, int, 0400);
-module_param(add_mtd_chip, int, 0400);
-module_param(ignorebad, int, 0400);
diff --git a/drivers/mtd/nand/gpmi/gpmi-bbt.c b/drivers/mtd/nand/gpmi/gpmi-bbt.c
deleted file mode 100644
index 7c658011bae1..000000000000
--- a/drivers/mtd/nand/gpmi/gpmi-bbt.c
+++ /dev/null
@@ -1,844 +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
- */
-#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/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <mach/dma.h>
-#include <mach/unique-id.h>
-#include "gpmi.h"
-
-/*
- * The equivalent of the BOOT_SEARCH_COUNT field in the OTP bits. That is, the
- * logarithm to base 2 of the number of strides in a search area (a stride is
- * 64 pages).
- */
-
-static int boot_search_count;
-
-/*
- * The size, in pages, of a search area stride.
- *
- * This number is dictated by the ROM, so it's not clear why it isn't at least
- * const, or perhaps a macro.
- */
-
-static int stride = 64;
-
-/*
- * Indicates how NCBs are to be comprehended.
- *
- * A value of 0 indicates a format that is easy to develop and test with, but
- * which the ROM can't actually boot.
- *
- * A value of 1 corresponds to the TA-1 ROM.
- *
- * A value of 3 corresponds to the TA-3 ROM.
- */
-
-static int ncb_version = 3;
-
-module_param(boot_search_count, int, 0400);
-module_param(ncb_version, int, 0400);
-
-/*
- * gpmi_read_page -
- *
- * @mtd: The owning MTD.
- * @start: The offset at which to begin reading.
- * @data: A pointer to a buff that will receive the data. This pointer may be
- * NULL, in which case this function will allocate a buffer.
- * @raw: If true, indicates that the caller doesn't want to use ECC.
- */
-void *gpmi_read_page(struct mtd_info *mtd, loff_t start, void *data, int raw)
-{
- int ret;
- struct mtd_oob_ops ops;
-
- /* If the caller didn't send in his own buffer, allocate one. */
-
- if (!data)
- data = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
- if (!data)
- return NULL;
-
- /* Check if the caller wants to use ECC. */
-
- if (raw)
- ops.mode = MTD_OOB_RAW;
- else
- ops.mode = MTD_OOB_PLACE;
-
- /*
- * Call nand_do_read_ops() to do the dirty work.
- */
-
- ops.datbuf = data;
- ops.len = mtd->writesize;
- ops.oobbuf = data + mtd->writesize;
- ops.ooblen = mtd->oobsize;
- ops.ooboffs = 0;
- ret = nand_do_read_ops(mtd, start, &ops);
-
- if (ret)
- return NULL;
- return data;
-}
-
-/*
- * gpmi_write_ncb - Writes an NCB to the medium.
- *
- * @mtd: The owning MTD.
- * @b: Boot Control Block information.
- */
-int gpmi_write_ncb(struct mtd_info *mtd, struct gpmi_bcb_info *b)
-{
- struct gpmi_ncb *ncb = NULL, *unencoded_ncb = NULL;
- struct nand_chip *chip = mtd->priv;
- int err;
- loff_t start = 0;
- struct mtd_oob_ops ops;
- struct erase_info instr;
- int ncb_count;
-
- /* Allocate an I/O buffer for the NCB page, with OOB. */
-
- ncb = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
- if (!ncb) {
- err = -ENOMEM;
- goto out;
- }
-
- /* Allocate a buffer within which we will construct the NCB. */
-
- unencoded_ncb = kzalloc(mtd->writesize, GFP_KERNEL);
- if (!unencoded_ncb) {
- err = -ENOMEM;
- goto out;
- }
-
- ops.mode = -1; /* if the value is not set in switch below,
- this will cause BUG. Take care. */
-
- /*
- * Check if we got any Boot Control Block information and, specifically,
- * if it contains an NCB for use to use. If not, we need to construct
- * our own.
- */
-
- if (b && b->pre_ncb)
- memcpy(unencoded_ncb, b->pre_ncb, b->pre_ncb_size);
- else {
- memcpy(&unencoded_ncb->fingerprint1, SIG1, sizeof(u32));
- memcpy(&unencoded_ncb->fingerprint2, SIG_NCB, sizeof(u32));
- if (b)
- unencoded_ncb->timing = b->timing;
- }
-
- /* Construct the encoded NCB from the unencoded one. */
-
- switch (ncb_version) {
- case 0:
- ops.mode = MTD_OOB_AUTO;
- memcpy(ncb, unencoded_ncb, sizeof(*unencoded_ncb));
- break;
-#ifdef CONFIG_MTD_NAND_GPMI_TA1
- case 1:
- ops.mode = MTD_OOB_RAW;
- gpmi_encode_hamming_ncb_22_16(unencoded_ncb,
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES,
- ncb, mtd->writesize + mtd->oobsize);
- break;
-#endif
-#ifdef CONFIG_MTD_NAND_GPMI_TA3
- case 3:
- ops.mode = MTD_OOB_RAW;
- gpmi_encode_hamming_ncb_13_8(unencoded_ncb,
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES,
- ncb, mtd->writesize + mtd->oobsize);
- break;
-#endif
-
- default:
- printk(KERN_ERR"Incorrect ncb_version = %d\n", ncb_version);
- err = -EINVAL;
- goto out;
- }
-
- /* Construct data structures for the write operation. */
-
- ops.datbuf = (u8 *)ncb;
- ops.len = mtd->writesize;
- ops.oobbuf = (u8 *)ncb + mtd->writesize;
- ops.ooblen = mtd->oobsize;
- ops.ooboffs = 0;
-
- ncb_count = 0;
- do {
- printk(KERN_NOTICE"GPMI: Trying to store NCB at addr %lx\n",
- (unsigned long)start);
-
- /*
- * Attempt to erase the block that will contain the current NCB.
- */
-
- memset(&instr, 0, sizeof(instr));
- instr.mtd = mtd;
- instr.addr = start;
- instr.len = (1 << chip->phys_erase_shift);
- err = nand_erase_nand(mtd, &instr, 0);
-
- /*
- * Check if the erase worked and, if so, write the NCB.
- */
-
- if (err == 0) {
- printk(KERN_NOTICE"GPMI: Erased, storing\n");
- err = nand_do_write_ops(mtd, start, &ops);
- printk(KERN_NOTICE"GPMI: NCB update %s (%d).\n",
- err ? "failed" : "succeeded", err);
- }
-
- /*
- * Move to the next block.
- */
-
- start += (1 << chip->phys_erase_shift);
- ncb_count++;
-
- } while (err != 0 && ncb_count < 100);
-
- /* Tell the caller where we ended up putting the NCB. */
-
- if (b)
- b->ncbblock = start >> chip->bbt_erase_shift;
-
-out:
-
- /* Free our buffers. */
-
- kfree(ncb);
- kfree(unencoded_ncb);
-
- return 0;
-}
-
-/*
- * gpmi_redundancy_check_one -
- *
- * @pg:
- * @dsize:
- * @esize:
- * @offset:
- * @o1:
- * @o2:
- */
-static int gpmi_redundancy_check_one(u8 *pg, int dsize, int esize, int offset,
- int o1, int o2)
-{
- int r;
-
- if (o1 == o2)
- return 0;
-
- r = memcmp(pg + o1 * dsize, pg + o2 * dsize, dsize);
- if (r) {
- pr_debug("DATA copies %d and %d are different: %d\n",
- o1, o2, r);
- return r;
- }
-
- r = memcmp(pg + o1 * esize + offset,
- pg + o2 * esize + offset, esize);
- if (r) {
- pr_debug("ECC copies %d and %d are different: %d\n", o1, o2, r);
- return r;
- }
- pr_debug("Both DATA and ECC copies %d and %d are identical\n", o1, o2);
- return r;
-}
-
-/*
- * gpmi_redundancy_check -
- *
- * @pg:
- * @dsize:
- * @esize:
- * @ecc_offset:
- */
-static int gpmi_redundancy_check(u8 *pg, int dsize, int esize, int ecc_offset)
-{
- if (gpmi_redundancy_check_one(pg, dsize, esize, ecc_offset, 0, 1) == 0)
- return 0;
- if (gpmi_redundancy_check_one(pg, dsize, esize, ecc_offset, 0, 2) == 0)
- return 0;
- if (gpmi_redundancy_check_one(pg, dsize, esize, ecc_offset, 1, 2) == 0)
- return 1;
- return -1;
-}
-
-/*
- * gpmi_ncb1_redundancy_check_one -
- *
- * @pg:
- * @dsize:
- * @esize:
- * @offset:
- * @o1:
- * @o2:
- */
-static inline int gpmi_ncb1_redundancy_check(u8 *pg)
-{
- return gpmi_redundancy_check(pg,
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES,
- NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES,
- NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY);
-}
-
-/*
- * gpmi_scan_sigmatel_bbt -
- *
- * @mtd: The owning MTD.
- * @nfo:
- */
-static int gpmi_scan_sigmatel_bbt(
- struct mtd_info *mtd, struct gpmi_bcb_info *nfo)
-{
- int page, r;
- u8 *pg;
- struct gpmi_ncb *result = NULL;
-
- /*
- * If the boot search count is 0, make it 1.
- *
- * This is old TA1 behavior. The correct answer is to map 0 to 2.
- */
-
- if (boot_search_count == 0)
- boot_search_count = 1;
-
- /* Check for nonsense. */
-
- if (nfo == NULL)
- return -EINVAL;
-
- /*
- * Loop through the medium, searching for the NCB.
- *
- * Note that this loop is wrong. Each stride is 64 pages, so it *should*
- * be:
- *
- * for (page = 0;
- * page < ((1<<boot_search_count) * 64); page += stride) {
- */
-
- pg = NULL;
- printk(KERN_NOTICE"Scanning for NCB...\n");
- for (page = 0; page < (1<<boot_search_count); page += stride) {
-
- /* Read the current page. */
-
- pg = gpmi_read_page(mtd, page * mtd->writesize,
- pg, ncb_version != 0);
-
- printk(KERN_NOTICE"GPMI: Checking page 0x%08X\n", page);
-
- /* Check for NCB version 0. */
-
- if (ncb_version == 0) {
- if (memcmp(pg, SIG1, SIG_SIZE) != 0)
- continue;
- printk(KERN_NOTICE"GPMI: Signature found at 0x%08X\n",
- page);
- result = (struct gpmi_ncb *)pg;
- }
-
-#ifdef CONFIG_MTD_NAND_GPMI_TA1
- if (ncb_version == 1) {
- void *dptr, *eccptr;
-
- if (memcmp(pg, SIG1, SIG_SIZE) != 0)
- continue;
- printk(KERN_NOTICE"GPMI: Signature found at 0x%08X\n",
- page);
-
- r = gpmi_ncb1_redundancy_check(pg);
-
- if (r < 0) {
- printk(KERN_ERR"GPMI: Oops. All three "
- "copies of NCB are differrent!\n");
- continue;
- }
-
- dptr = pg + r * NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES;
- eccptr = pg + NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY +
- r * NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES;
-
- if (gpmi_verify_hamming_22_16(dptr, eccptr,
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) < 0) {
- printk(KERN_ERR"Verification failed.\n");
- continue;
- }
- result = (struct gpmi_ncb *)pg;
- }
-#endif
-
-#ifdef CONFIG_MTD_NAND_GPMI_TA3
-
- /* Check for TA-3 NCB handling. */
-
- if (ncb_version == 3) {
-
- /*
- * A valid NCB page contains the following:
- *
- * +------------+
- * .
- * .
- * Don't Care
- * .
- * .
- * +------------+ 1036
- * | |
- * | NCB ECC |
- * | |
- * +------------+ 524
- * | |
- * | NCB |
- * | |
- * +------------+ 12
- * | Don't Care |
- * +------------+ 0
- *
- * Within the NCB, there are three "fingerprints":
- *
- * +-----------+--------------------+
- * | Offset In | |
- * | NCB Page | Fingerprint |
- * +-----------+--------------------+
- * | 0x0c | "STMP" 0x504d5453 |
- * | 0x38 | "NCB " 0x2042434E |
- * | 0x8c | "RBIN" 0x4E494252 |
- * +-----------+--------------------+
- */
-
- /* Check for the first signature. */
-
- if (memcmp(pg + 12, SIG1, SIG_SIZE) != 0)
- continue;
-
- printk(KERN_NOTICE"GPMI: Signature found at 0x%08X\n",
- page);
-
- /* Validate the NCB against the ECC stored with it. */
-
- if (gpmi_verify_hamming_13_8(
- pg + 12,
- pg + 524,
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) < 0) {
- printk(KERN_ERR"Verification failed.\n");
- continue;
- }
-
- /*
- * If control arrives here, we found what we were
- * looking for. We want to return the address of the
- * NCB itself.
- */
-
- result = (struct gpmi_ncb *)(pg + 12);
-
- }
-#endif
-
- if (result) {
- printk(KERN_NOTICE"GPMI: Valid NCB found "
- "at 0x%08x\n", page);
- nfo->timing = result->timing;
- nfo->ncbblock = page * mtd->writesize;
- break;
- }
-
- }
-
- /* Free the page buffer */
-
- kfree(pg);
-
- return result != NULL;
-}
-
-/**
- * gpmi_scan_bbt - Sets up to manage bad blocks.
- *
- * @mtd: The owning MTD.
- */
-int gpmi_scan_bbt(struct mtd_info *mtd)
-{
- struct gpmi_bcb_info stmp_bbt;
- struct nand_chip *this = mtd->priv;
- struct gpmi_nand_data *g = this->priv;
- int r;
- int numblocks, from, i, ign;
-
- memset(&stmp_bbt, 0, sizeof(stmp_bbt));
- g->transcribe_bbmark = 0;
-
- /*
- * The following code assumes the NCB uses the full page. This was true
- * in the TA1 revision of the boot ROM, but not later versions.
- */
-
- /*
- * Since NCB uses the full page, including BB pattern bits,
- * driver has to ignore result of gpmi_block_bad when reading
- * these pages.
- */
- ign = g->ignorebad;
-
- g->ignorebad = true; /* strictly speaking, I'd have to hide
- * the BBT too.
- * But we still scanning it :) */
-
- r = gpmi_scan_sigmatel_bbt(mtd, &stmp_bbt);
-
- /* and then, driver has to restore the setting */
- g->ignorebad = ign;
-
- /* Check if we found the NCB. */
-
- if (!r) {
-
- /*
- * If control arrives here, the medium has no NCB, so we
- * presume it is in common format. This means we must transcribe
- * the bad block marks.
- */
-
- g->transcribe_bbmark = !0;
-
- /*
- * Compute the number of blocks in the entire medium.
- */
-
- numblocks = this->chipsize >> this->bbt_erase_shift;
-
- /*
- * Loop over all the blocks in the medium, transcribing block
- * marks as we go.
- */
-
- from = 0;
- printk(KERN_NOTICE"Checking BB on common-formatted flash\n");
- for (i = stmp_bbt.ncbblock + 1; i < numblocks; i++) {
- /* check the block and transcribe the bb if needed */
- gpmi_block_bad(mtd, from, 0);
- from += (1 << this->bbt_erase_shift);
- }
- }
-
- /* Use the reference implementation's BBT scan. */
-
- r = nand_default_bbt(mtd);
-
- /* Check if we were transcribing block marks. */
-
- if (g->transcribe_bbmark) {
-
- /*
- * If control arrives here, we set the transcription flag
- * because we didn't find an NCB. Now that we've
- * transcribed all the bad block marks, we need to write an
- * NCB to show that the medium is now formatted for SigmaTel
- * Hardware.
- */
-
- g->transcribe_bbmark = 0;
-
- /*
- * Store the timings we discovered from the NCB in the
- * per-device data structure.
- */
-
- stmp_bbt.timing = gpmi_safe_timing;
-
- /* Write an NCB to the medium. */
-
- r = gpmi_write_ncb(mtd, &stmp_bbt);
-
- } else {
- /* NCB found, and its block should be marked as "good" */
- gpmi_block_mark_as(this, stmp_bbt.ncbblock, 0x00);
- }
-
- return r;
-}
-
-/**
- * gpmi_block_bad - Checks if a block is bad, and may transcribes its mark.
- *
- * @mtd: The owning MTD.
- * @ofs:
- * @getchip:
- */
-int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
-
-{
- int page, res = 0;
- struct nand_chip *chip = mtd->priv;
- u16 bad;
- struct gpmi_nand_data *g = chip->priv;
- int chipnr;
-
- /*
- * Compute the position of the block mark within the OOB (this code
- * appears to be wrong).
- */
-
- int badblockpos = chip->ecc.steps * chip->ecc.bytes;
-
- if (g->ignorebad)
- return 0;
-
- /*
- * Compute the page address of the first page in the block that contains
- * the given offset.
- */
-
- page = (int)(ofs >> chip->page_shift) & chip->pagemask;
-
- /*
- * Compute the chip number that contains the given offset, and select
- * it.
- */
-
- chipnr = (int)(ofs >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
-
- /*
- * If we're transcribing block marks, set the position to that in a
- * SigmaTel Hardware-format page.
- */
-
- if (g->transcribe_bbmark)
- /* bad block marks still are on first byte of OOB */
- badblockpos = 0;
-
- /* Read the block mark. */
-
- if (chip->options & NAND_BUSWIDTH_16) {
- chip->cmdfunc(mtd, NAND_CMD_READOOB, badblockpos & 0xFE,
- page);
- bad = cpu_to_le16(chip->read_word(mtd));
- if (badblockpos & 0x1)
- bad >>= 8;
- if ((bad & 0xFF) != 0xff)
- res = 1;
- } else {
- chip->cmdfunc(mtd, NAND_CMD_READOOB, badblockpos, page);
- if (chip->read_byte(mtd) != 0xff)
- res = 1;
- }
-
- /*
- * If we successfully read the block mark, and we're supposed to
- * transcribe it, then do so.
- */
-
- if (g->transcribe_bbmark && res)
- chip->block_markbad(mtd, ofs);
-
- /*
- * Deselect the chip.
- */
-
- chip->select_chip(mtd, -1);
-
- return res;
-}
-
-#if defined(CONFIG_STMP3XXX_UNIQUE_ID)
-/*
- * UID on NAND support
- */
-const int uid_size = 256;
-
-struct gpmi_uid_context {
- struct mtd_info *mtd;
- struct nand_chip *nand;
- u_int32_t start;
- u_int32_t size;
-};
-
-static int gpmi_read_uid(struct gpmi_uid_context *ctx, void *result)
-{
- void *pg = NULL;
- int page, o;
- int status = -ENOENT;
- int h_size = gpmi_hamming_ecc_size_22_16(uid_size);
-
- for (page = ctx->start >> ctx->nand->page_shift;
- page < (ctx->start + ctx->size) >> ctx->nand->page_shift;) {
- pr_debug("%s: reading page 0x%x\n", __func__, page);
- if (gpmi_block_bad(ctx->mtd, page * ctx->mtd->writesize, 0)) {
- pr_debug("%s: bad block %x, skipping it\n",
- __func__, page * ctx->mtd->writesize);
- page += (1 << ctx->nand->phys_erase_shift)
- >> ctx->nand->page_shift;
- continue;
- }
- pg = gpmi_read_page(ctx->mtd, page * ctx->mtd->writesize,
- pg, 0);
- if (pg)
- break;
- page++;
- }
-
- if (!pg)
- return status;
-
- o = gpmi_redundancy_check(pg, uid_size, h_size, 3 * uid_size);
- if (o >= 0) {
- if (gpmi_verify_hamming_22_16(
- pg + o * uid_size,
- pg + 3 * uid_size + h_size, uid_size) >= 0) {
- memcpy(result, pg + o * uid_size, uid_size);
- status = 0;
- }
- }
- kfree(pg);
- return status;
-}
-
-static int gpmi_write_uid(struct gpmi_uid_context *ctx, void *src)
-{
- struct mtd_oob_ops ops;
- struct erase_info instr;
- u8 *data = kzalloc(ctx->mtd->writesize + ctx->mtd->oobsize, GFP_KERNEL);
- int h_size = gpmi_hamming_ecc_size_22_16(uid_size);
- char ecc[h_size];
- u_int32_t start;
- int i;
- int err;
-
- if (!data)
- return -ENOMEM;
-
- gpmi_encode_hamming_22_16(src, uid_size, ecc, h_size);
- for (i = 0; i < 3; i++) {
- memcpy(data + i * uid_size, src, uid_size);
- memcpy(data + 3 * uid_size + i * h_size, ecc, h_size);
- }
-
- ops.mode = MTD_OOB_AUTO;
- ops.datbuf = data;
- ops.len = ctx->mtd->writesize;
- ops.oobbuf = NULL;
- ops.ooblen = ctx->mtd->oobsize;
- ops.ooboffs = 0;
-
- start = ctx->start;
-
- do {
- memset(&instr, 0, sizeof(instr));
- instr.mtd = ctx->mtd;
- instr.addr = start;
- instr.len = (1 << ctx->nand->phys_erase_shift);
- err = nand_erase_nand(ctx->mtd, &instr, 0);
- if (err == 0)
- err = nand_do_write_ops(ctx->mtd, start, &ops);
- start += (1 << ctx->nand->phys_erase_shift);
- if (start > ctx->start + ctx->size)
- break;
- } while (err != 0);
-
- return err;
-}
-
-static ssize_t gpmi_uid_store(void *context, const char *page,
- size_t count, int ascii)
-{
- u8 data[uid_size];
-
- memset(data, 0, sizeof(data));
- memcpy(data, page, uid_size < count ? uid_size : count);
- gpmi_write_uid(context, data);
- return count;
-}
-
-static ssize_t gpmi_uid_show(void *context, char *page, int ascii)
-{
- u8 result[uid_size];
- int i;
- char *p = page;
- int r;
-
- r = gpmi_read_uid(context, result);
- if (r < 0)
- return r;
-
- if (ascii) {
- for (i = 0; i < uid_size; i++) {
- if (i % 16 == 0) {
- if (i)
- *p++ = '\n';
- sprintf(p, "%04X: ", i);
- p += strlen(p);
- }
- sprintf(p, "%02X ", result[i]);
- p += strlen(p);
- }
- *p++ = '\n';
- return p - page;
-
- } else {
- memcpy(page, result, uid_size);
- return uid_size;
- }
-}
-
-static struct uid_ops gpmi_uid_ops = {
- .id_show = gpmi_uid_show,
- .id_store = gpmi_uid_store,
-};
-
-static struct gpmi_uid_context gpmi_uid_context;
-
-int __init gpmi_uid_init(const char *name, struct mtd_info *mtd,
- u_int32_t start, u_int32_t size)
-{
- gpmi_uid_context.mtd = mtd;
- gpmi_uid_context.nand = mtd->priv;
- gpmi_uid_context.start = start;
- gpmi_uid_context.size = size;
- return uid_provider_init(name, &gpmi_uid_ops, &gpmi_uid_context) ?
- 0 : -EFAULT;
-}
-
-void gpmi_uid_remove(const char *name)
-{
- uid_provider_remove(name);
-}
-#endif
diff --git a/drivers/mtd/nand/gpmi/gpmi-bch.c b/drivers/mtd/nand/gpmi/gpmi-bch.c
deleted file mode 100644
index fc0d866fe924..000000000000
--- a/drivers/mtd/nand/gpmi/gpmi-bch.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
- *
- * STMP378X BCH hardware ECC engine
- *
- * Author: dmitry pervushin <dimka@embeddedalley.com>
- *
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- * Copyright 2008-2010 Freescale Semiconductor, Inc.
- */
-
-/*
- * 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/kernel.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/dma.h>
-#include <mach/stmp3xxx.h>
-#include <mach/platform.h>
-#include <mach/irqs.h>
-#include <mach/regs-gpmi.h>
-#include "gpmi.h"
-
-#define BCH_MAX_NANDS 4
-
-static int bch_available(void *context);
-static int bch_setup(void *context, int index, int writesize, int oobsize);
-static int bch_read(void *context,
- int index,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob);
-static int bch_write(void *context,
- int index,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob);
-static int bch_stat(void *ctx, int index, struct mtd_ecc_stats *r);
-static int bch_reset(void *context, int index);
-
-/**
- * bch_state_t - Describes the state of the BCH ECC.
- *
- * @chip: A descriptor the GPMI driver uses to track this ECC.
- * @nands: An array of elements, each of which represents a physical chip.
- * @stat: Used by the interrupt level to communicate ECC statistics to the
- * base level.
- * @done: A struct completion used to manage ECC interrupts.
- * @writesize: The page data size.
- * @oobsize: The page OOB size.
- */
-
-struct bch_state_t {
- struct gpmi_ecc_descriptor chip;
- struct {
- struct mtd_ecc_stats stat;
- struct completion done;
- u32 writesize, oobsize;
- u32 ecc0, eccn, metasize;
- } nands[BCH_MAX_NANDS];
-};
-
-/* The singleton struct bch_state_t for the BCH ECC. */
-
-static struct bch_state_t state = {
- .chip = {
- .name = "bch",
- .setup = bch_setup,
- .stat = bch_stat,
- .read = bch_read,
- .write = bch_write,
- .reset = bch_reset,
- },
-};
-
-/**
- * bch_reset - Resets the BCH.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- * @index: ??
- */
-static int bch_reset(void *context, int index)
-{
- stmp3xxx_reset_block(REGS_BCH_BASE, true);
- __raw_writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
- REGS_BCH_BASE + HW_BCH_CTRL_SET);
- return 0;
-}
-
-/**
- * bch_stat - Gather statistics and clean up after a read operation.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- * @index: ??
- * @r: A statistics structure that will receive the results of the most
- * recent operation.
- */
-static int bch_stat(void *context, int index, struct mtd_ecc_stats *r)
-{
- struct bch_state_t *state = context;
-
- wait_for_completion(&state->nands[index].done);
-
- *r = state->nands[index].stat;
- state->nands[index].stat.failed = 0;
- state->nands[index].stat.corrected = 0;
- return 0;
-}
-
-/**
- * bch_irq - Interrupt handler for the BCH hardware.
- *
- * This function gains control when the BCH hardware interrupts. It acknowledges
- * the interrupt and gathers status information.
- *
- * @irq: The interrupt number.
- * @context: Context data -- a pointer to a struct bch_state_t.
- */
-static irqreturn_t bch_irq(int irq, void *context)
-{
- u32 b0, s0, ecc0;
- struct mtd_ecc_stats stat;
- int r;
- struct bch_state_t *state = context;
-
- s0 = __raw_readl(REGS_BCH_BASE + HW_BCH_STATUS0);
- r = (s0 & BM_BCH_STATUS0_COMPLETED_CE) >> 16;
-
- ecc0 = state->nands[r].ecc0;
- stat.corrected = stat.failed = 0;
-
- b0 = (s0 & BM_BCH_STATUS0_STATUS_BLK0) >> 8;
- if (b0 <= ecc0)
- stat.corrected += b0;
- if (b0 == 0xFE)
- stat.failed++;
-
- if (s0 & BM_BCH_STATUS0_UNCORRECTABLE)
- stat.failed++;
-
- __raw_writel(BM_BCH_CTRL_COMPLETE_IRQ, REGS_BCH_BASE + HW_BCH_CTRL_CLR);
-
- pr_debug("%s: chip %d, failed %d, corrected %d\n",
- __func__, r,
- state->nands[r].stat.failed,
- state->nands[r].stat.corrected);
- state->nands[r].stat.corrected += stat.corrected;
- state->nands[r].stat.failed += stat.failed;
- complete(&state->nands[r].done);
-
- return IRQ_HANDLED;
-}
-
-/**
- * bch_available - Returns whether the BCH hardware is available.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- */
-static int bch_available(void *context)
-{
- stmp3xxx_reset_block(REGS_BCH_BASE, true);
- return __raw_readl(REGS_BCH_BASE + HW_BCH_BLOCKNAME) == 0x20484342;
-}
-
-/**
- * bch_setup - Set up BCH for use.
- *
- * If the GPMI driver decides to use this ECC, it will call this function once,
- * before it starts any operations.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- * @index: ??
- * @writesize: The page data size.
- * @oobsize: The page OOB size.
- */
-static int bch_setup(void *context, int index, int writesize, int oobsize)
-{
- struct bch_state_t *state = context;
- u32 layout = (u32)REGS_BCH_BASE + 0x80 + index * 0x20;
- u32 ecc0, eccn, metasize;
- u32 reg;
-
- switch (writesize) {
- case 2048:
- ecc0 = 8;
- eccn = 8;
- metasize = 10;
- break;
- case 4096:
- if (oobsize == 128) {
- ecc0 = 8;
- eccn = 8;
- } else {
- ecc0 = 16;
- eccn = 16;
- }
-
- metasize = 10;
- break;
- default:
- printk(KERN_ERR"%s: cannot tune BCH for page size %d\n",
- __func__, writesize);
- return -EINVAL;
- }
-
- state->nands[index].oobsize = oobsize;
- state->nands[index].writesize = writesize;
- state->nands[index].metasize = metasize;
- state->nands[index].ecc0 = ecc0;
- state->nands[index].eccn = eccn;
-
- __raw_writel(BF(writesize/512 - 1, BCH_FLASH0LAYOUT0_NBLOCKS) |
- BF(metasize, BCH_FLASH0LAYOUT0_META_SIZE) |
- BF(ecc0 >> 1, BCH_FLASH0LAYOUT0_ECC0) | /* for oob */
- BF(512, BCH_FLASH0LAYOUT0_DATA0_SIZE), layout);
- __raw_writel(BF(writesize + oobsize, BCH_FLASH0LAYOUT1_PAGE_SIZE) |
- BF(eccn >> 1, BCH_FLASH0LAYOUT1_ECCN) | /* for dblock */
- BF(512, BCH_FLASH0LAYOUT1_DATAN_SIZE), layout + 0x10);
-
- /*
- * since driver only supports CS 0..3, layouts are mapped 1:1 :
- * FLASHnLAYOUT[1,2] => LAYOUTSELECT[n*2:n2*+1]
- */
- reg = __raw_readl(REGS_BCH_BASE + HW_BCH_LAYOUTSELECT);
- reg &= ~(0x03 << (index * 2));
- reg |= index << (index * 2);
- __raw_writel(reg, REGS_BCH_BASE + HW_BCH_LAYOUTSELECT);
-
- bch_reset(context, index);
-
- printk(KERN_DEBUG"%s: CS = %d, LAYOUT = 0x%08X, layout_reg = "
- "0x%08x+0x%08x: 0x%08x+0x%08x\n",
- __func__,
- index, __raw_readl(REGS_BCH_BASE + HW_BCH_LAYOUTSELECT),
- layout, layout + 0x10,
- __raw_readl(layout),
- __raw_readl(layout+0x10));
- return 0;
-}
-
-/**
- * bch_read - Fill in a DMA chain to read a page.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- * @cs: The chip number to read.
- * @chain: The main descriptor of the DMA chain to fill.
- * @error: ??
- * @page: Physical address of the target page data buffer.
- * @oob: Physical address of the target OOB data buffer.
- *
- * Return: status of operation -- 0 on success
- */
-static int bch_read(void *context,
- int index,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob)
-{
- unsigned long readsize = 0;
- u32 bufmask = 0;
- struct bch_state_t *state = context;
-
- if (!dma_mapping_error(NULL, oob)) {
- bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
- readsize += state->nands[index].oobsize;
- }
- if (!dma_mapping_error(NULL, page)) {
- bufmask |= (BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
- & ~BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY);
- readsize += state->nands[index].writesize;
- }
-
- pr_debug("readsize = %ld, bufmask = 0x%X\n", readsize, bufmask);
- bch_reset(context, index);
-
- /* wait for ready */
- chain->command->cmd =
- BF(1, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDWAIT4READY |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY,
- GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(BV_GPMI_CTRL0_ADDRESS__NAND_DATA, GPMI_CTRL0_ADDRESS) |
- BF(index, GPMI_CTRL0_CS);
- chain->command->alternate = 0;
- chain++;
-
- /* enable BCH and read NAND data */
- chain->command->cmd =
- BF(6, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__READ, GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(index, GPMI_CTRL0_CS) |
- BF(readsize, GPMI_CTRL0_XFER_COUNT);
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] =
- BM_GPMI_ECCCTRL_ENABLE_ECC |
- BF(0x02, GPMI_ECCCTRL_ECC_CMD) |
- BF(bufmask, GPMI_ECCCTRL_BUFFER_MASK);
- chain->command->pio_words[3] = readsize;
- chain->command->pio_words[4] = !dma_mapping_error(NULL, page) ? page : 0;
- chain->command->pio_words[5] = !dma_mapping_error(NULL, oob) ? oob : 0;
- chain->command->alternate = 0;
- chain++;
-
- /* disable BCH block */
- chain->command->cmd =
- BF(3, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDWAIT4READY |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY,
- GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(index, GPMI_CTRL0_CS) |
- BF(readsize, GPMI_CTRL0_XFER_COUNT);
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] = 0;
- chain->command->alternate = 0;
- chain++;
-
- /* and deassert nand lock */
- chain->command->cmd =
- BF(0, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->alternate = 0;
-
- init_completion(&state->nands[index].done);
- return 0;
-}
-
-static int bch_write(void *context,
- int index,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob)
-{
- unsigned long writesize = 0;
- u32 bufmask = 0;
- struct bch_state_t *state = context;
-
- if (!dma_mapping_error(NULL, oob)) {
- bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
- writesize += state->nands[index].oobsize;
- }
- if (!dma_mapping_error(NULL, page)) {
- bufmask |= (BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
- & ~BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY);
- writesize += state->nands[index].writesize;
- }
-
- pr_debug("writesize = %ld, bufmask = 0x%X\n", writesize, bufmask);
- bch_reset(context, index);
-
- /* enable BCH and write NAND data */
- chain->command->cmd =
- BF(6, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WRITE, GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(index, GPMI_CTRL0_CS) |
- BF(0, GPMI_CTRL0_XFER_COUNT);
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] =
- BM_GPMI_ECCCTRL_ENABLE_ECC |
- BF(0x03, GPMI_ECCCTRL_ECC_CMD) |
- BF(bufmask, GPMI_ECCCTRL_BUFFER_MASK);
- chain->command->pio_words[3] = writesize;
- chain->command->pio_words[4] =
- !dma_mapping_error(NULL, page) ? page : 0;
- chain->command->pio_words[5] =
- !dma_mapping_error(NULL, oob) ? oob : 0;
- chain->command->alternate = 0;
- chain++;
-
- /* emit IRQ */
- chain->command->cmd =
- BF(0, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
-
- init_completion(&state->nands[index].done);
-
- return 0;
-}
-
-/**
- * bch_init - Initialize and register ECC.
- *
- * The GPMI driver calls this function once, at the beginning of time, whether
- * or not it decides to use this ECC.
- */
-int __init bch_init(void)
-{
- int err;
-
- /* Check if the BCH hardware is available. */
-
- if (!bch_available(&state.chip))
- return -ENXIO;
-
- /* Give the GPMI driver a descriptor. */
-
- gpmi_ecc_add(&state.chip);
-
- /* Attempt to acquire the BCH interrupt. */
-
- err = request_irq(IRQ_BCH, bch_irq, 0, state.chip.name, &state);
- if (err)
- return err;
-
- printk(KERN_INFO"%s: initialized\n", __func__);
- return 0;
-}
-
-/**
- * bch_exit - Shut down and de-register ECC.
- */
-void bch_exit(void)
-{
- free_irq(IRQ_BCH, &state);
- gpmi_ecc_remove(&state.chip);
-}
diff --git a/drivers/mtd/nand/gpmi/gpmi-ecc8.c b/drivers/mtd/nand/gpmi/gpmi-ecc8.c
deleted file mode 100644
index 5c7f27840f47..000000000000
--- a/drivers/mtd/nand/gpmi/gpmi-ecc8.c
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
- *
- * STMP37XX/STMP378X ECC8 hardware ECC engine
- *
- * 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
- */
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/dma.h>
-#include <mach/stmp3xxx.h>
-#include <mach/irqs.h>
-#include <mach/regs-gpmi.h>
-#include <mach/regs-apbx.h>
-#include <mach/regs-apbh.h>
-#include <mach/platform.h>
-#include "gpmi.h"
-
-#define ECC8_MAX_NANDS 4
-
-static int ecc8_available(void *context);
-static int ecc8_setup(void *context, int index, int writesize, int oobsize);
-static int ecc8_read(void *context, int index,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob);
-static int ecc8_write(void *context, int index,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob);
-static int ecc8_stat(void *ctx, int index, struct mtd_ecc_stats *r);
-static int ecc8_reset(void *context, int index);
-
-struct ecc8_nand {
-};
-
-/**
- * ecc8_state_t - Describes the state of the Reed-Solomon ECC.
- *
- * @chip: A descriptor the GPMI driver uses to track this ECC.
- * @done: A struct completion used to manage ECC interrupts.
- * @stat: Used by the interrupt level to communicate ECC statistics to the
- * base level.
- * @writesize: The page data size.
- * @oobsize: The page OOB size.
- * @ecc_page: The number of ECC bytes associated with each 512-byte data
- * block.
- * @ecc_oob: The number of ECC bytes that cover the free bytes in the OOB.
- * @oob_free: The number of free bytes in the OOB. That is, the number of
- * OOB bytes that are *not* ECC bytes.
- * @r: A bit mask that sets the ECC_CMD field of the GPMI_ECCCTRL
- * register for reading.
- * @w: A bit mask that sets the ECC_CMD field of the GPMI_ECCCTRL
- * register for writing.
- * @bits: The number of 512-byte data blocks in a page. By coincidence,
- * this is also the strength of the ECC algorithm since the
- * hardware is constrained to use ECC-4 with 2K pages and ECC-8
- * with 4K pages. The ECC strength may be the original source of
- * this field's name, but the code actually uses this value in the
- * sense of the number of 512-byte blocks.
- * @s0_mask: This is presumably the mask that should be applied to the
- * ECC8_STATUS0 register before checking for ECC errors. In fact,
- * it is assigned but never used.
- * @s1_mask: This is presumably the mask that should be applied to the
- * ECC8_STATUS1 register before checking for ECC errors. In fact,
- * it is assigned but never used.
- */
-
-struct ecc8_state_t {
- struct gpmi_ecc_descriptor chip;
- struct completion done;
- struct mtd_ecc_stats stat;
- u32 writesize, oobsize;
- u32 ecc_page, ecc_oob, oob_free;
- u32 r, w;
- int bits;
- u32 s0_mask, s1_mask;
-};
-
-/* The singleton struct ecc8_state_t for the ECC8. */
-
-static struct ecc8_state_t state = {
- .chip = {
- .name = "ecc8",
- .setup = ecc8_setup,
- .stat = ecc8_stat,
- .read = ecc8_read,
- .write = ecc8_write,
- .reset = ecc8_reset,
- },
-};
-
-/**
- * ecc8_reset - Resets the ECC8.
- *
- * @context: Context data -- a pointer to a struct ecc8_state_t.
- * @index: ??
- */
-static int ecc8_reset(void *context, int index)
-{
- stmp3xxx_reset_block(REGS_ECC8_BASE, false);
- while (__raw_readl(REGS_ECC8_BASE + HW_ECC8_CTRL) & BM_ECC8_CTRL_AHBM_SFTRST)
- __raw_writel(BM_ECC8_CTRL_AHBM_SFTRST,
- REGS_ECC8_BASE + HW_ECC8_CTRL_CLR);
- __raw_writel(BM_ECC8_CTRL_COMPLETE_IRQ_EN,
- REGS_ECC8_BASE + HW_ECC8_CTRL_SET);
- return 0;
-}
-
-/**
- * ecc8_stat - Gather statistics and clean up after a read operation.
- *
- * @context: Context data -- a pointer to a struct ecc8_state_t.
- * @index: ??
- * @r: A statistics structure that will receive the results of the most
- * recent operation.
- */
-static int ecc8_stat(void *context, int index, struct mtd_ecc_stats *r)
-{
- struct ecc8_state_t *state = context;
-
- wait_for_completion(&state->done);
-
- *r = state->stat;
- state->stat.failed = 0;
- state->stat.corrected = 0;
- return 0;
-}
-
-/**
- * ecc8_irq - Interrupt handler for the ECC8 hardware.
- *
- * This function gains control when the ECC8 hardware interrupts. It
- * acknowledges the interrupt and gathers status information.
- *
- * @irq: The interrupt number.
- * @context: Context data -- a pointer to a struct ecc8_state_t.
- */
-static irqreturn_t ecc8_irq(int irq, void *context)
-{
- int r;
- struct mtd_ecc_stats ecc_stats;
- struct ecc8_state_t *state = context;
- u32 corr;
- u32 s0 = __raw_readl(REGS_ECC8_BASE + HW_ECC8_STATUS0),
- s1 = __raw_readl(REGS_ECC8_BASE + HW_ECC8_STATUS1);
-
- /* Get the physical chip number to which this operation applied. */
-
- r = (s0 & BM_ECC8_STATUS0_COMPLETED_CE) >> 16;
-
- /* Check if there were any errors. */
-
- if (s0 & BM_ECC8_STATUS0_CORRECTED ||
- s0 & BM_ECC8_STATUS0_UNCORRECTABLE) {
-
- ecc_stats.failed = 0;
- ecc_stats.corrected = 0;
-
- /* Check for errors in the OOB bytes. */
-
- s0 = (s0 & BM_ECC8_STATUS0_STATUS_AUX) >> 8;
- if (s0 <= 4)
- ecc_stats.corrected += s0;
- if (s0 == 0xE)
- ecc_stats.failed++;
-
- /* Check for errors in the data bytes. */
-
- for ( ; s1 != 0; s1 >>= 4) {
- corr = s1 & 0xF;
- if (corr == 0x0C)
- continue;
- if (corr == 0xE)
- ecc_stats.failed++;
- if (corr <= 8)
- ecc_stats.corrected += corr;
- s1 >>= 4;
- }
-
- /* Accumulate statistics. */
-
- state->stat.corrected += ecc_stats.corrected;
- state->stat.failed += ecc_stats.failed;
-
- }
-
- /* Acknowledge the interrupt. */
-
- complete(&state->done);
-
- __raw_writel(BM_ECC8_CTRL_COMPLETE_IRQ,
- REGS_ECC8_BASE + HW_ECC8_CTRL_CLR);
- return IRQ_HANDLED;
-}
-
-/**
- * ecc8_available - Returns whether the Reed-Solomon ECC hardware is available.
- *
- * Note that this function always returns true.
- *
- * @context: Context data -- a pointer to a struct ecc8_state_t.
- */
-static int ecc8_available(void *context)
-{
- return 1;
-}
-
-/**
- * ecc8_setup - Set up ECC for use.
- *
- * If the GPMI driver decides to use this ECC, it will call this function once,
- * before it starts any operations.
- *
- * @context: Context data -- a pointer to a struct ecc8_state_t.
- * @index: ??
- * @writesize: The page data size.
- * @oobsize: The page OOB size.
- */
-static int ecc8_setup(void *context, int index, int writesize, int oobsize)
-{
- struct ecc8_state_t *state = context;
-
- switch (writesize) {
- case 2048:
- state->ecc_page = 9;
- state->ecc_oob = 9;
- state->bits = 4;
- state->r = BF(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT,
- GPMI_ECCCTRL_ECC_CMD);
- state->w = BF(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT,
- GPMI_ECCCTRL_ECC_CMD);
- break;
- case 4096:
- state->ecc_page = 18;
- state->ecc_oob = 9;
- state->bits = 8;
- state->r = BF(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT,
- GPMI_ECCCTRL_ECC_CMD);
- state->w = BF(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT,
- GPMI_ECCCTRL_ECC_CMD);
- break;
- default:
- return -ENOTSUPP;
- }
-
- state->oob_free = oobsize -
- (state->bits * state->ecc_page) - state->ecc_oob;
- state->oobsize = oobsize;
- state->writesize = writesize;
-
- ecc8_reset(context, index);
-
- return 0;
-}
-
-/**
- * ecc8_read - Fill in a DMA chain to read a page.
- *
- * @context: Context data -- a pointer to a struct ecc8_state_t.
- * @cs: The chip number to read.
- * @chain: The main descriptor of the DMA chain to fill.
- * @error: ??
- * @page: Physical address of the target page data buffer.
- * @oob: Physical address of the target OOB data buffer.
- *
- * Return: status of operation -- 0 on success
- */
-static int ecc8_read(void *context, int cs,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob)
-{
- unsigned long readsize = 0;
- u32 bufmask = 0;
- struct ecc8_state_t *state = context;
-
- ecc8_reset(context, cs);
-
- state->s0_mask = state->s1_mask = 0;
-
- if (!dma_mapping_error(NULL, page)) {
- bufmask |= (1 << state->bits) - 1;
- readsize += (state->bits * state->ecc_page);
- readsize += state->writesize;
- }
- if (!dma_mapping_error(NULL, oob)) {
- bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__AUXILIARY;
- readsize += state->oob_free + state->ecc_oob;
- state->s0_mask = BM_ECC8_STATUS0_STATUS_AUX;
- if (dma_mapping_error(NULL, page))
- page = oob;
- }
-
- /* wait for ready */
- chain->command->cmd =
- BF(1, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDWAIT4READY |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY,
- GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(BV_GPMI_CTRL0_ADDRESS__NAND_DATA, GPMI_CTRL0_ADDRESS) |
- BF(cs, GPMI_CTRL0_CS);
- chain->command->buf_ptr = 0;
- chain++;
-
- /* enable ECC and read NAND data */
- chain->command->cmd =
- BF(6, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__READ, GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(cs, GPMI_CTRL0_CS) |
- BF(readsize, GPMI_CTRL0_XFER_COUNT);
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] =
- BM_GPMI_ECCCTRL_ENABLE_ECC |
- state->r |
- BF(bufmask, GPMI_ECCCTRL_BUFFER_MASK);
- chain->command->pio_words[3] = readsize;
- chain->command->pio_words[4] = !dma_mapping_error(NULL, page) ? page : 0;
- chain->command->pio_words[5] = !dma_mapping_error(NULL, oob) ? oob : 0;
- chain->command->buf_ptr = 0;
- chain++;
-
- /* disable ECC block */
- chain->command->cmd =
- BF(3, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDWAIT4READY |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY,
- GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF(cs, GPMI_CTRL0_CS);
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] = 0;
- chain->command->buf_ptr = 0;
- chain++;
-
- /* and deassert nand lock */
- chain->command->cmd =
- BF(0, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER, APBH_CHn_CMD_COMMAND);
- chain->command->buf_ptr = 0;
-
- init_completion(&state->done);
-
- return 0;
-}
-
-/**
- * ecc8_write - Fill in a DMA chain to write a page.
- *
- * @context: Context data -- a pointer to a struct ecc8_state_t.
- * @cs: The chip number to read.
- * @chain: The main descriptor of the DMA chain to fill.
- * @error: ??
- * @page: Physical address of the source page data buffer.
- * @oob: Physical address of the source OOB data buffer.
- *
- * Return: status of operation -- 0 on success
- */
-static int ecc8_write(void *context, int cs,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob)
-{
- u32 bufmask = 0;
- struct ecc8_state_t *state = context;
- u32 data_w, data_w_ecc,
- oob_w, oob_w_ecc;
-
- ecc8_reset(context, cs);
-
- data_w = data_w_ecc = oob_w = oob_w_ecc = 0;
-
- if (!dma_mapping_error(NULL, oob)) {
- bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__AUXILIARY;
- oob_w = state->oob_free;
- oob_w_ecc = oob_w + state->ecc_oob;
- }
- if (!dma_mapping_error(NULL, page)) {
- bufmask |= (1 << state->bits) - 1;
- data_w = state->bits * 512;
- data_w_ecc = data_w + state->bits * state->ecc_page;
- }
-
- /* enable ECC and send NAND data (page only) */
- chain->command->cmd =
- BF(data_w ? data_w : oob_w, APBH_CHn_CMD_XFER_COUNT) |
- BF(4, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_NANDLOCK |
- BM_APBH_CHn_CMD_CHAIN |
- BF(BV_APBH_CHn_CMD_COMMAND__DMA_READ, APBH_CHn_CMD_COMMAND);
- chain->command->pio_words[0] =
- BF(BV_GPMI_CTRL0_COMMAND_MODE__WRITE, GPMI_CTRL0_COMMAND_MODE) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BM_GPMI_CTRL0_LOCK_CS |
- BF(cs, GPMI_CTRL0_CS) |
- BF(BV_GPMI_CTRL0_ADDRESS__NAND_DATA, GPMI_CTRL0_ADDRESS) |
- BF(data_w + oob_w, GPMI_CTRL0_XFER_COUNT);
- chain->command->pio_words[1] = 0;
- chain->command->pio_words[2] =
- BM_GPMI_ECCCTRL_ENABLE_ECC |
- state->w |
- BF(bufmask, GPMI_ECCCTRL_BUFFER_MASK);
- chain->command->pio_words[3] =
- data_w_ecc + oob_w_ecc;
- if (!dma_mapping_error(NULL, page))
- chain->command->buf_ptr = page;
- else
- chain->command->buf_ptr = oob;
- chain++;
-
- if (!dma_mapping_error(NULL, page) && !dma_mapping_error(NULL, oob)) {
- /* send NAND data (OOB only) */
- chain->command->cmd =
- BM_APBH_CHn_CMD_CHAIN |
- BF(oob_w, APBH_CHn_CMD_XFER_COUNT) |
- BF(0, APBH_CHn_CMD_CMDWORDS) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_NANDLOCK |
- BF(BV_APBH_CHn_CMD_COMMAND__DMA_READ,
- APBH_CHn_CMD_COMMAND);
- chain->command->buf_ptr = oob; /* never dma_mapping_error() */
- chain++;
- }
- /* emit IRQ */
- chain->command->cmd =
- BF(0, APBH_CHn_CMD_CMDWORDS) |
- BF(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER,
- APBH_CHn_CMD_COMMAND) |
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_IRQONCMPLT;
-
- return 0;
-}
-
-/**
- * ecc8_init - Initialize and register ECC.
- *
- * The GPMI driver calls this function once, at the beginning of time, whether
- * or not it decides to use this ECC.
- */
-int __init ecc8_init(void)
-{
- int err;
-
- /* Check if the ECC8 hardware is available. */
-
- if (!ecc8_available(&state))
- return -ENXIO;
-
- /* Give the GPMI driver a descriptor. */
-
- gpmi_ecc_add(&state.chip);
-
- /* Attempt to acquire the ECC interrupt. */
-
- err = request_irq(IRQ_ECC8_IRQ, ecc8_irq, 0, state.chip.name, &state);
- if (err)
- return err;
-
- printk(KERN_INFO"%s: initialized\n", __func__);
- return 0;
-}
-
-/**
- * ecc8_exit - Shut down and de-register ECC.
- */
-void ecc8_exit(void)
-{
-
- /* Relinquish the ECC interrupt. */
-
- free_irq(IRQ_ECC8_IRQ, &state);
-
- /* Remove the descriptor for this ECC from the GPMI's list. */
-
- gpmi_ecc_remove(&state.chip);
-}
diff --git a/drivers/mtd/nand/gpmi/gpmi-hamming-13-8.c b/drivers/mtd/nand/gpmi/gpmi-hamming-13-8.c
deleted file mode 100644
index 256911050782..000000000000
--- a/drivers/mtd/nand/gpmi/gpmi-hamming-13-8.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
- *
- * NCB software ECC Hamming code
- *
- * 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
- */
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <mach/dma.h>
-#include "gpmi.h"
-
-#define BIT_VAL(v, n) (((v) >> (n)) & 0x1)
-#define B(n) (BIT_VAL(d, n))
-
-static u8 calculate_parity(u8 d)
-{
- u8 p = 0;
-
- if (d == 0 || d == 0xFF)
- return 0; /* optimization :) */
-
- p |= (B(6) ^ B(5) ^ B(3) ^ B(2)) << 0;
- p |= (B(7) ^ B(5) ^ B(4) ^ B(2) ^ B(1)) << 1;
- p |= (B(7) ^ B(6) ^ B(5) ^ B(1) ^ B(0)) << 2;
- p |= (B(7) ^ B(4) ^ B(3) ^ B(0)) << 3;
- p |= (B(6) ^ B(4) ^ B(3) ^ B(2) ^ B(1) ^ B(0)) << 4;
- return p;
-}
-
-static inline int even_number_of_1s(u8 byte)
-{
- int even = 1;
-
- while (byte > 0) {
- even ^= (byte & 0x1);
- byte >>= 1;
- }
- return even;
-}
-
-static int lookup_single_error(u8 syndrome)
-{
- int i;
- u8 syndrome_table[] = {
- 0x1C, 0x16, 0x13, 0x19,
- 0x1A, 0x07, 0x15, 0x0E,
- 0x01, 0x02, 0x04, 0x08,
- 0x10,
- };
-
- for (i = 0; i < ARRAY_SIZE(syndrome_table); i++)
- if (syndrome_table[i] == syndrome)
- return i;
- return -ENOENT;
-}
-
-int gpmi_verify_hamming_13_8(void *data, u8 *parity, size_t size)
-{
- int i;
- u8 *pdata = data;
- int bit_to_flip;
- u8 np, syndrome;
- int errors = 0;
-
- for (i = 0; i < size; i ++, pdata++) {
- np = calculate_parity(*pdata);
- syndrome = np ^ parity[i];
- if (syndrome == 0) /* cool */ {
- continue;
- }
-
- if (even_number_of_1s(syndrome))
- return -i; /* can't recover */
-
- bit_to_flip = lookup_single_error(syndrome);
- if (bit_to_flip < 0)
- return -i; /* can't fix the error */
-
- if (bit_to_flip < 8) {
- *pdata ^= (1 << bit_to_flip);
- errors++;
- }
- }
- return errors;
-}
-
-void gpmi_encode_hamming_13_8(void *source_block, size_t src_size,
- void *source_ecc, size_t ecc_size)
-{
- int i;
- u8 *src = source_block;
- u8 *ecc = source_ecc;
-
- for (i = 0; i < src_size && i < ecc_size; i++)
- ecc[i] = calculate_parity(src[i]);
-}
-
-void gpmi_encode_hamming_ncb_13_8(void *source_block, size_t source_size,
- void *target_block, size_t target_size)
-{
- if (target_size < 12 + 2 * NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
- return;
- memset(target_block, 0xFF, target_size);
- memcpy((u8 *)target_block + 12, source_block, source_size);
- gpmi_encode_hamming_13_8(source_block,
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES,
- (u8 *)target_block + 12 + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES,
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES);
-}
-
-unsigned gpmi_hamming_ecc_size_13_8(int block_size)
-{
- return block_size;
-}
diff --git a/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.c b/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.c
deleted file mode 100644
index cceb35feab2e..000000000000
--- a/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
- *
- * NCB software ECC Hamming code
- *
- * 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
- */
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <mach/dma.h>
-#include "gpmi.h"
-#include "gpmi-hamming-22-16.h"
-
-#define BIT_VAL(v, n) (((v) >> (n)) & 0x1)
-#define B(n) (BIT_VAL(d, n))
-#define BSEQ(a1, a2, a3, a4, a5, a6, a7, a8) \
- (B(a1) ^ B(a2) ^ B(a3) ^ B(a4) ^ B(a5) ^ B(a6) ^ B(a7) ^ B(a8))
-static u8 calculate_parity(u16 d)
-{
- u8 p = 0;
-
- if (d == 0 || d == 0xFFFF)
- return 0; /* optimization :) */
-
- p |= BSEQ(15, 12, 11, 8, 5, 4, 3, 2) << 0;
- p |= BSEQ(13, 12, 11, 10, 9, 7, 3, 1) << 1;
- p |= BSEQ(15, 14, 13, 11, 10, 9, 6, 5) << 2;
- p |= BSEQ(15, 14, 13, 8, 7, 6, 4, 0) << 3;
- p |= BSEQ(12, 9, 8, 7, 6, 2, 1, 0) << 4;
- p |= BSEQ(14, 10, 5, 4, 3, 2, 1, 0) << 5;
- return p;
-}
-
-static inline int even_number_of_1s(u8 byte)
-{
- int even = 1;
-
- while (byte > 0) {
- even ^= (byte & 0x1);
- byte >>= 1;
- }
- return even;
-}
-
-static int lookup_single_error(u8 syndrome)
-{
- int i;
- u8 syndrome_table[] = {
- 0x38, 0x32, 0x31, 0x23, 0x29, 0x25, 0x1C, 0x1A,
- 0x19, 0x16, 0x26, 0x07, 0x13, 0x0E, 0x2C, 0x0D,
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
- };
-
- for (i = 0; i < ARRAY_SIZE(syndrome_table); i++)
- if (syndrome_table[i] == syndrome)
- return i;
- return -ENOENT;
-}
-
-int gpmi_verify_hamming_22_16(void *data, u8 *parity, size_t size)
-{
- int i, j;
- int bit_index, bit_to_flip;
- u16 *pdata = data;
- u8 p = 0, np, syndrome;
- int errors = 0;
-
- for (bit_index = i = j = 0;
- i < size / sizeof(u16);
- i ++, pdata++) {
-
- switch (bit_index) {
-
- case 0:
- p = parity[j] & 0x3F;
- break;
- case 2:
- p = (parity[j++] & 0xC0) >> 6;
- p |= (parity[j] & 0x0F) << 2;
- break;
- case 4:
- p = (parity[j++] & 0xF0) >> 4;
- p |= (parity[j] & 0x03) << 4;
- break;
- case 6:
- p = (parity[j++] & 0xFC) >> 2;
- break;
- default:
- BUG(); /* how did you get this ?! */
- break;
- }
- bit_index = (bit_index + 2) % 8;
-
- np = calculate_parity(*pdata);
- syndrome = np ^ p;
- if (syndrome == 0) /* cool */ {
- continue;
- }
-
- if (even_number_of_1s(syndrome))
- return -i; /* can't recover */
-
- bit_to_flip = lookup_single_error(syndrome);
- if (bit_to_flip < 0)
- return -i; /* can't fix the error */
-
- if (bit_to_flip < 16) {
- *pdata ^= (1 << bit_to_flip);
- errors++;
- }
- }
- return errors;
-}
-
-void gpmi_encode_hamming_22_16(void *source_block, size_t src_size,
- void *source_ecc, size_t ecc_size)
-{
- int i, j, bit_index;
- u16 *src = source_block;
- u8 *ecc = source_ecc;
- u8 np;
-
- for (bit_index = j = i = 0;
- j < src_size/sizeof(u16) && i < ecc_size;
- j++) {
-
- np = calculate_parity(src[j]);
-
- switch (bit_index) {
-
- case 0:
- ecc[i] = np & 0x3F;
- break;
- case 2:
- ecc[i++] |= (np & 0x03) << 6;
- ecc[i] = (np & 0x3C) >> 2;
- break;
- case 4:
- ecc[i++] |= (np & 0x0F) << 4;
- ecc[i] = (np & 0x30) >> 4;
- break;
- case 6:
- ecc[i++] |= (np & 0x3F) << 2;
- break;
- }
- bit_index = (bit_index + 2) % 8;
- }
-
-}
-
-void gpmi_encode_hamming_ncb_22_16(void *source_block, size_t source_size,
- void *target_block, size_t target_size)
-{
- u8 *dst = target_block;
- u8 ecc[NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES];
-
- gpmi_encode_hamming_22_16(source_block,
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES,
- ecc,
- NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES);
- /* create THREE copies of source block */
- memcpy(dst + NAND_HC_ECC_OFFSET_FIRST_DATA_COPY,
- source_block, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES);
- memcpy(dst + NAND_HC_ECC_OFFSET_SECOND_DATA_COPY,
- source_block, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES);
- memcpy(dst + NAND_HC_ECC_OFFSET_THIRD_DATA_COPY,
- source_block, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES);
- /* ..and three copies of ECC block */
- memcpy(dst + NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY,
- ecc, NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES);
- memcpy(dst + NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY,
- ecc, NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES);
- memcpy(dst + NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY,
- ecc, NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES);
-}
-
-unsigned gpmi_hamming_ecc_size_22_16(int block_size)
-{
- return (((block_size * 8) / 16) * 6) / 8;
-}
diff --git a/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.h b/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.h
deleted file mode 100644
index 6959bf3c599e..000000000000
--- a/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
- *
- * NCB software ECC Hamming code
- *
- * 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 __LINUX_GPMI_H
-#define __LINUX_GPMI_H
-
-#define NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES (512)
-#define NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES \
- ((((NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES*8)/16)*6)/8)
-#define NAND_HC_ECC_OFFSET_FIRST_DATA_COPY (0)
-#define NAND_HC_ECC_OFFSET_SECOND_DATA_COPY \
- (NAND_HC_ECC_OFFSET_FIRST_DATA_COPY + \
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
-#define NAND_HC_ECC_OFFSET_THIRD_DATA_COPY \
- (NAND_HC_ECC_OFFSET_SECOND_DATA_COPY + \
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
-#define NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY \
- (NAND_HC_ECC_OFFSET_THIRD_DATA_COPY + \
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
-#define NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY \
- (NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY + \
- NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES)
-#define NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY \
- (NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY + \
- NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES)
-
-#endif
diff --git a/drivers/mtd/nand/gpmi/gpmi.h b/drivers/mtd/nand/gpmi/gpmi.h
deleted file mode 100644
index 6d107bd87688..000000000000
--- a/drivers/mtd/nand/gpmi/gpmi.h
+++ /dev/null
@@ -1,464 +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/partitions.h>
-#include <linux/timer.h>
-#include <mach/gpmi.h>
-#include <mach/regs-gpmi.h>
-#include <mach/regs-apbh.h>
-#include <mach/dma.h>
-#ifdef CONFIG_MTD_NAND_GPMI_BCH
-#include <mach/regs-bch.h>
-#endif
-#include <mach/regs-ecc8.h>
-
-#include "gpmi-hamming-22-16.h"
-#include "../nand_device_info.h"
-
-#define GPMI_ECC4_WR \
- (BM_GPMI_ECCCTRL_ENABLE_ECC | \
- BF(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT, GPMI_ECCCTRL_ECC_CMD))
-#define GPMI_ECC4_RD \
- (BM_GPMI_ECCCTRL_ENABLE_ECC | \
- BF(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT, GPMI_ECCCTRL_ECC_CMD))
-#define GPMI_ECC8_WR \
- (BM_GPMI_ECCCTRL_ENABLE_ECC | \
- BF(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT, GPMI_ECCCTRL_ECC_CMD))
-#define GPMI_ECC8_RD \
- (BM_GPMI_ECCCTRL_ENABLE_ECC | \
- BF(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT, GPMI_ECCCTRL_ECC_CMD))
-
-/* Fingerprints for Boot Control Blocks. */
-
-#define SIG1 "STMP"
-#define SIG_NCB "NCB "
-#define SIG_LDLB "LDLB"
-#define SIG_DBBT "DBBT"
-#define SIG_SIZE 4
-
-/**
- * struct gpmi_nand_timing - NAND Flash timing parameters.
- *
- * This structure contains the fundamental timing attributes for the NAND Flash
- * bus.
- *
- * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the
- * maximum of tDS and tWP. A negative value
- * indicates this characteristic isn't known.
- * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the
- * maximum of tDH, tWH and tREH. A negative value
- * indicates this characteristic isn't known.
- * @address_setup_in_ns: The address setup time, in nanoseconds. Usually
- * the maximum of tCLS, tCS and tALS. A negative
- * value indicates this characteristic isn't known.
- * @gpmi_sample_time_in_ns: A GPMI-specific timing parameter. A negative
- * value indicates this characteristic isn't known.
- * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A
- * negative value indicates this characteristic
- * isn't known.
- * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A
- * negative value indicates this characteristic
- * isn't known.
- * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A
- * negative value indicates this characteristic
- * isn't known.
- */
-
-struct gpmi_nand_timing {
- int8_t data_setup_in_ns;
- int8_t data_hold_in_ns;
- int8_t address_setup_in_ns;
- int8_t gpmi_sample_delay_in_ns;
- int8_t tREA_in_ns;
- int8_t tRLOH_in_ns;
- int8_t tRHOH_in_ns;
-};
-
-/**
- * struct gpmi_bcb_info - Information obtained from Boot Control Blocks.
- *
- * @timing: Timing values extracted from an NCB.
- * @ncbblock: The offset within the MTD at which the NCB was found.
- * @pre_ncb:
- * @pre_ncb_size:
- */
-
-struct gpmi_bcb_info {
- struct gpmi_nand_timing timing;
- loff_t ncbblock;
- const void *pre_ncb;
- size_t pre_ncb_size;
-};
-
-struct gpmi_ncb;
-
-int gpmi_erase(struct mtd_info *mtd, struct erase_info *instr);
-int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs);
-int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip);
-int gpmi_scan_bbt(struct mtd_info *mtd);
-int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip);
-#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES
-int gpmi_sysfs(struct platform_device *p, int create);
-#endif
-int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page, int sndcmd);
-int gpmi_write_ncb(struct mtd_info *mtd, struct gpmi_bcb_info *b);
-
-unsigned gpmi_hamming_ecc_size_22_16(int block_size);
-void gpmi_encode_hamming_ncb_22_16(void *source_block, size_t source_size,
- void *target_block, size_t target_size);
-void gpmi_encode_hamming_22_16(void *source_block, size_t src_size,
- void *source_ecc, size_t ecc_size);
-int gpmi_verify_hamming_22_16(void *data, u8 *parity, size_t size);
-
-unsigned gpmi_hamming_ecc_size_13_8(int block_size);
-void gpmi_encode_hamming_ncb_13_8(void *source_block, size_t source_size,
- void *target_block, size_t target_size);
-void gpmi_encode_hamming_13_8(void *source_block, size_t src_size,
- void *source_ecc, size_t ecc_size);
-int gpmi_verify_hamming_13_8(void *data, u8 *parity, size_t size);
-
-#define GPMI_DMA_MAX_CHAIN 20 /* max DMA commands in chain */
-
-/*
- * Sizes of data buffers to exchange commands/data with NAND chip.
- * Default values cover 4K NAND page (4096 data bytes + 218 bytes OOB)
- */
-#define GPMI_CMD_BUF_SZ 10
-#define GPMI_DATA_BUF_SZ NAND_MAX_PAGESIZE
-#define GPMI_WRITE_BUF_SZ NAND_MAX_PAGESIZE
-#define GPMI_OOB_BUF_SZ NAND_MAX_OOBSIZE
-
-#define GPMI_MAX_CHIPS 10
-
-/**
- * struct gpmi_ecc_descriptor - Abstract description of ECC.
- *
- * @name: The name of the ECC represented by this structure.
- * @list: Infrastructure for the list to which this structure belongs.
- * @setup: A pointer to a function that prepares the ECC to function.
- * @reset: A pointer to a function that resets the ECC to a known state. This
- * pointer is currently never used, and probably should be removed.
- * @read: A pointer to a function that fills in a given DMA chain such that
- * a page read will pass through the owning ECC.
- * @write: A pointer to a function that fills in a given DMA chain such that
- * a page write will pass through the owning ECC.
- * @stat: A pointer to a function that reports on ECC statistics for
- * the preceding read operation.
- */
-
-struct gpmi_ecc_descriptor {
- char name[40];
- struct list_head list;
- int (*setup)(void *ctx, int index, int writesize, int oobsize);
- int (*reset)(void *ctx, int index);
- int (*read)(void *ctx, int index,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob);
- int (*write)(void *ctx, int index,
- struct stmp3xxx_dma_descriptor *chain,
- dma_addr_t error,
- dma_addr_t page, dma_addr_t oob);
- int (*stat)(void *ctx, int index, struct mtd_ecc_stats *r);
-};
-
-/* ECC descriptor management. */
-
-struct gpmi_ecc_descriptor *gpmi_ecc_find(char *name);
-void gpmi_ecc_add(struct gpmi_ecc_descriptor *chip);
-void gpmi_ecc_remove(struct gpmi_ecc_descriptor *chip);
-
-/* Housecleaning functions for the ECC hardware blocks. */
-
-int bch_init(void);
-int ecc8_init(void);
-void bch_exit(void);
-void ecc8_exit(void);
-
-/**
- * struct gpmi_nand_data - GPMI driver per-device data structure.
- *
- * @dev: A pointer to the owning struct device.
- * @gpd: GPMI-specific platform data.
- * @io_base: The base I/O address of of the GPMI registers.
- * @clk: A pointer to the structure that represents the GPMI
- * clock.
- * @irq: The GPMI interrupt request number.
- * @inactivity_timer: A pointer to a timer the driver uses to shut itself
- * down after periods of inactivity.
- * @self_suspended: Indicates the driver suspended itself, rather than
- * being suspended by higher layers of software. This is
- * important because it effects how the driver wakes
- * itself back up.
- * @use_count: Used within the driver to hold off suspension until
- * all operations are complete.
- * @regulator: A pointer to the structure that represents the
- * power regulator supplying power to the GPMI.
- * @reg_uA: The GPMI current limit, in uA.
- * @ignorebad: Forces the driver to report that all blocks are good.
- * @bbt: Used to save a pointer to the in-memory NAND Flash MTD
- * Bad Block Table if the "ignorebad" flag is turned on
- * through the corresponding sysfs node.
- * @mtd: The data structure that represents this NAND Flash
- * medium to MTD.
- * @nand: The data structure that represents this NAND Flash
- * medium to the MTD NAND Flash system.
- * @device_info Detailed information about the NAND Flash device.
- * @partitions: A pointer to an array of partition descriptions
- * collected from the platform. If this member is NULL,
- * then no such partitions were given.
- * @partition_count: The number of elements in the partitions array.
- * @done: A struct completion used to manage GPMI interrupts.
- * @cmd_buffer:
- * @cmd_buffer_handle:
- * @cmd_buffer_size:
- * @cmd_buffer_sz: The number of command and address bytes queued up,
- * waiting for transmission to the NAND Flash.
- * @write_buffer:
- * @write_buffer_handle:
- * @write_buffer_size:
- * @read_buffer:
- * @read_buffer_handle:
- * @data_buffer:
- * @data_buffer_handle:
- * @data_buffer_size:
- * @oob_buffer:
- * @oob_buffer_handle:
- * @oob_buffer_size:
- * @verify_buffer:
- * @chips: An array of data structures, one for each physical
- * chip.
- * @cchip: A pointer to the element within the chips array that
- * represents the currently selected chip.
- * @selected_chip: The currently selectd chip number, or -1 if no chip
- * is selected.
- * @hwecc_type_read:
- * @hwecc_type_write:
- * @hwecc: Never used.
- * @ecc_oob_bytes: The number of ECC bytes covering the OOB bytes alone.
- * @oob_free: The total number of OOB bytes.
- * @transcribe_bbmark: Used by the bad block management code to indicate
- * that the medium is in common format and the bad block
- * marks must be transcribed.
- * @timing: The current timings installed in the hardware.
- * @saved_command: Used to "hook" the NAND Flash MTD default
- * implementation for the cmdfunc fuction pointer.
- * @raw_oob_mode:
- * @saved_read_oob: Used to "hook" the NAND Flash MTD interface function
- * for the MTD read_oob fuction pointer.
- * @saved_write_oob: Used to "hook" the NAND Flash MTD interface function
- * for the MTD write_oob fuction pointer.
- * @hc: A pointer to a structure that represents the ECC
- * in use.
- */
-
-struct gpmi_nand_data {
-
- struct platform_device *dev;
- struct gpmi_platform_data *gpd;
-
- void __iomem *io_base;
- struct clk *clk;
- int irq;
- struct timer_list timer;
- int self_suspended;
- int use_count;
- struct regulator *regulator;
- int reg_uA;
-
- int ignorebad;
- void *bbt;
-
- struct mtd_info mtd;
- struct nand_chip nand;
-
- struct nand_device_info device_info;
-
-#if defined(CONFIG_MTD_PARTITIONS) && defined(CONFIG_MTD_CONCAT)
- struct mtd_info *chip0_boot_mtd;
- struct mtd_info *chip1_boot_mtd;
- struct mtd_info *general_use_mtd;
- struct mtd_partition *partitions;
- unsigned partition_count;
-#endif
-
- struct completion done;
-
- u8 *cmd_buffer;
- dma_addr_t cmd_buffer_handle;
- int cmd_buffer_size, cmd_buffer_sz;
-
- u8 *write_buffer;
- dma_addr_t write_buffer_handle;
- int write_buffer_size;
- u8 *read_buffer; /* point in write_buffer */
- dma_addr_t read_buffer_handle;
-
- u8 *data_buffer;
- dma_addr_t data_buffer_handle;
- int data_buffer_size;
-
- u8 *oob_buffer;
- dma_addr_t oob_buffer_handle;
- int oob_buffer_size;
-
- void *verify_buffer;
-
- struct nchip {
- unsigned dma_ch;
- struct stmp37xx_circ_dma_chain chain;
- struct stmp3xxx_dma_descriptor d[GPMI_DMA_MAX_CHAIN];
- struct stmp3xxx_dma_descriptor error;
- int cs;
- } chips[GPMI_MAX_CHIPS];
- struct nchip *cchip;
- int selected_chip;
-
- unsigned hwecc_type_read, hwecc_type_write;
- int hwecc;
-
- int ecc_oob_bytes, oob_free;
-
- int transcribe_bbmark;
- struct gpmi_nand_timing timing;
-
- void (*saved_command)(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr);
-
- int raw_oob_mode;
- int (*saved_read_oob)(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops);
- int (*saved_write_oob)(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops);
-
- struct gpmi_ecc_descriptor *hc;
-
-};
-
-extern struct gpmi_nand_timing gpmi_safe_timing;
-
-/**
- * struct gpmi_ncb -
- *
- * @fingerprint1:
- * @timing:
- * @pagesize:
- * @page_plus_oob_size:
- * @sectors_per_block:
- * @sector_in_page_mask:
- * @sector_to_page_shift:
- * @num_nands:
- * @fingerprint2:
- */
-
-struct gpmi_ncb {
- u32 fingerprint1;
- struct gpmi_nand_timing timing;
- u32 pagesize;
- u32 page_plus_oob_size;
- u32 sectors_per_block;
- u32 sector_in_page_mask;
- u32 sector_to_page_shift;
- u32 num_nands;
- u32 reserved[3];
- u32 fingerprint2; /* offset 0x2C */
-};
-
-/**
- * struct gpmi_ldlb -
- *
- * @fingerprint1:
- * @major:
- * @minor:
- * @sub:
- * @nand_bitmap:
- * @fingerprint2:
- * @fw:
- * @fw_starting_nand:
- * @fw_starting_sector:
- * @fw_sector_stride:
- * @fw_sectors_total:
- * @fw_major:
- * @fw_minor:
- * @fw_sub:
- * @fw_reserved:
- * @bbt_blk:
- * @bbt_blk_backup:
- */
-
-struct gpmi_ldlb {
- u32 fingerprint1;
- u16 major, minor, sub, reserved;
- u32 nand_bitmap;
- u32 reserved1[7];
- u32 fingerprint2;
- struct {
- u32 fw_starting_nand;
- u32 fw_starting_sector;
- u32 fw_sector_stride;
- u32 fw_sectors_total;
- } fw[2];
- u16 fw_major, fw_minor, fw_sub, fw_reserved;
- u32 bbt_blk;
- u32 bbt_blk_backup;
-};
-
-static inline void gpmi_block_mark_as(struct nand_chip *chip,
- int block, int mark)
-{
- u32 o;
- int shift = (block & 0x03) << 1,
- index = block >> 2;
-
- if (chip->bbt) {
- mark &= 0x03;
-
- o = chip->bbt[index];
- o &= ~(0x03 << shift);
- o |= (mark << shift);
- chip->bbt[index] = o;
- }
-}
-
-static inline int gpmi_block_badness(struct nand_chip *chip, int block)
-{
- u32 o;
- int shift = (block & 0x03) << 1,
- index = block >> 2;
-
- if (chip->bbt) {
- o = (chip->bbt[index] >> shift) & 0x03;
- pr_debug("%s: block = %d, o = %d\n", __func__, block, o);
- return o;
- }
- return -1;
-}
-
-#ifdef CONFIG_STMP3XXX_UNIQUE_ID
-int __init gpmi_uid_init(const char *name, struct mtd_info *mtd,
- u_int32_t start, u_int32_t size);
-void gpmi_uid_remove(const char *name);
-#else
-#define gpmi_uid_init(name, mtd, start, size)
-#define gpmi_uid_remove(name)
-#endif
-
-#endif
diff --git a/drivers/mtd/nand/gpmi1/Makefile b/drivers/mtd/nand/gpmi1/Makefile
deleted file mode 100644
index 1009fbb7b3b5..000000000000
--- a/drivers/mtd/nand/gpmi1/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_MTD_NAND_GPMI1) += gpmi.o
-gpmi-objs += gpmi-base.o gpmi-bbt.o gpmi-bch.o
diff --git a/drivers/mtd/nand/gpmi1/gpmi-base.c b/drivers/mtd/nand/gpmi1/gpmi-base.c
deleted file mode 100644
index fb62a8667194..000000000000
--- a/drivers/mtd/nand/gpmi1/gpmi-base.c
+++ /dev/null
@@ -1,3233 +0,0 @@
-/*
- * Freescale GPMI NAND Flash Driver
- *
- * Author: dmitry pervushin <dimka@embeddedalley.com>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#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/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/concat.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
-#include <asm/div64.h>
-#include <asm/sizes.h>
-
-#include <mach/system.h>
-#include <mach/dmaengine.h>
-#include <mach/device.h>
-#include "gpmi.h"
-#include "../nand_device_info.h"
-
-#define TARGET_GPMI_CLOCK_RATE_IN_HZ (96000000)
-
-#define MAX_DATA_SETUP_CYCLES \
- (BM_GPMI_TIMING0_DATA_SETUP >> BP_GPMI_TIMING0_DATA_SETUP)
-
-#define MAX_DATA_SAMPLE_DELAY_CYCLES \
- ((uint32_t)(BM_GPMI_CTRL1_RDN_DELAY >> BP_GPMI_CTRL1_RDN_DELAY))
-
-/* Right shift value to get the frational GPMI time for data delay. */
-#define GPMI_DELAY_SHIFT (3)
-
-/* Max GPMI clock period the GPMI DLL can tolerate. */
-#define GPMI_MAX_DLL_PERIOD_NS (32)
-
-/*
- * The threshold for the GPMI clock period above which the DLL requires a divide
- * by two.
- */
-#define GPMI_DLL_HALF_THRESHOLD_PERIOD_NS (16)
-
-/* The number of GPMI clock cycles to wait for use of GPMI after DLL enable. */
-#define GPMI_WAIT_CYCLES_AFTER_DLL_ENABLE (64)
-
-/* The time in nanoseconds required for GPMI data read internal setup. */
-#define GPMI_DATA_SETUP_NS (0)
-
-/* The time in nanoseconds required for GPMI data read internal setup */
-#define GPMI_MAX_HARDWARE_DELAY_NS ((uint32_t)(16))
-
-/*
- * Max data delay possible for the GPMI.
- *
- * Use the min of the time (16 nS) or what will fit in the register. If the GPMI
- * clock period is greater than GPMI_MAX_DLL_PERIOD_NS then can't use the delay.
- *
- * Where:
- *
- * c is the GPMI clock period in nanoseconds.
- * f is the GPMI data sample delay fraction.
- *
- */
-#define GPMI_GET_MAX_DELAY_NS(c, f) \
- (\
- (c >= GPMI_MAX_DLL_PERIOD_NS) ? 0 :\
- min(GPMI_MAX_HARDWARE_DELAY_NS, \
- ((MAX_DATA_SAMPLE_DELAY_CYCLES * c) / f)) \
- )
-
-/*
- * Set this variable to a value greater than zero to see varying levels of
- * debugging output.
- */
-
-static int debug;
-
-/*
- * This variable counts the total number of times the driver has copied either
- * page data or OOB data from/to a DMA buffer.
- */
-
-static int copies;
-
-/*
- * Indicates that this driver should attempt to perform DMA directly to/from
- * buffers passed into this driver. If false, this driver will use its own
- * buffer for DMA and copy data between this buffer and the buffers that are
- * passed in.
- */
-
-static int map_buffers = true;
-
-static int ff_writes;
-
-/*
- * Forces all OOB reads and writes to NOT use ECC.
- */
-
-static int raw_mode;
-
-/*
- * Indicates the driver should register an MTD that represents the entire
- * medium.
- */
-
-static int add_mtd_entire;
-
-/*
- * Indicates the driver should report that *all* blocks are good.
- */
-
-static int ignorebad;
-
-/*
- * The maximum number of chips for which the NAND Flash MTD system is allowed to
- * scan.
- */
-
-static int max_chips = 4;
-
-/* Forward references. */
-
-static int gpmi_nand_init_hw(struct platform_device *pdev, int request_pins);
-static void gpmi_nand_release_hw(struct platform_device *pdev);
-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t * buf, int len);
-
-/*
- * This structure contains the "safe" GPMI timings that should succeed with any
- * NAND Flash device (although, with less-than-optimal performance).
- */
-
-struct gpmi_nand_timing gpmi_safe_timing = {
- .data_setup_in_ns = 80,
- .data_hold_in_ns = 60,
- .address_setup_in_ns = 25,
- .gpmi_sample_delay_in_ns = 6,
- .tREA_in_ns = -1,
- .tRLOH_in_ns = -1,
- .tRHOH_in_ns = -1,
-};
-
-/*
- * ECC layout descriptions for various device geometries.
- */
-
-static struct nand_ecclayout gpmi_oob_128 = {
- .oobfree = {
- {
- .offset = 2,
- .length = 56,
- }, {
- .length = 0,
- },
- },
-};
-
-static struct nand_ecclayout gpmi_oob_64 = {
- .oobfree = {
- {
- .offset = 2,
- .length = 16,
- }, {
- .length = 0,
- },
- },
-};
-
-/**
- * gpmi_cycles_ceil - Translates timings in nanoseconds to GPMI clock cycles.
- *
- * @ntime: The time in nanoseconds.
- * @period: The GPMI clock period.
- * @min: The minimum allowable number of cycles.
- */
-static inline u32 gpmi_cycles_ceil(u32 ntime, u32 period, u32 min)
-{
- int k;
-
- /*
- * Compute the minimum number of clock periods that entirely contain the
- * given time.
- */
-
- k = (ntime + period - 1) / period;
-
- return max(k, (int)min);
-
-}
-
-/**
- * gpmi_timer_expiry - Inactivity timer expiration handler.
- */
-static void gpmi_timer_expiry(unsigned long d)
-{
-#ifdef CONFIG_PM
- struct gpmi_nand_data *g = (struct gpmi_nand_data *)d;
-
- pr_debug("%s: timer expired\n", __func__);
- del_timer_sync(&g->timer);
-
- if (g->use_count ||
- __raw_readl(g->io_base + HW_GPMI_CTRL0) & BM_GPMI_CTRL0_RUN) {
- g->timer.expires = jiffies + 4 * HZ;
- add_timer(&g->timer);
- } else {
- __raw_writel(BM_GPMI_CTRL0_CLKGATE,
- g->io_base + HW_GPMI_CTRL0_SET);
- clk_disable(g->clk);
- g->self_suspended = 1;
- }
-#endif
-}
-
-/**
- * gpmi_self_wakeup - wakeup from self-pm light suspend
- */
-static void gpmi_self_wakeup(struct gpmi_nand_data *g)
-{
-#ifdef CONFIG_PM
- int i = 1000;
- clk_enable(g->clk);
- __raw_writel(BM_GPMI_CTRL0_CLKGATE, g->io_base + HW_GPMI_CTRL0_CLR);
- while (i--)
- if (!(__raw_readl(g->io_base +
- HW_GPMI_CTRL0) & BM_GPMI_CTRL0_CLKGATE))
- break;
-
- pr_debug("%s: i stopped at %d, data %p\n", __func__, i, g);
- g->self_suspended = 0;
- g->timer.expires = jiffies + 4 * HZ;
- add_timer(&g->timer);
-#endif
-}
-
-/**
- * gpmi_set_timings - Set GPMI timings.
- *
- * This function adjusts the GPMI hardware timing registers. If the override
- * parameter is NULL, this function will use the timings specified in the per-
- * device data. Otherwise, it will apply the given timings.
- *
- * @g: Per-device data.
- * @override: If not NULL, override the timings in the per-device data.
- */
-void gpmi_set_timings(struct gpmi_nand_data *g,
- struct gpmi_nand_timing *override)
-{
- struct gpmi_platform_data *gpd = g->gpd;
- struct gpmi_nand_timing target;
-
- unsigned long clock_frequency_in_hz;
- uint32_t gpmi_clock_period_in_ns;
- bool dynamic_timing_is_available;
- uint32_t gpmi_delay_fraction;
- uint32_t gpmi_max_delay_in_ns;
- uint32_t address_setup_in_cycles;
- uint32_t data_setup_in_ns;
- uint32_t data_setup_in_cycles;
- uint32_t data_hold_in_cycles;
- int32_t data_sample_delay_in_ns;
- uint32_t data_sample_delay_in_cycles;
- int32_t tEYE;
- uint32_t min_prop_delay_in_ns = gpd->min_prop_delay_in_ns;
- uint32_t max_prop_delay_in_ns = gpd->max_prop_delay_in_ns;
- uint32_t busy_timeout_in_cycles;
- uint32_t register_image;
- uint32_t dll_wait_time_in_us;
-
- /* Wake up. */
-
- if (g->self_suspended)
- gpmi_self_wakeup(g);
-
- g->use_count++;
-
- /*
- * Set the clock as close to the target rate as possible, and compute
- * its period.
- *
- * We first submit the target clock frequency to be rounded. If the
- * result is less than or equal to zero, then the clock refuses to be
- * adjusted and we just accept its current setting. Otherwise, we set
- * it to the successfully rounded frequency.
- */
-
- clock_frequency_in_hz =
- clk_round_rate(g->clk, TARGET_GPMI_CLOCK_RATE_IN_HZ);
-
- if (clock_frequency_in_hz <= 0)
- clock_frequency_in_hz = clk_get_rate(g->clk);
- else
- clk_set_rate(g->clk, clock_frequency_in_hz);
-
- gpmi_clock_period_in_ns = (1000000000 / clock_frequency_in_hz) + 1;
-
- /* Figure out where we're getting our new timing. */
-
- if (override)
- target = *override;
- else {
- target.data_setup_in_ns = g->device_info.data_setup_in_ns;
- target.data_hold_in_ns = g->device_info.data_hold_in_ns;
- target.address_setup_in_ns =
- g->device_info.address_setup_in_ns;
- target.gpmi_sample_delay_in_ns =
- g->device_info.gpmi_sample_delay_in_ns;
- target.tREA_in_ns = g->device_info.tREA_in_ns;
- target.tRLOH_in_ns = g->device_info.tRLOH_in_ns;
- target.tRHOH_in_ns = g->device_info.tRHOH_in_ns;
- }
-
- /* Check if dynamic timing information is available. */
-
- dynamic_timing_is_available = 0;
-
- if ((target.tREA_in_ns >= 0) &&
- (target.tRLOH_in_ns >= 0) &&
- (target.tRHOH_in_ns >= 0))
- dynamic_timing_is_available = !0;
-
- /* Reset the DLL and sample delay to known values. */
-
- __raw_writel(
- BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_DLL_ENABLE,
- g->io_base + HW_GPMI_CTRL1_CLR);
-
- /*
- * Check how fast the GPMI clock is running. If it's running very
- * slowly, we'll need to use half-periods.
- */
-
- if (gpmi_clock_period_in_ns > GPMI_DLL_HALF_THRESHOLD_PERIOD_NS) {
-
- /*
- * The GPMI clock period is high enough that the DLL
- * requires a divide by two.
- */
-
- register_image = __raw_readl(g->io_base + HW_GPMI_CTRL1);
- register_image |= BM_GPMI_CTRL1_HALF_PERIOD;
- __raw_writel(register_image, g->io_base + HW_GPMI_CTRL1);
-
- gpmi_delay_fraction = GPMI_DELAY_SHIFT + 1;
-
- } else {
-
- gpmi_delay_fraction = GPMI_DELAY_SHIFT;
-
- }
-
- gpmi_max_delay_in_ns =
- GPMI_GET_MAX_DELAY_NS(gpmi_clock_period_in_ns,
- gpmi_delay_fraction);
-
- busy_timeout_in_cycles = gpmi_cycles_ceil(10000000 / 4096,
- gpmi_clock_period_in_ns, 0);
-
- /*
- * The hardware quantizes the setup and hold parameters to intervals of
- * the GPMI clock period.
- *
- * Quantize the setup and hold parameters to the next-highest GPMI clock
- * period to make sure we use at least the requested times.
- *
- * For data setup and data hold, the chip interprets a value of zero as
- * the largest amount of delay supported. This is not what's intended by
- * a zero in the input parameter, so we modify the zero input parameter
- * to the smallest supported value.
- */
-
- address_setup_in_cycles = gpmi_cycles_ceil(target.address_setup_in_ns,
- gpmi_clock_period_in_ns, 0);
- data_setup_in_cycles = gpmi_cycles_ceil(target.data_setup_in_ns,
- gpmi_clock_period_in_ns, 1);
- data_hold_in_cycles = gpmi_cycles_ceil(target.data_hold_in_ns,
- gpmi_clock_period_in_ns, 1);
-
- /*
- * Check if dynamic timing is available. If not, we have to use a
- * simpler algorithm for computing the values we put in the hardware
- * registers.
- */
-
- if (!dynamic_timing_is_available) {
-
- /*
- * Get the delay time and include the required chip read setup
- * time.
- */
-
- data_sample_delay_in_ns =
- target.gpmi_sample_delay_in_ns + GPMI_DATA_SETUP_NS;
-
- /*
- * Extend the data setup time as needed to reduce delay time
- * below the max supported by hardware. Also keep it in the
- * allowable range
- */
-
- while ((data_sample_delay_in_ns > gpmi_max_delay_in_ns) &&
- (data_setup_in_cycles < MAX_DATA_SETUP_CYCLES)) {
-
- data_setup_in_cycles++;
- data_sample_delay_in_ns -= gpmi_clock_period_in_ns;
-
- if (data_sample_delay_in_ns < 0)
- data_sample_delay_in_ns = 0;
-
- }
-
- /*
- * Compute the number of cycles that corresponds to the data
- * sample delay.
- */
-
- data_sample_delay_in_cycles =
- gpmi_cycles_ceil(
- gpmi_delay_fraction * data_sample_delay_in_ns,
- gpmi_clock_period_in_ns, 0);
-
- if (data_sample_delay_in_cycles > MAX_DATA_SAMPLE_DELAY_CYCLES)
- data_sample_delay_in_cycles =
- MAX_DATA_SAMPLE_DELAY_CYCLES;
-
- /* Go set up the hadware. */
-
- goto set_up_the_hardware;
-
- }
-
- /*
- * If control arrives here, we can use a more dynamic algorithm for
- * computing the hardware register values.
- */
-
- /* Compute the data setup time for the given number of GPMI cycles. */
-
- data_setup_in_ns = gpmi_clock_period_in_ns * data_setup_in_cycles;
-
- /*
- * This accounts for chip specific GPMI read setup time on the
- * data sample circuit. See i.MX23 reference manual section
- * "14.3.4. High-Speed NAND Timing"
- */
-
- max_prop_delay_in_ns += GPMI_DATA_SETUP_NS;
-
- /*
- * Compute tEYE, the width of the data eye when reading from the
- * NAND Flash.
- *
- * Note that we use the quantized versions of setup and hold because the
- * hardware uses these quantized values, and these timings create the
- * eye.
- *
- * end of the eye = min_prop_delay_in_ns + target.tRHOH_in_ns +
- * data_setup_in_ns
- * start of the eye = max_prop_delay_in_ns + target.tREA_in_ns
- */
-
- tEYE = ((int)min_prop_delay_in_ns +
- (int)target.tRHOH_in_ns + (int)data_setup_in_ns) -
- ((int)max_prop_delay_in_ns + (int)target.tREA_in_ns);
-
- /*
- * The eye has to be open. Constrain tEYE to be greater than zero
- * and the number of data setup cycles to fit in the timing register.
- */
-
- while ((tEYE <= 0) && (data_setup_in_cycles < MAX_DATA_SETUP_CYCLES)) {
-
- /*
- * The eye is not open. An increase in data setup time causes a
- * coresponding increase to size of the eye.
- */
-
- /* Give an additional DataSetup cycle. */
- data_setup_in_cycles++;
- /* Keep the data setup time in step with the cycles. */
- data_setup_in_ns += gpmi_clock_period_in_ns;
- /* And adjust tEYE accordingly. */
- tEYE += gpmi_clock_period_in_ns;
-
- }
-
- /*
- * Compute the ideal point at which to sample the data at the center of
- * the eye.
- */
-
- /*
- * Find the delay to get to the center of the eye, in time units.
- *
- * Delay for center of the eye:
- *
- * ((end of the eye + start of the eye) / 2) - data_setup
- *
- * This simplifies to the following:
- */
-
- data_sample_delay_in_ns =
- ((int)max_prop_delay_in_ns +
- (int)target.tREA_in_ns +
- (int)min_prop_delay_in_ns +
- (int)target.tRHOH_in_ns -
- (int)data_setup_in_ns) >> 1;
-
- /* The chip can't handle a negative parameter for the sample point. */
-
- if (data_sample_delay_in_ns < 0)
- data_sample_delay_in_ns = 0;
-
- /*
- * Make sure the required delay time does not exceed the max allowed
- * value. Also make sure the quantized delay time (at
- * data_sample_delay_in_cycles) is within the eye.
- *
- * Increasing data setup decreases the delay time required to get to
- * into the eye. Increasing data setup also moves the rear of the eye
- * back, enlarging the eye (helpful in the case where quantized delay
- * time does not fall inside the initial eye).
- *
- * ____ _______________________________________
- * RDN \_______________/
- *
- * <----- tEYE ---->
- * /-------------------\
- * Read Data ----------------------------< >------
- * \-------------------/
- * ^ ^ ^ tEYE/2 ^
- * | | | |
- * |<--DataSetup-->|<----DelayTime----->| |
- * | | | |
- * | | |
- * | |<----Quantized DelayTime---------->|
- * | | |
- */
-
- /*
- * Extend the data setup time as needed to reduce delay time below the
- * max allowable value. Also keep data setup in the allowable range.
- */
-
- while ((data_sample_delay_in_ns > gpmi_max_delay_in_ns) &&
- (data_setup_in_cycles < MAX_DATA_SETUP_CYCLES)) {
-
- /* Give an additional data setup cycle. */
- data_setup_in_cycles++;
- /* Keep the data setup time in step with the cycles. */
- data_setup_in_ns += gpmi_clock_period_in_ns;
- /* And adjust tEYE accordingly. */
- tEYE += gpmi_clock_period_in_ns;
-
- /*
- * Decrease the delay time by one half data setup cycle worth,
- * to keep in the middle of the eye.
- */
- data_sample_delay_in_ns -= (gpmi_clock_period_in_ns >> 1);
-
- /* Do not allow a delay time less than zero. */
- if (data_sample_delay_in_ns < 0)
- data_sample_delay_in_ns = 0;
-
- }
-
- /*
- * The sample delay time is expressed in the chip in units of fractions
- * of GPMI clocks. Convert the delay time to an integer quantity of
- * fractional GPMI cycles.
- */
-
- data_sample_delay_in_cycles =
- gpmi_cycles_ceil(
- gpmi_delay_fraction * data_sample_delay_in_ns,
- gpmi_clock_period_in_ns, 0);
-
- if (data_sample_delay_in_cycles > MAX_DATA_SAMPLE_DELAY_CYCLES)
- data_sample_delay_in_cycles = MAX_DATA_SAMPLE_DELAY_CYCLES;
-
- #define DSAMPLE_IS_NOT_WITHIN_THE_DATA_EYE \
- (tEYE>>1 < abs((int32_t)((data_sample_delay_in_cycles * \
- gpmi_clock_period_in_ns) / gpmi_delay_fraction) - \
- data_sample_delay_in_ns))
-
- /*
- * While the quantized delay time is out of the eye, reduce the delay
- * time or extend the data setup time to get in the eye. Do not allow
- * the number of data setup cycles to exceed the max supported by
- * the hardware.
- */
-
- while (DSAMPLE_IS_NOT_WITHIN_THE_DATA_EYE
- && (data_setup_in_cycles < MAX_DATA_SETUP_CYCLES)) {
-
- if (((data_sample_delay_in_cycles * gpmi_clock_period_in_ns) /
- gpmi_delay_fraction) > data_sample_delay_in_ns){
-
- /*
- * If the quantized delay time is greater than the max
- * reach of the eye, decrease the quantized delay time
- * to get it into the eye or before the eye.
- */
-
- if (data_sample_delay_in_cycles != 0)
- data_sample_delay_in_cycles--;
-
- } else {
-
- /*
- * If the quantized delay time is less than the min
- * reach of the eye, shift up the sample point by
- * increasing data setup. This will also open the eye
- * (helping get the quantized delay time in the eye).
- */
-
- /* Give an additional data setup cycle. */
- data_setup_in_cycles++;
- /* Keep the data setup time in step with the cycles. */
- data_setup_in_ns += gpmi_clock_period_in_ns;
- /* And adjust tEYE accordingly. */
- tEYE += gpmi_clock_period_in_ns;
-
- /*
- * Decrease the delay time by one half data setup cycle
- * worth, to keep in the middle of the eye.
- */
- data_sample_delay_in_ns -= (gpmi_clock_period_in_ns>>1);
-
- /* ...and one less period for the delay time. */
- data_sample_delay_in_ns -= gpmi_clock_period_in_ns;
-
- /* Keep the delay time from going negative. */
- if (data_sample_delay_in_ns < 0)
- data_sample_delay_in_ns = 0;
-
- /*
- * Convert time to GPMI cycles and make sure the number
- * of cycles fits in the coresponding hardware register.
- */
-
- data_sample_delay_in_cycles =
- gpmi_cycles_ceil(gpmi_delay_fraction *
- data_sample_delay_in_ns,
- gpmi_clock_period_in_ns, 0);
-
- if (data_sample_delay_in_cycles >
- MAX_DATA_SAMPLE_DELAY_CYCLES)
- data_sample_delay_in_cycles =
- MAX_DATA_SAMPLE_DELAY_CYCLES;
-
-
- }
-
- }
-
- /*
- * Control arrives here when we've computed all the hardware register
- * values (using eithe the static or dynamic algorithm) and we're ready
- * to apply them.
- */
-
-set_up_the_hardware:
-
- /* Set the values in the registers. */
-
- dev_dbg(&g->dev->dev,
- "%s: tAS %u, tDS %u, tDH %u, tDSAMPLE %u, tBTO %u\n",
- __func__,
- address_setup_in_cycles,
- data_setup_in_cycles,
- data_hold_in_cycles,
- data_sample_delay_in_cycles,
- busy_timeout_in_cycles
- );
-
- /* Set up all the simple timing parameters. */
-
- register_image =
- BF_GPMI_TIMING0_ADDRESS_SETUP(address_setup_in_cycles) |
- BF_GPMI_TIMING0_DATA_HOLD(data_setup_in_cycles) |
- BF_GPMI_TIMING0_DATA_SETUP(data_hold_in_cycles) ;
-
- __raw_writel(register_image, g->io_base + HW_GPMI_TIMING0);
-
- __raw_writel(
- BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(busy_timeout_in_cycles),
- g->io_base + HW_GPMI_TIMING1);
-
- /*
- * Hey - pay attention!
- *
- * DLL_ENABLE must be set to zero when setting RDN_DELAY or
- * HALF_PERIOD.
- */
-
- /* BW_GPMI_CTRL1_DLL_ENABLE(0); */
- __raw_writel(BM_GPMI_CTRL1_DLL_ENABLE, g->io_base+HW_GPMI_CTRL1_CLR);
-
- if ((data_sample_delay_in_cycles == 0) ||
- (gpmi_clock_period_in_ns > GPMI_MAX_DLL_PERIOD_NS)) {
-
- /*
- * If no delay is desired, or if the GPMI clock period is out of
- * supported range, then don't enable the delay.
- */
-
- /* BW_GPMI_CTRL1_RDN_DELAY(0); */
- __raw_writel(BM_GPMI_CTRL1_RDN_DELAY,
- g->io_base + HW_GPMI_CTRL1_CLR);
- /* BW_GPMI_CTRL1_HALF_PERIOD(0); */
- __raw_writel(BM_GPMI_CTRL1_HALF_PERIOD,
- g->io_base + HW_GPMI_CTRL1_CLR);
-
- } else {
-
- /*
- * Set the delay and enable the DLL. GPMI_CTRL1_HALF_PERIOD is
- * assumed to have already been set properly.
- */
-
- /* BW_GPMI_CTRL1_RDN_DELAY(data_sample_delay_in_cycles); */
- register_image = __raw_readl(g->io_base + HW_GPMI_CTRL1);
- register_image &= ~BM_GPMI_CTRL1_RDN_DELAY;
- register_image |=
- (data_sample_delay_in_cycles << BP_GPMI_CTRL1_RDN_DELAY)
- & BM_GPMI_CTRL1_RDN_DELAY;
- __raw_writel(register_image, g->io_base + HW_GPMI_CTRL1);
-
- /* BW_GPMI_CTRL1_DLL_ENABLE(1); */
- __raw_writel(BM_GPMI_CTRL1_DLL_ENABLE,
- g->io_base + HW_GPMI_CTRL1_SET);
-
- /*
- * After we enable the GPMI DLL, we have to wait
- * GPMI_WAIT_CYCLES_AFTER_DLL_ENABLE GPMI clock cycles before
- * we can use the GPMI interface.
- *
- * Calculate the amount of time we need to wait, in
- * microseconds.
- */
-
- /*
- * Calculate the wait time and convert from nanoseconds to
- * microseconds.
- */
-
- dll_wait_time_in_us =
- (gpmi_clock_period_in_ns *
- GPMI_WAIT_CYCLES_AFTER_DLL_ENABLE) / 1000;
-
- if (!dll_wait_time_in_us)
- dll_wait_time_in_us = 1;
-
- /*
- * Wait for the DLL to settle.
- */
-
- udelay(dll_wait_time_in_us);
-
- }
-
- /* Allow the driver to go back to sleep, if it wants to. */
-
- g->use_count--;
-
-}
-
-/**
- * bch_mode - Return a hardware register value that selects BCH.
- */
-static inline u32 bch_mode(void)
-{
- u32 c1 = 0;
-
- c1 |= BM_GPMI_CTRL1_BCH_MODE;
-
- return c1;
-}
-
-/**
- * gpmi_nand_init_hw - Initialize the hardware.
- *
- * @pdev: A pointer to the owning platform device.
- * @request_pins: Indicates this function should request GPMI pins.
- *
- * Initialize GPMI hardware and set default (safe) timings for NAND access.
- * Returns error code or 0 on success
- */
-static int gpmi_nand_init_hw(struct platform_device *pdev, int request_pins)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
- struct gpmi_platform_data *gpd =
- (struct gpmi_platform_data *)pdev->dev.platform_data;
- int err = 0;
-
- /* Check if we're supposed to ask for our pins. */
-
- if (request_pins && gpd->pinmux_handler()) {
- dev_err(&pdev->dev, "Can't get GPMI pins\n");
- return -EIO;
- }
-
- /* Try to get the GPMI clock. */
-
- g->clk = clk_get(NULL, "gpmi");
- if (IS_ERR(g->clk)) {
- err = PTR_ERR(g->clk);
- dev_err(&pdev->dev, "Can't get GPMI clock\n");
- goto out;
- }
-
- /* Turn on the GPMI clock. */
-
- clk_enable(g->clk);
-
- /* Reset the GPMI block. */
-
- mxs_reset_block(HW_GPMI_CTRL0 + g->io_base, 1);
-
- /* this CLEARS reset, despite of its name */
- __raw_writel(BM_GPMI_CTRL1_DEV_RESET,
- g->io_base + HW_GPMI_CTRL1_SET);
-
- /* IRQ polarity */
- __raw_writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
- g->io_base + HW_GPMI_CTRL1_SET);
-
- /*
- * Select the ECC to use. The bch_mode() function returns a value that
- * selects whichever hardware is appropriate (q.v.).
- */
- __raw_writel(bch_mode(), g->io_base + HW_GPMI_CTRL1_SET);
-
- /* Choose NAND mode (1 means ATA, 0 - NAND */
- __raw_writel(BM_GPMI_CTRL1_GPMI_MODE,
- g->io_base + HW_GPMI_CTRL1_CLR);
-
-out:
- return err;
-}
-
-/**
- * gpmi_nand_release_hw - free the hardware
- *
- * @pdev: pointer to platform device
- *
- * In opposite to gpmi_nand_init_hw, release all acquired resources.
- */
-static void gpmi_nand_release_hw(struct platform_device *pdev)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
-
- __raw_writel(BM_GPMI_CTRL0_SFTRST, g->io_base + HW_GPMI_CTRL0_SET);
-
- clk_disable(g->clk);
- clk_put(g->clk);
-}
-
-/**
- * gpmi_dma_exchange - Run DMA to exchange with NAND chip
- *
- * @g: Per-device data structure.
- *
- * Run DMA and wait for completion
- */
-static int gpmi_dma_exchange(struct gpmi_nand_data *g)
-{
- struct platform_device *pdev = g->dev;
- unsigned long timeout;
- int err;
- LIST_HEAD(tmp_desc_list);
-
- if (g->self_suspended)
- gpmi_self_wakeup(g);
- g->use_count++;
-
- if (!g->regulator) {
- g->regulator = regulator_get(&pdev->dev, "mmc_ssp-2");
- if (g->regulator && !IS_ERR(g->regulator))
- regulator_set_mode(g->regulator, REGULATOR_MODE_NORMAL);
- else
- g->regulator = NULL;
- }
-
- if (g->regulator)
- regulator_set_current_limit(g->regulator, g->reg_uA, g->reg_uA);
-
- init_completion(&g->done);
- mxs_dma_enable_irq(g->cchip->dma_ch, 1);
-
- mxs_dma_enable(g->cchip->dma_ch);
-
- timeout = wait_for_completion_timeout(&g->done, msecs_to_jiffies(1000));
- err = (timeout <= 0) ? -ETIMEDOUT : 0;
-
- if (err)
- printk(KERN_ERR "%s: error %d, CS = %d, channel %d\n",
- __func__, err, g->cchip->cs, g->cchip->dma_ch);
-
- mxs_dma_cooked(g->cchip->dma_ch, &tmp_desc_list);
- mxs_dma_reset(g->cchip->dma_ch);
-
- if (g->regulator)
- regulator_set_current_limit(g->regulator, 0, 0);
-
- mod_timer(&g->timer, jiffies + 4 * HZ);
- g->use_count--;
-
- return err;
-}
-
-/**
- * gpmi_ecc_read_page - Replacement for nand_read_page
- *
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- */
-static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf)
-{
- struct gpmi_nand_data *g = chip->priv;
- struct mtd_ecc_stats stats;
- dma_addr_t bufphys, oobphys;
- int err;
-
- bufphys = oobphys = ~0;
-
- if (map_buffers && virt_addr_valid(buf))
- bufphys = dma_map_single(&g->dev->dev, buf,
- mtd->writesize, DMA_FROM_DEVICE);
- if (dma_mapping_error(&g->dev->dev, bufphys))
- bufphys = g->data_buffer_handle;
-
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_FROM_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys))
- oobphys = g->oob_buffer_handle;
-
- /* ECC read */
- (void)g->hc->read(g->hc, g->selected_chip, g->cchip->d,
- g->cchip->dma_ch, bufphys, oobphys);
-
- err = gpmi_dma_exchange(g);
-
- g->hc->stat(g->hc, g->selected_chip, &stats);
-
- if (stats.failed || stats.corrected) {
-
- pr_debug("%s: ECC failed=%d, corrected=%d\n",
- __func__, stats.failed, stats.corrected);
-
- g->mtd.ecc_stats.failed += stats.failed;
- g->mtd.ecc_stats.corrected += stats.corrected;
- }
-
- if (!dma_mapping_error(&g->dev->dev, oobphys)) {
- if (oobphys != g->oob_buffer_handle)
- dma_unmap_single(&g->dev->dev, oobphys,
- mtd->oobsize, DMA_FROM_DEVICE);
- else {
- memcpy(chip->oob_poi, g->oob_buffer, mtd->oobsize);
- copies++;
- }
- }
-
- if (!dma_mapping_error(&g->dev->dev, bufphys)) {
- if (bufphys != g->data_buffer_handle)
- dma_unmap_single(&g->dev->dev, bufphys,
- mtd->writesize, DMA_FROM_DEVICE);
- else {
- memcpy(buf, g->data_buffer, mtd->writesize);
- copies++;
- }
- }
-
- /* always fill the (possible ECC bytes with FF) */
- memset(chip->oob_poi + g->oob_free, 0xff, mtd->oobsize - g->oob_free);
-
- return err;
-}
-
-/**
- * is_ff - Checks if all the bits in a buffer are set.
- *
- * @buffer: The buffer of interest.
- * @size: The size of the buffer.
- */
-static inline int is_ff(const u8 *buffer, size_t size)
-{
- while (size--) {
- if (*buffer++ != 0xff)
- return 0;
- }
- return 1;
-}
-
-/**
- * gpmi_ecc_write_page - replacement for nand_write_page
- *
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- */
-static void gpmi_ecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t * buf)
-{
- struct gpmi_nand_data *g = chip->priv;
- struct gpmi_platform_data *gpd = g->gpd;
- uint8_t *bufvirt, *oobvirt;
- dma_addr_t bufphys, oobphys;
- int err;
- uint64_t last_write_byte_address;
-
- /* if we can't map it, copy it */
- bufvirt = (uint8_t *) buf;
- oobvirt = chip->oob_poi;
- bufphys = oobphys = ~0;
-
- if (map_buffers && virt_addr_valid(buf))
- bufphys = dma_map_single(&g->dev->dev,
- (void *)buf, mtd->writesize,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, bufphys)) {
- bufvirt = g->data_buffer;
- bufphys = g->data_buffer_handle;
- memcpy(g->data_buffer, buf, mtd->writesize);
- copies++;
- }
-
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys)) {
- oobvirt = g->oob_buffer;
- oobphys = g->oob_buffer_handle;
- memcpy(g->oob_buffer, chip->oob_poi, mtd->oobsize);
- copies++;
- }
-
- /*
- * Check if we're writing to the boot area.
- *
- * If we're writing to the boot area, then we're almost certainly
- * writing a boot stream. In that case, we need to hack the data that's
- * being written.
- */
-
- last_write_byte_address = g->last_write_page_address * mtd->writesize;
-
- if ((gpd->boot_area_size_in_bytes) &&
- (last_write_byte_address < gpd->boot_area_size_in_bytes)) {
- /*
- printk(KERN_INFO
- "Writing to the boot area at byte:0x%08llx page:0x%08x",
- last_write_byte_address, g->last_write_page_address);
- */
- oobvirt[0] = bufvirt[0];
- }
-
- /* call ECC */
- g->hc->write(g->hc, g->selected_chip, g->cchip->d,
- g->cchip->dma_ch, bufphys, oobphys);
-
- err = gpmi_dma_exchange(g);
- if (err < 0)
- printk(KERN_ERR "%s: dma error\n", __func__);
-
- if (!dma_mapping_error(&g->dev->dev, oobphys)) {
- if (oobphys != g->oob_buffer_handle)
- dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize,
- DMA_TO_DEVICE);
- }
-
- if (bufphys != g->data_buffer_handle)
- dma_unmap_single(&g->dev->dev, bufphys, mtd->writesize,
- DMA_TO_DEVICE);
-}
-
-/**
- * gpmi_write_buf - replacement for nand_write_buf
- *
- * @mtd: MTD device
- * @buf: data buffer
- * @len: length of the data buffer
- */
-static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t * buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct mxs_dma_desc **d = g->cchip->d;
- dma_addr_t phys;
- int err;
-
- BUG_ON(len > mtd->writesize);
-
- phys = ~0;
-
- if (map_buffers && virt_addr_valid(buf))
- phys = dma_map_single(&g->dev->dev,
- (void *)buf, len, DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, phys)) {
- phys = g->write_buffer_handle;
- memcpy(g->write_buffer, buf, len);
- copies++;
- }
-
- /* Write plain 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 = len;
-
- (*d)->cmd.address = phys;
-
- (*d)->cmd.pio_words[0] =
- BM_GPMI_CTRL0_LOCK_CS |
- BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)|
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(g->selected_chip) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) |
- BF_GPMI_CTRL0_XFER_COUNT(len) ;
- (*d)->cmd.pio_words[1] = 0;
- (*d)->cmd.pio_words[2] = 0;
- (*d)->cmd.pio_words[3] = 0;
-
- mxs_dma_desc_append(g->cchip->dma_ch, (*d));
- d++;
-
- err = gpmi_dma_exchange(g);
- if (err)
- printk(KERN_ERR "%s: dma error\n", __func__);
-
- if (phys != g->write_buffer_handle)
- dma_unmap_single(&g->dev->dev, phys, len, DMA_TO_DEVICE);
-
- if (debug >= 2)
- print_hex_dump_bytes("WBUF ", DUMP_PREFIX_OFFSET, buf, len);
-}
-
-/**
- * gpmi_read_buf - replacement for nand_read_buf
- *
- * @mtd: MTD device
- * @buf: pointer to the buffer
- * @len: size of the buffer
- */
-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t * buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct mxs_dma_desc **d = g->cchip->d;
- dma_addr_t phys;
- int err;
-
- phys = ~0;
-
- if (map_buffers && virt_addr_valid(buf))
- phys = dma_map_single(&g->dev->dev, buf, len, DMA_FROM_DEVICE);
- if (dma_mapping_error(&g->dev->dev, phys))
- phys = g->read_buffer_handle;
-
- /* read 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 = len;
-
- (*d)->cmd.address = phys;
-
- (*d)->cmd.pio_words[0] =
- BM_GPMI_CTRL0_LOCK_CS |
- BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(g->selected_chip) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) |
- BF_GPMI_CTRL0_XFER_COUNT(len) ;
-
- mxs_dma_desc_append(g->cchip->dma_ch, (*d));
- d++;
-
- (*d)->cmd.cmd.data = 0;
- (*d)->cmd.cmd.bits.command = NO_DMA_XFER;
- (*d)->cmd.cmd.bits.chain = 0;
- (*d)->cmd.cmd.bits.irq = 1;
- (*d)->cmd.cmd.bits.nand_lock = 0;
- (*d)->cmd.cmd.bits.nand_wait_4_ready = 1;
- (*d)->cmd.cmd.bits.dec_sem = 1;
- (*d)->cmd.cmd.bits.wait4end = 1;
- (*d)->cmd.cmd.bits.halt_on_terminate = 0;
- (*d)->cmd.cmd.bits.terminate_flush = 0;
- (*d)->cmd.cmd.bits.pio_words = 4;
- (*d)->cmd.cmd.bits.bytes = 0;
-
- (*d)->cmd.address = 0;
-
- (*d)->cmd.pio_words[0] =
- BF_GPMI_CTRL0_COMMAND_MODE(
- BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) |
- BM_GPMI_CTRL0_LOCK_CS |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(g->selected_chip) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) |
- 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(g->cchip->dma_ch, (*d));
- d++;
-
- err = gpmi_dma_exchange(g);
- if (err)
- printk(KERN_ERR "%s: dma error\n", __func__);
-
- if (phys != g->read_buffer_handle)
- dma_unmap_single(&g->dev->dev, phys, len, DMA_FROM_DEVICE);
- else {
- memcpy(buf, g->read_buffer, len);
- copies++;
- }
-
- if (debug >= 2)
- print_hex_dump_bytes("RBUF ", DUMP_PREFIX_OFFSET, buf, len);
-}
-
-/**
- * gpmi_read_byte - replacement for nand_read_byte
- * @mtd: MTD device
- *
- * Uses gpmi_read_buf to read 1 byte from device
- */
-static u8 gpmi_read_byte(struct mtd_info *mtd)
-{
- u8 b;
-
- gpmi_read_buf(mtd, (uint8_t *) &b, 1);
- return b;
-}
-
-/**
- * gpmi_read_word - replacement for nand_read_word
- * @mtd: The owning MTD.
- *
- * Uses gpmi_read_buf to read 2 bytes from device
- */
-static u16 gpmi_read_word(struct mtd_info *mtd)
-{
- u16 w;
-
- gpmi_read_buf(mtd, (uint8_t *) &w, sizeof(u16));
- return w;
-}
-
-/**
- * gpmi_dev_ready - Wait until the medium is ready.
- *
- * This function is supposed to return the instantaneous state of the medium.
- * Instead, it actually waits for the medium to be ready. This is mostly
- * harmless, but isn't actually correct.
- *
- * @mtd: The owning MTD.
- */
-static int gpmi_dev_ready(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct mxs_dma_desc **d = g->cchip->d;
- int ret;
-
- /* wait for ready */
-
- (*d)->cmd.cmd.data = 0;
- (*d)->cmd.cmd.bits.command = NO_DMA_XFER;
- (*d)->cmd.cmd.bits.chain = 0;
- (*d)->cmd.cmd.bits.irq = 1;
- (*d)->cmd.cmd.bits.nand_lock = 0;
- (*d)->cmd.cmd.bits.nand_wait_4_ready = 1;
- (*d)->cmd.cmd.bits.dec_sem = 1;
- (*d)->cmd.cmd.bits.wait4end = 1;
- (*d)->cmd.cmd.bits.halt_on_terminate = 0;
- (*d)->cmd.cmd.bits.terminate_flush = 0;
- (*d)->cmd.cmd.bits.pio_words = 4;
- (*d)->cmd.cmd.bits.bytes = 0;
-
- (*d)->cmd.address = 0;
-
- (*d)->cmd.pio_words[0] =
- BF_GPMI_CTRL0_COMMAND_MODE(
- BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(g->selected_chip) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) |
- 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(g->cchip->dma_ch, (*d));
- d++;
-
- ret = gpmi_dma_exchange(g);
-
- if (ret != 0)
- printk(KERN_ERR "gpmi: gpmi_dma_exchange() timeout!\n");
- return ret == 0;
-}
-
-/**
- * gpmi_hwcontrol - Send command/address byte to the NAND Flash.
- *
- * 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.
- * @cmd: The command byte.
- * @ctrl: Control flags.
- */
-static void gpmi_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
- unsigned i;
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- struct mxs_dma_desc **d = g->cchip->d;
- int ret;
-
- /*
- * Every operation begins with a series of command and address bytes,
- * which are distinguished by either the Address Latch Enable (ALE) or
- * Command Latch Enable (CLE) being asserted. Finally, when the caller
- * is actually ready to execute the command, he 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 (cmd != NAND_CMD_NONE)
- g->cmd_buffer[g->cmd_buffer_sz++] = cmd;
- return;
- }
-
- /*
- * If control arrives here, the caller has deasserted both the ALE and
- * CLE, which means he's ready to run an operation. Check if we actually
- * have any bytes to send.
- */
-
- if (g->cmd_buffer_sz == 0)
- return;
-
- /*
- * Check if this is a command that introduces a page write. If so, we
- * need to capture the page address to which we are writing.
- */
-
- if (g->cmd_buffer[0] == NAND_CMD_SEQIN) {
- g->last_write_page_address = 0;
- for (i = 3; i < g->cmd_buffer_sz; i++)
- g->last_write_page_address |=
- g->cmd_buffer[i] << ((i - 3) * 8);
- }
-
- /* output command */
-
- (*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 = g->cmd_buffer_sz;
-
- (*d)->cmd.address = g->cmd_buffer_handle;
-
- (*d)->cmd.pio_words[0] =
- BM_GPMI_CTRL0_LOCK_CS |
- BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)|
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(g->selected_chip) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) |
- BM_GPMI_CTRL0_ADDRESS_INCREMENT |
- BF_GPMI_CTRL0_XFER_COUNT(g->cmd_buffer_sz) ;
-
- (*d)->cmd.pio_words[1] = 0;
- (*d)->cmd.pio_words[2] = 0;
-
- mxs_dma_desc_append(g->cchip->dma_ch, (*d));
- d++;
-
- if (debug >= 3)
- print_hex_dump(KERN_INFO, "CMD ", DUMP_PREFIX_OFFSET, 16, 1,
- g->cmd_buffer, g->cmd_buffer_sz, 1);
-
- ret = gpmi_dma_exchange(g);
-
- if (ret != 0) {
- printk(KERN_ERR "%s: chip %d, dma error %d on the command:\n",
- __func__, g->selected_chip, ret);
- print_hex_dump(KERN_INFO, "CMD ", DUMP_PREFIX_OFFSET, 16, 1,
- g->cmd_buffer, g->cmd_buffer_sz, 1);
- }
-
- gpmi_dev_ready(mtd);
-
- g->cmd_buffer_sz = 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_nand_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 * 2,
- &g->write_buffer_handle, GFP_DMA);
- if (!g->write_buffer)
- goto out2;
-
- g->read_buffer = g->write_buffer + g->write_buffer_size;
- g->read_buffer_handle = g->write_buffer_handle + g->write_buffer_size;
-
- 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->verify_buffer = kzalloc(2 * (g->data_buffer_size +
- g->oob_buffer_size), GFP_KERNEL);
- if (!g->verify_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 * 2,
- 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_nand_data *g)
-{
- kfree(g->verify_buffer);
- 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 * 2,
- 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->data_buffer_size,
- g->data_buffer, g->data_buffer_handle);
-}
-
-/* only used in SW-ECC or NO-ECC cases */
-static int gpmi_verify_buf(struct mtd_info *mtd, const uint8_t * buf, int len)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
-
- chip->read_buf(mtd, g->verify_buffer, len);
-
- if (memcmp(buf, g->verify_buffer, len))
- return -EFAULT;
-
- return 0;
-}
-
-/**
- * gpmi_ecc_read_oob - replacement for nand_read_oob
- *
- * @mtd: MTD device
- * @chip: mtd->priv
- * @page: page address
- * @sndcmd: flag indicates that command should be sent
- */
-int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page, int sndcmd)
-{
- loff_t oob_offset = 0;
-#if 0
- struct gpmi_nand_data *g = chip->priv;
- struct mtd_ecc_stats stats;
- dma_addr_t bufphys, oobphys;
- int ecc;
- int ret;
-#endif
-
- if (sndcmd) {
- chip->cmdfunc(mtd, NAND_CMD_READ0, oob_offset, page);
- sndcmd = 0;
- }
-
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
- return 1;
-
-#if 0
-
- ecc = g->raw_oob_mode == 0 && raw_mode == 0;
-
- if (sndcmd) {
- if (!bch_mode() || !ecc)
- oob_offset = mtd->writesize;
- if (likely(ecc) && !bch_mode())
- oob_offset += chip->ecc.bytes * chip->ecc.steps;
- chip->cmdfunc(mtd, NAND_CMD_READ0, oob_offset, page);
- sndcmd = 0;
- }
-
- if (unlikely(!ecc)) {
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- return 1;
- }
-
- oobphys = ~0;
-
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_FROM_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys))
- oobphys = g->oob_buffer_handle;
-
- bufphys = ~0;
-
- if (map_buffers && bch_mode())
- bufphys = dma_map_single(&g->dev->dev, chip->buffers->databuf,
- mtd->writesize, DMA_FROM_DEVICE);
- if (bch_mode() && dma_mapping_error(&g->dev->dev, bufphys))
- bufphys = g->data_buffer_handle;
-
- /* ECC read */
- (void)g->hc->read(g->hc, g->selected_chip, g->cchip->d,
- g->cchip->dma_ch, bufphys, oobphys);
-
- ret = gpmi_dma_exchange(g);
-
- g->hc->stat(g->hc, g->selected_chip, &stats);
-
- if (stats.failed || stats.corrected) {
-
- printk(KERN_DEBUG "%s: ECC failed=%d, corrected=%d\n",
- __func__, stats.failed, stats.corrected);
-
- g->mtd.ecc_stats.failed += stats.failed;
- g->mtd.ecc_stats.corrected += stats.corrected;
- }
-
- if (oobphys != g->oob_buffer_handle)
- dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize,
- DMA_FROM_DEVICE);
- else {
- memcpy(chip->oob_poi, g->oob_buffer, mtd->oobsize);
- copies++;
- }
-
- if (bufphys != g->data_buffer_handle)
- dma_unmap_single(&g->dev->dev, bufphys, mtd->writesize,
- DMA_FROM_DEVICE);
-
-
- /* fill rest with ff */
- memset(chip->oob_poi + g->oob_free, 0xff, mtd->oobsize - g->oob_free);
-
- return ret ? ret : 1;
-
-#endif
-}
-
-/**
- * gpmi_ecc_write_oob - replacement for nand_write_oob
- *
- * @mtd: MTD device
- * @chip: mtd->priv
- * @page: page address
- */
-static int gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
-{
- int status = 0;
- struct gpmi_nand_data *g = chip->priv;
- loff_t oob_offset = 0;
- dma_addr_t oobphys = ~0, bufphys;
- int ecc;
- int err = 0;
-
- /* if OOB is all FF, leave it as such */
- if (is_ff(chip->oob_poi, mtd->oobsize)) {
- ff_writes++;
-
- pr_debug("%s: Skipping an empty page 0x%x (0x%x)\n",
- __func__, page, page << chip->page_shift);
- return 0;
- }
-
- ecc = g->raw_oob_mode == 0 && raw_mode == 0;
-
- /* Send command to start input data */
- if (!bch_mode() || !ecc) {
- oob_offset = mtd->writesize;
- if (likely(ecc)) {
- oob_offset += chip->ecc.bytes * chip->ecc.steps;
- memset(chip->oob_poi + g->oob_free, 0xff,
- mtd->oobsize - g->oob_free);
- }
- }
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, oob_offset, page);
-
- /* call ECC */
- if (likely(ecc)) {
-
- oobphys = ~0;
-
- if (map_buffers)
- oobphys = dma_map_single(&g->dev->dev, chip->oob_poi,
- mtd->oobsize, DMA_TO_DEVICE);
- if (dma_mapping_error(&g->dev->dev, oobphys)) {
- oobphys = g->oob_buffer_handle;
- memcpy(g->oob_buffer, chip->oob_poi, mtd->oobsize);
- copies++;
- }
-
- bufphys = ~0;
-
- if (bch_mode()) {
- bufphys = g->data_buffer_handle;
- memset(g->data_buffer, 0xff, mtd->writesize);
- }
-
- g->hc->write(g->hc, g->selected_chip, g->cchip->d,
- g->cchip->dma_ch, bufphys, oobphys);
-
- err = gpmi_dma_exchange(g);
-
- } else
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
- /* Send command to program the OOB data */
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-
- /* ..and wait for result */
- status = chip->waitfunc(mtd, chip);
-
- if (likely(ecc)) {
- if (oobphys != g->oob_buffer_handle)
- dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize,
- DMA_TO_DEVICE);
- }
-
- if (status & NAND_STATUS_FAIL) {
- pr_debug("%s: NAND_STATUS_FAIL\n", __func__);
- return -EIO;
- }
-
- return err;
-}
-
-/**
- * gpmi_isr - IRQ handler
- *
- * @irq: Interrupt number.
- * @context: IRQ context, pointer to gpmi_nand_data
- */
-static irqreturn_t gpmi_isr(int irq, void *context)
-{
- struct gpmi_nand_data *g = context;
-
- mxs_dma_ack_irq(g->cchip->dma_ch);
- complete(&g->done);
-
- __raw_writel(BM_GPMI_CTRL1_DEV_IRQ | BM_GPMI_CTRL1_TIMEOUT_IRQ,
- g->io_base + HW_GPMI_CTRL1_CLR);
- return IRQ_HANDLED;
-}
-
-/**
- * gpmi_select_chip() - NAND Flash MTD Interface select_chip()
- *
- * @mtd: A pointer to the owning MTD.
- * @chipnr: The chip number to select, or -1 to select no chip.
- */
-static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
-{
- struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
-
- if (chipnr == g->selected_chip)
- return;
-
- g->selected_chip = chipnr;
- g->cchip = NULL;
-
- if (chipnr == -1)
- return;
-
- g->cchip = g->chips + chipnr;
-}
-
-/**
- * gpmi_command() - NAND Flash MTD Interface cmdfunc()
- *
- * This function is a veneer that calls the function originally installed by the
- * NAND Flash MTD code.
- *
- * @mtd: A pointer to the owning MTD.
- * @command: The command code.
- * @column: The column address associated with this command code, or -1 if
- * no column address applies.
- * @page_addr: The page address associated with this command code, or -1 if no
- * page address applies.
- */
-static void gpmi_command(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr)
-{
- register struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
-
- g->saved_command(mtd, command, column, page_addr);
-}
-
-/**
- * gpmi_read_oob() - MTD Interface read_oob().
- *
- * This function is a veneer that replaces the function originally installed by
- * the NAND Flash MTD code.
- *
- * @mtd: A pointer to the MTD.
- * @from: The starting address to read.
- * @ops: Describes the operation.
- */
-static int gpmi_read_oob(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops)
-{
- register struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- int ret;
-
- g->raw_oob_mode = ops->mode == MTD_OOB_RAW;
- ret = g->saved_read_oob(mtd, from, ops);
- g->raw_oob_mode = 0;
- return ret;
-}
-
-/**
- * gpmi_read_oob() - MTD Interface write_oob().
- *
- * This function is a veneer that replaces the function originally installed by
- * the NAND Flash MTD code.
- *
- * @mtd: A pointer to the MTD.
- * @to: The starting address to write.
- * @ops: Describes the operation.
- */
-static int gpmi_write_oob(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops)
-{
- register struct nand_chip *chip = mtd->priv;
- struct gpmi_nand_data *g = chip->priv;
- int ret;
-
- g->raw_oob_mode = ops->mode == MTD_OOB_RAW;
- ret = g->saved_write_oob(mtd, to, ops);
- g->raw_oob_mode = 0;
- return ret;
-}
-
-/**
- * gpmi_write_page - [REPLACEABLE] write one page
- * @mtd: MTD device structure
- * @chip: NAND chip descriptor
- * @buf: the data to write
- * @page: page number to write
- * @cached: cached programming
- * @raw: use _raw version of write_page
- */
-static int gpmi_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int page, int cached, int raw)
-{
- struct gpmi_nand_data *g = chip->priv;
- int status, empty_data, empty_oob;
- int oobsz;
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- void *vbuf, *obuf;
-#if 0
- void *voob, *ooob;
-#endif
-#endif
-
- oobsz = likely(g->raw_oob_mode == 0 && raw_mode == 0) ?
- g->oob_free : mtd->oobsize;
-
- empty_data = is_ff(buf, mtd->writesize);
- empty_oob = is_ff(buf, oobsz);
-
- if (empty_data && empty_oob) {
- ff_writes++;
-
- pr_debug("%s: Skipping an empty page 0x%x (0x%x)\n",
- __func__, page, page << chip->page_shift);
- return 0;
- }
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-
- if (likely(raw == 0))
- chip->ecc.write_page(mtd, chip, buf);
- else
- chip->ecc.write_page_raw(mtd, chip, buf);
-
- /*
- * Cached progamming disabled for now, Not sure if its worth the
- * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
- */
- cached = 0;
-
- if (!cached || !(chip->options & NAND_CACHEPRG)) {
-
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-
- status = chip->waitfunc(mtd, chip);
-
- /*
- * See if operation failed and additional status checks are
- * available
- */
- if ((status & NAND_STATUS_FAIL) && (chip->errstat))
- status = chip->errstat(mtd, chip, FL_WRITING, status,
- page);
-
- if (status & NAND_STATUS_FAIL) {
- pr_debug("%s: NAND_STATUS_FAIL\n", __func__);
- return -EIO;
- }
- } else {
- chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
- }
-
-#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
- if (empty_data)
- return 0;
-
- obuf = g->verify_buffer;
-#if 1 /* make vbuf aligned by mtd->writesize */
- vbuf = obuf + mtd->writesize;
-#else
- ooob = obuf + mtd->writesize;
- vbuf = ooob + mtd->oobsize;
- voob = vbuf + mtd->writesize;
-#endif
-
- /* keep data around */
- memcpy(obuf, buf, mtd->writesize);
-#if 0
- memcpy(ooob, chip->oob_poi, oobsz);
-#endif
- /* Send command to read back the data */
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- if (likely(raw == 0))
- chip->ecc.read_page(mtd, chip, vbuf);
- else
- chip->ecc.read_page_raw(mtd, chip, vbuf);
-
-#if 0
- memcpy(voob, chip->oob_poi, oobsz);
-#endif
-
- if (!empty_data && memcmp(obuf, vbuf, mtd->writesize) != 0)
- return -EIO;
-#endif
-
- return 0;
-}
-
-/**
- * gpmi_read_page_raw - [Intern] read raw page data without ecc
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- */
-static int gpmi_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf)
-{
- chip->read_buf(mtd, buf, mtd->writesize);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- return 0;
-}
-
-/**
- * gpmi_write_page_raw - [Intern] raw page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- */
-static void gpmi_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
-{
- chip->write_buf(mtd, buf, mtd->writesize);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-}
-
-/**
- * gpmi_init_chip - Sets up the driver to control the given chip.
- *
- * @pdev: A pointer to the owning struct platform_device.
- * @g: Per-device data.
- * @n: The chip number.
- * @dma_ch: The DMA channel to use with this chip.
- */
-static int gpmi_init_chip(struct platform_device *pdev,
- struct gpmi_nand_data *g, int n, unsigned dma_ch)
-{
- struct device *dev = &pdev->dev;
- int err;
- int i;
-
- g->chips[n].cs = n;
- g->chips[n].dma_ch = dma_ch;
-
- err = mxs_dma_request(dma_ch, dev, dev_name(dev));
- if (err) {
- dev_err(&pdev->dev, "Can't acquire DMA channel %u\n", dma_ch);
- goto out_channel;
- }
-
- mxs_dma_reset(dma_ch);
- mxs_dma_ack_irq(dma_ch);
-
- for (i = 0; i < GPMI_DMA_MAX_CHAIN; i++) {
- g->chips[n].d[i] = mxs_dma_alloc_desc();
- if (!g->chips[n].d[i]) {
- err = -ENOMEM;
- dev_err(dev, "Cannot allocate all DMA descriptors.\n");
- goto out_descriptors;
- }
- }
-
-out_descriptors:
- while (--i >= 0)
- mxs_dma_free_desc(g->chips[n].d[i]);
-out_channel:
- return err;
-}
-
-/**
- * gpmi_deinit_chip - Tears down this driver's control of the given chip.
- *
- * @pdev: A pointer to the owning struct platform_device.
- * @g: Per-device data.
- * @n: The chip number.
- */
-static void gpmi_deinit_chip(struct platform_device *pdev,
- struct gpmi_nand_data *g, int n)
-{
- struct device *dev = &pdev->dev;
- int dma_ch;
- int i;
-
- if (n < 0) {
- for (n = 0; n < ARRAY_SIZE(g->chips); n++)
- gpmi_deinit_chip(pdev, g, n);
- return;
- }
-
- if (g->chips[n].dma_ch <= 0)
- return;
-
- dma_ch = g->chips[n].dma_ch;
-
- for (i = 0; i < GPMI_DMA_MAX_CHAIN; i++)
- mxs_dma_free_desc(g->chips[n].d[i]);
-
- mxs_dma_enable_irq(dma_ch, 0);
- mxs_dma_disable(dma_ch);
- mxs_dma_release(dma_ch, dev);
-}
-
-/**
- * gpmi_get_device_info() - Get information about the NAND Flash devices.
- *
- * @g: Per-device data.
- */
-static int gpmi_get_device_info(struct gpmi_nand_data *g)
-{
- unsigned i;
- uint8_t id_bytes[NAND_DEVICE_ID_BYTE_COUNT];
- struct mtd_info *mtd = &g->mtd;
- struct nand_chip *nand = &g->nand;
- struct nand_device_info *info;
-
- /* Read ID bytes from the first NAND Flash chip. */
-
- nand->select_chip(mtd, 0);
-
- gpmi_command(mtd, NAND_CMD_READID, 0x00, -1);
-
- for (i = 0; i < NAND_DEVICE_ID_BYTE_COUNT; i++)
- id_bytes[i] = nand->read_byte(mtd);
-
- /* Get 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;
- }
-
- /*
- * Copy the device info into the per-device data. We can't just keep
- * the pointer because that storage is reclaimed after initialization.
- */
-
- g->device_info = *info;
-
- /* Display the information we got. */
-
- nand_device_print_info(&g->device_info);
-
- /* Return success. */
-
- return 0;
-
-}
-
-/**
- * gpmi_scan_middle - Intermediate initialization.
- *
- * @g: Per-device data structure.
- *
- * Rather than call nand_scan(), this function makes the same calls, but
- * inserts this function into the initialization pathway.
- */
-static int gpmi_scan_middle(struct gpmi_nand_data *g)
-{
- struct mtd_info *mtd = &g->mtd;
- struct nand_chip *nand = &g->nand;
- struct nand_device_info *info = &g->device_info;
- int index = 0;
- uint64_t physical_medium_size_in_bytes;
- uint64_t logical_medium_size_in_bytes;
- uint64_t logical_chip_size_in_bytes;
- uint32_t page_data_size_in_bytes;
- uint32_t page_oob_size_in_bytes;
-
- /*
- * Hook the command function provided by the reference implementation.
- * This has to be done here, rather than at initialization time, because
- * the NAND Flash MTD installed the reference implementation only just
- * now.
- */
-
- g->saved_command = nand->cmdfunc;
- nand->cmdfunc = gpmi_command;
-
- /* Identify the NAND Flash devices. */
-
- if (gpmi_get_device_info(g))
- return -ENXIO;
-
- /* Update timings. */
-
- gpmi_set_timings(g, 0);
-
- /*
- * Compute some important facts about the medium.
- *
- * Note that we don't yet support a medium of size larger than 2 GiB. If
- * we find the physical medium is too large, then we pretend it's
- * smaller.
- */
-
- physical_medium_size_in_bytes =
- nand->numchips * info->chip_size_in_bytes;
-
- if (physical_medium_size_in_bytes > (2LL*SZ_1G)) {
- logical_medium_size_in_bytes = 2LL*SZ_1G;
- logical_chip_size_in_bytes = 2LL*SZ_1G;
- do_div(logical_chip_size_in_bytes, nand->numchips);
-
- } else {
- logical_medium_size_in_bytes = physical_medium_size_in_bytes;
- logical_chip_size_in_bytes = info->chip_size_in_bytes;
- }
-
- page_data_size_in_bytes = 1 << (fls(info->page_total_size_in_bytes)-1);
- page_oob_size_in_bytes = info->page_total_size_in_bytes -
- page_data_size_in_bytes;
-
- /*
- * In all currently-supported geometries, the number of ECC bytes that
- * apply to the OOB bytes is the same.
- */
-
- g->ecc_oob_bytes = 9;
-
- /* Configure ECC. */
-
- switch (page_data_size_in_bytes) {
- case 2048:
- nand->ecc.layout = &gpmi_oob_64;
- nand->ecc.bytes = 9;
- g->oob_free = 19;
- break;
- case 4096:
- nand->ecc.layout = &gpmi_oob_128;
- nand->ecc.bytes = 18;
- g->oob_free = 65;
- break;
- default:
- printk(KERN_ERR "Unsupported page data size %d.",
- page_data_size_in_bytes);
- return -ENXIO;
- break;
- }
-
- mtd->ecclayout = nand->ecc.layout;
-
- /* Configure the MTD geometry. */
-
- mtd->size = logical_medium_size_in_bytes;
- mtd->erasesize = info->block_size_in_pages * page_data_size_in_bytes;
- mtd->writesize = page_data_size_in_bytes;
- mtd->oobavail = mtd->ecclayout->oobavail;
- mtd->oobsize = page_oob_size_in_bytes;
- mtd->subpage_sft = 0; /* We don't support sub-page writing. */
-
- /* Configure the struct nand_chip geometry. */
-
- nand->chipsize = logical_chip_size_in_bytes;
- nand->page_shift = ffs(page_data_size_in_bytes) - 1;
- nand->pagemask = (nand->chipsize >> nand->page_shift) - 1;
- nand->subpagesize = mtd->writesize >> mtd->subpage_sft;
- nand->phys_erase_shift = ffs(mtd->erasesize) - 1;
- nand->bbt_erase_shift = nand->phys_erase_shift;
- nand->chip_shift = ffs(nand->chipsize) - 1;
-
- /* Sanity check */
-
- if (mtd->oobsize > NAND_MAX_OOBSIZE ||
- mtd->writesize > NAND_MAX_PAGESIZE) {
- printk(KERN_ERR "Internal error. Either page size "
- "(%d) > max (%d) "
- "or oob size (%d) > max(%d). Sorry.\n",
- mtd->oobsize, NAND_MAX_OOBSIZE,
- mtd->writesize, NAND_MAX_PAGESIZE);
- return -ERANGE;
- }
-
- /* Install the ECC. */
-
- g->hc = gpmi_ecc_find("bch");
- for (index = 0; index < nand->numchips; index++)
- g->hc->setup(g->hc, index, mtd->writesize, mtd->oobsize);
-
- /* Return success. */
-
- return 0;
-
-}
-
-/**
- * gpmi_register_with_mtd - Registers devices with MTD.
- *
- * @g: Per-device data.
- */
-static int gpmi_register_with_mtd(struct gpmi_nand_data *g)
-{
- struct mtd_info *mtd = &g->mtd;
-#if defined(CONFIG_MTD_PARTITIONS)
- int r;
- unsigned i;
- struct gpmi_platform_data *gpd = g->gpd;
- struct nand_chip *nand = &g->nand;
- struct mtd_partition partitions[2];
- struct mtd_info *search_mtd;
-
- /*
- * 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 table to find the MTDs we created. Since we're using
- * static strings, we can search the master table for an MTD with a name
- * field pointing to a known address.
- */
-
- static char *gpmi_0_boot_name = "gpmi-0-boot";
- static char *gpmi_general_use_name = "gpmi-general-use";
-#endif
-
- /* Initialize the MTD object. */
-
- mtd->priv = &g->nand;
- mtd->name = "gpmi-medium";
- mtd->owner = THIS_MODULE;
-
- /*
- * Signal Control
- */
-
- g->nand.cmd_ctrl = gpmi_hwcontrol;
-
- /*
- * Chip Control
- *
- * The cmdfunc pointer is assigned elsewhere.
- * We use the reference implementation of waitfunc.
- */
-
- g->nand.dev_ready = gpmi_dev_ready;
- g->nand.select_chip = gpmi_select_chip;
-
- /*
- * Low-level I/O
- */
-
- g->nand.read_byte = gpmi_read_byte;
- g->nand.read_word = gpmi_read_word;
- g->nand.read_buf = gpmi_read_buf;
- g->nand.write_buf = gpmi_write_buf;
- g->nand.verify_buf = gpmi_verify_buf;
-
- /*
- * ECC Control
- *
- * None of these functions are necessary:
- * - ecc.hwctl
- * - ecc.calculate
- * - ecc.correct
- */
-
- /*
- * ECC-aware I/O
- */
-
- g->nand.ecc.read_page = gpmi_ecc_read_page;
- g->nand.ecc.read_page_raw = gpmi_read_page_raw;
- g->nand.ecc.write_page = gpmi_ecc_write_page;
- g->nand.ecc.write_page_raw = gpmi_write_page_raw;
-
- /*
- * High-level I/O
- *
- * This driver doesn't assign the erase_cmd pointer at the NAND Flash
- * chip level. Instead, it intercepts the erase operation at the MTD
- * level (see the assignment to mtd.erase below).
- */
-
- g->nand.write_page = gpmi_write_page;
- g->nand.ecc.read_oob = gpmi_ecc_read_oob;
- g->nand.ecc.write_oob = gpmi_ecc_write_oob;
-
- /*
- * Bad Block Management
- *
- * We use the reference implementation of block_markbad.
- */
-
- g->nand.block_bad = gpmi_block_bad;
- g->nand.scan_bbt = gpmi_scan_bbt;
-
- g->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
- g->nand.ecc.size = 512;
-
- g->cmd_buffer_sz = 0;
-
- /*
- * We now want the NAND Flash MTD system to scan for chips and create
- * the MTD data structure that represents the medium.
- *
- * At this point, most drivers would call nand_scan(). Instead, this
- * driver directly performs most of the same operations nand_scan()
- * would, and introduces some additional initialization work in the
- * "middle."
- */
-
- pr_info("Scanning for NAND Flash chips...\n");
-
- if (nand_scan_ident(&g->mtd, max_chips)
- || gpmi_scan_middle(g)
- || nand_scan_tail(&g->mtd)) {
-
- /*
- * If control arrives here, something went wrong.
- */
-
- dev_err(&g->dev->dev, "No NAND Flash chips found\n");
- return !0;
-
- }
-
- /* Completely disallow partial page writes. */
-
- g->nand.options |= NAND_NO_SUBPAGE_WRITE;
- g->nand.subpagesize = g->mtd.writesize;
- g->mtd.subpage_sft = 0;
-
- /* Hook OOB read and write operations at the MTD level. */
-
- g->saved_read_oob = g->mtd.read_oob;
- g->saved_write_oob = g->mtd.write_oob;
- g->mtd.read_oob = gpmi_read_oob;
- g->mtd.write_oob = gpmi_write_oob;
-
-#if !defined(CONFIG_MTD_PARTITIONS)
-
- /*
- * If control arrives here, we're missing support for either or both of
- * MTD partitioning and concatenation. Do the simple thing and register
- * the entire medium.
- */
-
- pr_info("MTD partitioning and/or concatenation are disabled.\n"
- "Registering the entire GPMI medium...\n");
-
- add_mtd_device(mtd);
-
-#else
-
- /*
- * Our goal here is to partition the medium in a way that protects the
- * boot area. First, check if the platform data says we need to
- * protect it.
- */
-
- if (!gpd->boot_area_size_in_bytes) {
-
- /*
- * If control arrives here, we don't need to protect the boot
- * area. Make the entire medium available for general use.
- */
-
- pr_info("Boot area protection disabled.\n"
- "Opening the entire medium for general use.\n");
-
- g->general_use_mtd = mtd;
-
- } else {
-
- pr_info("Boot area protection enabled: 0x%x bytes.\n",
- gpd->boot_area_size_in_bytes);
-
- /*
- * If control arrives here, we need to protect the boot area.
- * First, check if the area we're supposed to protect is larger
- * than a single chip.
- */
-
- if (gpd->boot_area_size_in_bytes > nand->chipsize) {
- dev_emerg(&g->dev->dev, "Protected boot area size is "
- "larger than a single chip");
- BUG();
- }
-
- /*
- * We partition the medium like so:
- *
- * +------+-------------------------------------------+
- * | Boot | General Use |
- * +------+-------------------------------------------+
- */
-
- /* Chip 0 Boot */
-
- partitions[0].name = gpmi_0_boot_name;
- partitions[0].offset = 0;
- partitions[0].size = gpd->boot_area_size_in_bytes;
- partitions[0].mask_flags = 0;
-
- /* General Use */
-
- partitions[1].name = gpmi_general_use_name;
- partitions[1].offset = gpd->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 == gpmi_general_use_name)
- g->general_use_mtd = search_mtd;
- }
-
- if (!g->general_use_mtd) {
- dev_emerg(&g->dev->dev, "Can't find general "
- "use MTD");
- BUG();
- }
-
- }
-
- /*
- * When control arrives here, we've done whatever partitioning we needed
- * to protect the boot area, and we have identified a single MTD that
- * represents the "general use" portion of the medium. Check if the user
- * wants to partition the general use MTD further.
- */
-
- /* Check for dynamic partitioning information. */
-
- if (gpd->partition_source_types) {
- r = parse_mtd_partitions(mtd, gpd->partition_source_types,
- &g->partitions, 0);
- if (r > 0)
- g->partition_count = r;
- else {
- g->partitions = 0;
- g->partition_count = 0;
- }
- }
-
- /* Fall back to platform partitions? */
-
- if (!g->partition_count && gpd->partitions && gpd->partition_count) {
- g->partitions = gpd->partitions;
- g->partition_count = gpd->partition_count;
- }
-
- /* If we have partitions, implement them. */
-
- if (g->partitions) {
- pr_info("Applying partitions to the general use area.\n");
- add_mtd_partitions(g->general_use_mtd,
- g->partitions, g->partition_count);
- }
-
- /*
- * Check if we're supposed to register the MTD that represents
- * the entire medium.
- */
-
- if (add_mtd_entire) {
- pr_info("Registering the full NAND Flash medium MTD.\n");
- add_mtd_device(mtd);
- }
-
-#endif
-
- /* If control arrives here, everything went well. */
-
- return 0;
-
-}
-
-/**
- * gpmi_unregister_with_mtd - Unregisters devices with MTD.
- *
- * @g: Per-device data.
- */
-static void gpmi_unregister_with_mtd(struct gpmi_nand_data *g)
-{
- struct mtd_info *mtd = &g->mtd;
-#if defined(CONFIG_MTD_PARTITIONS)
- struct gpmi_platform_data *gpd = g->gpd;
-#endif
-
- /*
- * This function mirrors, in reverse, the structure of
- * gpmi_register_with_mtd(). See that function for details about how we
- * partition the medium.
- */
-
-#if !defined(CONFIG_MTD_PARTITIONS)
-
- del_mtd_device(mtd);
-
-#else
-
- /*
- * If we registered 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 (add_mtd_entire)
- del_mtd_device(mtd);
-
- /* If we partitioned the general use MTD, destroy the partitions. */
-
- if (g->partitions)
- del_mtd_partitions(g->general_use_mtd);
-
- /*
- * If we're protecting the boot area, we have some additional MTDs to
- * tear down.
- */
-
- if (gpd->boot_area_size_in_bytes) {
-
- /*
- * Destroy all the partition MTDs based directly on the medium
- * MTD.
- */
-
- del_mtd_partitions(mtd);
-
- }
-
-#endif
-
-}
-
-/**
- * show_timings() - Shows the current NAND Flash timing.
- *
- * @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_timings(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct gpmi_nand_data *g = dev_get_drvdata(d);
- uint32_t register_image;
- uint32_t data_setup_in_cycles;
- uint32_t effective_data_setup_in_ns;
- uint32_t data_hold_in_cycles;
- uint32_t effective_data_hold_in_ns;
- uint32_t address_setup_in_cycles;
- uint32_t effective_address_setup_in_ns;
- uint32_t sample_delay_in_cycles;
- uint32_t effective_sample_delay_in_ns;
- bool sample_delay_uses_half_period;
- uint32_t gpmi_clock_frequency_in_khz =
- clk_get_rate(g->clk);
- uint32_t gpmi_clock_period_in_ns =
- 1000000 / gpmi_clock_frequency_in_khz;
-
- /* Retrieve basic timing facts. */
-
- register_image = __raw_readl(g->io_base + HW_GPMI_TIMING0);
-
- data_setup_in_cycles = (register_image & BM_GPMI_TIMING0_DATA_SETUP)
- >> BP_GPMI_TIMING0_DATA_SETUP;
- data_hold_in_cycles = (register_image & BM_GPMI_TIMING0_DATA_HOLD)
- >> BP_GPMI_TIMING0_DATA_HOLD;
- address_setup_in_cycles =
- (register_image & BM_GPMI_TIMING0_ADDRESS_SETUP)
- >> BP_GPMI_TIMING0_ADDRESS_SETUP;
-
- effective_data_setup_in_ns =
- data_setup_in_cycles * gpmi_clock_period_in_ns;
- effective_data_hold_in_ns =
- data_hold_in_cycles * gpmi_clock_period_in_ns;
- effective_address_setup_in_ns =
- address_setup_in_cycles * gpmi_clock_period_in_ns;
-
- /* Retrieve facts about the sample delay. */
-
- register_image = __raw_readl(g->io_base + HW_GPMI_CTRL1);
-
- sample_delay_in_cycles = (register_image & BM_GPMI_CTRL1_RDN_DELAY)
- >> BP_GPMI_CTRL1_RDN_DELAY;
-
- sample_delay_uses_half_period =
- !!((register_image & BM_GPMI_CTRL1_HALF_PERIOD)
- >> BP_GPMI_CTRL1_HALF_PERIOD);
-
- effective_sample_delay_in_ns =
- sample_delay_in_cycles * gpmi_clock_period_in_ns;
-
- if (sample_delay_uses_half_period)
- effective_sample_delay_in_ns >>= 1;
-
- /* Show the results. */
-
- return sprintf(buf,
- "GPMI Clock Frequency : %u KHz\n"
- "GPMI Clock Period : %u ns\n"
- "Recorded Data Setup : %d ns\n"
- "Hardware Data Setup : %u cycles\n"
- "Effective Data Setup : %u ns\n"
- "Recorded Data Hold : %d ns\n"
- "Hardware Data Hold : %u cycles\n"
- "Effective Data Hold : %u ns\n"
- "Recorded Address Setup: %d ns\n"
- "Hardware Address Setup: %u cycles\n"
- "Effective Address Setup: %u ns\n"
- "Recorded Sample Delay : %d ns\n"
- "Hardware Sample Delay : %u cycles\n"
- "Using Half Period : %s\n"
- "Effective Sample Delay : %u ns\n"
- "Recorded tREA : %d ns\n"
- "Recorded tRLOH : %d ns\n"
- "Recorded tRHOH : %d ns\n"
- ,
- gpmi_clock_frequency_in_khz,
- gpmi_clock_period_in_ns,
- g->device_info.data_setup_in_ns,
- data_setup_in_cycles,
- effective_data_setup_in_ns,
- g->device_info.data_hold_in_ns,
- data_hold_in_cycles,
- effective_data_hold_in_ns,
- g->device_info.address_setup_in_ns,
- address_setup_in_cycles,
- effective_address_setup_in_ns,
- g->device_info.gpmi_sample_delay_in_ns,
- sample_delay_in_cycles,
- (sample_delay_uses_half_period ? "Yes" : "No"),
- effective_sample_delay_in_ns,
- g->device_info.tREA_in_ns,
- g->device_info.tRLOH_in_ns,
- g->device_info.tRHOH_in_ns);
-
-}
-
-/**
- * store_timings() - Sets the current NAND Flash timing.
- *
- * @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_timings(struct device *d, struct device_attribute *attr,
- const char *buf, size_t size)
-{
- const char *p, *end;
- struct gpmi_nand_timing t;
- struct gpmi_nand_data *g = dev_get_drvdata(d);
- char tmps[20];
- u8 *timings[] = {
- &t.data_setup_in_ns,
- &t.data_hold_in_ns,
- &t.address_setup_in_ns,
- &t.gpmi_sample_delay_in_ns,
- NULL,
- };
- u8 **timing = timings;
-
- p = buf;
-
- /* parse values */
- while (*timing != NULL) {
- unsigned long t_long;
-
- end = strchr(p, ',');
- memset(tmps, 0, sizeof(tmps));
- if (end)
- strncpy(tmps, p, min_t(int, sizeof(tmps) - 1, end - p));
- else
- strncpy(tmps, p, sizeof(tmps) - 1);
-
- if (strict_strtoul(tmps, 0, &t_long) < 0)
- return -EINVAL;
-
- if (t_long > 255)
- return -EINVAL;
-
- **timing = (u8) t_long;
- timing++;
-
- if (!end && *timing)
- return -EINVAL;
- p = end + 1;
- }
-
- gpmi_set_timings(g, &t);
-
- return size;
-}
-
-/**
- * show_stat() - Shows current statistics.
- *
- * @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_stat(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "copies\t\t%dff pages\t%d\n", copies, ff_writes);
-}
-
-/**
- * show_chips() - Shows the number of physical chips that were discovered.
- *
- * @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_chips(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct gpmi_nand_data *g = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", g->nand.numchips);
-}
-
-/**
- * show_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_ignorebad(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct gpmi_nand_data *g = dev_get_drvdata(d);
-
- return sprintf(buf, "%d\n", g->ignorebad);
-}
-
-/**
- * store_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_ignorebad(struct device *d, struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct gpmi_nand_data *g = dev_get_drvdata(d);
- const char *p = buf;
- unsigned long v;
-
- if (strict_strtoul(p, 0, &v) < 0)
- return size;
- if (v > 0)
- v = 1;
- if (v != g->ignorebad) {
- if (v) {
- g->bbt = g->nand.bbt;
- g->nand.bbt = NULL;
- g->ignorebad = 1;
- } else {
- g->nand.bbt = g->bbt;
- g->ignorebad = 0;
- }
- }
- return size;
-}
-
-static DEVICE_ATTR(timings, 0644, show_timings, store_timings);
-static DEVICE_ATTR(stat, 0444, show_stat, NULL);
-static DEVICE_ATTR(ignorebad, 0644, show_ignorebad, store_ignorebad);
-static DEVICE_ATTR(numchips, 0444, show_chips, NULL);
-
-static struct device_attribute *gpmi_attrs[] = {
- &dev_attr_timings,
- &dev_attr_stat,
- &dev_attr_ignorebad,
- &dev_attr_numchips,
- NULL,
-};
-
-/**
- * gpmi_sysfs() - Creates or removes sysfs nodes.
- *
- * @pdev: A pointer to the owning platform device.
- * @create: Indicates the nodes are to be created (otherwise, removed).
- */
-int gpmi_sysfs(struct platform_device *pdev, int create)
-{
- int err = 0;
- int i;
-
- if (create) {
- for (i = 0; gpmi_attrs[i]; i++) {
- err = device_create_file(&pdev->dev, gpmi_attrs[i]);
- if (err)
- break;
- }
- if (err)
- while (--i >= 0)
- device_remove_file(&pdev->dev, gpmi_attrs[i]);
- } else {
- for (i = 0; gpmi_attrs[i]; i++)
- device_remove_file(&pdev->dev, gpmi_attrs[i]);
- }
- return err;
-}
-
-/**
- * gpmi_nand_probe - Probes for a GPMI device and, if possible, takes ownership.
- *
- * @pdev: A pointer to the platform device.
- */
-static int __init gpmi_nand_probe(struct platform_device *pdev)
-{
- struct gpmi_nand_data *g;
- struct gpmi_platform_data *gpd;
- int err = 0;
- struct resource *r;
- int dma;
-
- /* Allocate memory for the per-device structure (and zero it). */
- g = kzalloc(sizeof(*g), GFP_KERNEL);
- if (!g) {
- dev_err(&pdev->dev, "failed to allocate gpmi_nand_data\n");
- err = -ENOMEM;
- goto out1;
- }
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "failed to get resource\n");
- err = -ENXIO;
- goto out2;
- }
- g->io_base = ioremap(r->start, r->end - r->start + 1);
- if (!g->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;
- }
-
- gpd = (struct gpmi_platform_data *)pdev->dev.platform_data;
- g->gpd = gpd;
- platform_set_drvdata(pdev, g);
- err = gpmi_nand_init_hw(pdev, 1);
- if (err)
- goto out3;
-
- init_timer(&g->timer);
- g->timer.data = (unsigned long)g;
- g->timer.function = gpmi_timer_expiry;
- g->timer.expires = jiffies + 4 * HZ;
- add_timer(&g->timer);
- dev_dbg(&pdev->dev, "%s: timer set to %ld\n",
- __func__, jiffies + 4 * HZ);
-
- g->reg_uA = gpd->io_uA;
- g->regulator = regulator_get(&pdev->dev, "mmc_ssp-2");
- if (g->regulator && !IS_ERR(g->regulator))
- regulator_set_mode(g->regulator, REGULATOR_MODE_NORMAL);
- else
- g->regulator = NULL;
-
- g->irq = r->start;
- err = request_irq(g->irq, gpmi_isr, 0, dev_name(&pdev->dev), g);
- if (err) {
- dev_err(&pdev->dev, "can't request GPMI IRQ\n");
- goto out4;
- }
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r) {
- dev_err(&pdev->dev, "can't get DMA resource\n");
- goto out5;
- }
-
- if (r->end - r->start > GPMI_MAX_CHIPS)
- dev_info(&pdev->dev, "too spread resource: max %d chips\n",
- GPMI_MAX_CHIPS);
-
- for (dma = r->start;
- dma < min_t(int, r->end, r->start + GPMI_MAX_CHIPS); dma++) {
- err = gpmi_init_chip(pdev, g, dma - r->start, dma);
- if (err)
- goto out6;
- }
-
- g->cmd_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");
- goto out6;
- }
-
- g->dev = pdev;
- g->nand.priv = g;
- g->timing = gpmi_safe_timing;
- g->selected_chip = -1;
- g->ignorebad = ignorebad; /* copy global setting */
-
- /* Set up timings. */
-
- gpmi_set_timings(g, &gpmi_safe_timing);
-
- /* Register with MTD. */
-
- if (gpmi_register_with_mtd(g))
- goto out7;
-
- /* Create sysfs nodes. */
-
- gpmi_sysfs(pdev, true);
-
- /* If control arrives here, everything worked. Return success. */
-
- return 0;
-
- ecc8_exit();
- bch_exit();
-out7:
- nand_release(&g->mtd);
- gpmi_free_buffers(pdev, g);
-out6:
- gpmi_deinit_chip(pdev, g, -1);
-out5:
- free_irq(g->irq, g);
-out4:
- del_timer_sync(&g->timer);
- gpmi_nand_release_hw(pdev);
-out3:
- platform_set_drvdata(pdev, NULL);
- iounmap(g->io_base);
-out2:
- kfree(g);
-out1:
- return err;
-}
-
-/**
- * gpmi_nand_remove - Dissociates this driver from the given device.
- *
- * @pdev: A pointer to the platform device.
- */
-static int __devexit gpmi_nand_remove(struct platform_device *pdev)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
-
- gpmi_unregister_with_mtd(g);
- del_timer_sync(&g->timer);
- gpmi_uid_remove("nand");
-
- gpmi_sysfs(pdev, false);
-
- nand_release(&g->mtd);
- gpmi_free_buffers(pdev, g);
- gpmi_deinit_chip(pdev, g, -1);
- gpmi_nand_release_hw(pdev);
- free_irq(g->irq, g);
- if (g->regulator)
- regulator_put(g->regulator);
- iounmap(g->io_base);
- kfree(g);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-
-/**
- * gpmi_nand_suspend() - Suspends this driver.
- *
- * @pdev: A pointer to the owning struct platform_device.
- * @pm: For future use, currently unused.
- */
-static int gpmi_nand_suspend(struct platform_device *pdev, pm_message_t pm)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
- int r = 0;
-
- /* If the driver suspended itself due to inactivity, wake it up. */
-
- if (g->self_suspended)
- gpmi_self_wakeup(g);
-
- /* Deactivate the inactivity timer. */
-
- del_timer_sync(&g->timer);
-
- /*
- * Suspend MTD's use of this device and, if that works, then shut down
- * the actual hardware.
- */
-
- r = g->mtd.suspend(&g->mtd);
- if (r == 0)
- gpmi_nand_release_hw(pdev);
-
- return r;
-
-}
-
-/**
- * gpmi_nand_resume() - Resumes this driver from suspend.
- *
- * @pdev: A pointer to the owning struct platform_device.
- */
-static int gpmi_nand_resume(struct platform_device *pdev)
-{
- struct gpmi_nand_data *g = platform_get_drvdata(pdev);
- int r;
-
- /*
- * Spin up the hardware.
- *
- * Unfortunately, this code ignores the result of hardware
- * initialization and spins up the driver unconditionally.
- */
-
- r = gpmi_nand_init_hw(pdev, 1);
- gpmi_set_timings(g, 0);
-
- /* Tell MTD it can use this device again. */
-
- g->mtd.resume(&g->mtd);
-
- /* Re-instate the inactivity timer. */
-
- g->timer.expires = jiffies + 4 * HZ;
- add_timer(&g->timer);
-
- return r;
-
-}
-
-#else
-#define gpmi_nand_suspend NULL
-#define gpmi_nand_resume NULL
-#endif
-
-/*
- * The global list of ECC descriptors.
- *
- * Each descriptor represents an ECC option that's available to the driver.
- */
-
-static LIST_HEAD(gpmi_ecc_descriptor_list);
-
-/**
- * gpmi_ecc_add() - Adds the given ECC descriptor.
- *
- * @name: The name of interest.
- */
-void gpmi_ecc_add(struct gpmi_ecc_descriptor *chip)
-{
- list_add(&chip->list, &gpmi_ecc_descriptor_list);
-}
-EXPORT_SYMBOL_GPL(gpmi_ecc_add);
-
-/**
- * gpmi_ecc_remove() - Removes an ECC descriptor with the given name.
- *
- * @name: The name of interest.
- */
-void gpmi_ecc_remove(struct gpmi_ecc_descriptor *chip)
-{
- list_del(&chip->list);
-}
-EXPORT_SYMBOL_GPL(gpmi_ecc_remove);
-
-/**
- * gpmi_ecc_find() - Tries to find an ECC descriptor with the given name.
- *
- * @name: The name of interest.
- */
-struct gpmi_ecc_descriptor *gpmi_ecc_find(char *name)
-{
- struct gpmi_ecc_descriptor *c;
-
- list_for_each_entry(c, &gpmi_ecc_descriptor_list, list)
- if (strncmp(c->name, name, sizeof(c->name)) == 0)
- return c;
-
- return NULL;
-
-}
-EXPORT_SYMBOL_GPL(gpmi_ecc_find);
-
-/*
- * This structure represents this driver to the platform management system.
- */
-
-static struct platform_driver gpmi_nand_driver = {
- .probe = gpmi_nand_probe,
- .remove = __devexit_p(gpmi_nand_remove),
- .driver = {
- .name = "gpmi",
- .owner = THIS_MODULE,
- },
- .suspend = gpmi_nand_suspend,
- .resume = gpmi_nand_resume,
-};
-
-static int __init gpmi_nand_init(void)
-{
- int return_value;
-
- pr_info("GPMI NAND Flash driver\n");
-
- /* Initialize the BCH hardware block. */
-
- bch_init();
-
- /* Attempt to register this driver with the platform. */
-
- return_value = platform_driver_register(&gpmi_nand_driver);
-
- if (return_value)
- pr_err("GPMI NAND Flash driver registration failed\n");
-
- return return_value;
-
-}
-
-static void __exit gpmi_nand_exit(void)
-{
- pr_info("GPMI NAND Flash driver exiting...\n");
- platform_driver_unregister(&gpmi_nand_driver);
-}
-
-module_init(gpmi_nand_init);
-module_exit(gpmi_nand_exit);
-MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("GPMI NAND Flash driver");
-module_param(max_chips, int, 0400);
-module_param(map_buffers, int, 0600);
-module_param(raw_mode, int, 0600);
-module_param(debug, int, 0600);
-module_param(add_mtd_entire, int, 0400);
-module_param(ignorebad, int, 0400);
diff --git a/drivers/mtd/nand/gpmi1/gpmi-bbt.c b/drivers/mtd/nand/gpmi1/gpmi-bbt.c
deleted file mode 100644
index 7888e5f2703d..000000000000
--- a/drivers/mtd/nand/gpmi1/gpmi-bbt.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Freescale i.MX28 GPMI (General-Purpose-Media-Interface)
- *
- * Author: dmitry pervushin <dimka@embeddedalley.com>
- *
- * Copyright 2008-2010 Freescale Semiconductor, Inc.
- * Copyright 2008 Embedded Alley Solutions, Inc.
- */
-
-/*
- * 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/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <mach/dma.h>
-#include "gpmi.h"
-
-/* Fingerprints for Boot Control Blocks. */
-
-#define SIG_FCB "FCB "
-#define SIG_DBBT "DBBT"
-#define SIG_SIZE 4
-
-/*
- * The equivalent of the BOOT_SEARCH_COUNT field in the OTP bits. That is, the
- * logarithm to base 2 of the number of strides in a search area (a stride is
- * 64 pages).
- */
-
-static int boot_search_count;
-
-module_param(boot_search_count, int, 0400);
-
-/*
- * The size, in pages, of a search area stride.
- *
- * This number is dictated by the ROM, so it's not clear why it isn't at least
- * const, or perhaps a macro.
- */
-
-static const int stride_size_in_pages = 64;
-
-/*
- * read_page -
- *
- * @mtd: The owning MTD.
- * @start: The offset at which to begin reading.
- * @data: A pointer to a buff that will receive the data. This pointer may be
- * NULL, in which case this function will allocate a buffer.
- * @raw: If true, indicates that the caller doesn't want to use ECC.
- */
-static void *read_page(struct mtd_info *mtd, loff_t start, void *data, int raw)
-{
- int ret;
- struct mtd_oob_ops ops;
-
- /* If the caller didn't send in his own buffer, allocate one. */
-
- if (!data)
- data = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
- if (!data)
- return NULL;
-
- /* Check if the caller wants to use ECC. */
-
- if (raw)
- ops.mode = MTD_OOB_RAW;
- else
- ops.mode = MTD_OOB_PLACE;
-
- /*
- * Call nand_do_read_ops() to do the dirty work.
- */
-
- ops.datbuf = data;
- ops.len = mtd->writesize;
- ops.oobbuf = data + mtd->writesize;
- ops.ooblen = mtd->oobsize;
- ops.ooboffs = 0;
- ret = nand_do_read_ops(mtd, start, &ops);
-
- if (ret)
- return NULL;
- return data;
-}
-
-/*
- * gpmi_write_fcbs - Writes FCBs to the medium.
- *
- * @mtd: The owning MTD.
- */
-static void gpmi_write_fcbs(struct mtd_info *mtd)
-{
- unsigned int i;
- unsigned int page_size_in_bytes;
- unsigned int block_size_in_bytes;
- 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;
- void *fcb;
- struct nand_chip *chip = mtd->priv;
- struct mtd_oob_ops ops;
- struct erase_info instr;
-
- /* Compute some important facts. */
-
- page_size_in_bytes = mtd->writesize;
- block_size_in_bytes = 1 << chip->phys_erase_shift;
- block_size_in_pages = 1 << (chip->phys_erase_shift - chip->page_shift);
-
- search_area_size_in_strides = (1 << boot_search_count) - 1;
- search_area_size_in_pages =
- search_area_size_in_strides * stride_size_in_pages + 1;
- search_area_size_in_blocks =
- (search_area_size_in_pages + (block_size_in_pages - 1)) /
- block_size_in_pages;
-
- /* Allocate an I/O buffer for the FCB page, with OOB. */
-
- fcb = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
- if (!fcb)
- return;
-
- /* Write the FCB signature into the buffer. */
-
- memcpy(((uint8_t *) fcb) + 0x10, SIG_FCB, SIG_SIZE);
-
- /* Erase the entire search area. */
-
- for (i = 0; i < search_area_size_in_blocks; i++) {
- memset(&instr, 0, sizeof(instr));
- instr.mtd = mtd;
- instr.addr = i * block_size_in_bytes;
- instr.len = block_size_in_bytes;
- nand_erase_nand(mtd, &instr, 0);
- }
-
- /* Construct the data structure for the write operation. */
-
- ops.datbuf = (u8 *)fcb;
- ops.len = mtd->writesize;
- ops.oobbuf = (u8 *)fcb + mtd->writesize;
- ops.ooblen = mtd->oobsize;
- ops.ooboffs = 0;
- ops.mode = MTD_OOB_RAW;
-
- /* Loop over FCB locations in the search area. */
-
- for (i = 0; i <= search_area_size_in_strides; i++) {
-
- printk(KERN_NOTICE"Writing FCB in page 0x%08x\n",
- i * stride_size_in_pages);
-
- nand_do_write_ops(mtd,
- i * stride_size_in_pages * page_size_in_bytes, &ops);
-
- }
-
- /* Free our buffer. */
-
- kfree(fcb);
-
-}
-
-/*
- * gpmi_scan_for_fcb - Scans the medium for an FCB.
- *
- * @mtd: The owning MTD.
- */
-static int gpmi_scan_for_fcb(struct mtd_info *mtd)
-{
- int result = 0;
- int page;
- u8 *pg;
-
- /* If the boot search count is 0, make it 2. */
-
- if (boot_search_count == 0)
- boot_search_count = 2;
-
- /* Loop through the medium, searching for the FCB. */
-
- printk(KERN_NOTICE"Scanning for FCB...\n");
-
- pg = NULL;
-
- for (page = 0;
- page < ((1 << boot_search_count) * stride_size_in_pages);
- page += stride_size_in_pages) {
-
- /* Read the current page. */
-
- pg = read_page(mtd, page * mtd->writesize, pg, !0);
-
- printk(KERN_NOTICE"Looking for FCB in page 0x%08x\n", page);
-
- /*
- * A valid FCB page contains the following:
- *
- * +------------+
- * .
- * .
- * Don't Care
- * .
- * .
- * +------------+ 1036
- * | |
- * | FCB ECC |
- * | |
- * +------------+ 524
- * | |
- * | FCB |
- * | |
- * +------------+ 12
- * | Don't Care |
- * +------------+ 0
- *
- * Within the FCB, there is a "fingerprint":
- *
- * +-----------+--------------------+
- * | Offset In | |
- * | FCB Page | Fingerprint |
- * +-----------+--------------------+
- * | 0x10 | "FCB " 0x46434220 |
- * +-----------+--------------------+
- */
-
- /* Check for the fingerprint. */
-
- if (memcmp(pg + 16, SIG_FCB, SIG_SIZE) != 0)
- continue;
-
- printk(KERN_NOTICE"Found FCB in page 0x%08X\n", page);
-
- result = !0;
-
- break;
-
- }
-
- if (!result)
- printk(KERN_NOTICE"No FCB found\n");
-
- /* Free the page buffer */
-
- kfree(pg);
-
- return result;
-
-}
-
-/**
- * gpmi_block_bad - Claims all blocks are good.
- *
- * @mtd: The owning MTD.
- * @ofs: The offset of the block.
- * @getchip: ??
- *
- * In principle, this function is called when the NAND Flash MTD system isn't
- * allowed to keep an in-memory bad block table, so it must 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 need do nothing more than always return success.
- */
-int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
-{
- return 0;
-}
-
-/**
- * transcribe_block_mark - Transcribes a block mark.
- *
- * @mtd: The owning MTD.
- * @ofs: Identifies the block of interest.
- */
-static void transcribe_block_mark(struct mtd_info *mtd, loff_t ofs)
-
-{
- int page;
- struct nand_chip *chip = mtd->priv;
- int chipnr;
-
- /*
- * Compute the position of the block mark within the OOB (this code
- * appears to be wrong).
- */
-
- int badblockpos = chip->ecc.steps * chip->ecc.bytes;
-
- /*
- * Compute the page address of the first page in the block that contains
- * the given offset.
- */
-
- page = (int)(ofs >> chip->page_shift) & chip->pagemask;
-
- /*
- * Compute the chip number that contains the given offset, and select
- * it.
- */
-
- chipnr = (int)(ofs >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
-
- /* bad block marks still are on first byte of OOB */
-
- badblockpos = 0;
-
- /* Read the block mark. */
-
- chip->cmdfunc(mtd, NAND_CMD_READOOB, badblockpos, page);
-
- if (chip->read_byte(mtd) != 0xff) {
- printk(KERN_NOTICE"Transcribing block mark in block 0x%08x\n",
- (unsigned) (ofs >> chip->phys_erase_shift));
- chip->block_markbad(mtd, ofs);
- }
-
- /*
- * Deselect the chip.
- */
-
- chip->select_chip(mtd, -1);
-
-}
-
-/**
- * gpmi_scan_bbt - Sets up to manage bad blocks.
- *
- * @mtd: The owning MTD.
- */
-int gpmi_scan_bbt(struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd->priv;
- int r;
- int transcription_is_needed;
- unsigned int search_area_size_in_strides;
- unsigned page;
- unsigned block;
- int numblocks, from, i;
- struct nand_chip *chip = mtd->priv;
-
- /* Search for the FCB. */
-
- transcription_is_needed = !gpmi_scan_for_fcb(mtd);
-
- /* Check if we found the FCB. */
-
- if (transcription_is_needed) {
-
- printk(KERN_NOTICE"Transcribing bad block marks...\n");
-
- /*
- * If control arrives here, the medium has no FCB, so we
- * presume it is in common format. This means we must transcribe
- * the block marks.
- *
- * Compute the number of blocks in the entire medium.
- */
-
- numblocks = this->chipsize >> this->bbt_erase_shift;
-
- /*
- * Loop over all the blocks in the medium, transcribing block
- * marks as we go.
- */
-
- from = 0;
- for (i = 0; i < numblocks; i++) {
- /* Transcribe the mark in this block, if needed. */
- transcribe_block_mark(mtd, from);
- from += (1 << this->bbt_erase_shift);
- }
-
- /*
- * Put an FCB in the medium to indicate the block marks have
- * been transcribed.
- */
-
- gpmi_write_fcbs(mtd);
-
- }
-
- /* Use the reference implementation's BBT scan. */
-
- r = nand_default_bbt(mtd);
-
- /* Mark all NCB blocks as good. */
-
- search_area_size_in_strides = (1 << boot_search_count) - 1;
-
- for (i = 0; i <= search_area_size_in_strides; i++) {
-
- /* Compute the current FCB page.*/
-
- page = i * stride_size_in_pages;
-
- /* Compute the block that contains the current FCB page.*/
-
- block = page >> (chip->phys_erase_shift - chip->page_shift);
-
- /* Mark the block good. */
-
- printk(KERN_NOTICE"Forcing good FCB block 0x%08x\n", block);
-
- gpmi_block_mark_as(this, block, 0x00);
-
- }
-
- return r;
-}
diff --git a/drivers/mtd/nand/gpmi1/gpmi-bch.c b/drivers/mtd/nand/gpmi1/gpmi-bch.c
deleted file mode 100644
index b4404d583530..000000000000
--- a/drivers/mtd/nand/gpmi1/gpmi-bch.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Freescale i.MX28 GPMI (General-Purpose-Media-Interface)
- *
- * STMP378X BCH hardware ECC engine
- *
- * Author: dmitry pervushin <dimka@embeddedalley.com>
- *
- * Copyright 2008-2010 Freescale Semiconductor, Inc.
- * Copyright 2008 Embedded Alley Solutions, Inc.
- */
-
-/*
- * 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/kernel.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/dma.h>
-#include <mach/irqs.h>
-#include <mach/system.h>
-#include "regs-gpmi.h"
-#include "gpmi.h"
-
-#define BCH_MAX_NANDS 8
-
-/**
- * bch_state_t - Describes the state of the BCH ECC.
- *
- * @chip: A descriptor the GPMI driver uses to track this ECC.
- * @nands: An array of elements, each of which represents a physical chip.
- * @stat: Used by the interrupt level to communicate ECC statistics to the
- * base level.
- * @done: A struct completion used to manage ECC interrupts.
- * @writesize: The page data size.
- * @oobsize: The page OOB size.
- */
-
-struct bch_state_t {
- struct gpmi_ecc_descriptor chip;
- struct {
- struct mtd_ecc_stats stat;
- struct completion done;
- u32 writesize, oobsize;
- u32 ecc0, eccn, metasize;
- } nands[BCH_MAX_NANDS];
-};
-
-/**
- * bch_reset - Resets the BCH.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- * @index: ??
- */
-static int bch_reset(void *context, int index)
-{
- mxs_reset_block(IO_ADDRESS(BCH_PHYS_ADDR), true);
- __raw_writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
- IO_ADDRESS(BCH_PHYS_ADDR) + HW_BCH_CTRL_SET);
- return 0;
-}
-
-/**
- * bch_stat - Gather statistics and clean up after a read operation.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- * @index: ??
- * @r: A statistics structure that will receive the results of the most
- * recent operation.
- */
-static int bch_stat(void *context, int index, struct mtd_ecc_stats *r)
-{
- struct bch_state_t *state = context;
-
- wait_for_completion(&state->nands[index].done);
-
- *r = state->nands[index].stat;
- state->nands[index].stat.failed = 0;
- state->nands[index].stat.corrected = 0;
- return 0;
-}
-
-/**
- * bch_irq - Interrupt handler for the BCH hardware.
- *
- * This function gains control when the BCH hardware interrupts. It acknowledges
- * the interrupt and gathers status information.
- *
- * @irq: The interrupt number.
- * @context: Context data -- a pointer to a struct bch_state_t.
- */
-static irqreturn_t bch_irq(int irq, void *context)
-{
- u32 b0, s0, ecc0;
- struct mtd_ecc_stats stat;
- int r;
- struct bch_state_t *state = context;
-
- s0 = __raw_readl(IO_ADDRESS(BCH_PHYS_ADDR) + HW_BCH_STATUS0);
- r = (s0 & BM_BCH_STATUS0_COMPLETED_CE) >> 16;
-
- ecc0 = state->nands[r].ecc0;
- stat.corrected = stat.failed = 0;
-
- b0 = (s0 & BM_BCH_STATUS0_STATUS_BLK0) >> 8;
- if (b0 <= ecc0)
- stat.corrected += b0;
- if (b0 == 0xFE)
- stat.failed++;
-
- if (s0 & BM_BCH_STATUS0_UNCORRECTABLE)
- stat.failed++;
-
- __raw_writel(BM_BCH_CTRL_COMPLETE_IRQ,
- IO_ADDRESS(BCH_PHYS_ADDR) + HW_BCH_CTRL_CLR);
-
- pr_debug("%s: chip %d, failed %d, corrected %d\n",
- __func__, r,
- state->nands[r].stat.failed,
- state->nands[r].stat.corrected);
- state->nands[r].stat.corrected += stat.corrected;
- state->nands[r].stat.failed += stat.failed;
- complete(&state->nands[r].done);
-
- return IRQ_HANDLED;
-}
-
-/**
- * bch_available - Returns whether the BCH hardware is available.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- */
-static int bch_available(void *context)
-{
- mxs_reset_block(IO_ADDRESS(BCH_PHYS_ADDR), true);
- return __raw_readl(IO_ADDRESS(BCH_PHYS_ADDR) + HW_BCH_BLOCKNAME) ==
- 0x20484342;
-}
-
-/**
- * bch_setup - Set up BCH for use.
- *
- * The GPMI driver calls this function for every chip.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- * @index: ??
- * @writesize: The page data size.
- * @oobsize: The page OOB size.
- */
-static int bch_setup(void *context, int index, int writesize, int oobsize)
-{
- struct bch_state_t *state = context;
- u32 ecc0, eccn, metasize;
-
- switch (writesize) {
- case 2048:
- ecc0 = 8;
- eccn = 8;
- metasize = 10;
- break;
- case 4096:
- if (oobsize == 128) {
- ecc0 = 8;
- eccn = 8;
- } else {
- ecc0 = 16;
- eccn = 16;
- }
-
- metasize = 10;
- break;
- default:
- printk(KERN_ERR"%s: cannot tune BCH for page size %d\n",
- __func__, writesize);
- return -EINVAL;
- }
-
- state->nands[index].oobsize = oobsize;
- state->nands[index].writesize = writesize;
- state->nands[index].metasize = metasize;
- state->nands[index].ecc0 = ecc0;
- state->nands[index].eccn = eccn;
-
- /* Configure layout 0. */
-
- __raw_writel(
- BF_BCH_FLASH0LAYOUT0_NBLOCKS(writesize/512 - 1) |
- BF_BCH_FLASH0LAYOUT0_META_SIZE(metasize) |
- BF_BCH_FLASH0LAYOUT0_ECC0(ecc0 >> 1) |
- BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(512) ,
- IO_ADDRESS(BCH_PHYS_ADDR) + HW_BCH_FLASH0LAYOUT0);
-
- __raw_writel(
- BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(writesize + oobsize) |
- BF_BCH_FLASH0LAYOUT1_ECCN(eccn >> 1) |
- BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(512) ,
- IO_ADDRESS(BCH_PHYS_ADDR) + HW_BCH_FLASH0LAYOUT1);
-
- /* Set *all* chip selects to use layout 0. */
-
- __raw_writel(0, IO_ADDRESS(BCH_PHYS_ADDR) + HW_BCH_LAYOUTSELECT);
-
- bch_reset(context, index);
-
- return 0;
-}
-
-/**
- * bch_read - Fill in a DMA chain to read a page.
- *
- * @context: Context data -- a pointer to a struct bch_state_t.
- * @cs: The chip number to read.
- * @chain: The main descriptor of the DMA chain to fill.
- * @page: Physical address of the target page data buffer.
- * @oob: Physical address of the target OOB data buffer.
- *
- * Return: status of operation -- 0 on success
- */
-static int bch_read(void *context,
- int index,
- struct mxs_dma_desc **d, unsigned channel,
- dma_addr_t page, dma_addr_t oob)
-{
- unsigned long readsize = 0;
- u32 bufmask = 0;
- struct bch_state_t *state = context;
-
- if (!dma_mapping_error(NULL, oob)) {
- bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
- readsize += state->nands[index].oobsize;
- }
-
- if (!dma_mapping_error(NULL, page)) {
- bufmask |= (BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
- & ~BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY);
- readsize += state->nands[index].writesize;
- }
-
- bch_reset(context, index);
-
- /* Wait for the medium to report ready. */
-
- (*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] =
- BF_GPMI_CTRL0_COMMAND_MODE(
- BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) |
- BM_GPMI_CTRL0_LOCK_CS |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(index) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) |
- BF_GPMI_CTRL0_XFER_COUNT(0) ;
-
- mxs_dma_desc_append(channel, (*d));
- d++;
-
- /* enable BCH and read 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 = 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] =
- BM_GPMI_CTRL0_LOCK_CS |
- BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(index) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) |
- BF_GPMI_CTRL0_XFER_COUNT(readsize) ;
-
- (*d)->cmd.pio_words[1] = 0;
- (*d)->cmd.pio_words[2] =
- BM_GPMI_ECCCTRL_ENABLE_ECC |
- BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__DECODE) |
- BF_GPMI_ECCCTRL_BUFFER_MASK(bufmask) ;
- (*d)->cmd.pio_words[3] = readsize;
- (*d)->cmd.pio_words[4] = !dma_mapping_error(NULL, page) ? page : 0;
- (*d)->cmd.pio_words[5] = !dma_mapping_error(NULL, oob) ? oob : 0;
-
- mxs_dma_desc_append(channel, (*d));
- d++;
-
- /* disable BCH block */
-
- (*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] =
- BF_GPMI_CTRL0_COMMAND_MODE(
- BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) |
- BM_GPMI_CTRL0_LOCK_CS |
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(index) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) |
- BF_GPMI_CTRL0_XFER_COUNT(readsize) ;
-
- (*d)->cmd.pio_words[1] = 0;
- (*d)->cmd.pio_words[2] = 0;
-
- mxs_dma_desc_append(channel, (*d));
- d++;
-
- /* and deassert nand lock */
-
- (*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(channel, (*d));
- d++;
-
- init_completion(&state->nands[index].done);
-
- return 0;
-
-}
-
-static int bch_write(void *context,
- int index,
- struct mxs_dma_desc **d, unsigned channel,
- dma_addr_t page, dma_addr_t oob)
-{
- unsigned long writesize = 0;
- u32 bufmask = 0;
- struct bch_state_t *state = context;
-
- if (!dma_mapping_error(NULL, oob)) {
- bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
- writesize += state->nands[index].oobsize;
- }
- if (!dma_mapping_error(NULL, page)) {
- bufmask |= (BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
- & ~BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY);
- writesize += state->nands[index].writesize;
- }
-
- bch_reset(context, index);
-
- /* enable BCH and write 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 = 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] =
- BM_GPMI_CTRL0_LOCK_CS |
- BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)|
- BM_GPMI_CTRL0_WORD_LENGTH |
- BF_GPMI_CTRL0_CS(index) |
- BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) |
- BF_GPMI_CTRL0_XFER_COUNT(0) ;
-
- (*d)->cmd.pio_words[1] = 0;
-
- (*d)->cmd.pio_words[2] =
- BM_GPMI_ECCCTRL_ENABLE_ECC |
- BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE) |
- BF_GPMI_ECCCTRL_BUFFER_MASK(bufmask) ;
-
- (*d)->cmd.pio_words[3] = writesize;
- (*d)->cmd.pio_words[4] = !dma_mapping_error(NULL, page) ? page : 0;
- (*d)->cmd.pio_words[5] = !dma_mapping_error(NULL, oob) ? oob : 0;
-
- mxs_dma_desc_append(channel, (*d));
- d++;
-
- init_completion(&state->nands[index].done);
-
- return 0;
-}
-
-/* The singleton struct bch_state_t for the BCH ECC. */
-
-static struct bch_state_t state = {
- .chip = {
- .name = "bch",
- .setup = bch_setup,
- .stat = bch_stat,
- .read = bch_read,
- .write = bch_write,
- .reset = bch_reset,
- },
-};
-
-/**
- * bch_init - Initialize and register ECC.
- *
- * The GPMI driver calls this function once, at the beginning of time, whether
- * or not it decides to use this ECC.
- */
-int __init bch_init(void)
-{
- int err;
-
- /* Check if the BCH hardware is available. */
-
- if (!bch_available(&state.chip))
- return -ENXIO;
-
- /* Give the GPMI driver a descriptor. */
-
- gpmi_ecc_add(&state.chip);
-
- /* Attempt to acquire the BCH interrupt. */
-
- err = request_irq(IRQ_BCH, bch_irq, 0, state.chip.name, &state);
- if (err)
- return err;
-
- printk(KERN_INFO"%s: initialized\n", __func__);
- return 0;
-}
-
-/**
- * bch_exit - Shut down and de-register ECC.
- */
-void bch_exit(void)
-{
- free_irq(IRQ_BCH, &state);
- gpmi_ecc_remove(&state.chip);
-}
diff --git a/drivers/mtd/nand/gpmi1/gpmi.h b/drivers/mtd/nand/gpmi1/gpmi.h
deleted file mode 100644
index 072c2ad2f442..000000000000
--- a/drivers/mtd/nand/gpmi1/gpmi.h
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
- *
- * Author: dmitry pervushin <dimka@embeddedalley.com>
- *
- * Copyright 2008-2010 Freescale Semiconductor, Inc.
- * 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/partitions.h>
-#include <linux/timer.h>
-#include <mach/dmaengine.h>
-#include "regs-gpmi.h"
-#include "regs-bch.h"
-
-#include "../nand_device_info.h"
-
-/* The number of DMA descriptors we need to allocate. */
-
-#define DMA_DESCRIPTOR_COUNT (4)
-
-#define NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES (512)
-#define NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES \
- ((((NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES*8)/16)*6)/8)
-#define NAND_HC_ECC_OFFSET_FIRST_DATA_COPY (0)
-#define NAND_HC_ECC_OFFSET_SECOND_DATA_COPY \
- (NAND_HC_ECC_OFFSET_FIRST_DATA_COPY + \
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
-#define NAND_HC_ECC_OFFSET_THIRD_DATA_COPY \
- (NAND_HC_ECC_OFFSET_SECOND_DATA_COPY + \
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
-#define NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY \
- (NAND_HC_ECC_OFFSET_THIRD_DATA_COPY + \
- NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
-#define NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY \
- (NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY + \
- NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES)
-#define NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY \
- (NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY + \
- NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES)
-
-/**
- * struct gpmi_nand_timing - NAND Flash timing parameters.
- *
- * This structure contains the fundamental timing attributes for the NAND Flash
- * bus.
- *
- * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the
- * maximum of tDS and tWP. A negative value
- * indicates this characteristic isn't known.
- * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the
- * maximum of tDH, tWH and tREH. A negative value
- * indicates this characteristic isn't known.
- * @address_setup_in_ns: The address setup time, in nanoseconds. Usually
- * the maximum of tCLS, tCS and tALS. A negative
- * value indicates this characteristic isn't known.
- * @gpmi_sample_time_in_ns: A GPMI-specific timing parameter. A negative
- * value indicates this characteristic isn't known.
- * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A
- * negative value indicates this characteristic
- * isn't known.
- * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A
- * negative value indicates this characteristic
- * isn't known.
- * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A
- * negative value indicates this characteristic
- * isn't known.
- */
-
-struct gpmi_nand_timing {
- int8_t data_setup_in_ns;
- int8_t data_hold_in_ns;
- int8_t address_setup_in_ns;
- int8_t gpmi_sample_delay_in_ns;
- int8_t tREA_in_ns;
- int8_t tRLOH_in_ns;
- int8_t tRHOH_in_ns;
-};
-
-/**
- * struct gpmi_bcb_info - Information obtained from Boot Control Blocks.
- *
- * @timing: Timing values extracted from an NCB.
- * @ncbblock: The offset within the MTD at which the NCB was found.
- * @pre_ncb:
- * @pre_ncb_size:
- */
-
-struct gpmi_bcb_info {
- struct gpmi_nand_timing timing;
- loff_t ncbblock;
- const void *pre_ncb;
- size_t pre_ncb_size;
-};
-
-struct gpmi_ncb;
-
-int gpmi_erase(struct mtd_info *mtd, struct erase_info *instr);
-int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs);
-int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip);
-int gpmi_scan_bbt(struct mtd_info *mtd);
-int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip);
-#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES
-int gpmi_sysfs(struct platform_device *p, int create);
-#endif
-int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page, int sndcmd);
-int gpmi_write_ncb(struct mtd_info *mtd, struct gpmi_bcb_info *b);
-
-unsigned gpmi_hamming_ecc_size_22_16(int block_size);
-void gpmi_encode_hamming_ncb_22_16(void *source_block, size_t source_size,
- void *target_block, size_t target_size);
-void gpmi_encode_hamming_22_16(void *source_block, size_t src_size,
- void *source_ecc, size_t ecc_size);
-int gpmi_verify_hamming_22_16(void *data, u8 *parity, size_t size);
-
-unsigned gpmi_hamming_ecc_size_13_8(int block_size);
-void gpmi_encode_hamming_ncb_13_8(void *source_block, size_t source_size,
- void *target_block, size_t target_size);
-void gpmi_encode_hamming_13_8(void *source_block, size_t src_size,
- void *source_ecc, size_t ecc_size);
-int gpmi_verify_hamming_13_8(void *data, u8 *parity, size_t size);
-
-#define GPMI_DMA_MAX_CHAIN 20 /* max DMA commands in chain */
-
-/*
- * Sizes of data buffers to exchange commands/data with NAND chip.
- * Default values cover 4K NAND page (4096 data bytes + 218 bytes OOB)
- */
-#define GPMI_CMD_BUF_SZ 10
-#define GPMI_DATA_BUF_SZ NAND_MAX_PAGESIZE
-#define GPMI_WRITE_BUF_SZ NAND_MAX_PAGESIZE
-#define GPMI_OOB_BUF_SZ NAND_MAX_OOBSIZE
-
-#define GPMI_MAX_CHIPS 10
-
-/**
- * struct gpmi_ecc_descriptor - Abstract description of ECC.
- *
- * @name: The name of the ECC represented by this structure.
- * @list: Infrastructure for the list to which this structure belongs.
- * @setup: A pointer to a function that prepares the ECC to function.
- * @reset: A pointer to a function that resets the ECC to a known state. This
- * pointer is currently never used, and probably should be removed.
- * @read: A pointer to a function that fills in a given DMA chain such that
- * a page read will pass through the owning ECC.
- * @write: A pointer to a function that fills in a given DMA chain such that
- * a page write will pass through the owning ECC.
- * @stat: A pointer to a function that reports on ECC statistics for
- * the preceding read operation.
- */
-
-struct gpmi_ecc_descriptor {
- char name[40];
- struct list_head list;
- int (*setup)(void *ctx, int index, int writesize, int oobsize);
- int (*reset)(void *ctx, int index);
- int (*read)(void *ctx, int index,
- struct mxs_dma_desc *chain[], unsigned channel,
- dma_addr_t page, dma_addr_t oob);
- int (*write)(void *ctx, int index,
- struct mxs_dma_desc *chain[], unsigned channel,
- dma_addr_t page, dma_addr_t oob);
- int (*stat)(void *ctx, int index, struct mtd_ecc_stats *r);
-};
-
-/* ECC descriptor management. */
-
-struct gpmi_ecc_descriptor *gpmi_ecc_find(char *name);
-void gpmi_ecc_add(struct gpmi_ecc_descriptor *chip);
-void gpmi_ecc_remove(struct gpmi_ecc_descriptor *chip);
-
-/* Housecleaning functions for the ECC hardware blocks. */
-
-int bch_init(void);
-int ecc8_init(void);
-void bch_exit(void);
-void ecc8_exit(void);
-
-/**
- * struct gpmi_nand_data - GPMI driver per-device data structure.
- *
- * @dev: A pointer to the owning struct device.
- * @gpd: GPMI-specific platform data.
- * @io_base: The base I/O address of of the GPMI registers.
- * @clk: A pointer to the structure that represents the GPMI
- * clock.
- * @irq: The GPMI interrupt request number.
- * @inactivity_timer: A pointer to a timer the driver uses to shut itself
- * down after periods of inactivity.
- * @self_suspended: Indicates the driver suspended itself, rather than
- * being suspended by higher layers of software. This is
- * important because it effects how the driver wakes
- * itself back up.
- * @use_count: Used within the driver to hold off suspension until
- * all operations are complete.
- * @regulator: A pointer to the structure that represents the
- * power regulator supplying power to the GPMI.
- * @reg_uA: The GPMI current limit, in uA.
- * @ignorebad: Forces the driver to report that all blocks are good.
- * @bbt: Used to save a pointer to the in-memory NAND Flash MTD
- * Bad Block Table if the "ignorebad" flag is turned on
- * through the corresponding sysfs node.
- * @mtd: The data structure that represents this NAND Flash
- * medium to MTD.
- * @nand: The data structure that represents this NAND Flash
- * medium to the MTD NAND Flash system.
- * @device_info Detailed information about the NAND Flash device.
- * @partitions: A pointer to an array of partition descriptions
- * collected from the platform. If this member is NULL,
- * then no such partitions were given.
- * @partition_count: The number of elements in the partitions array.
- * @done: A struct completion used to manage GPMI interrupts.
- * @cmd_buffer:
- * @cmd_buffer_handle:
- * @cmd_buffer_size:
- * @cmd_buffer_sz: The number of command and address bytes queued up,
- * waiting for transmission to the NAND Flash.
- * @write_buffer:
- * @write_buffer_handle:
- * @write_buffer_size:
- * @read_buffer:
- * @read_buffer_handle:
- * @data_buffer:
- * @data_buffer_handle:
- * @data_buffer_size:
- * @oob_buffer:
- * @oob_buffer_handle:
- * @oob_buffer_size:
- * @verify_buffer:
- * @dma_descriptors: An array of DMA descriptors used in I/O operations.
- * @chips: An array of data structures, one for each physical
- * chip.
- * @cchip: A pointer to the element within the chips array that
- * represents the currently selected chip.
- * @selected_chip: The currently selectd chip number, or -1 if no chip
- * is selected.
- * @hwecc_type_read:
- * @hwecc_type_write:
- * @hwecc: Never used.
- * @ecc_oob_bytes: The number of ECC bytes covering the OOB bytes alone.
- * @oob_free: The total number of OOB bytes.
- * @transcribe_bbmark: Used by the bad block management code to indicate
- * that the medium is in common format and the bad block
- * marks must be transcribed.
- * @timing: The current timings installed in the hardware.
- * @saved_command: Used to "hook" the NAND Flash MTD default
- * implementation for the cmdfunc fuction pointer.
- * @raw_oob_mode:
- * @saved_read_oob: Used to "hook" the NAND Flash MTD interface function
- * for the MTD read_oob fuction pointer.
- * @saved_write_oob: Used to "hook" the NAND Flash MTD interface function
- * for the MTD write_oob fuction pointer.
- * @hc: A pointer to a structure that represents the ECC
- * in use.
- */
-
-struct gpmi_nand_data {
-
- struct platform_device *dev;
- struct gpmi_platform_data *gpd;
-
- void __iomem *io_base;
- struct clk *clk;
- int irq;
- struct timer_list timer;
- int self_suspended;
- int use_count;
- struct regulator *regulator;
- int reg_uA;
-
- int ignorebad;
- void *bbt;
-
- struct mtd_info mtd;
- struct nand_chip nand;
-
- struct nand_device_info device_info;
-
- unsigned last_write_page_address;
-
-#if defined(CONFIG_MTD_PARTITIONS)
- struct mtd_info *general_use_mtd;
- struct mtd_partition *partitions;
- unsigned partition_count;
-#endif
-
- struct completion done;
-
- u8 *cmd_buffer;
- dma_addr_t cmd_buffer_handle;
- int cmd_buffer_size, cmd_buffer_sz;
-
- u8 *write_buffer;
- dma_addr_t write_buffer_handle;
- int write_buffer_size;
- u8 *read_buffer; /* point in write_buffer */
- dma_addr_t read_buffer_handle;
-
- u8 *data_buffer;
- dma_addr_t data_buffer_handle;
- int data_buffer_size;
-
- u8 *oob_buffer;
- dma_addr_t oob_buffer_handle;
- int oob_buffer_size;
-
- void *verify_buffer;
-
- struct mxs_dma_desc *dma_descriptors[DMA_DESCRIPTOR_COUNT];
-
- struct nchip {
- int cs;
- unsigned dma_ch;
- struct mxs_dma_desc *d[GPMI_DMA_MAX_CHAIN];
- } chips[GPMI_MAX_CHIPS];
- struct nchip *cchip;
- int selected_chip;
-
- int hwecc;
-
- int ecc_oob_bytes, oob_free;
-
- struct gpmi_nand_timing timing;
-
- void (*saved_command)(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr);
-
- int raw_oob_mode;
- int (*saved_read_oob)(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops);
- int (*saved_write_oob)(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops);
-
- struct gpmi_ecc_descriptor *hc;
-
-};
-
-extern struct gpmi_nand_timing gpmi_safe_timing;
-
-/**
- * struct gpmi_ncb -
- *
- * @fingerprint1:
- * @timing:
- * @pagesize:
- * @page_plus_oob_size:
- * @sectors_per_block:
- * @sector_in_page_mask:
- * @sector_to_page_shift:
- * @num_nands:
- * @fingerprint2:
- */
-
-struct gpmi_fcb {
- u32 fingerprint1;
- struct gpmi_nand_timing timing;
- u32 pagesize;
- u32 page_plus_oob_size;
- u32 sectors_per_block;
- u32 sector_in_page_mask;
- u32 sector_to_page_shift;
- u32 num_nands;
- u32 reserved[3];
- u32 fingerprint2; /* offset 0x2C */
-};
-
-/**
- * struct gpmi_ldlb -
- *
- * @fingerprint1:
- * @major:
- * @minor:
- * @sub:
- * @nand_bitmap:
- * @fingerprint2:
- * @fw:
- * @fw_starting_nand:
- * @fw_starting_sector:
- * @fw_sector_stride:
- * @fw_sectors_total:
- * @fw_major:
- * @fw_minor:
- * @fw_sub:
- * @fw_reserved:
- * @bbt_blk:
- * @bbt_blk_backup:
- */
-
-struct gpmi_ldlb {
- u32 fingerprint1;
- u16 major, minor, sub, reserved;
- u32 nand_bitmap;
- u32 reserved1[7];
- u32 fingerprint2;
- struct {
- u32 fw_starting_nand;
- u32 fw_starting_sector;
- u32 fw_sector_stride;
- u32 fw_sectors_total;
- } fw[2];
- u16 fw_major, fw_minor, fw_sub, fw_reserved;
- u32 bbt_blk;
- u32 bbt_blk_backup;
-};
-
-static inline void gpmi_block_mark_as(struct nand_chip *chip,
- int block, int mark)
-{
- u32 o;
- int shift = (block & 0x03) << 1,
- index = block >> 2;
-
- if (chip->bbt) {
- mark &= 0x03;
-
- o = chip->bbt[index];
- o &= ~(0x03 << shift);
- o |= (mark << shift);
- chip->bbt[index] = o;
- }
-}
-
-static inline int gpmi_block_badness(struct nand_chip *chip, int block)
-{
- u32 o;
- int shift = (block & 0x03) << 1,
- index = block >> 2;
-
- if (chip->bbt) {
- o = (chip->bbt[index] >> shift) & 0x03;
- pr_debug("%s: block = %d, o = %d\n", __func__, block, o);
- return o;
- }
- return -1;
-}
-
-#ifdef CONFIG_STMP3XXX_UNIQUE_ID
-int __init gpmi_uid_init(const char *name, struct mtd_info *mtd,
- u_int32_t start, u_int32_t size);
-void gpmi_uid_remove(const char *name);
-#else
-#define gpmi_uid_init(name, mtd, start, size)
-#define gpmi_uid_remove(name)
-#endif
-
-#endif