1. add mtd rk29 nandc driver & yaffs2 2.modify rk29_sdk_defconfig to enable I/D cache...
authorhxy <hxy@rock-chips.com>
Sat, 6 Nov 2010 03:58:19 +0000 (11:58 +0800)
committerhxy <hxy@rock-chips.com>
Sat, 6 Nov 2010 03:58:19 +0000 (11:58 +0800)
arch/arm/configs/rk29_sdk_defconfig
arch/arm/mach-rk2818/devices.c
arch/arm/mach-rk29/board-rk29sdk.c
arch/arm/mach-rk29/devices.c
arch/arm/mach-rk29/devices.h
arch/arm/mach-rk29/include/mach/rk29_nand.h [new file with mode: 0644]
arch/arm/mach-rk29/io.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/rk29_nand.c [new file with mode: 0644]
fs/yaffs2/yaffs_fs.c

index 22664fc85e3f0b151765628d98265f8db8cd6f1f..1f464a8388ac45cffac7da9ba7a0ed3207c4fb5f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.32.9
-# Wed Oct 20 15:12:34 2010
+# Sat Nov  6 11:33:18 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -68,16 +68,10 @@ CONFIG_RESOURCE_COUNTERS=y
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="../initramfs"
-CONFIG_INITRAMFS_ROOT_UID=0
-CONFIG_INITRAMFS_ROOT_GID=0
-# CONFIG_RD_GZIP is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
-# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
-# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
-# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -224,8 +218,8 @@ CONFIG_CPU_CP15_MMU=y
 #
 CONFIG_ARM_THUMB=y
 # CONFIG_ARM_THUMBEE is not set
-CONFIG_CPU_ICACHE_DISABLE=y
-CONFIG_CPU_DCACHE_DISABLE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
 CONFIG_ARM_L1_CACHE_SHIFT=5
@@ -425,7 +419,89 @@ CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_RK29=y
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
@@ -435,6 +511,7 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
 CONFIG_MISC_DEVICES=y
 # CONFIG_ANDROID_PMEM is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
@@ -711,6 +788,11 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 #
 # CONFIG_RK2818_POWER is not set
 
+#
+# GPU Vivante
+#
+CONFIG_VIVANTE=y
+
 #
 # CMMB
 #
@@ -719,22 +801,12 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_XATTR=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
 # CONFIG_EXT4_FS is not set
-CONFIG_JBD=y
-CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
+# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
@@ -789,6 +861,18 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
+# CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -1040,6 +1124,8 @@ CONFIG_CRC16=y
 CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_REED_SOLOMON=y
 CONFIG_REED_SOLOMON_ENC8=y
 CONFIG_REED_SOLOMON_DEC8=y
index 97dfd87e64b1b6fbf68a040a7da494b7ef550316..b9132b80f8638c86626f523e0d2287ce8bc7cae9 100755 (executable)
@@ -28,7 +28,7 @@
 #include <linux/mtd/partitions.h>
 
 #include <mach/gpio.h>
-#include <mach/rk2818_nand.h>
+#include <mach/rk29_nand.h>
 #include <mach/iomux.h>
 #include <mach/rk2818_camera.h>                          /* ddl@rock-chips.com : camera support */
 #include <linux/i2c.h>  
index 16e21b452cf4ff3543251a85452a99b0a2c7105e..40d097a7bf5d191a3b04905c36f5cc7c1e60f6c1 100755 (executable)
@@ -35,6 +35,7 @@
 #include <mach/irqs.h>\r
 #include <mach/rk29_iomap.h>\r
 #include <mach/board.h>\r
+#include <mach/rk29_nand.h>\r
 \r
 \r
 #include <linux/mtd/nand.h>\r
 \r
 extern struct sys_timer rk29_timer;\r
 \r
