]> code.ossystems Code Review - openembedded-core.git/commitdiff
linux-rp-2.6.23: Add patch to get zylonite mtd working (forward ported 2.6.14 driver...
authorRichard Purdie <richard@openedhand.com>
Wed, 13 Feb 2008 01:04:52 +0000 (01:04 +0000)
committerRichard Purdie <richard@openedhand.com>
Wed, 13 Feb 2008 01:04:52 +0000 (01:04 +0000)
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@3786 311d38ba-8fff-0310-9ca6-ca027cbcb966

meta/packages/linux/linux-rp-2.6.23/defconfig-zylonite
meta/packages/linux/linux-rp-2.6.23/zylonite_mtd-r0.patch [new file with mode: 0644]
meta/packages/linux/linux-rp_2.6.23.bb

index 8be4a3bd47ce15a17be3ae7b1b87a1b61afcf68b..14ea6c355f7f91d805124b2588a8f95445080270 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc4
-# Tue Sep 25 15:57:10 2007
+# Linux kernel version: 2.6.23
+# Tue Feb 12 18:04:14 2008
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -65,7 +65,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -262,6 +261,7 @@ CONFIG_BINFMT_ELF=y
 # Power management options
 #
 # CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
 
 #
 # Networking
@@ -272,6 +272,7 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=m
+# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
@@ -304,6 +305,7 @@ CONFIG_INET_TCP_DIAG=y
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
 # CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
@@ -370,7 +372,6 @@ CONFIG_IP_NF_RAW=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
@@ -551,6 +552,7 @@ CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_SHARPSL is not set
+CONFIG_MTD_NAND_ZYLONITE=y
 # CONFIG_MTD_NAND_NANDSIM is not set
 # CONFIG_MTD_NAND_PLATFORM is not set
 # CONFIG_MTD_ONENAND is not set
@@ -964,11 +966,8 @@ CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-# CONFIG_LOGO_OHAND_CLUT224 is not set
-# CONFIG_LOGO_OZ240_CLUT224 is not set
-# CONFIG_LOGO_OZ480_CLUT224 is not set
-# CONFIG_LOGO_OZ640_CLUT224 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_LOGO_OHAND_CLUT224=y
 
 #
 # Sound
@@ -1025,7 +1024,7 @@ CONFIG_SND_VERBOSE_PROCFS=y
 #
 # CONFIG_SOUND_PRIME is not set
 CONFIG_HID_SUPPORT=y
-CONFIG_HID=m
+CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
@@ -1237,7 +1236,13 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
 # CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
diff --git a/meta/packages/linux/linux-rp-2.6.23/zylonite_mtd-r0.patch b/meta/packages/linux/linux-rp-2.6.23/zylonite_mtd-r0.patch
new file mode 100644 (file)
index 0000000..231b3d7
--- /dev/null
@@ -0,0 +1,4062 @@
+Gross hacks to make the Zylonite boot from flash in VGA.
+
+Flash driver forward ported to 2.6.14
+
+Index: linux-2.6.23/drivers/mtd/nand/Kconfig
+===================================================================
+--- linux-2.6.23.orig/drivers/mtd/nand/Kconfig 2008-02-12 18:02:36.000000000 +0000
++++ linux-2.6.23/drivers/mtd/nand/Kconfig      2008-02-12 18:03:07.000000000 +0000
+@@ -223,6 +223,10 @@
+       tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
+       depends on ARCH_PXA
++config MTD_NAND_ZYLONITE
++      tristate "Support for NAND Flash on Zylonite"
++      depends on ARCH_PXA
++
+ config MTD_NAND_BASLER_EXCITE
+       tristate  "Support for NAND Flash on Basler eXcite"
+       depends on BASLER_EXCITE
+Index: linux-2.6.23/drivers/mtd/nand/Makefile
+===================================================================
+--- linux-2.6.23.orig/drivers/mtd/nand/Makefile        2008-02-12 18:02:36.000000000 +0000
++++ linux-2.6.23/drivers/mtd/nand/Makefile     2008-02-12 18:03:27.000000000 +0000
+@@ -19,6 +19,7 @@
+ obj-$(CONFIG_MTD_NAND_H1900)          += h1910.o
+ obj-$(CONFIG_MTD_NAND_RTC_FROM4)      += rtc_from4.o
+ obj-$(CONFIG_MTD_NAND_SHARPSL)                += sharpsl.o
++obj-$(CONFIG_MTD_NAND_ZYLONITE)               += mhn_nand.o
+ obj-$(CONFIG_MTD_NAND_TS7250)         += ts7250.o
+ obj-$(CONFIG_MTD_NAND_NANDSIM)                += nandsim.o
+ obj-$(CONFIG_MTD_NAND_CS553X)         += cs553x_nand.o
+Index: linux-2.6.23/drivers/mtd/nand/mhn_nand.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23/drivers/mtd/nand/mhn_nand.c   2008-02-12 23:54:00.000000000 +0000
+@@ -0,0 +1,3869 @@
++/*
++ *  drivers/mtd/nand/mhn_nand.c
++ *
++ *  Copyright (C) 2005 Intel Coporation (chao.xie@intel.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Overview:
++ *   This is a device driver for the NAND flash device on zylonite board
++ *   which utilizes the Samsung K9K1216Q0C parts. This is a 64Mibit NAND
++ *   flash device.
++
++ *(C) Copyright 2006 Marvell International Ltd.
++ * All Rights Reserved
++ */
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/delay.h>
++#include <asm/dma.h>
++#include <asm/arch/mfp.h>
++//#include <asm/arch/cpu-freq-voltage-mhn.h>
++
++//#define NDCR 0xf0000000
++//#define NDCR        (*((volatile u32 *)0xf0000000))
++//#define NDCR              __REG_2(0x43100000)  /* Data Flash Control register */
++#define NDCR_SPARE_EN             (0x1<<31)
++#define NDCR_ECC_EN               (0x1<<30)
++#define NDCR_DMA_EN               (0x1<<29)
++#define NDCR_ND_RUN               (0x1<<28)
++#define NDCR_DWIDTH_C             (0x1<<27)
++#define NDCR_DWIDTH_M             (0x1<<26)
++#define NDCR_PAGE_SZ              (0x1<<24)
++#define NDCR_NCSX         (0x1<<23)
++#define NDCR_ND_MODE              (0x3<<21)
++#define NDCR_NAND_MODE    0x0
++#define NDCR_CLR_PG_CNT           (0x1<<20)
++#define NDCR_CLR_ECC      (       0x1<<19)
++#define NDCR_RD_ID_CNT_MASK       (0x7<<16)
++#define NDCR_RD_ID_CNT(x)       (((x) << 16) & NDCR_RD_ID_CNT_MASK)
++#define NDCR_RA_START     (0x1<<15)
++#define NDCR_PG_PER_BLK   (0x1<<14)
++#define NDCR_ND_ARB_EN    (0x1<<12)
++
++//#define NDSR        (*((volatile u32 *)0xf0000014))
++//#define NDSR              __REG_2(0x43100014)  /* Data Controller Status Register */
++#define NDSR_RDY  (0x1<<11)
++#define NDSR_CS0_PAGED    (0x1<<10)
++#define NDSR_CS1_PAGED    (0x1<<9)
++#define NDSR_CS0_CMDD     (0x1<<8)
++#define NDSR_CS1_CMDD     (0x1<<7)
++#define NDSR_CS0_BBD      (0x1<<6)
++#define NDSR_CS1_BBD      (0x1<<5)
++#define NDSR_DBERR        (0x1<<4)
++#define NDSR_SBERR        (0x1<<3)
++#define NDSR_WRDREQ       (0x1<<2)
++#define NDSR_RDDREQ       (0x1<<1)
++#define NDSR_WRCMDREQ     (0x1)
++
++#define OSCR              __REG(0x40A00010)  /* OS Timer Counter Register */
++//#define NDCB0             __REG_2(0x43100048)  /* Data Controller Command Buffer0 */
++//#define NDCB1             __REG_2(0x4310004C)  /* Data Controller Command Buffer1 */
++//#define NDCB2             __REG_2(0x43100050)  /* Data Controller Command Buffer2 */
++#define NDCB0_AUTO_RS             (0x1<<25)
++#define NDCB0_CSEL                (0x1<<24)
++#define NDCB0_CMD_TYPE_MASK       (0x7<<21)
++#define   NDCB0_CMD_TYPE(x)       (((x) << 21) & NDCB0_CMD_TYPE_MASK)
++#define NDCB0_NC          (0x1<<20)
++#define NDCB0_DBC         (0x1<<19)
++#define NDCB0_ADDR_CYC_MASK       (0x7<<16)
++#define   NDCB0_ADDR_CYC(x)       (((x) << 16) & NDCB0_ADDR_CYC_MASK)
++#define NDCB0_CMD2_MASK           (0xff<<8)
++#define NDCB0_CMD1_MASK           (0xff)
++#define NDCB0_ADDR_CYC_SHIFT      (16)
++#define DCMD0             __REG(0x4000020c)  /* DMA Command Address Register Channel 0 */
++#define DCMD1             __REG(0x4000021c)  /* DMA Command Address Register Channel 1 */
++#define DCMD2             __REG(0x4000022c)  /* DMA Command Address Register Channel 2 */
++#define DCMD3             __REG(0x4000023c)  /* DMA Command Address Register Channel 3 */
++#define DCMD4             __REG(0x4000024c)  /* DMA Command Address Register Channel 4 */
++#define DCMD5             __REG(0x4000025c)  /* DMA Command Address Register Channel 5 */
++#define DCMD6             __REG(0x4000026c)  /* DMA Command Address Register Channel 6 */
++#define DCMD7             __REG(0x4000027c)  /* DMA Command Address Register Channel 7 */
++#define DCMD8             __REG(0x4000028c)  /* DMA Command Address Register Channel 8 */
++#define DCMD9             __REG(0x4000029c)  /* DMA Command Address Register Channel 9 */
++#define DCMD10            __REG(0x400002ac)  /* DMA Command Address Register Channel 10 */
++#define DCMD11            __REG(0x400002bc)  /* DMA Command Address Register Channel 11 */
++#define DCMD12            __REG(0x400002cc)  /* DMA Command Address Register Channel 12 */
++#define DCMD13            __REG(0x400002dc)  /* DMA Command Address Register Channel 13 */
++#define DCMD14            __REG(0x400002ec)  /* DMA Command Address Register Channel 14 */
++#define DCMD15            __REG(0x400002fc)  /* DMA Command Address Register Channel 15 */
++#define DCMD(x)           __REG2(0x4000020c, (x) << 4)
++#define DCMD_INCSRCADDR   (1 << 31)       /* Source Address Increment Setting. */
++#define DCMD_INCTRGADDR   (1 << 30)       /* Target Address Increment Setting. */
++#define DCMD_FLOWSRC      (1 << 29)       /* Flow Control by the source. */
++#define DCMD_FLOWTRG      (1 << 28)       /* Flow Control by the target. */
++#define DCMD_STARTIRQEN   (1 << 22)       /* Start Interrupt Enable */
++#define DCMD_ENDIRQEN     (1 << 21)       /* End Interrupt Enable */
++#define DCMD_ENDIAN       (1 << 18)       /* Device Endian-ness. */
++#define DCMD_BURST8       (1 << 16)       /* 8 byte burst */
++#define DCMD_BURST16      (2 << 16)       /* 16 byte burst */
++#define DCMD_BURST32      (3 << 16)       /* 32 byte burst */
++#define DCMD_WIDTH1       (1 << 14)       /* 1 byte width */
++#define DCMD_WIDTH2       (2 << 14)       /* 2 byte width (HalfWord) */
++#define DCMD_WIDTH4       (3 << 14)       /* 4 byte width (Word) */
++#define DCMD_LENGTH       0x01fff         /* length mask (max = 8K - 1) */
++#define DCMD_RXPCDR       (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
++#define DCMD_RXMCDR       (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
++#define DCMD_TXPCDR       (DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4)
++#define DRCMR(n)  __REG2(0x40000100, (n)<<2)
++#define DRCMR97           __REG(0x40001184)  /* Request to Channel Map Register for NAND interface data transmit & receive Request */
++#define DRCMR98           __REG(0x40001188)  /* Reserved */
++#define DRCMR99           __REG(0x4000118C)  /* Request to Channel Map Register for NAND interface command transmit Request */
++#define DRCMRRXSADR       DRCMR2
++#define DRCMRTXSADR       DRCMR3
++#define DRCMRRXBTRBR      DRCMR4
++#define DRCMRTXBTTHR      DRCMR5
++#define DRCMRRXFFRBR      DRCMR6
++#define DRCMRTXFFTHR      DRCMR7
++#define DRCMRRXMCDR       DRCMR8
++#define DRCMRRXMODR       DRCMR9
++#define DRCMRTXMODR       DRCMR10
++#define DRCMRRXPCDR       DRCMR11
++#define DRCMRTXPCDR       DRCMR12
++#define DRCMRRXSSDR       DRCMR13
++#define DRCMRTXSSDR       DRCMR14
++#define DRCMRRXICDR       DRCMR17
++#define DRCMRTXICDR       DRCMR18
++#define DRCMRRXSTRBR      DRCMR19
++#define DRCMRTXSTTHR      DRCMR20
++#define DRCMRRXMMC        DRCMR21
++#define DRCMRTXMMC        DRCMR22
++#define DRCMRRXMMC2       DRCMR93
++#define DRCMRTXMMC2       DRCMR94
++#define DRCMRRXMMC3       DRCMR100
++#define DRCMRTXMMC3       DRCMR101
++#define DRCMRUDC(x)       DRCMR((x) + 24)
++#define DRCMR_MAPVLD      (1 << 7)        /* Map Valid (read / write) */
++#define DRCMR_CHLNUM      0x1f            /* mask for Channel Number (read / write) */
++#define DCSR0             __REG(0x40000000)  /* DMA Control / Status Register for Channel 0 */
++#define DCSR1             __REG(0x40000004)  /* DMA Control / Status Register for Channel 1 */
++#define DCSR2             __REG(0x40000008)  /* DMA Control / Status Register for Channel 2 */
++#define DCSR3             __REG(0x4000000c)  /* DMA Control / Status Register for Channel 3 */
++#define DCSR4             __REG(0x40000010)  /* DMA Control / Status Register for Channel 4 */
++#define DCSR5             __REG(0x40000014)  /* DMA Control / Status Register for Channel 5 */
++#define DCSR6             __REG(0x40000018)  /* DMA Control / Status Register for Channel 6 */
++#define DCSR7             __REG(0x4000001c)  /* DMA Control / Status Register for Channel 7 */
++#define DCSR8             __REG(0x40000020)  /* DMA Control / Status Register for Channel 8 */
++#define DCSR9             __REG(0x40000024)  /* DMA Control / Status Register for Channel 9 */
++#define DCSR10            __REG(0x40000028)  /* DMA Control / Status Register for Channel 10 */
++#define DCSR11            __REG(0x4000002c)  /* DMA Control / Status Register for Channel 11 */
++#define DCSR12            __REG(0x40000030)  /* DMA Control / Status Register for Channel 12 */
++#define DCSR13            __REG(0x40000034)  /* DMA Control / Status Register for Channel 13 */
++#define DCSR14            __REG(0x40000038)  /* DMA Control / Status Register for Channel 14 */
++#define DCSR15            __REG(0x4000003c)  /* DMA Control / Status Register for Channel 15 */
++#define DCSR16            __REG(0x40000040)  /* DMA Control / Status Register for Channel 16 */
++#define DCSR17            __REG(0x40000044)  /* DMA Control / Status Register for Channel 17 */
++#define DCSR18            __REG(0x40000048)  /* DMA Control / Status Register for Channel 18 */
++#define DCSR19            __REG(0x4000004c)  /* DMA Control / Status Register for Channel 19 */
++#define DCSR20            __REG(0x40000050)  /* DMA Control / Status Register for Channel 20 */
++#define DCSR21            __REG(0x40000054)  /* DMA Control / Status Register for Channel 21 */
++#define DCSR22            __REG(0x40000058)  /* DMA Control / Status Register for Channel 22 */
++#define DCSR23            __REG(0x4000005c)  /* DMA Control / Status Register for Channel 23 */
++#define DCSR24            __REG(0x40000060)  /* DMA Control / Status Register for Channel 24 */
++#define DCSR25            __REG(0x40000064)  /* DMA Control / Status Register for Channel 25 */
++#define DCSR26            __REG(0x40000068)  /* DMA Control / Status Register for Channel 26 */
++#define DCSR27            __REG(0x4000006c)  /* DMA Control / Status Register for Channel 27 */
++#define DCSR28            __REG(0x40000070)  /* DMA Control / Status Register for Channel 28 */
++#define DCSR29            __REG(0x40000074)  /* DMA Control / Status Register for Channel 29 */
++#define DCSR30            __REG(0x40000078)  /* DMA Control / Status Register for Channel 30 */
++#define DCSR31            __REG(0x4000007c)  /* DMA Control / Status Register for Channel 31 */
++#define DCSR(x)           __REG2(0x40000000, (x) << 2)
++#define DCSR_RUN  (1 << 31)       /* Run Bit (read / write) */
++#define DCSR_NODESC       (1 << 30)       /* No-Descriptor Fetch (read / write) */
++#define DCSR_STOPIRQEN    (1 << 29)       /* Stop Interrupt Enable (read / write) */
++#define DCSR_EORIRQEN     (1 << 28)       /* End of Receive Interrupt Enable (R/W) */
++#define DCSR_EORJMPEN     (1 << 27)       /* Jump to next descriptor on EOR */
++#define DCSR_EORSTOPEN    (1 << 26)       /* STOP on an EOR */
++#define DCSR_SETCMPST     (1 << 25)       /* Set Descriptor Compare Status */
++#define DCSR_CLRCMPST     (1 << 24)       /* Clear Descriptor Compare Status */
++#define DCSR_CMPST        (1 << 10)       /* The Descriptor Compare Status */
++#define DCSR_EORINTR      (1 << 9)        /* The end of Receive */
++#define DCSR_REQPEND      (1 << 8)        /* Request Pending (read-only) */
++#define DCSR_RASINTR      (1 << 4)        /* Request After Channel Stopped */
++#define DCSR_STOPSTATE    (1 << 3)        /* Stop State (read-only) */
++#define DCSR_ENDINTR      (1 << 2)        /* End Interrupt (read / write) */
++#define DCSR_STARTINTR    (1 << 1)        /* Start Interrupt (read / write) */
++#define DCSR_BUSERR       (1 << 0)        /* Bus Error Interrupt (read / write) */
++#define DDADR(x)  __REG2(0x40000200, (x) << 4)
++//#define __REG_2(x)        (*((volatile u32 *)io_p2v_2(x)))
++#define IRQ_NAND      PXA_IRQ(45)
++#define   CKEN_NAND       4       ///< NAND Flash Controller Clock Enable
++
++/* #define CONFIG_MTD_NAND_MONAHANS_DEBUG */
++#ifdef CONFIG_MTD_NAND_MONAHANS_DEBUG
++#define D1(x) do { \
++              printk(KERN_DEBUG "%s: ", __FUNCTION__); \
++              x; \
++      }while(0)
++
++#define       DPRINTK(fmt,args...) printk(KERN_DEBUG fmt, ##args )
++#define PRINT_BUF(buf, num)   print_buf(buf, num)
++#else
++#define D1(x)
++#define DPRINTK(fmt,args...)
++#define PRINT_BUF(buf, num)
++#endif
++
++/* DFC timing 0 register */
++#define DFC_TIMING_tRP                0
++#define DFC_TIMING_tRH                3
++#define DFC_TIMING_tWP                8
++#define DFC_TIMING_tWH                11
++#define DFC_TIMING_tCS                16
++#define DFC_TIMING_tCH                19
++
++/* DFC timing 1 register */
++#define DFC_TIMING_tAR                0
++#define DFC_TIMING_tWHR               4
++#define DFC_TIMING_tR         16
++
++/* max value for each timing setting in DFC */
++#define DFC_TIMING_MAX_tCH    7
++#define DFC_TIMING_MAX_tCS    7
++#define DFC_TIMING_MAX_tWH    7
++#define DFC_TIMING_MAX_tWP    7
++#define DFC_TIMING_MAX_tRH    7
++#define DFC_TIMING_MAX_tRP    7
++#define DFC_TIMING_MAX_tR     65535
++#define DFC_TIMING_MAX_tWHR   15
++#define DFC_TIMING_MAX_tAR    15
++
++/*
++ * The Data Flash Controller Flash timing structure
++ * For NAND flash used on Zylonite board(Samsung K9K1216Q0C),
++ * user should use value at end of each row of following member
++ * bracketed.
++ */
++struct dfc_flash_timing {
++      uint32_t   tCH; /* Enable signal hold time */
++      uint32_t   tCS; /* Enable signal setup time */
++      uint32_t   tWH; /* ND_nWE high duration */
++      uint32_t   tWP; /* ND_nWE pulse time */
++      uint32_t   tRH; /* ND_nRE high duration */
++      uint32_t   tRP; /* ND_nRE pulse width */
++      uint32_t   tR;  /* ND_nWE high to ND_nRE low for read */
++      uint32_t   tWHR;/* ND_nWE high to ND_nRE low delay for status read */
++      uint32_t   tAR; /* ND_ALE low to ND_nRE low delay */
++};
++
++/* DFC command type */
++enum {
++      DFC_CMD_READ            = 0x00000000,
++      DFC_CMD_PROGRAM         = 0x00200000,
++      DFC_CMD_ERASE           = 0x00400000,
++      DFC_CMD_READ_ID         = 0x00600000,
++      DFC_CMD_STATUS_READ     = 0x00800000,
++      DFC_CMD_RESET           = 0x00a00000
++};
++
++/*
++ * The Data Flash Controller Flash specification structure
++ * For NAND flash used on Zylonite board(Samsung K9K1216Q0C),
++ * user should use value at end of each row of following member
++ * bracketed.
++ */
++struct dfc_flash_info {
++      struct dfc_flash_timing timing; /* NAND Flash timing */
++
++      int      enable_arbiter;/* Data flash bus arbiter enable (ND_ARB_EN) */
++      uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
++      uint32_t row_addr_start;/* Row address start position (RA_START) */
++      uint32_t read_id_bytes; /* returned ID bytes(RD_ID_CNT) */
++      uint32_t dfc_mode;      /* NAND, CARBONDALE, PIXLEY... (ND_MODE) */
++      uint32_t ncsx;          /* Chip select don't care bit (NCSX) */
++      uint32_t page_size;     /* Page size in bytes (PAGE_SZ) */
++      uint32_t oob_size;      /* OOB size */
++      uint32_t flash_width;   /* Width of Flash memory (DWIDTH_M) */
++      uint32_t dfc_width;     /* Width of flash controller(DWIDTH_C) */
++      uint32_t num_blocks;    /* Number of physical blocks in Flash */
++      uint32_t chip_id;
++
++      /* command codes */
++      uint32_t read1;         /* Read */
++      uint32_t read2;         /* unused, DFC don't support yet */
++      uint32_t program;       /* two cycle command */
++      uint32_t read_status;
++      uint32_t read_id;
++      uint32_t erase;         /* two cycle command */
++      uint32_t reset;
++      uint32_t lock;          /* lock whole flash */
++      uint32_t unlock;        /* two cycle command, supporting partial unlock */
++      uint32_t lock_status;   /* read block lock status */
++
++      /* addr2ndcb1 - encode address cycles into register NDCB1 */
++      /* ndbbr2addr - convert register NDBBR to bad block address */
++      int (*addr2ndcb1)(uint16_t cmd, uint32_t addr, uint32_t *p);
++      int (*ndbbr2addr)(uint16_t cmd, uint32_t ndbbr,uint32_t *p);
++};
++
++enum {
++      DFC_FLASH_NULL = 0 ,
++      DFC_FLASH_Samsung_512Mb_X_16 = 1,
++      DFC_FLASH_Micron_1Gb_X_8 = 2,
++      DFC_FLASH_Micron_1Gb_X_16 = 3,
++      DFC_FLASH_STM_1Gb_X_16 = 4,
++      DFC_FLASH_STM_2Gb_X_16 = 5,
++      DFC_FLASH_END,
++};
++
++static int dfc_get_flash_info(int type, struct dfc_flash_info **flash_info);
++
++#define               DFC_NDCR        0
++#define               DFC_NDTR0CS0    1
++#define               DFC_NDTR1CS0    3
++#define               DFC_NDSR        5
++#define               DFC_NDPCR       6
++#define               DFC_NDBDR0      7
++#define               DFC_NDBDR1      8
++#define               DFC_NDDB        16
++#define               DFC_NDCB0       18
++#define               DFC_NDCB1       19
++#define               DFC_NDCB2       20
++
++/* The Data Flash Controller Mode structure */
++struct dfc_mode {
++      int   enable_dma;       /* DMA, or nonDMA mode */
++      int   enable_ecc;       /* ECC on/off */
++      int   enable_spare;     /* Spare enable */
++      int   chip_select;      /* CS0 or CS1 */
++};
++
++/* The Data Flash Controller Context structure */
++struct dfc_context {
++      unsigned char __iomem   *membase;       /* DFC register base */
++      struct dfc_mode         *dfc_mode;      /* DFC mode */
++      int                     data_dma_ch;    /* Data DMA channel number */
++      int                     cmd_dma_ch;     /* CMD  DMA channel number */
++      struct dfc_flash_info   *flash_info; /* Flash Spec */
++      struct mtd_info         *mtd;
++};
++
++#define NDCB0_DMA_ADDR        0x43100048
++#define NDDB_DMA_ADDR 0x43100040
++
++#define NDSR_MASK     0xFFF
++
++/* The following data is a rough evaluation */
++
++/* microsecond, for readID/readStatus/reset */
++#define NAND_OTHER_TIMEOUT            10
++/* microsecond, for readID/readStatus/reset */
++#define NAND_CMD_TIMEOUT              10
++
++#define BBT_BLOCK_BAD 0x03
++#define BBT_BLOCK_GOOD        0x00
++#define BBT_BLOCK_REV1        0x01
++#define BBT_BLOCK_REV2        0x02
++
++#define BUFLEN                (2048 + 64)
++
++/*
++ * DFC data size enumeration transfered from/to controller,
++ * including padding (zero)to be a multiple of 32.
++ */
++enum {
++      DFC_DATA_SIZE_STATUS = 8,       /* ReadStatus/ReadBlockLockStatus */
++      DFC_DATA_SIZE_ID = 7,   /* ReadID */
++
++      DFC_DATA_SIZE_32 = 32,
++      DFC_DATA_SIZE_512 = 512,        /* R/W disabling spare area */
++      DFC_DATA_SIZE_520 = 520,        /* Spare=1, ECC=1 */
++      DFC_DATA_SIZE_528 = 528,        /* Spare=1, ECC=0 */
++      DFC_DATA_SIZE_544 = 544,        /* R/W enabling spare area.(DMA mode)*/
++
++      DFC_DATA_SIZE_64 = 64,
++      DFC_DATA_SIZE_2048 = 2048,      /* R/W disabling spare area */
++      DFC_DATA_SIZE_2088 = 2088,      /* R/W enabling spare area with ecc */
++      DFC_DATA_SIZE_2112 = 2112,      /* R/W enabling spare area without ecc*/
++      DFC_DATA_SIZE_2096 = 2096,      /* R/W enabling spare area */
++      DFC_DATA_SIZE_UNUSED = 0xFFFF
++};
++
++/* DFC padding size enumeration transfered from/to controller */
++enum {
++      /*
++       * ReadStatus/ReadBlockLockStatus/ReadID/
++       * Read/Program disabling spare area(Both 512 and 2048)
++       * Read/Program enabling spare area, disabling ECC
++       */
++      DFC_PADDING_SIZE_0 = 0,
++
++      /* Read/program with SPARE_EN=1, ECC_EN=0, pgSize=512 */
++      DFC_PADDING_SIZE_16 = 16,
++      /* for read/program with SPARE_EN=1, ECC_EN=1, pgSize=512 and 2048 */
++      DFC_PADDING_SIZE_24 = 24,
++      DFC_PADDING_SIZE_UNUSED = 0xFFFF
++};
++
++static unsigned int flash_config = DFC_FLASH_NULL;
++
++void dfc_set_timing(struct dfc_context *context, struct dfc_flash_timing *t);
++void dfc_set_dma(struct dfc_context *context);
++void dfc_set_ecc(struct dfc_context *context);
++void dfc_set_spare(struct dfc_context *context);
++
++int dfc_get_pattern(struct dfc_context *context, uint16_t cmd,
++                      int *data_size, int *padding);
++
++static int dfc_wait_event(struct dfc_context *context, uint32_t event,
++              uint32_t *event_out, uint32_t timeout, int enable_int);
++
++int dfc_send_cmd(struct dfc_context *context, uint16_t cmd,
++              uint32_t addr, int num_pages);
++
++void dfc_stop(struct dfc_context *context);
++void dfc_read_fifo_partial(struct dfc_context *context, uint8_t *buffer,
++                      int nbytes, int data_size);
++void dfc_write_fifo_partial(struct dfc_context *context, uint8_t *buffer,
++                      int nbytes, int data_size);
++
++void dfc_read_fifo(struct dfc_context *context, uint8_t *buffer, int nbytes);
++void dfc_write_fifo(struct dfc_context *context, uint8_t *buffer, int nbytes);
++
++void dfc_read_badblock_addr(struct dfc_context *context, uint32_t *bbaddr);
++
++void dfc_clear_int(struct dfc_context *context, uint32_t int_mask);
++void dfc_enable_int(struct dfc_context *context, uint32_t int_mask);
++void dfc_disable_int(struct dfc_context *context, uint32_t int_mask);
++
++/* high level primitives */
++int dfc_init(struct dfc_context *context, int type);
++int dfc_init_no_gpio(struct dfc_context *context, int type);
++
++int dfc_reset_flash(struct dfc_context *context);
++
++int dfc_setup_cmd_dma(struct dfc_context *context,
++              uint16_t cmd, uint32_t addr, int num_pages,
++              uint32_t *buf, uint32_t buf_phys,
++              uint32_t next_desc_phys, uint32_t dma_int_en,
++              struct pxa_dma_desc *dma_desc);
++
++int dfc_setup_data_dma(struct dfc_context *context,
++              uint16_t cmd, uint32_t buf_phys,
++              uint32_t next_desc_phys, uint32_t dma_int_en,
++              struct pxa_dma_desc *dma_desc);
++
++void dfc_start_cmd_dma(struct dfc_context *context,
++                      struct pxa_dma_desc *dma_desc);
++void dfc_start_data_dma(struct dfc_context *context,
++                      struct pxa_dma_desc *dma_desc);
++static int monahans_df_dev_ready(struct mtd_info *mtd);
++
++#ifdef CONFIG_DVFM
++static int mhn_nand_dvfm_notifier(unsigned cmd, void *client_data, void *info);
++static struct mhn_fv_notifier dvfm_notifier = {
++      .name           = "monahans-nand-flash",
++      .priority       = 0,
++      .notifier_call  = mhn_nand_dvfm_notifier,
++};
++#endif
++
++static unsigned short search_rel_block(int block, struct mtd_info *mtd);
++
++/*****************************************************************************
++ * The DFC registers read/write routines
++ *****************************************************************************/
++static inline void dfc_write(struct dfc_context *context, int offset,
++              unsigned long value)
++{
++      offset <<= 2;
++      writel(value, context->membase + offset);
++}
++
++static inline unsigned int dfc_read(struct dfc_context *context, int offset)
++{
++      offset <<= 2;
++      return __raw_readl(context->membase + offset);
++}
++
++/****************************************************************************
++ * Flash Information
++ ***************************************************************************/
++
++static int Samsung512MbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int Samsung512MbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info samsung512MbX16 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 0,       /* tCS, Enable signal setup time */
++              .tWH = 20,      /* tWH, ND_nWE high duration */
++              .tWP = 40,      /* tWP, ND_nWE pulse time */
++              .tRH = 30,      /* tRH, ND_nRE high duration */
++              .tRP = 40,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 11123,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 110,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 32,   /* Pages per block */
++      .row_addr_start = 0,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 2,     /* 2 bytes, returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 512,       /* Page size in bytes */
++      .oob_size = 16,         /* OOB size in bytes */
++      .flash_width = 16,      /* Width of Flash memory */
++      .dfc_width = 16,        /* Width of flash controller */
++      .num_blocks = 4096,     /* Number of physical blocks in Flash */
++      .chip_id =  0x46ec,
++
++      /* command codes */
++      .read1 = 0x0000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = Samsung512MbX16Addr2NDCB1,
++      .ndbbr2addr = Samsung512MbX16NDBBR2Addr,
++};
++
++static int Samsung512MbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++
++      if (addr >= 0x4000000) return -EINVAL;
++
++      if (cmd == samsung512MbX16.read1 || cmd == samsung512MbX16.program) {
++              ndcb1 = (addr & 0xFF) | ((addr >> 1) & 0x01FFFF00);
++      } else if (cmd == samsung512MbX16.erase) {
++              ndcb1 = ((addr >> 9) & 0x00FFFFFF);
++      }
++
++      *p = ndcb1;
++      return 0;
++
++}
++
++static int Samsung512MbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      *p = ndbbr << 9;
++      return 0;
++}
++
++static int Micron1GbX8Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int Micron1GbX8NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info micron1GbX8 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 25,      /* tCS, Enable signal setup time */
++              .tWH = 15,      /* tWH, ND_nWE high duration */
++              .tWP = 25,      /* tWP, ND_nWE pulse time */
++              .tRH = 15,      /* tRH, ND_nRE high duration */
++              .tRP = 25,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 25000,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 60,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 64,   /* Pages per block */
++      .row_addr_start = 1,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 4,     /* Returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 2048,      /* Page size in bytes */
++      .oob_size = 64,         /* OOB size in bytes */
++      .flash_width = 8,       /* Width of Flash memory */
++      .dfc_width = 8,         /* Width of flash controller */
++      .num_blocks = 1024,     /* Number of physical blocks in Flash */
++      .chip_id =  0xa12c,
++      /* command codes */
++      .read1 = 0x3000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = Micron1GbX8Addr2NDCB1,
++      .ndbbr2addr = Micron1GbX8NDBBR2Addr,
++};
++
++static int Micron1GbX8Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++      uint32_t page;
++
++      if (addr >= 0x8000000)
++              return -EINVAL;
++      page = addr / micron1GbX8.page_size;
++      addr =  (page / micron1GbX8.page_per_block) << 18 |
++              (page % micron1GbX8.page_per_block) << 12;
++
++      if (cmd == micron1GbX8.read1 || cmd == micron1GbX8.program) {
++              ndcb1 = (addr & 0xFFF) | ((addr << 4) & 0xFFFF0000);
++      }
++      else if (cmd == micron1GbX8.erase) {
++              ndcb1 = ((addr >> 18) << 6) & 0xFFFF;
++      }
++
++      *p = ndcb1;
++      return 0;
++}
++
++static int Micron1GbX8NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      if (cmd == micron1GbX8.read1 || cmd == micron1GbX8.program) {
++              *p = ((ndbbr & 0xF) << 8) | ((ndbbr >> 8) << 16);
++      }
++      else if (cmd == micron1GbX8.erase) {
++              *p = (ndbbr >> 6) << 18;
++      }
++
++
++      return 0;
++}
++
++
++static int Micron1GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int Micron1GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info micron1GbX16 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 25,      /* tCS, Enable signal setup time */
++              .tWH = 15,      /* tWH, ND_nWE high duration */
++              .tWP = 25,      /* tWP, ND_nWE pulse time */
++              .tRH = 15,      /* tRH, ND_nRE high duration */
++              .tRP = 25,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 25000,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 60,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 64,   /* Pages per block */
++      .row_addr_start = 1,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 4,     /* Returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 2048,      /* Page size in bytes */
++      .oob_size = 64,         /* OOB size in bytes */
++      .flash_width = 16,      /* Width of Flash memory */
++      .dfc_width = 16,        /* Width of flash controller */
++      .num_blocks = 1024,     /* Number of physical blocks in Flash */
++      .chip_id =  0xb12c,
++
++      /* command codes */
++      .read1 = 0x3000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = Micron1GbX16Addr2NDCB1,
++      .ndbbr2addr = Micron1GbX16NDBBR2Addr,
++};
++
++static int Micron1GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++      uint32_t page;
++
++      if (addr >= 0x8000000)
++              return -EINVAL;
++      page = addr / micron1GbX16.page_size;
++      addr =  (page / micron1GbX16.page_per_block) << 17 |
++              (page % micron1GbX16.page_per_block) << 11;
++
++      if (cmd == micron1GbX16.read1 || cmd == micron1GbX16.program) {
++              ndcb1 = (addr & 0x7FF) | ((addr << 5) & 0xFFFF0000);
++      }
++      else if (cmd == micron1GbX16.erase) {
++              ndcb1 = ((addr >> 17) << 6) & 0xFFFF;
++      }
++      *p = ndcb1;
++      return 0;
++}
++
++static int Micron1GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      if (cmd == micron1GbX16.read1 || cmd == micron1GbX16.program) {
++              *p = ((ndbbr & 0x7) << 8) | ((ndbbr >> 8) << 16);
++      }
++      else if (cmd == micron1GbX16.erase) {
++              *p = (ndbbr >> 6) << 17;
++      }
++
++      return 0;
++}
++
++static int STM1GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int STM1GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info stm1GbX16 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 10,      /* tCS, Enable signal setup time */
++              .tWH = 20,      /* tWH, ND_nWE high duration */
++              .tWP = 25,      /* tWP, ND_nWE pulse time */
++              .tRH = 20,      /* tRH, ND_nRE high duration */
++              .tRP = 25,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 25000,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 60,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 64,   /* Pages per block */
++      .row_addr_start = 1,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 4,     /* Returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 2048,      /* Page size in bytes */
++      .oob_size = 64,         /* OOB size in bytes */
++      .flash_width = 16,      /* Width of Flash memory */
++      .dfc_width = 16,        /* Width of flash controller */
++      .num_blocks = 1024,     /* Number of physical blocks in Flash */
++      .chip_id =  0xb120,
++
++      /* command codes */
++      .read1 = 0x3000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = STM1GbX16Addr2NDCB1,
++      .ndbbr2addr = STM1GbX16NDBBR2Addr,
++};
++
++static int STM1GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++      uint32_t page;
++
++      if (addr >= 0x8000000)
++              return -EINVAL;
++      page = addr / stm1GbX16.page_size;
++      addr =  (page / stm1GbX16.page_per_block) << 17 |
++              (page % stm1GbX16.page_per_block) << 11;
++
++      if (cmd == stm1GbX16.read1 || cmd == stm1GbX16.program) {
++              ndcb1 = (addr & 0x7FF) | ((addr << 5) & 0xFFFF0000);
++      }
++      else if (cmd == stm1GbX16.erase) {
++              ndcb1 = ((addr >> 17) << 6) & 0xFFFF;
++      }
++      *p = ndcb1;
++      return 0;
++}
++
++static int STM1GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      if (cmd == stm1GbX16.read1 || cmd == stm1GbX16.program) {
++              *p = ((ndbbr & 0x7) << 8) | ((ndbbr >> 8) << 16);
++      }
++      else if (cmd == stm1GbX16.erase) {
++              *p = (ndbbr >> 6) << 17;
++      }
++
++      return 0;
++}
++
++static int STM2GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int STM2GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info stm2GbX16 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 10,      /* tCS, Enable signal setup time */
++              .tWH = 20,      /* tWH, ND_nWE high duration */
++              .tWP = 25,      /* tWP, ND_nWE pulse time */
++              .tRH = 20,      /* tRH, ND_nRE high duration */
++              .tRP = 25,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 25000,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 60,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 64,   /* Pages per block */
++      .row_addr_start = 1,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 4,     /* Returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 2048,      /* Page size in bytes */
++      .oob_size = 64,         /* OOB size in bytes */
++      .flash_width = 16,      /* Width of Flash memory */
++      .dfc_width = 16,        /* Width of flash controller */
++      .num_blocks = 2048,     /* Number of physical blocks in Flash */
++      .chip_id =  0xca20,
++
++      /* command codes */
++      .read1 = 0x3000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = STM2GbX16Addr2NDCB1,
++      .ndbbr2addr = STM2GbX16NDBBR2Addr,
++};
++
++static int STM2GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++      uint32_t page;
++
++      if (addr >= 0x8000000)
++              return -EINVAL;
++      page = addr / stm2GbX16.page_size;
++      addr =  (page / stm2GbX16.page_per_block) << 17 |
++              (page % stm2GbX16.page_per_block) << 11;
++
++      if (cmd == stm2GbX16.read1 || cmd == stm2GbX16.program) {
++              ndcb1 = (addr & 0x7FF) | ((addr << 5) & 0xFFFF0000);
++      }
++      else if (cmd == stm2GbX16.erase) {
++              ndcb1 = ((addr >> 17) << 6) & 0xFFFF;
++      }
++      *p = ndcb1;
++      return 0;
++}
++
++static int STM2GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      if (cmd == stm2GbX16.read1 || cmd == stm2GbX16.program) {
++              *p = ((ndbbr & 0x7) << 8) | ((ndbbr >> 8) << 16);
++      }
++      else if (cmd == stm2GbX16.erase) {
++              *p = (ndbbr >> 6) << 17;
++      }
++
++      return 0;
++}
++
++static struct {
++      int type;
++      struct dfc_flash_info *flash_info;
++} type_info[] = {
++      { DFC_FLASH_Samsung_512Mb_X_16, &samsung512MbX16},
++      { DFC_FLASH_Micron_1Gb_X_8, &micron1GbX8},
++      { DFC_FLASH_Micron_1Gb_X_16, &micron1GbX16},
++      { DFC_FLASH_STM_1Gb_X_16, &stm1GbX16},
++      { DFC_FLASH_STM_2Gb_X_16, &stm2GbX16},
++      { DFC_FLASH_NULL, NULL},
++};
++
++int dfc_get_flash_info(int type, struct dfc_flash_info **flash_info)
++{
++      uint32_t i = 0;
++
++      while(type_info[i].type != DFC_FLASH_NULL) {
++              if (type_info[i].type == type) {
++                      *flash_info = type_info[i].flash_info;
++                      return 0;
++              }
++              i++;
++      }
++      *flash_info = NULL;
++      return -EINVAL;
++}
++
++/******************************************************************************
++  dfc_set_timing
++
++  Description:
++      This function sets flash timing property in DFC timing register
++      according to input timing value embodied in context structure.
++      It is called once during the hardware initialization.
++  Input Parameters:
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++//#if defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
++#define DFC_CLOCK     208
++//#else
++//#define DFC_CLOCK   104
++//#endif
++#define CLOCK_NS      DFC_CLOCK/1000
++
++void dfc_set_timing(struct dfc_context *context, struct dfc_flash_timing *t)
++{
++      struct dfc_flash_timing timing = *t;
++
++      uint32_t  r0 = 0;
++      uint32_t  r1 = 0;
++
++      /*
++       * num of clock cycles = time (ns) / one clock sycle (ns) + 1
++       * - integer division will truncate the result, so add a 1 in all cases
++       * - subtract the extra 1 cycle added to all register timing values
++       */
++      timing.tCH = min(((int) (timing.tCH * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tCH);
++      timing.tCS = min(((int) (timing.tCS * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tCS);
++      timing.tWH = min(((int) (timing.tWH * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tWH);
++      timing.tWP = min(((int) (timing.tWP * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tWP);
++      timing.tRH = min(((int) (timing.tRH * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tRH);
++      timing.tRP = min(((int) (timing.tRP * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tRP);
++
++      r0 = (timing.tCH << DFC_TIMING_tCH) |
++           (timing.tCS << DFC_TIMING_tCS) |
++           (timing.tWH << DFC_TIMING_tWH) |
++           (timing.tWP << DFC_TIMING_tWP) |
++           (timing.tRH << DFC_TIMING_tRH) |
++           (timing.tRP << DFC_TIMING_tRP);
++
++      dfc_write(context, DFC_NDTR0CS0, r0);
++
++      timing.tR   = min(((int) (timing.tR   * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tR);
++      timing.tWHR = min(((int) (timing.tWHR * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tWHR);
++      timing.tAR  = min(((int) (timing.tAR  * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tAR);
++
++      r1 = (timing.tR   << DFC_TIMING_tR)   |
++           (timing.tWHR << DFC_TIMING_tWHR) |
++           (timing.tAR  << DFC_TIMING_tAR);
++
++      dfc_write(context, DFC_NDTR1CS0, r1);
++      return;
++}
++
++/******************************************************************************
++  dfc_set_dma
++
++  Description:
++              Enables or Disables DMA in line with setting in DFC mode of context
++              structure. DMA mode of DFC. Performs a read-modify-write operation that
++              only changes the driven DMA_EN bit field In DMA mode, all commands and
++              data are transferred by DMA.  DMA can be enable/disable on the fly.
++  Input Parameters:
++      context -Pointer to DFC context structure
++      Output Parameters:
++              None
++      Returns:
++              None
++*******************************************************************************/
++void
++dfc_set_dma(struct dfc_context* context)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      if (context->dfc_mode->enable_dma)
++              ndcr |= NDCR_DMA_EN;
++      else
++              ndcr &= ~NDCR_DMA_EN;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      /* Read again to make sure write work */
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++
++/******************************************************************************
++  dfc_set_ecc
++
++  Description:
++              This function enables or disables hardware ECC capability of DFC in line
++              with setting in DFC mode of context structure.
++  Input Parameters:
++      context -Pointer to DFC context structure
++      Output Parameters:
++              None
++      Returns:
++              None
++*******************************************************************************/
++void
++dfc_set_ecc(struct dfc_context* context)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      if (context->dfc_mode->enable_ecc)
++              ndcr |= NDCR_ECC_EN;
++      else
++              ndcr &= ~NDCR_ECC_EN;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      /* Read again to make sure write work */
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++/******************************************************************************
++  dfc_set_spare
++
++  Description:
++              This function enables or disables accesses to spare area of NAND Flash
++              through DFC in line with setting in DFC mode of context structure.
++  Input Parameters:
++      context -Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void
++dfc_set_spare(struct dfc_context* context)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      if (context->dfc_mode->enable_spare)
++              ndcr |= NDCR_SPARE_EN;
++      else
++              ndcr &= ~NDCR_SPARE_EN;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      /* Read again to make sure write work */
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++static unsigned int get_delta (unsigned int start)
++{
++    unsigned int stop = OSCR;
++    return (stop - start);
++}
++
++static int dfc_wait_event(struct dfc_context *context, uint32_t event,
++              uint32_t *event_out, uint32_t timeout, int enable_int)
++{
++      uint32_t ndsr;
++      uint32_t to = 3 * timeout;      /* 3 ticks ~ 1us */
++      int status;
++      int start = OSCR;
++
++      if (enable_int)
++              dfc_enable_int(context, event);
++
++      while (1) {
++              ndsr = dfc_read(context, DFC_NDSR);
++              ndsr &= NDSR_MASK;
++              if (ndsr & event) {
++                      /* event happened */
++                      *event_out = ndsr & event;
++                      dfc_clear_int(context, *event_out);
++                      status = 0;
++                      break;
++              } else if (get_delta(start) > to) {
++                      status = -ETIME;
++                      break;
++              }
++      }
++
++      if (enable_int)
++              dfc_disable_int(context, event);
++      return status;
++}
++
++/******************************************************************************
++  dfc_get_pattern
++
++  Description:
++      This function is used to retrieve buffer size setting for a transaction
++      based on cmd.
++  Input Parameters:
++      context - Pointer to DFC context structure
++      cmd
++        Specifies type of command to be sent to NAND flash .The LSB of this
++        parameter defines the first command code for 2-cycles command. The
++        MSB defines the second command code for 2-cycles command. If MSB is
++        set to zero, this indicates that one cycle command
++      Output Parameters:
++      data_size
++        It is used to retrieve  length of data transferred to/from DFC,
++        which includes padding bytes
++      padding
++        It is used to retrieve how many padding bytes there should be
++        in buffer of data_size.
++      Returns:
++      0
++        If size setting is returned successfully
++      -EINVAL
++        If page size specified in flash spec of context structure is not 512 or
++        2048;If specified command index is not read1/program/erase/reset/readID/
++        readStatus.
++*******************************************************************************/
++int dfc_get_pattern(struct dfc_context *context, uint16_t cmd,
++                      int *data_size, int *padding)
++{
++      struct dfc_mode* dfc_mode = context->dfc_mode;
++      struct dfc_flash_info * flash_info = context->flash_info;
++      uint32_t page_size = context->flash_info->page_size; /* 512 or 2048 */
++
++      if (cmd == flash_info->read1 ||
++              cmd == flash_info->program) {
++              if (512 == page_size) {
++                      /* add for DMA */
++                      if (dfc_mode->enable_dma) {
++                              *data_size = DFC_DATA_SIZE_544;
++                              if (dfc_mode->enable_ecc)
++                                      *padding = DFC_PADDING_SIZE_24;
++                              else
++                                      *padding = DFC_PADDING_SIZE_16;
++                      } else if (!dfc_mode->enable_spare) {
++                              *data_size = DFC_DATA_SIZE_512;
++                              *padding = DFC_PADDING_SIZE_0;
++                      } else {
++
++                              if (dfc_mode->enable_ecc)
++                                      *data_size = DFC_DATA_SIZE_520;
++                              else
++                                      *data_size = DFC_DATA_SIZE_528;
++
++                              *padding = DFC_PADDING_SIZE_0;
++                      }
++              } else if (2048 == page_size) {
++                      /* add for DMA */
++                      if (dfc_mode->enable_dma) {
++                              *data_size = DFC_DATA_SIZE_2112;
++                              if (dfc_mode->enable_ecc)
++                                      *padding = DFC_PADDING_SIZE_24;
++                              else
++                                      *padding = DFC_PADDING_SIZE_0;
++                      } else if (!dfc_mode->enable_spare) {
++                              *data_size = DFC_DATA_SIZE_2048;
++                              *padding = DFC_PADDING_SIZE_0;
++                      } else {
++
++                              if (dfc_mode->enable_ecc)
++                                      *data_size = DFC_DATA_SIZE_2088;
++                              else
++                                      *data_size = DFC_DATA_SIZE_2112;
++
++                              *padding = DFC_PADDING_SIZE_0;
++                      }
++              } else /* if the page_size is neither 512 or 2048 */
++                      return -EINVAL;
++      } else if (cmd == flash_info->read_id) {
++              *data_size = DFC_DATA_SIZE_ID;
++              *padding = DFC_PADDING_SIZE_0;
++      } else if(cmd == flash_info->read_status) {
++              *data_size = DFC_DATA_SIZE_STATUS;
++              *padding = DFC_PADDING_SIZE_0;
++      } else if (cmd == flash_info->erase || cmd == flash_info->reset) {
++              *data_size = DFC_DATA_SIZE_UNUSED;
++              *padding = DFC_PADDING_SIZE_UNUSED;
++      } else
++              return -EINVAL;
++      return 0;
++}
++
++
++/******************************************************************************
++  dfc_send_cmd
++
++  Description:
++      This function configures DFC to send command through DFC to NAND flash
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      cmd
++        Specifies type of command to be sent to NAND flash .The LSB of this
++        parameter defines the first command code for 2-cycles command. The
++        MSB defines the second command code for 2-cycles command. If MSB is
++        set to zero, this indicates that one cycle command
++      addr
++        Address sent out to the flash device withthis command. For page read/
++        program commands , 4-cycles address is sent. For erase command only
++        3-cycles address is sent. If it is equal to 0xFFFFFFFF, the address
++        should not be used.
++      num_pages
++        It specifies the number of pages of data to be transferred for
++        a program or read commands. Unused for any other commands than
++        read/program.
++
++  Output Parameters:
++      None
++  Returns:
++      0
++        If size setting is returned successfully
++      -EINVAL
++        If specified command index is not read1/program/erase/reset/readID/
++        readStatus.
++*******************************************************************************/
++int dfc_send_cmd(struct dfc_context *context, uint16_t cmd,
++                      uint32_t addr, int num_pages)
++{
++      struct dfc_flash_info *flash_info = context->flash_info;
++      struct dfc_mode *dfc_mode = context->dfc_mode;
++      uint8_t  cmd2;
++      uint32_t event_out;
++      uint32_t ndcb0=0, ndcb1=0, ndcb2=0, ndcr;
++      int status;
++
++      /* It is a must to set ND_RUN firstly, then write command buffer
++       * If conversely,it does not work
++       */
++      dfc_write(context, DFC_NDSR, NDSR_MASK);
++
++      /* Set ND_RUN */
++      ndcr = dfc_read(context, DFC_NDCR);
++      dfc_write(context, DFC_NDCR, (ndcr | NDCR_ND_RUN));
++
++      // Wait for write command request
++      status = dfc_wait_event(context, NDSR_WRCMDREQ,
++              &event_out, NAND_CMD_TIMEOUT, 0);
++
++      if (status) /* Timeout */
++              return status;
++
++      cmd2 = (cmd>>8) & 0xFF;
++      ndcb0 = cmd | (dfc_mode->chip_select<<24) | ((cmd2?1:0)<<19);
++
++      if (cmd == flash_info->read1) {
++              if (0xFFFFFFFF != addr) {
++                      ndcb0 |= NDCB0_ADDR_CYC(4);
++                      status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++                      if (status)
++                              return status;
++                      ndcb2 = (num_pages - 1) << 8;
++              }
++      } else if (cmd == flash_info->program) {
++              ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
++              ndcb0 |= NDCB0_ADDR_CYC(4);
++              status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++              if (status)
++                      return status;
++              ndcb2 = (num_pages-1) << 8;
++      } else if (cmd == flash_info->erase) {
++              ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS;
++              ndcb0 |= NDCB0_ADDR_CYC(3);
++              status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++              if (status)
++                      return status;
++      } else if (cmd == flash_info->read_id) {
++              ndcb0 |= NDCB0_CMD_TYPE(3);
++      } else if(cmd == flash_info->read_status) {
++              ndcb0 |= NDCB0_CMD_TYPE(4);
++      } else if(cmd == flash_info->reset) {
++              ndcb0 |= NDCB0_CMD_TYPE(5);
++      } else if (cmd == flash_info->lock) {
++              ndcb0 |= NDCB0_CMD_TYPE(5);
++      } else
++              return -EINVAL;
++
++      /* Write to DFC command register */
++      dfc_write(context, DFC_NDCB0, ndcb0);
++      dfc_write(context, DFC_NDCB0, ndcb1);
++      dfc_write(context, DFC_NDCB0, ndcb2);
++
++      return 0;
++}
++
++/******************************************************************************
++  dfc_stop
++
++  Description:
++      This function clears ND_RUN bit of NDCR.
++  Input Parameters:
++      context--Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_stop(struct dfc_context *context)
++{
++      unsigned int ndcr;
++      ndcr = dfc_read(context, DFC_NDCR);
++      dfc_write(context, DFC_NDCR, (ndcr & ~NDCR_ND_RUN));
++      ndcr = dfc_read(context, DFC_NDCR);
++
++      return;
++}
++
++int dfc_setup_cmd_dma(struct dfc_context *context,
++              uint16_t cmd, uint32_t addr, int num_pages,
++              uint32_t *buf, uint32_t buf_phys,
++              uint32_t next_desc_phys, uint32_t dma_int_en,
++              struct pxa_dma_desc *dma_desc)
++{
++      struct dfc_flash_info *flash_info = context->flash_info;
++      struct dfc_mode *dfc_mode = context->dfc_mode;
++      uint8_t  cmd2;
++      uint32_t event_out;
++      uint32_t ndcb0=0, ndcb1=0, ndcb2=0, ndcr;
++      int status;
++
++      /*
++       * It is a must to set ND_RUN firstly, then write command buffer
++       * If conversely,it does not work
++       */
++      dfc_write(context, DFC_NDSR, NDSR_MASK);
++
++      /* Set ND_RUN */
++      ndcr = dfc_read(context, DFC_NDCR);
++      ndcr |= NDCR_ND_RUN;
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      /* Wait for write command request */
++      status = dfc_wait_event(context, NDSR_WRCMDREQ,
++              &event_out, NAND_CMD_TIMEOUT, 0);
++
++      if (status)
++              return status; /* Timeout */
++
++      cmd2 = (cmd>>8) & 0xFF;
++      ndcb0 = cmd | (dfc_mode->chip_select<<24) | ((cmd2?1:0)<<19);
++
++      if (cmd == flash_info->read1) {
++              if (0xFFFFFFFF != addr) {
++                      ndcb0 |= NDCB0_ADDR_CYC(4);
++                      status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++                      if (status)
++                              return status;
++                      ndcb2 = (num_pages-1) << 8;
++              }
++      } else if (cmd == flash_info->program) {
++              ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
++              ndcb0 |= NDCB0_ADDR_CYC(4);
++
++              status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++              if (status)
++                      return status;
++              ndcb2 = (num_pages-1) << 8;
++      } else if (cmd == flash_info->erase) {
++              ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS;
++              ndcb0 |= NDCB0_ADDR_CYC(3);
++
++              status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++              if (status)
++                      return status;
++      } else if (cmd == flash_info->read_id) {
++              ndcb0 |= NDCB0_CMD_TYPE(3);
++      } else if (cmd == flash_info->read_status) {
++              ndcb0 |= NDCB0_CMD_TYPE(4);
++      } else if (cmd == flash_info->reset) {
++              ndcb0 |= NDCB0_CMD_TYPE(5);
++      } else if (cmd == flash_info->lock) {
++              ndcb0 |= NDCB0_CMD_TYPE(5);
++      } else
++              return -EINVAL;
++
++      *((uint32_t *)buf) = ndcb0;
++      *((uint32_t *)buf + 1) = ndcb1;
++      *((uint32_t *)buf + 2) = ndcb2;
++
++      dma_int_en &= (DCMD_STARTIRQEN | DCMD_ENDIRQEN);
++
++      dma_desc->ddadr = next_desc_phys;
++      dma_desc->dsadr = buf_phys;
++      dma_desc->dtadr = NDCB0_DMA_ADDR;
++      dma_desc->dcmd  = DCMD_INCSRCADDR | DCMD_FLOWTRG | dma_int_en |
++                        DCMD_WIDTH4 | DCMD_BURST16 | 12;
++      return 0;
++}
++
++int dfc_setup_data_dma(struct dfc_context* context,
++              uint16_t cmd, uint32_t buf_phys,
++              uint32_t next_desc_phys, uint32_t dma_int_en,
++              struct pxa_dma_desc* dma_desc)
++{
++      struct dfc_flash_info * flash_info = context->flash_info;
++      int data_size, padding;
++
++      dfc_get_pattern(context, cmd, &data_size, &padding);
++
++      dma_desc->ddadr = next_desc_phys;
++      dma_int_en &= (DCMD_STARTIRQEN | DCMD_ENDIRQEN);
++
++      if (cmd == flash_info->program) {
++
++              dma_desc->dsadr = buf_phys;
++              dma_desc->dtadr = NDDB_DMA_ADDR;
++              dma_desc->dcmd  = DCMD_INCSRCADDR | DCMD_FLOWTRG | dma_int_en |
++                                DCMD_WIDTH4 | DCMD_BURST32 | data_size;
++
++      } else if (cmd == flash_info->read1 || cmd == flash_info->read_id ||
++                 cmd == flash_info->read_status) {
++
++              dma_desc->dsadr = NDDB_DMA_ADDR;
++              dma_desc->dtadr = buf_phys;
++              dma_desc->dcmd  = DCMD_INCTRGADDR | DCMD_FLOWSRC | dma_int_en |
++                                DCMD_WIDTH4 | DCMD_BURST32 | data_size;
++      }
++      else
++              return -EINVAL;
++      return 0;
++}
++
++void dfc_start_cmd_dma(struct dfc_context* context, struct pxa_dma_desc* dma_desc)
++{
++      DRCMR99 = DRCMR_MAPVLD | context->cmd_dma_ch;   /* NAND CMD DRCMR */
++      DDADR(context->cmd_dma_ch) = (uint32_t)dma_desc;
++      DCSR(context->cmd_dma_ch) |= DCSR_RUN;
++}
++
++void dfc_start_data_dma(struct dfc_context* context, struct pxa_dma_desc* dma_desc)
++{
++      DRCMR97 = DRCMR_MAPVLD | context->data_dma_ch;
++      DDADR(context->data_dma_ch) = (uint32_t)dma_desc;
++      DCSR(context->data_dma_ch) |= DCSR_RUN;
++}
++
++/******************************************************************************
++  dfc_read_fifo_partial
++
++  Description:
++      This function reads data from data buffer of DFC.Bytes can be any less than
++      or equal to data_size, the left is ignored by ReadFIFO though they will be
++      read from NDDB to clear data buffer.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      nbytes
++        Indicating how much data should be read into buffer.
++      data_size
++        Specifing length of data transferred to/from DFC, which includes
++        padding bytes
++  Output Parameters:
++      pBuffer
++        Pointer to the data buffer where data should be placed.
++      Returns:
++        None
++*******************************************************************************/
++void dfc_read_fifo_partial(struct dfc_context *context, uint8_t *buffer,
++              int nbytes, int data_size)
++{
++      uint32_t data = 0;
++      uint32_t i = 0;
++      uint32_t bytes_multi;
++      uint32_t bytes_remain;
++
++
++      if (1 == data_size) {
++              data = dfc_read(context, DFC_NDDB) & 0xFF;
++              *buffer++ = (uint8_t)data;
++      } else if (2 == data_size) {
++              data = dfc_read(context, DFC_NDDB) & 0xFFFF;
++              *buffer++ = data & 0xFF;
++              *buffer++ = (data >> 8) & 0xFF;
++      } else {
++              bytes_multi = (nbytes & 0xFFFFFFFC);
++              bytes_remain = nbytes & 0x03;
++
++              i = 0;
++              /* Read the bytes_multi*4 bytes data */
++              while (i < bytes_multi) {
++                      data = dfc_read(context, DFC_NDDB);
++                      /* FIXME: we don't know whether the buffer
++                       * align to 4 bytes or not. Cast the buffer
++                       * to int is not safe here. Especially under
++                       * gcc 4.x. Used memcpy here. But the memcpy
++                       * may be not correct on BE architecture.
++                       * --by Yin, Fengwei
++                       */
++                      memcpy(buffer, &data, sizeof(data));
++                      i += sizeof(data);
++                      buffer += sizeof(data);
++              }
++
++              /* Read the left bytes_remain bytes data */
++              if (bytes_remain) {
++                      data = dfc_read(context, DFC_NDDB);
++                      for (i = 0; i < bytes_remain; i++)
++                              *buffer++ = (uint8_t)((data >> (8*i)) & 0xFF);
++              }
++
++              /* When read the remain bytes, we always read 4 bytes data
++               * to DFC. So the data_size should subtract following number.
++               */
++              data_size -= bytes_multi + (bytes_remain ? sizeof(data) : 0);
++
++              /* We need Read data_size bytes data totally */
++              while (data_size > 0) {
++                      data = dfc_read(context, DFC_NDDB);
++                      data_size -= sizeof(data);
++              }
++
++/*
++              while(i < ((uint32_t)data_size) ) {
++                      if (i < bytes_multi) {
++                              temp = (uint32_t *)buffer;
++                              *temp = dfc_reg->nddb;
++                      } else if (i == bytes_multi && bytes_remain){
++                              uint32_t j = 0;
++                              data = dfc_reg->nddb;
++                              while (j++ < bytes_remain) {
++                                      *buffer++ = (uint8_t)   \
++                                              ((data>>(8*j)) & 0xFF);
++                              }
++                      } else {
++                              data = dfc_reg->nddb;
++                      }
++                      i += 4;
++                      buffer += 4;
++              }
++*/
++      }
++      return;
++}
++
++/******************************************************************************
++  dfc_write_fifo_partial
++
++  Description:
++      Write to data buffer of DFC from a buffer. Bytes can be same as
++      data_size, also can be data_size-padding, but can¡¯t be random value,
++      the left will be automatically padded by WriteFIFO.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      bytes
++        Indicating how much data should be read into buffer.
++      data_size
++        Specifing length of data transferred to/from DFC, which includes
++        padding bytes
++      buffer
++        Pointer to the data buffer where data will be taken from to be written
++        to DFC data buffer
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_write_fifo_partial(struct dfc_context *context, uint8_t *buffer,
++              int nbytes, int data_size)
++{
++      uint32_t i = 0;
++
++      uint32_t bytes_multi = (nbytes & 0xFFFFFFFC);
++      uint32_t bytes_remain = nbytes & 0x03;
++      uint32_t temp;
++      /*
++       * caller guarantee buffer contains appropriate data thereby
++       * it is impossible for nbytes not to be a multiple of 4 byte
++       */
++
++      /* Write the bytes_multi*4 bytes data */
++      while (i < bytes_multi) {
++              temp = buffer[0] | buffer[1] << 8 |
++                              buffer[2] << 16 | buffer[3] << 24;
++              dfc_write(context, DFC_NDDB, temp);
++              buffer += 4;
++              i += 4;
++      }
++
++      /* Write the left bytes_remain bytes data */
++      if (bytes_remain) {
++              temp = 0xFFFFFFFF;
++              for (i = 0; i < bytes_remain; i++)
++                      temp &= *buffer++ << i*8;
++
++              dfc_write(context, DFC_NDDB, temp);
++      }
++
++      /* When write the remain bytes, we always write 4 bytes data
++       * to DFC. So the data_size should subtract following number.
++       */
++      data_size -= bytes_multi + (bytes_remain ? sizeof(temp) : 0);
++
++      while (data_size > 0) {
++              dfc_write(context, DFC_NDDB, 0xFFFFFFFF);
++              data_size -= 4;
++      }
++
++/*
++      while (i < ((uint32_t)data_size)) {
++              if (i < bytes_multi) {
++                      temp = (uint32_t *)buffer;
++                      dfc_reg->nddb = *temp;
++              }
++              else if (i == bytes_multi && bytes_remain) {
++                              uint32_t j = 0, data = 0xFFFFFFFF;
++                              while (j < bytes_remain) {
++                                data &= (uint8_t)(*buffer) << j;
++                                buffer++;
++                                j++;
++                              }
++                      dfc_reg->nddb = data;
++              }
++              else {
++                      dfc_reg->nddb = 0xFFFFFFFF;
++              }
++              i += 4;
++              buffer += 4;
++      }
++*/
++
++      return;
++}
++
++/******************************************************************************
++  dfc_read_fifo
++  Description:
++      This function reads data from data buffer of DFC.Bytes can be any less
++      than or equal to data_size, the left is ignored by ReadFIFO though they
++      will be read from NDDB to clear data buffer.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      nbytes
++        Indicating how much data should be read into buffer.
++      data_size
++        Specifing length of data transferred to/from DFC, which includes
++        padding bytes
++  Output Parameters:
++      buffer
++        Pointer to the data buffer where data should be placed.
++  Returns:
++      None
++*******************************************************************************/
++
++void dfc_read_fifo(struct dfc_context *context, uint8_t *buffer, int nbytes)
++{
++      uint32_t i = 0;
++
++      uint32_t bytes_multi = (nbytes & 0xFFFFFFFC);
++      uint32_t bytes_remain = nbytes & 0x03;
++      uint32_t temp;
++
++      /* Read the bytes_multi*4 bytes data */
++      while (i < bytes_multi) {
++              temp = dfc_read(context, DFC_NDDB);
++              /* FIXME: we don't know whether the buffer
++               * align to 4 bytes or not. Cast the buffer
++               * to int is not safe here. Especially under
++               * gcc 4.x. Used memcpy here. But the memcpy
++               * may be not correct on BE architecture.
++               * --by Yin, Fengwei
++               */
++              memcpy(buffer, &temp, sizeof(temp));
++              i += sizeof(temp);
++              buffer += sizeof(temp);
++      }
++
++      /* Read the left bytes_remain bytes data */
++      temp = dfc_read(context, DFC_NDDB);
++      for (i = 0; i < bytes_remain; i++) {
++              *buffer++ = (uint8_t)((temp >> (8*i)) & 0xFF);
++      }
++
++/*
++      while (i < bytes_multi) {
++          temp = (uint32_t *)buffer;
++          *temp = dfc_reg->nddb;
++          i += 4;
++          buffer += 4;
++      }
++
++      if (bytes_remain) {
++              data = dfc_reg->nddb;
++              for (i = 0; i < bytes_remain; i++) {
++                      *buffer++ = (uint8_t)((data>>(8*i)) & 0xFF);
++              }
++      }
++*/
++
++      return;
++}
++
++/******************************************************************************
++  dfc_write_fifo
++  Description:
++      Write to data buffer of DFC from a buffer.Bytes can be same as data_size,
++      also can be data_size-padding, but can¡¯t be random value, the left will
++      be automatically padded by WriteFIFO.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      nbytes
++        Indicating how much data should be read into buffer.
++      data_size
++        Specifing length of data transferred to/from DFC, which includes
++        padding bytes
++      buffer
++        Pointer to the data buffer where data will be taken from to be written to
++        DFC data buffer
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_write_fifo(struct dfc_context *context, uint8_t *buffer, int nbytes)
++{
++      uint32_t bytes_multi = (nbytes & 0xFFFFFFFC);
++      uint32_t bytes_remain = nbytes & 0x03;
++      uint32_t i=0;
++      uint32_t temp;
++
++      /* Write the bytes_multi*4 bytes data */
++      while (i < bytes_multi) {
++              temp = buffer[0] | buffer[1] << 8 |
++                              buffer[2] << 16 | buffer[3] << 24;
++              dfc_write(context, DFC_NDDB, temp);
++              buffer += 4;
++              i += 4;
++      }
++
++      /* Write the left bytes_remain bytes data */
++      temp = 0xFFFFFFFF;
++      for (i = 0; i < bytes_remain; i++)
++              temp &= *buffer++ << i*8;
++      dfc_write(context, DFC_NDDB, temp);
++
++/*
++      while (i < nbytes) {
++          temp = (uint32_t *)buffer;
++          dfc_reg->nddb = *temp;
++          i += 4;
++          buffer += 4;
++      }
++*/
++}
++
++/******************************************************************************
++  dfc_read_badblock_addr
++
++  Description:
++      This function reads bad block address in units of block starting from 0
++      if bad block is detected. It takes into the account if the operation is
++      for CS0 or CS1  depending on settings of chip_select parameter of DFC
++      Mode structure.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++  Output Parameters:
++      pBadBlockAddr
++        Used to retrieve bad block address back to caller if bad block is
++        detected
++  Returns:
++      None
++*******************************************************************************/
++void dfc_read_badblock_addr(struct dfc_context *context, uint32_t *bbaddr)
++{
++      uint32_t ndbdr;
++      if (0 == context->dfc_mode->chip_select)
++              ndbdr = dfc_read(context, DFC_NDBDR0);
++      else
++              ndbdr = dfc_read(context, DFC_NDBDR1);
++
++      if (512 == context->flash_info->page_size) {
++              ndbdr = (ndbdr >> 5) & 0xFFF;
++              *bbaddr = ndbdr;
++      } else if (2048 == context->flash_info->page_size) {
++              /* 16 bits LB */
++              ndbdr = (ndbdr >> 8);
++              *bbaddr = ndbdr;
++      }
++      return;
++}
++
++/******************************************************************************
++  dfc_enable_int
++
++  Description:
++      This function is used to enable DFC interrupts. The bits in int_mask
++      will be used to unmask NDCR register to enable corresponding interrupts.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      int_mask
++        Specifies what interrupts to enable
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_enable_int(struct dfc_context *context, uint32_t int_mask)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      ndcr &= ~int_mask;
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++/******************************************************************************
++  dfc_disable_int
++
++  Description:
++      This function is used to disable DFC interrupts.
++      The bits inint_mask will be used to mask NDCR register to disable
++      corresponding interrupts.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      int_mask
++        Specifies what interrupts to disable
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_disable_int(struct dfc_context *context, uint32_t int_mask)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      ndcr |= int_mask;
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++/******************************************************************************
++  dfc_clear_int
++
++  Description:
++      This function is used to disable DFC interrupts.
++      The bits in int_mask will be used to clear corresponding interrupts
++      in NDCR register
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      int_mask
++        Specifies what interrupts to clear
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_clear_int(struct dfc_context *context, uint32_t int_mask)
++{
++      dfc_write(context, DFC_NDSR, int_mask);
++
++      dfc_read(context, DFC_NDSR);
++      return;
++}
++
++/*
++ * high level primitives
++ */
++
++/******************************************************************************
++  dfc_init
++
++  Description:
++      This function does entire DFC initialization according to the NAND
++      flash type currently used with platform, including setting MFP, set
++      flash timing, set DFC mode, configuring specified flash parameters
++      in DFC, clear ECC logic and page count register.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      0
++        if MFPRs are set correctly
++      -EINVAL
++        if specified flash is not support by check bytes per page and pages per
++        block
++******************************************************************************/
++
++static mfp_cfg_t pxa300_nand_cfg[] = {
++      /* NAND */
++      MFP_CFG_X(DF_INT_RnB, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nRE_nOE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nWE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_CLE_nOE, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nADV1_ALE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nCS0, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nCS1, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_IO0, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO1, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO2, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO3, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO4, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO5, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO6, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO7, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO8, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO9, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO10, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO11, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO12, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO13, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO14, AF1, DS08X, PULL_LOW),
++};
++
++#define ARRAY_AND_SIZE(x)     (x), ARRAY_SIZE(x)
++
++int dfc_init(struct dfc_context* context, int type)
++{
++      int status;
++      struct dfc_flash_info * flash_info;
++      uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
++
++      status = dfc_get_flash_info(type, &flash_info);
++      if (status)
++              return status;
++      context->flash_info = flash_info;
++
++      pxa3xx_mfp_config(ARRAY_AND_SIZE(pxa300_nand_cfg));
++      //enable_dfc_pins();
++
++      dfc_set_timing(context, &context->flash_info->timing);
++
++      if (flash_info->enable_arbiter)
++              ndcr |= NDCR_ND_ARB_EN;
++
++      if (64 == flash_info->page_per_block)
++              ndcr |= NDCR_PG_PER_BLK;
++      else if (32 != flash_info->page_per_block)
++              return -EINVAL;
++
++      if (flash_info->row_addr_start)
++              ndcr |= NDCR_RA_START;
++
++      ndcr |=  (flash_info->read_id_bytes)<<16;
++
++      ndcr |= (flash_info->dfc_mode) << 21;
++
++      if (flash_info->ncsx)
++              ndcr |= NDCR_NCSX;
++
++      if (2048 == flash_info->page_size)
++              ndcr |= NDCR_PAGE_SZ;
++      else if (512 != flash_info->page_size)
++              return -EINVAL;
++
++      if (16 == flash_info->flash_width)
++              ndcr |= NDCR_DWIDTH_M;
++      else if (8 != flash_info->flash_width)
++              return -EINVAL;
++
++      if (16 == flash_info->dfc_width)
++              ndcr |= NDCR_DWIDTH_C;
++      else if (8 != flash_info->dfc_width)
++              return -EINVAL;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      dfc_set_dma(context);
++      dfc_set_ecc(context);
++      dfc_set_spare(context);
++
++      return 0;
++}
++
++/******************************************************************************
++  dfc_init_no_gpio
++
++  Description:
++      This function does entire DFC initialization according to the NAND
++      flash type currently used with platform, including set flash timing,
++      set DFC mode, configuring specified flash parameters in DFC, clear
++      ECC logic and page count register. The only difference with dfc_init
++      is that it does not set MFP&GPIO, very useful in OS loader
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      0
++        if MFPRs are set correctly
++      -EINVAL
++        if specified flash is not support by check bytes per page and pages
++        per block
++******************************************************************************/
++int dfc_init_no_gpio(struct dfc_context* context, int type)
++{
++      struct dfc_flash_info * flash_info;
++      uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
++      int status;
++
++      status = dfc_get_flash_info(type, &flash_info);
++      if (status)
++              return status;
++      context->flash_info = flash_info;
++
++      dfc_set_timing(context, &context->flash_info->timing);
++
++      if (flash_info->enable_arbiter)
++              ndcr |= NDCR_ND_ARB_EN;
++
++      if (64 == flash_info->page_per_block)
++              ndcr |= NDCR_PG_PER_BLK;
++      else if (32 != flash_info->page_per_block)
++              return -EINVAL;
++
++      if (flash_info->row_addr_start)
++              ndcr |= NDCR_RA_START;
++
++      ndcr |=  (flash_info->read_id_bytes)<<16;
++
++      ndcr |= (flash_info->dfc_mode) << 21;
++
++      if (flash_info->ncsx)
++              ndcr |= NDCR_NCSX;
++
++      if (2048 == flash_info->page_size)
++              ndcr |= NDCR_PAGE_SZ;
++      else if (512 != flash_info->page_size)
++              return -EINVAL;
++
++      if (16 == flash_info->flash_width)
++              ndcr |= NDCR_DWIDTH_M;
++      else if (8 != flash_info->flash_width)
++              return -EINVAL;
++
++      if (16 == flash_info->dfc_width)
++              ndcr |= NDCR_DWIDTH_C;
++      else if (8 != flash_info->dfc_width)
++              return -EINVAL;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      dfc_set_dma(context);
++      dfc_set_ecc(context);
++      dfc_set_spare(context);
++
++      return 0;
++}
++
++/*
++ * This macro will be used in following NAND operation functions.
++ * It is used to clear command buffer to ensure cmd buffer is empty
++ * in case of operation is timeout
++ */
++#define ClearCMDBuf()         do {                                    \
++                              dfc_stop(context);              \
++                              udelay(NAND_OTHER_TIMEOUT);     \
++                      } while (0)
++
++/******************************************************************************
++  dfc_reset_flash
++
++  Description:
++      It reset the flash. The function can be called at any time when the
++      device is in Busy state during random read/program/erase mode and
++      reset operation will abort all these operations. After reset operation
++      the device is ready to wait for next command
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      0
++        execution succeeds
++      -ETIME
++        if timeout
++*******************************************************************************/
++int dfc_reset_flash(struct dfc_context *context)
++{
++      struct dfc_flash_info *flash_info = context->flash_info;
++      uint32_t event, event_out;
++      unsigned long timeo;
++      int status;
++
++      /* Send command */
++      dfc_send_cmd(context, (uint16_t)flash_info->reset, 0xFFFFFFFF, 0);
++
++      event = (context->dfc_mode->chip_select)? \
++                      NDSR_CS1_CMDD : NDSR_CS0_CMDD;
++
++      /* Wait for CMDDM(command done successfully) */
++      status = dfc_wait_event(context, event, &event_out,
++              NAND_OTHER_TIMEOUT, 0);
++
++      if (status) {
++              ClearCMDBuf();
++              return status;
++      }
++
++
++      /* Wait until flash device is stable or timeout (10ms) */
++      timeo = jiffies + HZ;
++      do {
++              if (monahans_df_dev_ready(context->mtd))
++                      break;
++      } while (time_before(jiffies, timeo));
++
++      return 0;
++}
++
++int dfc_readid(struct dfc_context *context, uint32_t *id)
++{
++      struct dfc_flash_info *flash_info = context->flash_info;
++      uint32_t event_out;
++      int status;
++      char tmp[DFC_DATA_SIZE_ID];
++
++      /* Send command */
++      status = dfc_send_cmd(context, (uint16_t)flash_info->read_id,
++                      0xFFFFFFFF, 0);
++      if (status) {
++              ClearCMDBuf();
++              return status;
++      }
++
++      /* Wait for CMDDM(command done successfully) */
++      status = dfc_wait_event(context, NDSR_RDDREQ, &event_out,
++              NAND_OTHER_TIMEOUT, 0);
++      if (status) {
++              ClearCMDBuf();
++              return status;
++      }
++      dfc_read_fifo_partial(context, (unsigned char *)tmp,
++                      context->flash_info->read_id_bytes, DFC_DATA_SIZE_ID);
++
++      *id = tmp[0] | (tmp[1] << 8);
++      return 0;
++}
++
++#define ERR_NONE              0x0
++#define ERR_DMABUSERR         (-0x01)
++#define ERR_SENDCMD           (-0x02)
++#define ERR_DBERR             (-0x03)
++#define ERR_BBERR             (-0x04)
++#define ERR_BUSY              (-0x05)
++
++#define STATE_CMD_SEND                0x1
++#define STATE_CMD_HANDLE      0x2
++#define STATE_DMA_TRANSFER    0x3
++#define STATE_DMA_DONE                0x4
++#define STATE_READY           0x5
++#define STATE_SUSPENDED               0x6
++#define       STATE_DATA_TRANSFER     0x7
++
++#define NAND_RELOC_MAX                127
++#define NAND_RELOC_HEADER     0x524e
++#define MAX_CHIP              1
++#define NAND_CMD_DMA_LEN      12
++
++#define MAX_TIM_SIZE  0x1000
++#define MAX_BBT_SLOTS 24
++
++struct reloc_item {
++      unsigned short from;
++      unsigned short to;
++};
++
++struct reloc_table {
++      unsigned short header;
++      unsigned short total;
++      struct reloc_item reloc[NAND_RELOC_MAX];
++};
++
++struct monahans_dfc_info {
++      unsigned int            state;
++      struct dfc_context      *context;
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      dma_addr_t              data_buf_addr;
++      char                    *data_buf;
++      int                     data_dma;
++      struct pxa_dma_desc     *data_desc;
++      dma_addr_t              data_desc_addr;
++      dma_addr_t              cmd_buf_addr;
++      char                    *cmd_buf;
++      int                     cmd_dma;
++      struct pxa_dma_desc     *cmd_desc;
++      dma_addr_t              cmd_desc_addr;
++      u64                     dma_mask;
++#else
++      char                    *data_buf;
++#endif
++      u32                     current_slot;
++      struct reloc_table      table;
++      unsigned int            table_init;
++      /* relate to the command */
++      unsigned int            cmd;
++      unsigned int            addr;
++      unsigned int            column;
++      int                     retcode;
++      unsigned int            buf_count;
++      struct completion       cmd_complete;
++};
++
++static struct dfc_mode dfc_mode =
++{
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      1,      /* enable DMA */
++#else
++      0,
++#endif
++      1,      /* enable ECC */
++      1,      /* enable SPARE */
++      0,      /* CS0 */
++};
++
++
++struct dfc_context dfc_context =
++{
++      0,      /* Initialized at function monahans_df_init() */
++      &dfc_mode,
++      0,      /* data dma channel */
++      0,      /* cmd dma channel */
++      NULL,   /* &zylonite_flashinfo */
++};
++
++
++/*
++ * MTD structure for Zylonite board
++ */
++static struct mtd_info *monahans_mtd = NULL;
++
++/*
++ * BootRom and XDB will use last 127 block, and they will keep all the status
++ * of the bootloader and image, so skip the first 2M size and last 2M size
++ */
++static struct mtd_partition partition_info[] = {
++      {
++              name:           "Bootloader",
++//#ifdef      CONFIG_CPU_MONAHANS_LV
++              size:           0x00060000,
++//#else
++//            size:           0x00040000,
++//#endif
++              offset:         0,
++              mask_flags:     MTD_WRITEABLE  /* force read-only */
++      },{
++              name:           "Kernel",
++              size:           0x00200000,
++//#ifdef      CONFIG_CPU_MONAHANS_LV
++              offset:         0x00060000,
++//#else
++//            offset:         0x00040000,
++//#endif
++              mask_flags:     MTD_WRITEABLE  /* force read-only */
++      },{
++              name:           "Filesystem",
++              size:           0x05000000,
++//#ifdef      CONFIG_CPU_MONAHANS_LV
++              offset:         0x00260000,
++//#else
++//            offset:         0x00240000,
++//#endif
++      }, {
++              name:           "MassStorage",
++              size:           0x0, /* It will be set at probe function */
++              offset:         MTDPART_OFS_APPEND /* Append after fs section */
++      }, {
++              name:           "BBT",
++              size:           0x0, /* It will be set at probe function */
++              offset:         MTDPART_OFS_APPEND,/* Append after fs section */
++              mask_flags:     MTD_WRITEABLE  /* force read-only */
++      }
++};
++
++#define               PART_NUM        ARRAY_SIZE(partition_info)
++
++/* MHN_OBM_V2 is related to BBT in MOBM V2
++ * MHN_OBM_V3 is related to BBT in MOBM V3
++ */
++enum {
++      MHN_OBM_NULL = 0,
++      MHN_OBM_V1,
++      MHN_OBM_V2,
++      MHN_OBM_V3,
++      MHN_OBM_INVAL
++} MHN_OBM_TYPE;
++
++static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
++static uint8_t scan_main_bbt_pattern[] = { 'p', 'x', 'a', '1' };
++static uint8_t scan_mirror_bbt_pattern[] = { '0', 'a', 'x', 'p' };
++
++static struct nand_bbt_descr monahans_bbt_default = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .maxblocks = 2,
++      .len = 2,
++      .offs = 0,
++      .pattern = scan_ff_pattern,
++};
++
++static struct nand_bbt_descr monahans_bbt_main = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .veroffs = 6,
++      .maxblocks = 2,
++        .offs = 2,
++        .len = 4,
++        .pattern = scan_main_bbt_pattern,
++};
++
++static struct nand_bbt_descr monahans_bbt_mirror = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .veroffs = 6,
++      .maxblocks = 2,
++        .offs = 2,
++        .len = 4,
++        .pattern = scan_mirror_bbt_pattern,
++};
++
++#if 0
++static struct nand_bbt_descr monahans_bbt_main = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .veroffs = 2,
++      .maxblocks = 2,
++        .offs =               0x0,
++        .len =                        2,
++        .pattern =            scan_ff_pattern
++};
++static struct nand_bbt_descr monahans_bbt_mirror = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .veroffs = 2,
++      .maxblocks = 2,
++        .offs = 0x0,
++        .len = 2,
++        .pattern = scan_ff_pattern
++};
++#endif
++
++static struct nand_ecclayout monahans_lb_nand_oob = {
++      .eccbytes = 24,
++      .eccpos = {
++              40, 41, 42, 43, 44, 45, 46, 47,
++              48, 49, 50, 51, 52, 53, 54, 55,
++              56, 57, 58, 59, 60, 61, 62, 63},
++      .oobfree = { {2, 38} }
++};
++
++/*
++ * Monahans OOB size is only 8 bytes, and the rest 8 bytes is controlled by
++ * hardware for ECC. We construct virutal ECC buffer. Acutally, ECC is 6 bytes
++ * and the remain 2 bytes are reserved.
++ */
++static struct nand_ecclayout monahans_sb_nand_oob = {
++      .eccbytes = 6,
++      .eccpos = {8, 9, 10, 11, 12, 13 },
++      .oobfree = { {2, 6} }
++};
++
++
++static inline int is_buf_blank(u8 * buf, int size)
++{
++      int i = 0;
++      while(i < size) {
++              if (*((unsigned long *)(buf + i)) != 0xFFFFFFFF)
++                      return 0;
++              i += 4;
++      }
++      if (i > size) {
++              i -= 4;
++              while( i < size) {
++                      if(*(buf + i) != 0xFF)
++                              return 0;
++                      i++;
++              }
++      }
++      return 1;
++}
++
++static void print_buf(char *buf, int num)
++{
++      int i = 0;
++
++      while (i < num) {
++              printk(KERN_ERR "0x%08x: %02x %02x %02x %02x %02x %02x %02x"
++              " %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
++              (unsigned int) (i),  buf[i], buf[i+1], buf[i+2],
++              buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7],
++              buf[i+8], buf[i+9], buf[i+10],buf[i+11], buf[i+12],
++              buf[i+13], buf[i+14], buf[i+15]);
++              i += 16;
++      }
++}
++
++static int inline enable_dfc_dma(struct dfc_context *context, int enable)
++{
++      int ret = dfc_mode.enable_dma;
++      unsigned long ndcr;
++
++      if (!enable) {
++              ndcr = dfc_read(context, DFC_NDCR);
++              ndcr &= ~NDCR_DMA_EN;
++              dfc_write(context, DFC_NDCR, ndcr);
++              dfc_mode.enable_dma = 0;
++      } else {
++              ndcr = dfc_read(context, DFC_NDCR);
++              ndcr |= NDCR_DMA_EN;
++              dfc_write(context, DFC_NDCR, ndcr);
++              dfc_mode.enable_dma = 1;
++      }
++      return ret;
++}
++
++
++static void inline dump_info(struct monahans_dfc_info *info)
++{
++      if (!info)
++              return;
++
++      printk(KERN_ERR "cmd:0x%x; addr:0x%x; retcode:%d; state:%d \n",
++              info->cmd, info->addr, info->retcode, info->state);
++}
++
++static void inline  enable_hw_ecc(struct dfc_context* context, int enable)
++{
++      unsigned long ndcr;
++
++      if (!enable) {
++              ndcr = dfc_read(context, DFC_NDCR);
++              ndcr &= ~NDCR_ECC_EN;
++              dfc_write(context, DFC_NDCR, ndcr);
++              dfc_mode.enable_ecc = 0;
++      }
++      else {
++              ndcr = dfc_read(context, DFC_NDCR);
++              ndcr |= NDCR_ECC_EN;
++              dfc_write(context, DFC_NDCR, ndcr);
++              dfc_mode.enable_ecc = 1;
++      }
++}
++
++/*
++ * Now, we are not sure that the NDSR_RDY mean the flash is ready.
++ * Need more test.
++ */
++static int monahans_df_dev_ready(struct mtd_info *mtd)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++
++      struct dfc_context* context = info->context;
++
++      return ((dfc_read(context, DFC_NDSR) & NDSR_RDY));
++}
++
++/* each read, we can only read 4bytes from NDDB, we must buffer it */
++static u_char monahans_df_read_byte(struct mtd_info *mtd)
++{
++      char retval = 0xFF;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++
++      if (info->column < info->buf_count) {
++              /* Has just send a new command? */
++              retval = info->data_buf[info->column++];
++      }
++      return retval;
++}
++
++static void monahans_df_write_byte(struct mtd_info *mtd, u8 byte)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++      info->data_buf[info->column++] = byte;
++}
++
++static u16 monahans_df_read_word(struct mtd_info *mtd)
++{
++      u16 retval = 0xFFFF;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++
++      if (!(info->column & 0x01) && info->column < info->buf_count) {
++              retval = *((u16 *)(info->data_buf+info->column));
++              info->column += 2;
++      }
++      return retval;
++}
++
++static void monahans_df_write_word(struct mtd_info *mtd, u16 word)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++
++      if (!(info->column & 0x01) && info->column < info->buf_count) {
++              *((u16 *)(info->data_buf+info->column)) = word;
++              info->column += 2;
++      }
++}
++
++static void monahans_df_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++      int real_len = min((unsigned int)len, info->buf_count - info->column);
++
++      memcpy(buf, info->data_buf + info->column, real_len);
++      info->column += real_len;
++}
++
++static void monahans_df_write_buf(struct mtd_info *mtd,
++              const u_char *buf, int len)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++      int real_len = min((unsigned int)len, info->buf_count - info->column);
++
++      memcpy(info->data_buf + info->column, buf, real_len);
++      info->column += real_len;
++}
++
++static int monahans_df_verify_buf(struct mtd_info *mtd,
++              const u_char *buf, int len)
++{
++      return 0;
++}
++
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++static void monahans_dfc_cmd_dma_irq(int channel, void *data,
++              struct pt_regs *regs)
++{
++      unsigned int dcsr;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)data;
++      struct dfc_context* context = info->context;
++      struct dfc_mode* dfc_mode = context->dfc_mode;
++      unsigned int intm;
++
++      dcsr = DCSR(channel);
++      DCSR(channel) = dcsr;
++
++      intm = (dfc_mode->chip_select) ? \
++              (NDSR_CS1_BBD | NDSR_CS1_CMDD) : (NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++      D1(printk("cmd dma interrupt, channel:%d, DCSR:0x%08x\n", \
++                      channel, dcsr));
++
++      if (dcsr & DCSR_BUSERR) {
++              info->retcode = ERR_DMABUSERR;
++              complete(&info->cmd_complete);
++      } else {
++              if ((info->cmd == NAND_CMD_READ0) ||
++                              (info->cmd == NAND_CMD_READOOB)|| \
++                              (info->cmd == NAND_CMD_READID) || \
++                              (info->cmd == NAND_CMD_STATUS)) {
++                      dfc_enable_int(context, NDSR_RDDREQ | NDSR_DBERR);
++              } else if (info->cmd == NAND_CMD_PAGEPROG)
++                      dfc_enable_int(context, NDSR_WRDREQ);
++              else if (info->cmd == NAND_CMD_ERASE1)
++                      dfc_enable_int(context, intm);
++      }
++
++      return;
++}
++
++
++static void monahans_dfc_data_dma_irq(int channel, void *data,
++              struct pt_regs *regs)
++{
++      unsigned int dcsr, intm;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)data;
++      struct dfc_context* context = info->context;
++      struct dfc_mode* dfc_mode = context->dfc_mode;
++
++      dcsr = DCSR(channel);
++      DCSR(channel) = dcsr;
++
++      intm = (dfc_mode->chip_select) ? \
++              (NDSR_CS1_BBD | NDSR_CS1_CMDD) : (NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++      D1(printk("data dma interrupt, channel:%d, DCSR:0x%08x\n",
++                      channel, dcsr));
++      if (dcsr & DCSR_BUSERR) {
++              info->retcode = ERR_DMABUSERR;
++              complete(&info->cmd_complete);
++      }
++
++      if (info->cmd == NAND_CMD_PAGEPROG) {
++              /* DMA interrupt may be interrupted by other IRQs*/
++              info->state = STATE_DMA_DONE;
++              dfc_enable_int(context, intm);
++      } else {
++              info->state = STATE_READY;
++              complete(&info->cmd_complete);
++      }
++
++}
++#endif
++
++static irqreturn_t monahans_dfc_irq(int irq, void *devid)
++{
++      unsigned int status, event, intm, cmd;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)devid;
++      struct dfc_context* context = info->context;
++      struct dfc_mode* dfc_mode = context->dfc_mode;
++
++      intm =  (dfc_mode->chip_select) ? \
++              (NDSR_CS1_BBD | NDSR_CS1_CMDD) : (NDSR_CS0_BBD | NDSR_CS0_CMDD);
++      event = (dfc_mode->chip_select) ? \
++              (NDSR_CS1_BBD | NDSR_CS1_CMDD) : (NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++      status = dfc_read(context, DFC_NDSR);
++      D1(printk("DFC irq, NDSR:0x%x\n", status));
++      if (status & (NDSR_RDDREQ | NDSR_DBERR)) {
++              if (status & NDSR_DBERR) {
++                      info->retcode = ERR_DBERR;
++              }
++
++              dfc_disable_int(context, NDSR_RDDREQ | NDSR_DBERR);
++              dfc_clear_int(context, NDSR_RDDREQ | NDSR_DBERR);
++              if (info->cmd == NAND_CMD_READID)
++                      cmd = context->flash_info->read_id;
++              else if (info->cmd == NAND_CMD_STATUS)
++                      cmd = context->flash_info->read_status;
++              else if (info->cmd == NAND_CMD_READ0 ||
++                              info->cmd == NAND_CMD_READOOB)
++                      cmd = context->flash_info->read1;
++              else {
++                      printk(KERN_ERR "No according command:0x%x happens\n",
++                                      info->cmd);
++                      goto out;
++              }
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++              info->state = STATE_DMA_TRANSFER;
++              dfc_start_data_dma(context,
++                              (struct pxa_dma_desc*)info->data_desc_addr);
++#else
++              info->state = STATE_DATA_TRANSFER;
++              complete(&info->cmd_complete);
++#endif
++      } else if (status & NDSR_WRDREQ) {
++              dfc_disable_int(context, NDSR_WRDREQ);
++              dfc_clear_int(context, NDSR_WRDREQ);
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++              info->state = STATE_DMA_TRANSFER;
++              dfc_start_data_dma(context,
++                              (struct pxa_dma_desc*)info->data_desc_addr);
++#else
++              info->state = STATE_DATA_TRANSFER;
++              complete(&info->cmd_complete);
++#endif
++      } else if (status & event) {
++              if (status & NDSR_CS0_BBD) {
++                      info->retcode = ERR_BBERR;
++              }
++
++              dfc_disable_int(context, intm);
++              dfc_clear_int(context, event);
++              info->state = STATE_READY;
++              complete(&info->cmd_complete);
++      }
++out:
++      return IRQ_HANDLED;
++}
++
++static int dfc_send_command(struct mtd_info *mtd, unsigned int cmd,
++                              unsigned int addr, unsigned int num_pages,
++                              unsigned int event)
++{
++
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++      struct dfc_context* context = info->context;
++      int status;
++      int ret;
++
++      D1(printk("ready send command, cmd:0x%x, at address:0x%x,"
++              " num_pages:%d, wait event:0x%x\n", cmd, addr, num_pages, event));
++
++      info->state = STATE_CMD_SEND;
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      status = dfc_setup_cmd_dma(context, cmd, addr, num_pages,
++                      (uint32_t *)info->cmd_buf, info->cmd_buf_addr,
++                      DDADR_STOP, DCMD_ENDIRQEN, info->cmd_desc);
++#else
++      status = dfc_send_cmd(context, cmd, addr, num_pages);
++#endif
++      if (status) {
++              info->retcode = ERR_SENDCMD;
++              dfc_stop(context);
++              udelay(20);
++              printk(KERN_ERR "fail send command\n");
++              return info->retcode;
++      }
++      info->state = STATE_CMD_HANDLE;
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      dfc_setup_data_dma(context, cmd, info->data_buf_addr,
++                      DDADR_STOP, DCMD_ENDIRQEN, info->data_desc);
++      dfc_start_cmd_dma(context, (struct pxa_dma_desc*)info->cmd_desc_addr);
++#endif
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++      dfc_enable_int(context, event);
++#endif
++      ret = wait_for_completion_timeout(&info->cmd_complete, 2*HZ);
++      if (!ret){
++              printk(KERN_ERR "Command time out\n");
++              dump_info(info);
++      }
++      D1(printk("command return, cmd:0x%x, retcode:%d\n",
++                      info->cmd, info->retcode));
++      return 0;
++}
++
++static void monahans_df_command(struct mtd_info *mtd, unsigned command,
++              int column, int page_addr )
++{
++      struct nand_chip *this = (struct nand_chip *)(mtd->priv);
++      struct monahans_dfc_info *info =
++                      (struct monahans_dfc_info *)(this->priv);
++      struct dfc_context *context = info->context;
++      struct dfc_flash_info * flash_info = context->flash_info;
++      int ret, pages_shift;
++      int status;
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++      int datasize;
++              int paddingsize;
++#endif
++      unsigned int to;
++
++      D1(printk("command:0x%x at address:0x%x, column:0x%x\n",
++                      command, page_addr, column));
++
++      if (info->state != STATE_READY) {
++              printk(KERN_ERR "CHIP is not ready.\n");
++              dump_info(info);
++              info->retcode = ERR_BUSY;
++              return;
++      }
++      info->retcode = ERR_NONE;
++      pages_shift = this->phys_erase_shift - this->page_shift;
++      if (info->table_init) {
++              to = search_rel_block((page_addr >> pages_shift), mtd);
++      if (to) {
++                      page_addr = (to << pages_shift) | (page_addr
++                                      & ((1 << pages_shift) - 1));
++              }
++      }
++
++      switch ( command ) {
++      case NAND_CMD_READOOB:
++              /*
++               * DFC has mark the last 8 bytes OOB data if HARDEARE_ECC is
++               * enabled. We must first disable the HARDWARE_ECC for getting
++               * all the 16 bytes OOB
++               */
++              enable_hw_ecc(context, 0);
++              info->buf_count = mtd->writesize + mtd->oobsize;
++              info->column = mtd->writesize + column;
++              info->cmd = command;
++              info->addr = page_addr << this->page_shift;
++              ret = dfc_send_command(mtd, flash_info->read1, info->addr,
++                              1, NDSR_RDDREQ | NDSR_DBERR);
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              dfc_get_pattern(info->context, flash_info->read1, &datasize,
++                              &paddingsize);
++              dfc_read_fifo_partial(info->context, info->data_buf,
++                              min(info->buf_count, datasize), datasize);
++              info->state = STATE_READY;
++#endif
++              /* We only are OOB, so if the data has error, does not matter */
++              if (info->retcode == ERR_DBERR)
++                      info->retcode = ERR_NONE;
++              enable_hw_ecc(context, 1);
++              break;
++
++      case NAND_CMD_READ0:
++              enable_hw_ecc(context, 1);
++              info->column = column;
++              info->cmd = command;
++              info->buf_count = mtd->writesize + mtd->oobsize;
++              memset(info->data_buf, 0xFF, info->buf_count);
++              info->addr = page_addr << this->page_shift;
++
++              ret = dfc_send_command(mtd, flash_info->read1, info->addr,
++                              1, NDSR_RDDREQ | NDSR_DBERR);
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              dfc_get_pattern(info->context, flash_info->read1, &datasize,
++                              &paddingsize);
++              dfc_read_fifo_partial(info->context, info->data_buf,
++                              min(info->buf_count, datasize), datasize);
++              info->state = STATE_READY;
++#endif
++              /* When the data buf is blank, the DFC will report DB error */
++              if (info->retcode == ERR_DBERR && is_buf_blank(info->data_buf,
++                              mtd->writesize))
++                      info->retcode = ERR_NONE;
++
++              if (info->retcode == ERR_DBERR) {
++                      printk(KERN_ERR "DB error at address 0x%x\n",
++                              info->addr);
++                      print_buf(info->data_buf, info->buf_count);
++              }
++              break;
++      case NAND_CMD_SEQIN:
++              /* Write only OOB? */
++
++              info->cmd = command;
++              if (column >= mtd->writesize) {
++                      info->buf_count = mtd->writesize + mtd->oobsize;
++                      enable_hw_ecc(context, 0);
++              } else {
++                      info->buf_count = mtd->writesize + mtd->oobsize;
++                      enable_hw_ecc(context, 1);
++              }
++              memset(info->data_buf, 0xFF, mtd->writesize + mtd->oobsize);
++              info->column = column;
++              info->addr = page_addr << this->page_shift;
++              break;
++      case NAND_CMD_PAGEPROG:
++              /* prevois command is NAND_CMD_SEIN ?*/
++              if (info->cmd != NAND_CMD_SEQIN) {
++                      info->cmd = command;
++                      info->retcode = ERR_SENDCMD;
++                      printk(KERN_ERR "Monahans NAND device: "
++                              "No NAND_CMD_SEQIN executed before.\n");
++                      enable_hw_ecc(context, 1);
++                      break;
++              }
++              info->cmd = command;
++              ret = dfc_send_command(mtd, flash_info->program, info->addr,
++                              1, NDSR_WRDREQ);
++
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              if (ret != 0)
++                      break;
++
++              dfc_get_pattern(info->context, flash_info->program, &datasize,
++                              &paddingsize);
++              dfc_write_fifo_partial(info->context, info->data_buf, datasize,
++                              datasize);
++
++              if (info->context->dfc_mode->chip_select)
++                      dfc_enable_int(info->context,
++                              NDSR_CS1_BBD | NDSR_CS1_CMDD);
++              else
++                      dfc_enable_int(info->context,
++                              NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++              ret = wait_for_completion_timeout(&info->cmd_complete, 2*HZ);
++              if (!ret){
++                      printk(KERN_ERR "Programm Command time out\n");
++                      dump_info(info);
++              }
++
++              if (info->retcode == ERR_BBERR) {
++                      mtd->block_markbad(mtd, info->addr);
++              }
++#endif
++              break;
++      case NAND_CMD_ERASE1:
++              info->cmd = command;
++              info->addr = (page_addr >> pages_shift) << this->phys_erase_shift;
++
++              if (info->context->dfc_mode->chip_select)
++                      ret = dfc_send_command(mtd, flash_info->erase,
++                              info->addr, 0, NDSR_CS1_BBD | NDSR_CS1_CMDD);
++              else
++                      ret = dfc_send_command(mtd, flash_info->erase,
++                              info->addr, 0, NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++              if (info->retcode == ERR_BBERR) {
++                      mtd->block_markbad(mtd, info->addr);
++              }
++              break;
++      case NAND_CMD_ERASE2:
++              break;
++      case NAND_CMD_READID:
++              info->cmd = command;
++              info->buf_count = flash_info->read_id_bytes;
++              info->column = 0;
++              info->addr = 0xFFFFFFFF;
++              ret = dfc_send_command(mtd, flash_info->read_id, info->addr,
++                              0, NDSR_RDDREQ);
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              dfc_get_pattern(info->context, flash_info->read_id, &datasize,
++                              &paddingsize);
++              dfc_read_fifo_partial(info->context, info->data_buf,
++                              info->buf_count, datasize);
++              info->state = STATE_READY;
++#endif
++              D1(printk("ReadID, [1]:0x%x, [2]:0x%x\n",
++                      info->data_buf[0], info->data_buf[1]));
++              break;
++      case NAND_CMD_STATUS:
++              info->cmd = command;
++              info->buf_count = 1;
++              info->column = 0;
++              info->addr = 0xFFFFFFFF;
++              ret = dfc_send_command(mtd, flash_info->read_status,
++                      info->addr, 0, NDSR_RDDREQ);
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              dfc_get_pattern(info->context, flash_info->read_status,
++                      &datasize, &paddingsize);
++              dfc_read_fifo_partial(info->context, info->data_buf,
++                      info->buf_count, datasize);
++              info->state = STATE_READY;
++#endif
++              break;
++
++      case NAND_CMD_RESET:
++              status = dfc_reset_flash(&dfc_context);
++              if (status) {
++                      printk(KERN_WARNING "Monahans NAND device:"
++                              "NAND_CMD_RESET error\n");
++              }
++              break;
++      default:
++              printk(KERN_WARNING "Monahans NAND device:"
++                      "Non-support the command.\n");
++              break;
++      }
++
++      if (info->retcode != ERR_NONE)
++              dfc_stop(info->context);
++}
++
++static void monahans_df_select_chip(struct mtd_info *mtd, int chip)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++
++      if (chip <= MAX_CHIP)
++              info->context->dfc_mode->chip_select = chip;
++      else
++              printk(KERN_ERR "Monahans NAND device:"
++                      "not select the NAND chips!\n");
++}
++
++static int monahans_df_waitfunc(struct mtd_info *mtd,
++              struct nand_chip *this)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++
++      /* monahans_df_send_command has waited for command complete */
++      if (this->state == FL_WRITING || this->state == FL_ERASING) {
++              if (info->retcode == ERR_NONE)
++                      return 0;
++              else {
++                      /*
++                       * any error make it return 0x01 which will tell
++                       * the caller the erase and write fail
++                       */
++                      return 0x01;
++              }
++      }
++
++      return 0;
++}
++
++static int monahans_df_calculate_ecc(struct mtd_info *mtd,
++              const u_char *dat, u_char *ecc_code)
++{
++      return 0;
++}
++
++static int monahans_df_correct_data(struct mtd_info *mtd,
++              u_char *dat, u_char *read_ecc, u_char *calc_ecc)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++
++      /*
++       * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we
++       * consider it as a ecc error which will tell the caller the
++       * read fail We have distinguish all the errors, but the
++       * nand_read_ecc only check this function return value
++       */
++      if (info->retcode != ERR_NONE)
++              return -1;
++
++      return 0;
++}
++
++static void monahans_df_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++      return;
++}
++
++/*
++ * The relocation table management is different between MOBM V2 and V3.
++ *
++ * MOBM V2 is applied on chips taped out before MhnLV A0.
++ * MOBM V3 is applied on chips taped out after MhnLV A0. It's also applied
++ * on MhnLV A0.
++ */
++static int calc_obm_ver(void)
++{
++      unsigned int    cpuid;
++      /* read CPU ID */
++      __asm__ (
++              "mrc p15, 0, %0, c0, c0, 0\n"
++              : "=r" (cpuid)
++      );
++      /* It's not xscale chip. */
++      if ((cpuid & 0xFFFF0000) != 0x69050000)
++              return MHN_OBM_INVAL;
++      /* It's MhnP Ax */
++      if ((cpuid & 0x0000FFF0) == 0x00006420)
++              return MHN_OBM_V2;
++      /* It's MhnP Bx */
++      if ((cpuid & 0x0000FFF0) == 0x00006820) {
++              if ((cpuid & 0x0F) <= 5)
++                      return MHN_OBM_V2;
++              else
++                      return MHN_OBM_V3;
++      }
++      /* It's MhnL Ax */
++      if ((cpuid & 0x0000FFF0) == 0x00006880) {
++              if ((cpuid & 0x0F) == 0)
++                      return MHN_OBM_V2;
++              else
++                      return MHN_OBM_V3;
++      }
++      /* It's MhnLV Ax */
++      if ((cpuid & 0x0000FFF0) == 0x00006890)
++              return MHN_OBM_V3;
++      return MHN_OBM_INVAL;
++}
++
++
++/*
++ * MOBM maintains a relocation table. It's used to replace bad blocks.
++ * If block A is bad, it will use block B instead.
++ * There're 127 relocated blocks. All of them reside in the bottom of NAND
++ * flash. So they're reserved and can't be calculated in mtd size and chip
++ * size.
++ */
++static int read_reloc_table(struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      struct dfc_context *context = NULL;
++      struct reloc_table *table = NULL;
++      int page, maxslot;
++      int obm, valid;
++
++      obm = calc_obm_ver();
++      this = (struct nand_chip *)(mtd->priv);
++      info = (struct monahans_dfc_info *)(this->priv);
++      context = info->context;
++
++      mtd->size -= (NAND_RELOC_MAX * mtd->erasesize);
++      this->chipsize -= (NAND_RELOC_MAX << this->phys_erase_shift);
++      page = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
++
++      this->select_chip(mtd, 0);
++      valid = 0;
++      if (obm == MHN_OBM_V2) {
++              /* On MOBM V2, the relocation table resides in the last page
++               * of the first block.
++               */
++              memset(info->data_buf, 0, BUFLEN);
++              monahans_df_command(mtd, NAND_CMD_READ0, 0, page);
++      memcpy(((unsigned char *)&(info->table)), info->data_buf,
++                      sizeof(struct reloc_table));
++              if (info->table.header == NAND_RELOC_HEADER)
++                      valid = 1;
++      } else if (obm == MHN_OBM_V3) {
++              /* On MOBM V3, there're several relocation tables in the first
++               * block.
++               * When new bad blocks are found, a new relocation table will
++               * be generated and written back to the first block. But the
++               * original relocation table won't be erased. Even if the new
++               * relocation table is written wrong, system can still find an
++               * old one.
++               * One page contains one slot.
++               */
++              maxslot = 1 << (this->phys_erase_shift - this->page_shift);
++              page = maxslot - MAX_BBT_SLOTS;
++              for (; page < maxslot; page++) {
++                      monahans_df_command(mtd, NAND_CMD_READ0, 0, page);
++                      table = (struct reloc_table *)info->data_buf;
++                      if (info->retcode == ERR_NONE) {
++                              if (table->header != NAND_RELOC_HEADER) {
++                                      continue;
++      } else {
++                                      memcpy(((unsigned char *)&(info->table)),
++                                              table, sizeof(struct reloc_table));
++                                      valid = 1;
++                                      break;
++                              }
++                      }
++      }
++
++      } else {
++              printk(KERN_ERR "The version of MOBM isn't supported\n");
++      }
++      if (valid) {
++              memcpy(((unsigned char *)&(info->table)), info->data_buf,
++                      sizeof(struct reloc_table));
++              printk(KERN_DEBUG "relocation table at page:%d\n", page);
++              PRINT_BUF((unsigned char *)&(info->table),
++                      sizeof(struct reloc_table));
++      info->table_init = 1;
++      } else {
++              /* There should be a valid relocation table slot at least. */
++              printk(KERN_ERR "NO VALID relocation table can be \
++                              recognized\n");
++              printk(KERN_ERR "CAUTION: It may cause unpredicated error\n");
++              printk(KERN_ERR "Please re-initialize the NAND flash.\n");
++              memset((unsigned char *)&(info->table), 0,
++                              sizeof(struct reloc_table));
++              info->table_init = 0;
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/* add the relocation entry into the relocation table
++ * It's valid on MOBM V3.
++ * If the relocated block is bad, an new entry will be added into the
++ * bottom of the relocation table.
++ */
++static int update_rel_table(struct mtd_info *mtd, int block)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      struct reloc_table *table = NULL;
++      int obm, reloc_block;
++
++      this = (struct nand_chip *)(mtd->priv);
++      info = (struct monahans_dfc_info *)(this->priv);
++      obm = calc_obm_ver();
++      if (obm == MHN_OBM_V3) {
++              table = &info->table;
++              if (info->table_init == 0) {
++                      printk(KERN_ERR "Error: the initial relocation \
++                                      table can't be read\n");
++                      memset(table, 0, sizeof(struct reloc_table));
++                      table->header = NAND_RELOC_HEADER;
++                      info->table_init = 1;
++              }
++              if (table->total == 0) {
++                      /* Point to the first relocated block.
++                       * It resides in the last block of flash.
++                       * the relocation entry has calculated in
++                       * chipsize
++                       */
++                      reloc_block = (this->chipsize
++                                      >> this->phys_erase_shift)
++                                      + NAND_RELOC_MAX - 1;
++              } else if (table->total < NAND_RELOC_MAX) {
++                      reloc_block = table->reloc[table->total - 1].to - 1;
++              } else {
++                      printk(KERN_ERR "Relocation table exceed max number, \
++                              cannot mark block 0x%x as bad block\n", block);
++                      return -ENOSPC;
++              }
++              /* Make sure that reloc_block is pointing to a valid block */
++              for (; ; reloc_block--) {
++                      /* The relocate table is full */
++                      if (reloc_block < (this->chipsize
++                                      >> this->phys_erase_shift))
++                              return -ENOSPC;
++                      this->cmdfunc(mtd, NAND_CMD_ERASE1, 0, reloc_block
++                                      << (this->phys_erase_shift
++                                      - this->page_shift));
++                      if (info->retcode == ERR_NONE)
++                              break;
++              }
++              /* Create the relocated block information in the table */
++              table->reloc[table->total].from = block;
++              table->reloc[table->total].to = reloc_block;
++              table->total++;
++      }
++      return 0;
++}
++
++/* Write the relocation table back to device, if there's room. */
++static int sync_rel_table(struct mtd_info *mtd, int *idx)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      int obm, start_page, len;
++
++      if (*idx >= MAX_BBT_SLOTS) {
++              printk(KERN_ERR "Can't write relocation table to device \
++                              any more.\n");
++              return -1;
++      }
++      if (*idx < 0) {
++              printk(KERN_ERR "Wrong Slot is specified.\n");
++              return -1;
++      }
++      this = (struct nand_chip *)(mtd->priv);
++      info = (struct monahans_dfc_info *)(this->priv);
++      len = 4;
++      len += info->table.total << 2;
++      obm = calc_obm_ver();
++      if (obm == MHN_OBM_V3) {
++              /* write to device */
++              start_page = 1 << (this->phys_erase_shift - this->page_shift);
++              start_page = start_page - 1 - *idx;
++              memset(&(info->data_buf), 0xFF, BUFLEN);
++              memcpy(&(info->data_buf), &(info->table), len);
++
++              printk(KERN_DEBUG "DUMP relocation table before write. \
++                              page:0x%x\n", start_page);
++              monahans_df_command(mtd, NAND_CMD_SEQIN, 0, start_page);
++              monahans_df_command(mtd, NAND_CMD_PAGEPROG, 0, start_page);
++              /* write to idx */
++              (*idx)++;
++              /* dump it */
++              memset(&(info->data_buf), 0, BUFLEN);
++              monahans_df_command(mtd, NAND_CMD_READOOB, 0, start_page);
++              PRINT_BUF(info->data_buf, len);
++      }
++      return 0;
++}
++
++
++/* Find the relocated block of the bad one.
++ * If it's a good block, return 0. Otherwise, return a relocated one.
++ * idx points to the next relocation entry
++ * If the relocated block is bad, an new entry will be added into the
++ * bottom of the relocation table.
++ */
++static unsigned short search_rel_block(int block, struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      struct reloc_table *table = NULL;
++      int i, max, reloc_block = 0;
++
++      this = (struct nand_chip *)(mtd->priv);
++      info = (struct monahans_dfc_info *)(this->priv);
++      table = &(info->table);
++      if ((block <= 0) || (block > this->chipsize)
++                      || (info->table_init == 0) || (table->total == 0))
++              return 0;
++      if (table->total > NAND_RELOC_MAX)
++              table->total = NAND_RELOC_MAX;
++      max = table->total;
++      for (i = 0; i < max; i++) {
++              if (block == table->reloc[i].from)
++                      reloc_block = table->reloc[i].to;
++      }
++      return reloc_block;
++}
++
++/*
++ * Check whether the block is a bad one.
++ * At first, it will search the relocation table.
++ * If necessary, it will search the BBT. Because relocation table can only
++ * maintain limited record. If there're more bad blocks, they can't be
++ * recorded in relocation table. They can only be recorded in BBT.
++ */
++static int monahans_df_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
++{
++      struct nand_chip *this = NULL;
++      int page, block, reloc_block, chipnr, res = 0;
++      u16 bad;
++
++      /* At here, we only support one flash chip */
++      this = (struct nand_chip *)mtd->priv;
++      block = (int)(ofs >> this->phys_erase_shift);
++      /* search the block in the relocation table */
++      reloc_block = search_rel_block(block, mtd);
++      if (reloc_block) {
++              ofs = ((reloc_block << this->phys_erase_shift) |
++                      (ofs & ((1 << this->phys_erase_shift) - 1)));
++      }
++
++      /* search BBT
++       * Maybe the relocation table is full, but some bad blocks aren't
++       * recordered in it.
++       * The below code are copied from nand_block_bad().
++       */
++      if (getchip) {
++              page = (int)(ofs >> this->page_shift);
++              chipnr = (int)(ofs >> this->chip_shift);
++
++              /* Select the NAND chips */
++              this->select_chip(mtd, chipnr);
++      } else
++              page = (int)ofs;
++
++      if (this->options & NAND_BUSWIDTH_16) {
++              this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE,
++                              page & this->pagemask);
++              bad = cpu_to_le16(this->read_word(mtd));
++              if (this->badblockpos & 0x1)
++                      bad >>= 1;
++              if ((bad & 0xFF) != 0xFF)
++                      res = 1;
++      } else {
++              this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos,
++                              page & this->pagemask);
++              if (this->read_byte(mtd) != 0xFF)
++                      res = 1;
++      }
++
++      return res;
++}
++
++static int monahans_df_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      unsigned char buf[2] = {0, 0};
++      int block, reloc_block, page, ret;
++
++      this = (struct nand_chip *)mtd->priv;
++      info = (struct monahans_dfc_info *)(this->priv);
++      /* Get block number */
++      block = ((int)ofs) >> this->bbt_erase_shift;
++      ret = update_rel_table(mtd, block);
++      if (!ret) {
++              sync_rel_table(mtd, &(info->current_slot));
++              return 0;
++              } else {
++              reloc_block = search_rel_block(block, mtd);
++              if (reloc_block)
++                      block = reloc_block;
++              if (this->bbt)
++                      this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
++      }
++
++      /* Do we have a flash based bad block table ? */
++      if (this->options & NAND_USE_FLASH_BBT)
++              return nand_update_bbt(mtd, ofs);
++
++      /* mark the bad block flag at the first two pages */
++      page = block << (this->phys_erase_shift - this->page_shift);
++      ofs = mtd->writesize + this->badblockpos;
++      this->cmdfunc(mtd, NAND_CMD_SEQIN, ofs, page);
++      this->write_buf(mtd, buf, 2);
++      this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++      page++;
++      this->cmdfunc(mtd, NAND_CMD_SEQIN, ofs, page);
++      this->write_buf(mtd, buf, 2);
++      this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++      return 0;
++}
++
++static int dump_bbt_flash(struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      int block, page, totlen;
++
++      this = (struct nand_chip *)mtd->priv;
++      info = (struct monahans_dfc_info *)this->priv;
++      block = (this->chipsize >> this->phys_erase_shift) - 1;
++      totlen = (this->chipsize >> this->phys_erase_shift) >> 2;
++      printk(KERN_ERR "totlen:0x%x\n", totlen);
++      this->select_chip(mtd, 0);
++      if (this->bbt_td) {
++              printk(KERN_ERR "BBT page:0x%x\n", this->bbt_td->pages[0]);
++              page = this->bbt_td->pages[0];
++              if (this->bbt_td->pages[0] <= 0) {
++                      page = block << (this->phys_erase_shift
++                              - this->page_shift);
++              }
++              while (totlen > 0) {
++                      printk(KERN_ERR "page:0x%x\n", page);
++                      monahans_df_command(mtd, NAND_CMD_READ0, 0, page);
++                      printk(KERN_ERR "read result:0x%x\n", info->retcode);
++                      PRINT_BUF(info->data_buf, BUFLEN);
++                      totlen -= (1 << this->page_shift);
++                      page++;
++              }
++      }
++      if (this->bbt_md) {
++              printk(KERN_ERR "BBT page:0x%x\n", this->bbt_md->pages[0]);
++              page = this->bbt_md->pages[0];
++              if (this->bbt_td->pages[0] <= 0) {
++                      page = block << (this->phys_erase_shift
++                              - this->page_shift);
++                      }
++              while (totlen > 0) {
++                      printk(KERN_ERR "page:0x%x\n", page);
++                      monahans_df_command(mtd, NAND_CMD_READ0, 0, page);
++                      printk(KERN_ERR "read result:0x%x\n", info->retcode);
++                      PRINT_BUF(info->data_buf, BUFLEN);
++                      totlen -= (1 << this->page_shift);
++                      page++;
++              }
++
++      }
++      return 0;
++}
++
++static int dump_bbt_mem(struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++
++      this = (struct nand_chip *)mtd->priv;
++      PRINT_BUF(this->bbt, 225);
++      return 0;
++}
++
++static int monahans_df_scan_bbt(struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++      int ret;
++
++      this = (struct nand_chip *)mtd->priv;
++      ret = read_reloc_table(mtd);
++      if (ret) {
++              printk(KERN_ERR "Failed to get relocation table\n");
++              printk(KERN_ERR "Try to build a new BBT. It may result \
++                              unpredicated error.\n");
++              /* Create new memory based and flash based BBT */
++      }
++      nand_scan_bbt(mtd, &monahans_bbt_default);
++      //dump_bbt_flash(mtd);
++      dump_bbt_mem(mtd);
++      return 0;
++#if 0
++      /* Read flashed based BBT from device */
++      return (nand_scan_bbt(mtd, &monahans_bbt_main));
++#endif
++}
++
++
++static int monahans_df_probe(struct platform_device *pdev)
++{
++      struct nand_chip *this;
++      struct monahans_dfc_info *info;
++      int status = -1;
++      unsigned int data_buf_len;
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      unsigned int buf_len;
++#endif
++      int i, ret = 0;
++
++      printk(KERN_ERR "Nand driver probe\n");
++
++      dfc_context.membase = ioremap_nocache(0x43100000, 0x100000);
++      if (!dfc_context.membase)
++              printk(KERN_ERR "Couldn't ioremap\n");
++
++      pxa_set_cken(CKEN_NAND, 1);
++
++      for (i = DFC_FLASH_NULL + 1; i < DFC_FLASH_END; i++)
++      {
++              uint32_t id;
++
++              status = dfc_init(&dfc_context, i);
++              if (status)
++                      continue;
++              status = dfc_readid(&dfc_context, &id);
++              if (status)
++                      continue;
++              printk(KERN_DEBUG "id:0x%x, chipid:0x%x\n",
++                      id, dfc_context.flash_info->chip_id);
++              if (id == dfc_context.flash_info->chip_id)
++                      break;
++      }
++
++      if(i == DFC_FLASH_END) {
++              printk(KERN_ALERT "Monahans NAND device:"
++                      "Nand Flash initialize failure!\n");
++              ret = -ENXIO;
++              goto out;
++      }
++      flash_config = i;
++
++      monahans_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) +
++                      sizeof(struct monahans_dfc_info) , GFP_KERNEL);
++      if (!monahans_mtd) {
++              printk (KERN_ERR "Monahans NAND device:"
++                      "Unable to allocate NAND MTD device structure.\n");
++              ret = -ENOMEM;
++              goto out;
++        }
++
++      /* Get pointer to private data */
++      this = (struct nand_chip *)((void *)monahans_mtd + sizeof(struct mtd_info));
++      info = (struct monahans_dfc_info *)((void *)this + sizeof(struct nand_chip));
++      dfc_context.mtd = monahans_mtd;
++
++      monahans_mtd->priv = this;
++      this->priv = info;
++      data_buf_len = dfc_context.flash_info->page_size +
++              dfc_context.flash_info->oob_size;
++      info->state = STATE_READY;
++      init_completion(&info->cmd_complete);
++      info->table_init = 0;
++      memset(&info->table, 0x0, sizeof(struct reloc_table));
++      printk(KERN_DEBUG "%s: this->controller: 0x%x, &this->controller: 0x%x\n",__func__, (unsigned int)this->controller, (unsigned int)&(this->controller));
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      info->dma_mask = 0xffffffffUL;
++
++      dev->dma_mask = &info->dma_mask;
++      dev->coherent_dma_mask = 0xffffffffUL;
++
++      /* alloc dma data buffer for data
++       * buffer + 2*descriptor + command buffer
++       */
++      buf_len = ALIGN(2*sizeof(struct pxa_dma_desc), 32) +
++              ALIGN(data_buf_len, 32) + ALIGN(NAND_CMD_DMA_LEN, 32);
++
++      printk(KERN_INFO "Try to allocate dma buffer(len:%d)"
++              "for data buffer + 2*descriptor + command buffer\n", buf_len);
++      info->data_desc = (struct pxa_dma_desc*)dma_alloc_writecombine(dev,
++                      buf_len, &info->data_desc_addr, GFP_KERNEL);
++      if (!info->data_desc) {
++              printk(KERN_ERR "Monahans NAND device:"
++                      "Unable to alloc dma buffer\n");
++              ret = -ENOMEM;
++              goto free_mtd;
++      }
++
++      info->cmd_desc = (struct pxa_dma_desc*)((char *)info->data_desc +
++                      sizeof(struct pxa_dma_desc));
++      info->cmd_desc_addr = (dma_addr_t)((char *)info->data_desc_addr +
++                      sizeof(struct pxa_dma_desc));
++      info->data_buf = (char *)info->data_desc +
++              ALIGN(2*sizeof(struct pxa_dma_desc), 32);
++      info->data_buf_addr = (dma_addr_t)((char *)info->data_desc_addr +
++              ALIGN(2*sizeof(struct pxa_dma_desc), 32));
++      info->cmd_buf = (char *)info->data_buf + ALIGN(data_buf_len, 32);
++      info->cmd_buf_addr = (dma_addr_t)((char *)info->data_buf_addr +
++                      ALIGN(data_buf_len, 32));
++
++      D1(printk("Get dma buffer for data dma descriptor, virt:0x%x, phys0x:%x\n",
++              (unsigned int)info->data_desc, info->data_desc_addr));
++      D1(printk("Get dma buffer for command dma descriptors, virt:0x%x,"
++              "phys0x:%x\n", (unsigned int)info->cmd_desc, info->cmd_desc_addr));
++      D1(printk("Get dma buffer for data, virt:0x%x, phys0x:%x\n",
++              (unsigned int)info->data_buf, info->data_buf_addr));
++      D1(printk("Get dma buffer for command, virt:0x%x, phys0x:%x\n",
++              (unsigned int)info->cmd_buf, info->cmd_buf_addr));
++
++      D1(printk("Try to allocate dma channel for data\n"));
++
++      info->data_dma = pxa_request_dma("NAND DATA", DMA_PRIO_LOW,
++                      monahans_dfc_data_dma_irq, info);
++      if (info->data_dma < 0) {
++              printk(KERN_ERR "Monahans NAND device:"
++                      "Unable to alloc dma channel for data\n");
++              ret = info->data_dma;
++              goto free_buf;
++      }
++      D1(printk("Get dma channel:%d for data\n", info->data_dma));
++
++      D1(printk("Try to allocate dma channel for command\n"));
++      info->cmd_dma = pxa_request_dma("NAND CMD", DMA_PRIO_LOW,
++                      monahans_dfc_cmd_dma_irq, info);
++      if (info->cmd_dma < 0) {
++              printk(KERN_ERR "Monahans NAND device:"
++                      "Unable to alloc dma channel for command\n");
++              ret = info->cmd_dma;
++              goto free_data_dma;
++      }
++      D1(printk("Get dma channel:%d for command\n", info->cmd_dma));
++
++      dfc_context.cmd_dma_ch  = info->cmd_dma;
++      dfc_context.data_dma_ch = info->data_dma;
++#else
++      printk(KERN_DEBUG "Try to allocate data buffer(len:%d)\n", data_buf_len);
++      info->data_buf = kmalloc(data_buf_len, GFP_KERNEL);
++      if (!info->data_buf) {
++              printk(KERN_ERR "Monahans NAND device:"
++                      "Unable to alloc data buffer\n");
++              ret = -ENOMEM;
++              goto free_mtd;
++      }
++#endif
++
++      D1(printk("Try to request irq:%d\n", IRQ_NAND));
++      ret = request_irq(IRQ_NAND, monahans_dfc_irq, 0, pdev->name, info);
++      if (ret < 0) {
++              printk(KERN_ERR "Monahans NAND device: Unable to request irq\n");
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++              goto free_cmd_dma;
++#else
++              goto free_buf;
++#endif
++      }
++
++      D1(printk("Success request irq\n"));
++
++      /* set address of NAND IO lines */
++      this->options = (dfc_context.flash_info->flash_width == 16)? \
++                      NAND_BUSWIDTH_16: 0 | NAND_USE_FLASH_BBT;
++
++      /* this->IO_ADDR_R = this->IO_ADDR_W = NDDB */
++      this->waitfunc = monahans_df_waitfunc;
++      this->select_chip = monahans_df_select_chip;
++      this->dev_ready = monahans_df_dev_ready;
++      this->cmdfunc = monahans_df_command;
++      this->read_word= monahans_df_read_word;
++      /*this->write_word= monahans_df_write_word;*/
++      this->read_byte = monahans_df_read_byte;
++      this->read_buf = monahans_df_read_buf;
++      this->write_buf = monahans_df_write_buf;
++      this->verify_buf = monahans_df_verify_buf;
++      this->ecc.hwctl = monahans_df_enable_hwecc;
++      this->ecc.calculate = monahans_df_calculate_ecc;
++      this->ecc.correct = monahans_df_correct_data;
++      this->block_bad = monahans_df_block_bad;
++      this->block_markbad = monahans_df_block_markbad;
++      this->scan_bbt = monahans_df_scan_bbt;
++      this->chip_delay= 25;
++      this->bbt_td = &monahans_bbt_main;
++      this->bbt_md = &monahans_bbt_mirror;
++
++      /* If the NAND flash is small block flash, only 512-byte pagesize
++       * is supported.
++       * Adjust parameters of BBT what is depended on large block nand
++       * flash or small block nand flash.
++       */
++      if (dfc_context.flash_info->oob_size > 16) {
++              this->ecc.layout = &monahans_lb_nand_oob;
++              this->ecc.mode = NAND_ECC_HW;
++              this->ecc.size = 2048;
++              this->ecc.bytes = 24;
++              this->bbt_td->offs = 2;
++              this->bbt_td->veroffs = 6;
++              this->bbt_md->offs = 2;
++              this->bbt_md->veroffs = 6;
++              this->badblockpos = NAND_LARGE_BADBLOCK_POS;
++              monahans_bbt_default.offs = NAND_LARGE_BADBLOCK_POS;
++              monahans_bbt_default.len = 2;
++              /* when scan_bbt() is executed, bbt version can get */
++              monahans_bbt_default.veroffs = 2;
++      } else {
++              this->ecc.layout = &monahans_sb_nand_oob;
++              this->ecc.mode = NAND_ECC_HW;
++              this->ecc.size = 512;
++              this->ecc.bytes = 6;
++              this->bbt_td->offs = 8;
++              this->bbt_td->veroffs = 12;
++              this->bbt_md->offs = 8;
++              this->bbt_md->veroffs = 12;
++              this->badblockpos = NAND_SMALL_BADBLOCK_POS;
++              monahans_bbt_default.offs = NAND_SMALL_BADBLOCK_POS;
++              monahans_bbt_default.len = 1;
++              monahans_bbt_default.veroffs = 8;
++      }
++
++      info->context = &dfc_context;
++      /* TODO: allocate dma buffer and channel */
++
++      platform_set_drvdata(pdev, monahans_mtd);
++
++      if (nand_scan(monahans_mtd, 1)) {
++              printk(KERN_ERR "Nand scan failed\n");
++              ret = -ENXIO;
++              goto free_irq;
++      }
++
++      /* There is a potential limitation that no more partition can be
++       * added between MassStorage and BBT(last block).
++       *
++       * The last 127 blocks is reserved for relocation table, they aren't
++       * statistical data of mtd size and chip size.
++       *
++       * BBT partitions contains 4 blocks. Two blocks are used to store
++       * main descriptor, the other two are used to store mirror descriptor.
++       */
++      partition_info[PART_NUM - 1].size = (monahans_bbt_main.maxblocks
++                                      + monahans_bbt_mirror.maxblocks)
++                                      << this->phys_erase_shift;
++      partition_info[PART_NUM - 1].offset = this->chipsize
++                                      - partition_info[PART_NUM - 1].size;
++      partition_info[PART_NUM - 2].offset = partition_info[PART_NUM - 3].offset
++                                      + partition_info[PART_NUM - 3].size;
++      partition_info[PART_NUM - 2].size = this->chipsize
++                                      - partition_info[PART_NUM - 2].offset
++                                      - partition_info[PART_NUM - 1].size;
++      add_mtd_partitions(monahans_mtd, partition_info, PART_NUM);
++
++#ifdef CONFIG_DVFM
++        dvfm_notifier.client_data = info;
++        mhn_fv_register_notifier(&dvfm_notifier);
++#endif
++
++      return 0;
++
++free_irq:
++      free_irq(IRQ_NAND, info);
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++free_cmd_dma:
++      pxa_free_dma(info->cmd_dma);
++free_data_dma:
++      pxa_free_dma(info->data_dma);
++free_buf:
++      dma_free_writecombine(dev, buf_len, info->data_desc, info->data_desc_addr);
++#else
++free_buf:
++      kfree(info->data_buf);
++#endif
++free_mtd:
++      kfree(monahans_mtd);
++out:
++      return ret;
++
++}
++
++static int __devexit monahans_df_remove(struct platform_device *dev)
++{
++      struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(dev);
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      unsigned int data_buf_len = dfc_context.flash_info->page_size +
++                      dfc_context.flash_info->oob_size;
++      unsigned int buf_len = ALIGN(2*sizeof(struct pxa_dma_desc), 32) +
++                      ALIGN(data_buf_len, 32) + ALIGN(NAND_CMD_DMA_LEN, 32);
++#endif
++
++#ifdef CONFIG_DVFM
++        mhn_fv_unregister_notifier(&dvfm_notifier);
++#endif
++
++      platform_set_drvdata(dev, NULL);
++
++      del_mtd_device(mtd);
++      del_mtd_partitions(mtd);
++      free_irq(IRQ_NAND, info);
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      pxa_free_dma(info->cmd_dma);
++      pxa_free_dma(info->data_dma);
++      dma_free_writecombine(dev, buf_len, info->data_desc,
++              info->data_desc_addr);
++#else
++      kfree(info->data_buf);
++#endif
++      kfree(mtd);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int monahans_df_suspend(struct platform_device *dev, pm_message_t state, u32 level)
++{
++      struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(dev);
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++
++      if( SUSPEND_DISABLE == level){ /*SUSPEND_NOTIFY*/
++              if (info->state != STATE_READY) {
++                      printk(KERN_ERR "current state is %d\n", info->state);
++                      return -EAGAIN;
++              }
++              info->state = STATE_SUSPENDED;
++              /*
++               * The PM code need read the mobm from NAND.
++               * So the NAND clock can't be stop here.
++               * The PM code will cover this.
++               */
++              /* pxa_set_cken(CKEN_NAND, 0); */
++      }
++      return 0;
++}
++
++static int monahans_df_resume(struct platform_device *dev, u32 level)
++{
++      struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(dev);
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++      int status;
++
++      if(RESUME_ENABLE == level){
++              if (info->state != STATE_SUSPENDED)
++                      printk(KERN_WARNING "Error State after resume back\n");
++
++              info->state = STATE_READY;
++
++              pxa_set_cken(CKEN_NAND, 1);
++
++              status = dfc_init(&dfc_context, flash_config);
++              if (status) {
++                      printk(KERN_ALERT "Monahans NAND device:"
++                              "Nand Flash initialize failure!\n");
++                      return -ENXIO;
++              }
++      }
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_DVFM
++static int mhn_nand_dvfm_notifier(unsigned cmd, void *client_data, void *info)
++{
++      struct monahans_dfc_info *dfc_info =
++                      (struct monahans_dfc_info *)client_data;
++
++      switch (cmd) {
++      case FV_NOTIFIER_QUERY_SET :
++              if (dfc_info->state != STATE_READY)
++                      return -1;
++              break;
++
++      case FV_NOTIFIER_PRE_SET :
++              break;
++
++      case FV_NOTIFIER_POST_SET :
++              break;
++      }
++
++      return 0;
++}
++#endif
++
++static struct platform_driver monahans_df_driver = {
++      .probe          = monahans_df_probe,
++      .remove         = __devexit_p(monahans_df_remove),
++#ifdef CONFIG_PM
++      .suspend        = monahans_df_suspend,
++      .resume         = monahans_df_resume,
++#endif
++      .driver         = {
++              .name           = "monahans-nand-flash",
++      }
++};
++
++static void __exit monahans_df_cleanup(void)
++{
++      printk(KERN_ERR "Nand driver registered\n");
++      platform_driver_unregister(&monahans_df_driver);
++}
++
++static int __init monahans_df_init(void)
++{
++      return platform_driver_register(&monahans_df_driver);
++}
++
++module_init(monahans_df_init);
++module_exit(monahans_df_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jingqing.xu (jingqing.xu@intel.com)");
++MODULE_DESCRIPTION("Glue logic layer for NAND flash on monahans DFC");
++
++
+Index: linux-2.6.23/arch/arm/mach-pxa/zylonite.c
+===================================================================
+--- linux-2.6.23.orig/arch/arm/mach-pxa/zylonite.c     2008-02-12 21:12:29.000000000 +0000
++++ linux-2.6.23/arch/arm/mach-pxa/zylonite.c  2008-02-13 00:50:30.000000000 +0000
+@@ -29,6 +29,8 @@
+ #include "generic.h"
+ int gpio_backlight;
++int gpio_vsync;
++int gpio_vsync1;
+ int gpio_eth_irq;
+ int lcd_id;
+@@ -54,6 +56,11 @@
+       .resource       = smc91x_resources,
+ };
++static struct platform_device nand_device = {
++      .name           = "monahans-nand-flash",
++      .id             = -1,
++};
++
+ #if defined(CONFIG_FB_PXA) || (CONFIG_FB_PXA_MODULES)
+ static void zylonite_backlight_power(int on)
+ {
+@@ -96,7 +103,7 @@
+ };
+ static struct pxafb_mode_info sharp_ls037_modes[] = {
+-      [0] = {
++      [1] = {
+               .pixclock       = 158000,
+               .xres           = 240,
+               .yres           = 320,
+@@ -109,8 +116,8 @@
+               .lower_margin   = 3,
+               .sync           = 0,
+       },
+-      [1] = {
+-              .pixclock       = 39700,
++      [0] = {
++              .pixclock       = 45000,
+               .xres           = 480,
+               .yres           = 640,
+               .bpp            = 16,
+@@ -137,6 +144,11 @@
+       /* backlight GPIO: output, default on */
+       gpio_direction_output(gpio_backlight, 1);
++      gpio_direction_output(gpio_vsync, 0);
++      gpio_direction_output(gpio_vsync1, 0);
++
++      printk(KERN_ERR "LCD ID is %x\n", lcd_id);
++
+       if (lcd_id & 0x20) {
+               set_pxa_fb_info(&zylonite_sharp_lcd_info);
+               return;
+@@ -169,6 +181,8 @@
+       smc91x_resources[1].start = gpio_to_irq(gpio_eth_irq);
+       smc91x_resources[1].end   = gpio_to_irq(gpio_eth_irq);
+       platform_device_register(&smc91x_device);
++      platform_device_register(&nand_device);
++      printk(KERN_ERR "Nand device registered\n");
+       zylonite_init_lcd();
+ }
+Index: linux-2.6.23/arch/arm/mach-pxa/zylonite_pxa300.c
+===================================================================
+--- linux-2.6.23.orig/arch/arm/mach-pxa/zylonite_pxa300.c      2008-02-12 20:52:26.000000000 +0000
++++ linux-2.6.23/arch/arm/mach-pxa/zylonite_pxa300.c   2008-02-13 00:26:37.000000000 +0000
+@@ -104,6 +104,30 @@
+       /* Ethernet */
+       GPIO2_nCS3,
+       GPIO99_GPIO,
++
++      /* NAND */
++      MFP_CFG_X(DF_INT_RnB, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nRE_nOE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nWE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_CLE_nOE, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nADV1_ALE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nCS0, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nCS1, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_IO0, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO1, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO2, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO3, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO4, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO5, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO6, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO7, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO8, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO9, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO10, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO11, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO12, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO13, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO14, AF1, DS08X, PULL_LOW),
+ };
+ static mfp_cfg_t pxa310_mfp_cfg[] __initdata = {
+@@ -163,6 +187,9 @@
+               pxa3xx_mfp_write(lcd_detect_pins[i], mfpr_save[i]);
+ }
++extern int gpio_vsync;
++extern int gpio_vsync1;
++
+ void __init zylonite_pxa300_init(void)
+ {
+       if (cpu_is_pxa300() || cpu_is_pxa310()) {
+@@ -174,6 +201,8 @@
+               /* GPIO pin assignment */
+               gpio_backlight = mfp_to_gpio(MFP_PIN_GPIO20);
++              gpio_vsync = mfp_to_gpio(GPIO76_LCD_VSYNC);
++              gpio_vsync1 = mfp_to_gpio(GPIO71_LCD_LDD_17);
+       }
+       if (cpu_is_pxa300()) {
+Index: linux-2.6.23/drivers/video/pxafb.c
+===================================================================
+--- linux-2.6.23.orig/drivers/video/pxafb.c    2008-02-13 00:05:42.000000000 +0000
++++ linux-2.6.23/drivers/video/pxafb.c 2008-02-13 00:06:02.000000000 +0000
+@@ -1543,9 +1543,9 @@
+         if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
+                 dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: %08x\n",
+                         inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
+-        if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
+-                dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
+-                        inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
++        //if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
++        //        dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
++        //                inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
+         if (inf->lccr0 & LCCR0_DPD &&
+           ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
+            (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
+Index: linux-2.6.23/include/asm-arm/arch-pxa/mfp-pxa300.h
+===================================================================
+--- linux-2.6.23.orig/include/asm-arm/arch-pxa/mfp-pxa300.h    2008-02-13 00:44:38.000000000 +0000
++++ linux-2.6.23/include/asm-arm/arch-pxa/mfp-pxa300.h 2008-02-13 00:49:38.000000000 +0000
+@@ -175,13 +175,13 @@
+ #define GPIO68_LCD_LDD_14     MFP_CFG_DRV(GPIO68, AF1, DS01X)
+ #define GPIO69_LCD_LDD_15     MFP_CFG_DRV(GPIO69, AF1, DS01X)
+ #define GPIO70_LCD_LDD_16     MFP_CFG_DRV(GPIO70, AF1, DS01X)
+-#define GPIO71_LCD_LDD_17     MFP_CFG_DRV(GPIO71, AF1, DS01X)
++#define GPIO71_LCD_LDD_17     MFP_CFG_DRV(GPIO71, AF0, DS01X)
+ #define GPIO62_LCD_CS_N               MFP_CFG_DRV(GPIO62, AF2, DS01X)
+ #define GPIO72_LCD_FCLK               MFP_CFG_DRV(GPIO72, AF1, DS01X)
+ #define GPIO73_LCD_LCLK               MFP_CFG_DRV(GPIO73, AF1, DS01X)
+ #define GPIO74_LCD_PCLK               MFP_CFG_DRV(GPIO74, AF1, DS01X)
+ #define GPIO75_LCD_BIAS               MFP_CFG_DRV(GPIO75, AF1, DS01X)
+-#define GPIO76_LCD_VSYNC      MFP_CFG_DRV(GPIO76, AF2, DS01X)
++#define GPIO76_LCD_VSYNC      MFP_CFG_DRV(GPIO76, AF0, DS01X)
+ #define GPIO15_LCD_CS_N               MFP_CFG_DRV(GPIO15,  AF2, DS01X)
+ #define GPIO127_LCD_CS_N      MFP_CFG_DRV(GPIO127, AF1, DS01X)
index 6c6c229f09bc9371b6987cbdd5510fbe0f382c1e..c9b20de4855981f885a24810c2786899fb9ccc87 100644 (file)
@@ -1,6 +1,6 @@
 require linux-rp.inc
 
-PR = "r29"
+PR = "r30"
 
 # Handy URLs
 # git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git;protocol=git;tag=ef7d1b244fa6c94fb76d5f787b8629df64ea4046
@@ -138,6 +138,7 @@ SRC_URI_append_zylonite ="\
        file://arm_pxa_20070923.patch;patch=1 \
        file://pxa_fb_overlay.patch;patch=1 \
        file://zylonite-boot.patch;patch=1 \
+       file://zylonite_mtd-r0.patch;patch=1 \
        "
 
 S = "${WORKDIR}/linux-2.6.23"