+int rk29_nand_io_init(void)\r
+{\r
+    return 0;\r
+}\r
+\r
+struct rk29_nand_platform_data rk29_nand_data = {\r
+    .width      = 1,     /* data bus width in bytes */\r
+    .hw_ecc     = 1,     /* hw ecc 0: soft ecc */\r
+    .num_flash    = 1,\r
+    .io_init   = rk29_nand_io_init,\r
+};\r
 \r
 static struct rk29_gpio_bank rk29_gpiobankinit[] = {\r
        {\r
@@ -280,6 +292,9 @@ static struct platform_device *devices[] __initdata = {
 #ifdef CONFIG_UART1_RK29       \r
        &rk29_device_uart1,\r
 #endif \r
+#ifdef CONFIG_MTD_NAND_RK29\r
+       &rk29_device_nand,\r
+#endif\r
 \r
 #ifdef CONFIG_FB_RK29\r
     &rk29_device_fb,\r
index ba31c5790368b2ca1ed46d1c7be6d99b286c6f8f..117d8891848d57e32cfb69e6bf4ed1cc44edafee 100755 (executable)
@@ -20,6 +20,7 @@
 #include <mach/irqs.h>
 #include <mach/rk29_iomap.h>
  
+#include "devices.h" 
  
 /*
  * rk29 4 uarts device
@@ -172,4 +173,24 @@ struct platform_device rk29_device_fb = {
        }
 };
 #endif
+#if defined(CONFIG_MTD_NAND_RK29)  
+static struct resource nand_resources[] = {
+       {
+               .start  = RK29_NANDC_PHYS,
+               .end    =       RK29_NANDC_PHYS+RK29_NANDC_SIZE -1,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+struct platform_device rk29_device_nand = {
+       .name   = "rk29-nand",
+       .id             =  -1, 
+       .resource       = nand_resources,
+       .num_resources= ARRAY_SIZE(nand_resources),
+       .dev    = {
+               .platform_data= &rk29_nand_data,
+       },
+       
+};
+#endif
 
index e2e28e8346dcdb59cde31a09d15aeda2c8124ca4..134f662e9bbab5b1a23e4501e0e487066569f575 100755 (executable)
@@ -16,6 +16,7 @@
 #ifndef __ARCH_ARM_MACH_RK29_DEVICES_H
 #define __ARCH_ARM_MACH_RK29_DEVICES_H
 
+extern struct rk29_nand_platform_data rk29_nand_data;
 
 extern struct platform_device rk29_device_uart0;
 extern struct platform_device rk29_device_uart1;
@@ -23,5 +24,6 @@ extern struct platform_device rk29_device_uart2;
 extern struct platform_device rk29_device_uart3;
 extern struct platform_device rk29_device_gpu;
 extern struct platform_device rk29_device_fb;
+extern struct platform_device rk29_device_nand;
 
 #endif
\ No newline at end of file
diff --git a/arch/arm/mach-rk29/include/mach/rk29_nand.h b/arch/arm/mach-rk29/include/mach/rk29_nand.h
new file mode 100644 (file)
index 0000000..0d1b116
--- /dev/null
@@ -0,0 +1,128 @@
+
+/*
+ * arch/arm/mach-rk29/include/mach/rk29_nand.h
+ *
+ * Copyright (C) 2010 RockChip, Inc.
+ * Author: 
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ASM_ARCH_RK29_NAND_H
+#define __ASM_ARCH_RK29_NAND_H
+
+
+//BCHCTL¼Ä´æÆ÷
+#define     BCH_WR                  0x0002
+#define     BCH_RST                 0x0001
+//FLCTL¼Ä´æÆ÷
+#define     FL_RDY                     (0x1<<20)
+#define     FL_LBA_EN                  (0x1<<11)
+#define     FL_COR_EN                  (0x1<<10)
+#define     FL_INT_EN                  (0x1<<9)
+#define     FL_INTCLR                  (0x1<<8)
+#define     FL_STMOD                   (0x1<<7)
+#define     FL_TRCNT                   (0x3<<5)
+#define     FL_STADDR                  (0x1<<4)
+#define     FL_BYPASS                  (0x1<<3)
+#define     FL_START                   (0x1<<2)
+#define     FL_RDN                     (0x1<<1)
+#define     FL_RST                     (0x1<<0)
+//FMCTL¼Ä´æÆ÷
+#define     FMC_WP                     (0x1<<8)
+#define     FMC_FRDY                           (0x1<<9)
+#define     FMC_FRDY_INT_EN    (0x1<<10)
+#define     FMC_FRDY_INT_CLR           (0x1<<11)
+//FMWAIT¼Ä´æÆ÷
+#define     FMW_RWCS_OFFSET            0
+#define     FMW_RWPW_OFFSET    5
+#define     FMW_RDY                             (0x1<<11)
+#define     FMW_CSRW_OFFSET            12
+#define     FMW_DLY_OFFSET             24//16
+
+struct rk29_nand_timing {
+       unsigned int    tCH;  /* Enable signal hold time */
+       unsigned int    tCS;  /* Enable signal setup time */
+       unsigned int    tWH;  /* ND_nWE high duration */
+       unsigned int    tWP;  /* ND_nWE pulse time */
+       unsigned int    tRH;  /* ND_nRE high duration */
+       unsigned int    tRP;  /* ND_nRE pulse width */
+       unsigned int    tR;   /* ND_nWE high to ND_nRE low for read */
+       unsigned int    tWHR; /* ND_nWE high to ND_nRE low for status read */
+       unsigned int    tAR;  /* ND_ALE low to ND_nRE low delay */
+};
+
+struct rk29_nand_cmdset {
+       uint16_t        read1;
+       uint16_t        read2;
+       uint16_t        program;
+       uint16_t        read_status;
+       uint16_t        read_id;
+       uint16_t        erase;
+       uint16_t        reset;
+       uint16_t        lock;
+       uint16_t        unlock;
+       uint16_t        lock_status;
+};
+
+typedef volatile struct tagCHIP_IF
+{
+           uint32_t data;
+           uint32_t addr;
+           uint32_t cmd;
+           uint32_t RESERVED[0x3d];
+}CHIP_IF, *pCHIP_IF;
+
+//NANDC Registers
+typedef volatile struct tagNANDC
+{
+       volatile  uint32_t FMCTL; 
+       volatile  uint32_t FMWAIT;
+       volatile  uint32_t FLCTL;
+       volatile  uint32_t BCHCTL; 
+       volatile  uint32_t BCHST; 
+       volatile  uint32_t RESERVED1[(0x200-0x14)/4];   //FLR
+       volatile  uint32_t spare[0x200/4]; 
+          volatile  uint32_t FMCTL1; 
+       volatile  uint32_t FMWAIT1;
+       volatile  uint32_t FLCTL1;
+       volatile  uint32_t BCHCTL1; 
+       volatile  uint32_t BCHST1; 
+       volatile  uint32_t RESERVED2[(0x200-0x14)/4]; 
+          volatile  uint32_t RESERVED3[0x200/4]; 
+       volatile  CHIP_IF chip[8];
+       volatile  uint32_t buf[0x800/4]; 
+}NANDC, *pNANDC;
+
+struct rk29_nand_flash {
+       const struct rk29_nand_timing *timing;        /* NAND Flash timing */
+       const struct rk29_nand_cmdset *cmdset;
+
+       uint32_t page_per_block;                /* Pages per block (PG_PER_BLK) */
+       uint32_t page_size;                             /* Page size in bytes (PAGE_SZ) */
+       uint32_t flash_width;                   /* Width of Flash memory (DWIDTH_M) */
+       uint32_t num_blocks;                    /* Number of physical blocks in Flash */
+       uint32_t chip_id;
+};
+
+struct rk29_nand_platform_data {
+       
+       int width;                      /* data bus width in bytes */
+       int hw_ecc;                     /* 1:hw ecc,    0: soft ecc */
+       struct mtd_partition *parts;
+       unsigned int    nr_parts;
+       size_t          num_flash;
+    int (*io_init)(void);
+    int (*io_deinit)(void);
+};
+
+
+#endif /* __ASM_ARCH_RK29_NAND_H */
+
index 163fffe13c215995c4f7af1020d454ddd37d0600..9f681ccb3b9455fd801b4d3c12585e44f0c76926 100644 (file)
@@ -45,6 +45,7 @@ static struct map_desc rk29_io_desc[] __initdata = {
        RK29_DEVICE(GPIO4),
        RK29_DEVICE(GPIO5),
        RK29_DEVICE(GPIO6),
+       RK29_DEVICE(NANDC),
 };
 
 void __init rk29_map_common_io(void)
index 6e999604337e87c7b497c2e5c95fbb91209911c0..623a645b808e090209a9f675940ecd88a609d3d6 100644 (file)
@@ -365,6 +365,11 @@ config MTD_NAND_RK2818
         depends on ARCH_RK2818
         help
           This enables the NAND flash controller on the RK2818 SoC
+config MTD_NAND_RK29
+        tristate "NAND Flash support for RK29sdk"
+        depends on ARCH_RK29
+        help
+          This enables the NAND flash controller on the RK29 SoC
           
 config MTD_NAND_PXA3xx
        tristate "Support for NAND flash devices on PXA3xx"
index 063518202051dc0f9eb5ec63b57b42d3d38671e1..36ee8b51a5101427715eff7cd741a4e5b7381772 100644 (file)
@@ -43,5 +43,5 @@ obj-$(CONFIG_MTD_NAND_TXX9NDFMC)      += txx9ndfmc.o
 obj-$(CONFIG_MTD_NAND_W90P910)         += w90p910_nand.o
 obj-$(CONFIG_MTD_NAND_NOMADIK)         += nomadik_nand.o
 obj-$(CONFIG_MTD_NAND_RK2818)          += rk2818_nand.o
-
+obj-$(CONFIG_MTD_NAND_RK29)            += rk29_nand.o
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/rk29_nand.c b/drivers/mtd/nand/rk29_nand.c
new file mode 100644 (file)
index 0000000..dc36e5f
--- /dev/null
@@ -0,0 +1,1096 @@
+
+/*
+ * drivers/mtd/nand/rk29_nand.c
+ *
+ * Copyright (C) 2010 RockChip, Inc.
+ * Author: hxy@rock-chips.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.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/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/rk29_nand.h>
+#include <mach/rk29_iomap.h>
+#include <mach/iomux.h>
+
+#define PROGRAM_BUSY_COUNT   10000
+#define ERASE_BUSY_COUNT           20000
+#define READ_BUSY_COUNT            5000
+#define RESET_BUSY_COUNT                       20000
+
+/* Define delays in microsec for NAND device operations */
+#define TROP_US_DELAY   2000
+
+
+#ifdef CONFIG_DM9000_USE_NAND_CONTROL
+static DEFINE_MUTEX(rknand_mutex);
+#define RKNAND_LOCK()   do { int panic = in_interrupt() | in_atomic(); if (!panic) mutex_lock(&rknand_mutex); } while (0)
+#define RKNAND_UNLOCK() do { int panic = in_interrupt() | in_atomic(); if (!panic) mutex_unlock(&rknand_mutex); } while (0)
+#else
+#define RKNAND_LOCK()   do {} while (0)
+#define RKNAND_UNLOCK() do {} while (0)
+#endif
+
+struct rk29_nand_mtd {
+       struct mtd_info         mtd;
+       struct nand_chip                nand;
+       struct mtd_partition    *parts;
+       struct device           *dev;
+       const struct rk29_nand_flash *flash_info;
+
+       struct clk                      *clk;
+       unsigned long                   clk_rate;
+       void __iomem                    *regs;
+       int                                     cs;                     // support muliple nand chip,record current chip select
+       u_char                          accesstime;
+#ifdef CONFIG_CPU_FREQ
+       struct notifier_block   freq_transition;
+#endif
+
+};
+
+/* OOB placement block for use with software ecc generation */
+static struct nand_ecclayout nand_sw_eccoob_8 = {
+       .eccbytes = 48,
+       .eccpos = { 8, 9, 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
+                         32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55},
+       .oobfree = {{0,8},{56, 72}}
+};
+
+/* OOB placement block for use with hardware ecc generation */
+static struct nand_ecclayout nand_hw_eccoob_16 = {
+       .eccbytes = 28,
+       .eccpos = { 4,  5, 6,  7,  8, 9, 10,11,12,13,14,15,16,17,
+                         18,19,20,21,22,23,24,25,26,27,28,29,30,31},
+       .oobfree = {{0, 4}}
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+
+static void rk29_nand_wait_busy(struct mtd_info *mtd, uint32_t timeout)
+{
+      
+    struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+       
+       while (timeout > 0)
+       {
+               timeout--;
+               udelay(10);
+               if ( pRK29NC->FMCTL& FMC_FRDY) 
+                       break;
+               
+       }
+       
+    return;
+}
+
+static void rk29_nand_wait_bchdone(struct mtd_info *mtd, uint32_t timeout)
+{
+      
+    struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+       
+       while (timeout > 0)
+       {
+               timeout--;
+               udelay(1);
+               if(pRK29NC->BCHST &(1<<1))
+                       break;          
+       }
+       
+    return;
+}
+
+// only for dma mode 
+static void wait_op_done(struct mtd_info *mtd, int max_retries, uint16_t param)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+       
+       while (max_retries-- > 0) {
+               udelay(1);
+               if (pRK29NC->FLCTL & FL_RDY)
+                       break;          
+       }             
+}
+
+static int rk29_nand_dev_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+         
+       if(pRK29NC->FMCTL& FMC_FRDY)
+          return 1;
+       else
+          return 0;
+}
+
+/*
+*  ÉèÖÃƬѡ
+*/
+static void rk29_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+
+                  
+       if( chip<0 )
+            pRK29NC->FMCTL &=0xffffff00;   // release chip select
+       else
+         {
+              master->cs = chip;
+               pRK29NC->FMCTL &=0xffffff00;
+               pRK29NC ->FMCTL |= 0x1<<chip;  // select chip
+         }
+       
+}
+
+/*
+ *   ¶ÁÒ»¸ö×Ö½ÚÊý¾Ý
+*/
+static u_char rk29_nand_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+       
+       u_char ret = 0; 
+         
+       ret = (u_char)(pRK29NC ->chip[master->cs].data);
+
+       return ret;
+}
+
+/*
+ *   ¶ÁÒ»¸öword ³¤¶ÈÊý¾Ý
+*/
+static u16 rk29_nand_read_word(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+
+       
+       u_char tmp1 = 0,tmp2=0;
+       u16 ret=0;
+       
+       tmp1 = (u_char)(pRK29NC ->chip[master->cs].data);
+       tmp2 = (u_char)(pRK29NC ->chip[master->cs].data);
+
+       ret =   (tmp2 <<8)|tmp1;
+       
+       return ret;
+}
+
+static void rk29_nand_read_buf(struct mtd_info *mtd, u_char* const buf, int len)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+       uint32_t  i, chipnr;
+        
+       RKNAND_LOCK();
+
+       chipnr = master->cs ;
+          
+       rk29_nand_select_chip(mtd,chipnr);
+       
+       
+       
+       if ( len < mtd->writesize )   // read oob
+       {
+               pRK29NC ->BCHCTL = BCH_RST;
+              pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;         
+               wait_op_done(mtd,TROP_US_DELAY,0);
+               rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;  
+               memcpy(buf,(u_char *)(pRK29NC->spare),4);  //  only use nandc sram0
+       }
+       else
+       {
+           pRK29NC->FLCTL |= FL_BYPASS;  // dma mode           
+           for(i=0;i<mtd->writesize/0x400;i++)
+               {
+                      pRK29NC ->BCHCTL = BCH_RST;
+               pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;        
+                       wait_op_done(mtd,TROP_US_DELAY,0);
+                       rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;
+               memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400);  //  only use nandc sram0
+               }
+       }
+
+       
+       
+       rk29_nand_select_chip(mtd,-1);
+
+       RKNAND_UNLOCK();
+
+       
+       return; 
+
+}
+
+static void rk29_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+     
+       uint32_t  i = 0, chipnr;
+          
+        
+        RKNAND_LOCK();
+
+        chipnr = master->cs ;
+
+       rk29_nand_select_chip(mtd,chipnr);
+       
+         pRK29NC->FLCTL |= FL_BYPASS;  // dma mode
+         
+          
+         for(i=0;i<mtd->writesize/0x400;i++)
+           {
+              memcpy((u_char *)(pRK29NC->buf),buf+i*0x400,0x400);  //  only use nandc sram0    
+               pRK29NC ->BCHCTL =BCH_WR|BCH_RST;               
+               pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|0x1<<5|FL_RDN|FL_BYPASS|FL_START;
+               wait_op_done(mtd,TROP_US_DELAY,0);      
+           }
+       
+
+         
+       rk29_nand_select_chip(mtd,-1);
+         
+         RKNAND_UNLOCK();
+
+
+}
+
+
+static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, int page_addr)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+
+       uint32_t timeout = 1000;
+       char status,ret;
+
+       
+       switch (command) {
+
+       case NAND_CMD_READID:
+               pRK29NC ->chip[master->cs].cmd = command;
+               pRK29NC ->chip[master->cs].addr = 0x0;
+               while (timeout>0)
+               {
+                 timeout --;
+                  udelay(1);  
+                 if(pRK29NC->FLCTL&FL_INTCLR)
+                        break;
+                 
+               }
+               
+               rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
+               break;
+               
+       case NAND_CMD_READ0:
+              pRK29NC ->chip[master->cs].cmd = command;
+              if ( column>= 0 )
+                {
+                   pRK29NC ->chip[master->cs].addr = column & 0xff;    
+                   if( mtd->writesize > 512) 
+                        pRK29NC ->chip[master->cs].addr = (column >> 8) & 0xff;
+                }
+               if ( page_addr>=0 )
+                  {
+                       pRK29NC ->chip[master->cs].addr = page_addr & 0xff;
+                       pRK29NC ->chip[master->cs].addr = (page_addr >> 8) & 0xFF;
+                       pRK29NC ->chip[master->cs].addr = (page_addr >> 16) & 0xff;
+                  }
+               if( mtd->writesize > 512)
+                   pRK29NC ->chip[0].cmd = NAND_CMD_READSTART;
+
+               rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
+               
+               break;
+               
+       case NAND_CMD_READ1:
+              pRK29NC ->chip[master->cs].cmd = command;
+               break;
+               
+       case NAND_CMD_READOOB:
+               pRK29NC ->BCHCTL = 0x0;         
+               if( mtd->writesize > 512 )
+                       command = NAND_CMD_READ0;  // È«²¿¶Á£¬°üÀ¨¶Áoob
+               
+               pRK29NC ->chip[master->cs].cmd = command;  
+
+              if ( mtd->writesize >512 )
+               {
+                       if ( column>= 0 )
+                        {
+                          pRK29NC ->chip[master->cs].addr = column  & 0xff;    
+                            pRK29NC ->chip[master->cs].addr = ( column   >> 8) & 0xff;
+                        }
+                       if ( page_addr>=0 )
+                          {
+                               pRK29NC ->chip[master->cs].addr = page_addr & 0xff;
+                               pRK29NC ->chip[master->cs].addr = (page_addr >> 8) & 0xFF;
+                               pRK29NC ->chip[master->cs].addr = (page_addr >> 16) & 0xff;
+                          }
+                       pRK29NC ->chip[master->cs].cmd = NAND_CMD_READSTART;
+              }
+               else
+               {
+                  pRK29NC ->chip[master->cs].addr = column;
+               }
+                       
+               rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
+               
+        
+               break;  
+               
+       case NAND_CMD_PAGEPROG:
+               pRK29NC ->FMCTL |= FMC_WP;  //½â³ýд±£»¤
+               pRK29NC ->chip[master->cs].cmd = command;
+               rk29_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT);
+               
+               pRK29NC ->chip[master->cs].cmd  = NAND_CMD_STATUS;
+               status = pRK29NC ->chip[master->cs].data;
+               
+               if(status&0x1)
+                       ret = -1;
+               else
+                       ret =0;
+               
+               break;
+               
+       case NAND_CMD_ERASE1:
+               pRK29NC ->FMCTL |= FMC_WP;  //½â³ýд±£»¤
+               pRK29NC ->BCHCTL = 0x0;
+               pRK29NC ->chip[master->cs].cmd  = command;
+               if ( page_addr>=0 )
+                  {
+                       pRK29NC ->chip[master->cs].addr = page_addr & 0xff;
+                       pRK29NC ->chip[master->cs].addr = (page_addr>>8)&0xff;
+                       pRK29NC ->chip[master->cs].addr = (page_addr>>16)&0xff;
+                  }  
+               break;
+               
+       case NAND_CMD_ERASE2:
+               pRK29NC ->FMCTL |= FMC_WP;  //½â³ýд±£»¤
+               pRK29NC ->chip[master->cs].cmd  = command;             
+               rk29_nand_wait_busy(mtd,ERASE_BUSY_COUNT);
+               pRK29NC ->chip[master->cs].cmd  = NAND_CMD_STATUS;
+               status = pRK29NC ->chip[master->cs].data;
+               
+               if(status&0x1)
+                       ret = -1;
+               else
+                       ret =0;
+               
+               break;
+               
+       case NAND_CMD_SEQIN:
+               pRK29NC ->FMCTL |= FMC_WP;  //½â³ýд±£»¤
+               pRK29NC ->chip[master->cs].cmd  = command;
+              udelay(1);
+               if ( column>= 0 )
+                 {
+                   pRK29NC ->chip[master->cs].addr = column;
+                    if( mtd->writesize > 512) 
+                      pRK29NC ->chip[master->cs].addr = (column >> 8) & 0xff;
+                 }
+               if( page_addr>=0 )
+                 {
+                       pRK29NC ->chip[master->cs].addr = page_addr & 0xff;
+                       pRK29NC ->chip[master->cs].addr = (page_addr>>8)&0xff;
+                       pRK29NC ->chip[master->cs].addr = (page_addr>>16)&0xff;
+                }
+               
+               break;
+               
+       case NAND_CMD_STATUS:
+               pRK29NC ->BCHCTL = 0x0;
+               pRK29NC ->chip[master->cs].cmd = command;
+               while (timeout>0)
+               {
+                 timeout --;
+                  udelay(1);  
+                 if(pRK29NC->FLCTL&FL_INTCLR)
+                        break;
+                 
+               }
+               break;
+
+       case NAND_CMD_RESET:
+               pRK29NC ->chip[master->cs].cmd = command;
+               while (timeout>0)
+               {
+                 timeout --;
+                  udelay(1);  
+                 if(pRK29NC->FLCTL&FL_INTCLR)
+                        break;
+                 
+               }
+               rk29_nand_wait_busy(mtd,RESET_BUSY_COUNT);
+               break;
+
+       /* This applies to read commands */
+       default:
+              pRK29NC ->chip[master->cs].cmd = command;
+               break;
+       }
+
+       udelay (1);
+   
+}
+
+int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc_code)
+{
+     struct nand_chip *nand_chip = mtd->priv;
+     struct rk29_nand_mtd *master = nand_chip->priv;
+     pNANDC pRK29NC=  (pNANDC)(master->regs);
+     int eccdata[7],i;
+        
+       for(i=0;i<7;i++) 
+        {
+           eccdata[i] = pRK29NC->spare[i+1];
+
+                  
+           ecc_code[i*4] = eccdata[i]& 0xff;
+           ecc_code[i*4+1] = (eccdata[i]>> 8)& 0xff;
+           ecc_code[i*4+2] = (eccdata[i]>>16)& 0xff;
+           ecc_code[i*4+3] = (eccdata[i]>>24)& 0xff;
+                 
+         }             
+       
+     return 0;
+}
+
+ void rk29_nand_hwctl_ecc(struct mtd_info *mtd, int mode)
+ {
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+
+       pRK29NC->BCHCTL = 1;  // reset bch and enable hw ecc
+               
+       return;
+ }
+ int rk29_nand_correct_data(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,uint8_t *calc_ecc)
+ {
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);                
+
+       // hw correct data
+       if( pRK29NC->BCHST & (1<<2) )
+        {
+               DEBUG(MTD_DEBUG_LEVEL0,
+                     "rk2818 nand :hw ecc uncorrectable error\n");
+               return -1;
+       }
+       
+       return 0;
+ }
+ int rk29_nand_read_page(struct mtd_info *mtd,struct nand_chip *chip,uint8_t *buf, int page)
+ {
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+         
+       int i,chipnr;
+
+          
+       RKNAND_LOCK();
+
+       chipnr = master->cs ;
+       
+       rk29_nand_select_chip(mtd,chipnr);
+       rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
+          
+       pRK29NC->FLCTL |= FL_BYPASS;  // dma mode
+         
+       for(i=0;i<mtd->writesize/0x400;i++)
+       {
+              pRK29NC ->BCHCTL = BCH_RST;
+              pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;         
+               wait_op_done(mtd,TROP_US_DELAY,0);   
+               rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;
+          
+              memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400);  //  only use nandc sram0
+       }
+       
+               
+       rk29_nand_select_chip(mtd,-1);
+
+       RKNAND_UNLOCK();
+       
+    return 0;
+       
+ }
+
+void  rk29_nand_write_page(struct mtd_info *mtd,struct nand_chip *chip,const uint8_t *buf)
+ {
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+       uint32_t  i = 0, chipnr;
+          
+       RKNAND_LOCK();
+
+       chipnr = master->cs ;
+          
+       rk29_nand_select_chip(mtd,chipnr);
+       
+       pRK29NC->FLCTL |= FL_BYPASS;  // dma mode
+
+               
+         for(i=0;i<mtd->writesize/0x400;i++)
+          {
+              memcpy((u_char *)(pRK29NC->buf),(buf+i*0x400),0x400);  //  only use nandc sram0          
+              if(i==0)
+                  memcpy((u_char *)(pRK29NC->spare),(u_char *)(chip->oob_poi + chip->ops.ooboffs),4);  
+                       
+               pRK29NC ->BCHCTL = BCH_WR|BCH_RST;              
+               pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_RDN|FL_BYPASS|FL_START;
+               wait_op_done(mtd,TROP_US_DELAY,0);      
+          }
+
+         pRK29NC ->chip[0].cmd = NAND_CMD_PAGEPROG;
+        
+
+         
+         rk29_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT);
+         
+        rk29_nand_select_chip(mtd,-1);
+
+     RKNAND_UNLOCK();
+       
+    return;
+         
+ }
+
+int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd)
+{      
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+       int i,chipnr;
+
+         
+       if (sndcmd) {
+               chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+               sndcmd = 0;
+       }
+
+       RKNAND_LOCK();
+
+       chipnr = master->cs ;
+
+       rk29_nand_select_chip(mtd,chipnr);
+
+       rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
+
+       
+       pRK29NC->FLCTL |= FL_BYPASS;  // dma mode
+
+       
+
+       
+       for(i=0;i<mtd->writesize/0x400;i++)
+       {
+              pRK29NC ->BCHCTL = BCH_RST;
+              pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;         
+               wait_op_done(mtd,TROP_US_DELAY,0);   
+               rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;          
+              if(i==0)
+                 memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK29NC->spare),4); 
+       }
+
+          
+        rk29_nand_select_chip(mtd,-1);
+
+        RKNAND_UNLOCK();
+
+
+       return sndcmd;
+}
+
+int    rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct rk29_nand_mtd *master = nand_chip->priv;
+       pNANDC pRK29NC=  (pNANDC)(master->regs);
+
+       int i,chipnr;
+
+       
+    RKNAND_LOCK();
+
+       chipnr = master->cs ;
+       
+       rk29_nand_select_chip(mtd,chipnr);
+
+       rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
+          
+       pRK29NC->FLCTL |= FL_BYPASS;  // dma mode
+
+       
+          
+       for(i=0;i<mtd->writesize/0x400;i++)
+       {
+              pRK29NC ->BCHCTL = BCH_RST;
+              pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;         
+               wait_op_done(mtd,TROP_US_DELAY,0);   
+               rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;          
+              memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400);  //  only use nandc sram0
+              if(i==0)
+                 memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK29NC->spare),4); 
+       }
+
+        
+        rk29_nand_select_chip(mtd,-1);
+        RKNAND_UNLOCK();
+
+        
+    return 0;
+}
+
+static int rk29_nand_setrate(struct rk29_nand_mtd *info)
+{
+       pNANDC pRK29NC=  (pNANDC)(info->regs);
+       
+       unsigned long clkrate = clk_get_rate(info->clk);
+
+       u_char accesstime,rwpw,csrw,rwcs;
+
+       unsigned int ns=0,timingcfg;
+
+       unsigned long flags; 
+
+       //scan nand flash access time
+       if ( info->accesstime ==0x00 )
+              accesstime=50;
+       else if ( info->accesstime==0x80)
+               accesstime=25;
+       else if ( info->accesstime==0x08)
+               accesstime=20;
+       else
+               accesstime=60;   //60ns
+#if 0
+       info->clk_rate = clkrate;
+       clkrate /= 1000000;     /* turn clock into MHz for ease of use */
+       
+       if(clkrate>0 && clkrate<200)
+          ns= 1000/clkrate; // ns
+        else
+          return -1;
+               
+       timingcfg = (accesstime + ns -1)/ns;
+
+       timingcfg = (timingcfg>=3) ? (timingcfg-2) : timingcfg;           //csrw+1, rwcs+1
+
+       rwpw = timingcfg-timingcfg/4;
+       csrw = timingcfg/4;
+       rwcs = (timingcfg/4 >=1)?(timingcfg/4):1;
+#else
+       rwpw = 4;
+       csrw = 1;
+       rwcs = 2;
+#endif
+
+       RKNAND_LOCK();
+
+       pRK29NC ->FMWAIT |=  (rwcs<<FMW_RWCS_OFFSET)|(rwpw<<FMW_RWPW_OFFSET)|(csrw<<FMW_CSRW_OFFSET);
+
+       RKNAND_UNLOCK();
+
+
+       return 0;
+}
+
+/* cpufreq driver support */
+
+#ifdef CONFIG_CPU_FREQ
+
+static int rk29_nand_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data)
+{
+       struct rk29_nand_mtd *info;
+       unsigned long newclk;
+
+       info = container_of(nb, struct rk29_nand_mtd, freq_transition);
+       newclk = clk_get_rate(info->clk);
+
+       if (val == CPUFREQ_POSTCHANGE && newclk != info->clk_rate) 
+        {
+               rk29_nand_setrate(info);
+       }
+
+       return 0;
+}
+
+static inline int rk29_nand_cpufreq_register(struct rk29_nand_mtd *info)
+{
+       info->freq_transition.notifier_call = rk29_nand_cpufreq_transition;
+
+       return cpufreq_register_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void rk29_nand_cpufreq_deregister(struct rk29_nand_mtd *info)
+{
+       cpufreq_unregister_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int rk29_nand_cpufreq_register(struct rk29_nand_mtd *info)
+{
+       return 0;
+}
+
+static inline void rk29_nand_cpufreq_deregister(struct rk29_nand_mtd *info)
+{
+}
+#endif
+
+
+static int rk29_nand_probe(struct platform_device *pdev)
+{
+       struct nand_chip *this;
+       struct mtd_info *mtd;
+       struct rk29_nand_platform_data *pdata = pdev->dev.platform_data;
+       struct rk29_nand_mtd *master;
+       struct resource *res;
+       int err = 0;
+       pNANDC pRK29NC;
+       u_char  maf_id,dev_id,ext_id3,ext_id4;
+    struct nand_chip *chip;
+    
+#ifdef CONFIG_MTD_PARTITIONS
+       struct mtd_partition *partitions = NULL;
+       int num_partitions = 0;
+#endif
+
+      /* Allocate memory for MTD device structure and private data */
+       master = kzalloc(sizeof(struct rk29_nand_mtd), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+        master->dev = &pdev->dev;
+       /* structures must be linked */
+       this = &master->nand;
+       mtd = &master->mtd;
+       mtd->priv = this;
+       mtd->owner = THIS_MODULE;
+       mtd->name = dev_name(&pdev->dev);
+          
+       /* 50 us command delay time */
+       this->chip_delay = 5;
+
+       this->priv = master;
+       this->dev_ready = rk29_nand_dev_ready;
+       this->cmdfunc = rk29_nand_cmdfunc;
+       this->select_chip = rk29_nand_select_chip;
+       this->read_byte = rk29_nand_read_byte;
+       this->read_word = rk29_nand_read_word;
+       this->write_buf = rk29_nand_write_buf;
+       this->read_buf = rk29_nand_read_buf;
+       this->options |= NAND_USE_FLASH_BBT;    // open bbt options
+       
+          
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               err = -ENODEV;
+               goto outres;
+       }
+
+       master->regs = ioremap(res->start, res->end - res->start + 1);
+       if (!master->regs) {
+               err = -EIO;
+               goto outres;
+       }
+
+       if (pdata->hw_ecc) {
+               this->ecc.calculate = rk29_nand_calculate_ecc;
+               this->ecc.hwctl = rk29_nand_hwctl_ecc;
+               this->ecc.correct = rk29_nand_correct_data;
+               this->ecc.mode = NAND_ECC_HW;
+               this->ecc.read_page = rk29_nand_read_page;
+               this->ecc.write_page = rk29_nand_write_page;
+               this->ecc.read_oob = rk29_nand_read_oob;
+               this->ecc.read_page_raw = rk29_nand_read_page_raw;
+               this->ecc.size = 1024;
+               this->ecc.bytes = 28;
+               this->ecc.layout = &nand_hw_eccoob_16;  
+       } else {
+               this->ecc.size = 256;
+               this->ecc.bytes = 3;
+               this->ecc.layout = &nand_sw_eccoob_8;
+               this->ecc.mode = NAND_ECC_SOFT;         
+       }
+
+
+
+       master->clk = clk_get(NULL, "nandc");
+
+       clk_enable(master->clk);
+       
+       pRK29NC =  (pNANDC)(master->regs);
+       pRK29NC ->FMCTL = FMC_WP|FMC_FRDY;
+       pRK29NC ->FMWAIT |=  (1<<FMW_RWCS_OFFSET)|(4<<FMW_RWPW_OFFSET)|(1<<FMW_CSRW_OFFSET);
+       pRK29NC ->BCHCTL = 0x1;
+
+       this->select_chip(mtd, 0);
+       this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+       maf_id = this->read_byte(mtd);
+       dev_id = this->read_byte(mtd);
+       ext_id3 = this->read_byte(mtd);
+       ext_id4 = this->read_byte(mtd);
+       
+       master->accesstime = ext_id4&0x88;
+       
+       rk29_nand_setrate(master);
+       
+       /* Reset NAND */
+       this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+       /* NAND bus width determines access funtions used by upper layer */
+       if (pdata->width == 2) {
+               this->options |= NAND_BUSWIDTH_16;
+               this->ecc.layout = &nand_hw_eccoob_16;
+       }
+      // iomux flash  cs1~cs7
+    if (pdata && pdata->io_init) {
+        pdata->io_init();
+    }  
+   
+       /* Scan to find existence of the device */
+#if 0
+          if (nand_scan(mtd, 8)) {     // rk2818 nandc support max 8 cs
+#else
+          if (nand_scan(mtd, 1)) {      // test for fpga board nand
+#endif
+               DEBUG(MTD_DEBUG_LEVEL0,
+                     "RK2818 NAND: Unable to find any NAND device.\n");
+               err = -ENXIO;
+               goto outscan;
+       }
+
+       //¸ù¾ÝƬѡÇé¿ö»Ö¸´IO MUXԭʼֵ
+#if 0
+    chip = mtd->priv;
+    switch(chip->numchips)
+    {
+        case 1:
+            rk2818_mux_api_mode_resume(GPIOA5_FLASHCS1_SEL_NAME);
+        case 2:
+            rk2818_mux_api_mode_resume(GPIOA6_FLASHCS2_SEL_NAME);
+        case 3:
+            rk2818_mux_api_mode_resume(GPIOA7_FLASHCS3_SEL_NAME);
+        case 4:
+            rk2818_mux_api_mode_resume(GPIOE_SPI1_FLASH_SEL1_NAME);
+        case 5:
+        case 6:
+            rk2818_mux_api_mode_resume(GPIOE_SPI1_FLASH_SEL_NAME);
+        case 7:
+        case 8:
+            break;
+        default:
+            DEBUG(MTD_DEBUG_LEVEL0, "RK2818 NAND: numchips error!!!\n");
+    }
+#endif    
+#if 0
+      // rk281x dma mode bch must  (1k data + 32 oob) bytes align , so cheat system writesize =1024,oobsize=32
+       mtd->writesize = 1024;
+       mtd->oobsize = 32;
+#endif
+
+#ifdef CONFIG_MTD_PARTITIONS
+        num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
+       if (num_partitions > 0) {
+               printk(KERN_INFO "Using commandline partition definition\n");
+              add_mtd_partitions(mtd, partitions, num_partitions);
+                if(partitions)
+                kfree(partitions);
+       } else if (pdata->nr_parts) {
+               printk(KERN_INFO "Using board partition definition\n");
+               add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
+       } else
+#endif
+       {
+               printk(KERN_INFO "no partition info available, registering whole flash at once\n");
+               add_mtd_device(mtd);
+       }
+
+       platform_set_drvdata(pdev, master);
+
+       err =rk29_nand_cpufreq_register(master);
+       if (err < 0) {
+               printk(KERN_ERR"rk2818 nand failed to init cpufreq support\n");
+               goto outscan;
+       }
+
+       return 0;
+       
+outres:
+outscan:
+       iounmap(master->regs);
+       kfree(master);
+
+       return err;
+       
+}
+
+static int rk29_nand_remove(struct platform_device *pdev)
+{
+       struct rk29_nand_mtd *master = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if(master == NULL)
+               return 0;
+
+       rk29_nand_cpufreq_deregister(master);
+       
+
+       nand_release(&master->mtd);
+
+       if(master->regs!=NULL){
+               iounmap(master->regs);
+               master->regs = NULL;
+       }
+
+       if (master->clk != NULL && !IS_ERR(master->clk)) {
+               clk_disable(master->clk);
+               clk_put(master->clk);
+       }
+       
+       kfree(master);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int rk29_nand_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct mtd_info *info = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL0, "RK2818_NAND : NAND suspend\n");
+       if (info)
+               ret = info->suspend(info);
+       return ret;
+}
+
+static int rk29_nand_resume(struct platform_device *pdev)
+{
+       struct mtd_info *info = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL0, "RK2818_NAND : NAND resume\n");
+       /* Enable the NFC clock */
+
+       if (info)
+               info->resume(info);
+
+       return ret;
+}
+#else
+#define rk29_nand_suspend   NULL
+#define rk29_nand_resume    NULL
+#endif /* CONFIG_PM */
+
+
+static struct platform_driver rk29_nand_driver = {
+       .driver = {
+                  .name = "rk29-nand",
+                  },
+       .probe    = rk29_nand_probe,
+       .remove = rk29_nand_remove,
+       .suspend = rk29_nand_suspend,
+       .resume = rk29_nand_resume,
+};
+
+static int __init rk29_nand_init(void)
+{
+       /* Register the device driver structure. */
+       printk("rk29_nand_init\n");
+       return platform_driver_register(&rk29_nand_driver);;
+}
+
+static void __exit rk29_nand_exit(void)
+{
+       /* Unregister the device structure */
+       platform_driver_unregister(&rk29_nand_driver);
+}
+
+#ifdef CONFIG_DM9000_USE_NAND_CONTROL
+// nandc dma cs mutex for dm9000 interface
+void rk29_nand_status_mutex_lock(void)
+{
+     pNANDC pRK29NC=  (pNANDC)RK2818_NANDC_BASE;
+     mutex_lock(&rknand_mutex);
+     pRK29NC->FMCTL &=0xffffff00;   // release chip select
+
+}
+
+int rk29_nand_status_mutex_trylock(void)
+{
+     pNANDC pRK29NC=  (pNANDC)RK2818_NANDC_BASE;
+     if( mutex_trylock(&rknand_mutex))
+       {
+               pRK29NC->FMCTL &=0xffffff00;   // release chip select
+               return 1;      // ready 
+       }
+      else
+               return 0;     // busy
+}
+
+void rk29_nand_status_mutex_unlock(void)
+{
+     mutex_unlock(&rknand_mutex);
+     return;
+}
+#endif
+
+module_init(rk29_nand_init);
+module_exit(rk29_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("hxy <hxy@rock-chips.com>");
+MODULE_DESCRIPTION("MTD NAND driver for rk29 device");
+
index b3f4f03127607d5e835b750a3682bc0c7a49da46..2910bac817b448952840fadc68be022515cbc1a1 100644 (file)
@@ -2189,7 +2189,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        dev->nReservedBlocks = 5;
        dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
        dev->inbandTags = options.inband_tags;
-#ifdef CONFIG_ARCH_RK2818
+#if defined (CONFIG_ARCH_RK2818) || (CONFIG_ARCH_RK29)
        dev->inbandTags = 1;
 #endif