From 94e13fa2d585581db946b10041eecca452a0fdca Mon Sep 17 00:00:00 2001 From: hxy Date: Sat, 6 Nov 2010 11:58:19 +0800 Subject: [PATCH] 1. add mtd rk29 nandc driver & yaffs2 2.modify rk29_sdk_defconfig to enable I/D cache and config mtd/yaffs2 filesystem --- arch/arm/configs/rk29_sdk_defconfig | 136 ++- arch/arm/mach-rk2818/devices.c | 2 +- arch/arm/mach-rk29/board-rk29sdk.c | 15 + arch/arm/mach-rk29/devices.c | 21 + arch/arm/mach-rk29/devices.h | 2 + arch/arm/mach-rk29/include/mach/rk29_nand.h | 128 +++ arch/arm/mach-rk29/io.c | 1 + drivers/mtd/nand/Kconfig | 5 + drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/rk29_nand.c | 1096 +++++++++++++++++++ fs/yaffs2/yaffs_fs.c | 2 +- 11 files changed, 1382 insertions(+), 28 deletions(-) create mode 100644 arch/arm/mach-rk29/include/mach/rk29_nand.h create mode 100644 drivers/mtd/nand/rk29_nand.c diff --git a/arch/arm/configs/rk29_sdk_defconfig b/arch/arm/configs/rk29_sdk_defconfig index 22664fc85e3f..1f464a8388ac 100644 --- a/arch/arm/configs/rk29_sdk_defconfig +++ b/arch/arm/configs/rk29_sdk_defconfig @@ -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 diff --git a/arch/arm/mach-rk2818/devices.c b/arch/arm/mach-rk2818/devices.c index 97dfd87e64b1..b9132b80f863 100755 --- a/arch/arm/mach-rk2818/devices.c +++ b/arch/arm/mach-rk2818/devices.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include /* ddl@rock-chips.com : camera support */ #include diff --git a/arch/arm/mach-rk29/board-rk29sdk.c b/arch/arm/mach-rk29/board-rk29sdk.c index 16e21b452cf4..40d097a7bf5d 100755 --- a/arch/arm/mach-rk29/board-rk29sdk.c +++ b/arch/arm/mach-rk29/board-rk29sdk.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -44,6 +45,17 @@ extern struct sys_timer rk29_timer; +int rk29_nand_io_init(void) +{ + return 0; +} + +struct rk29_nand_platform_data rk29_nand_data = { + .width = 1, /* data bus width in bytes */ + .hw_ecc = 1, /* hw ecc 0: soft ecc */ + .num_flash = 1, + .io_init = rk29_nand_io_init, +}; static struct rk29_gpio_bank rk29_gpiobankinit[] = { { @@ -280,6 +292,9 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_UART1_RK29 &rk29_device_uart1, #endif +#ifdef CONFIG_MTD_NAND_RK29 + &rk29_device_nand, +#endif #ifdef CONFIG_FB_RK29 &rk29_device_fb, diff --git a/arch/arm/mach-rk29/devices.c b/arch/arm/mach-rk29/devices.c index ba31c5790368..117d8891848d 100755 --- a/arch/arm/mach-rk29/devices.c +++ b/arch/arm/mach-rk29/devices.c @@ -20,6 +20,7 @@ #include #include +#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 diff --git a/arch/arm/mach-rk29/devices.h b/arch/arm/mach-rk29/devices.h index e2e28e8346dc..134f662e9bba 100755 --- a/arch/arm/mach-rk29/devices.h +++ b/arch/arm/mach-rk29/devices.h @@ -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 index 000000000000..0d1b116ec20b --- /dev/null +++ b/arch/arm/mach-rk29/include/mach/rk29_nand.h @@ -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 */ + diff --git a/arch/arm/mach-rk29/io.c b/arch/arm/mach-rk29/io.c index 163fffe13c21..9f681ccb3b94 100644 --- a/arch/arm/mach-rk29/io.c +++ b/arch/arm/mach-rk29/io.c @@ -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) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 6e999604337e..623a645b808e 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -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" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 063518202051..36ee8b51a510 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -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 index 000000000000..dc36e5fbd73f --- /dev/null +++ b/drivers/mtd/nand/rk29_nand.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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<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;iwritesize/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;iwritesize/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;iwritesize/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;iwritesize/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;iwritesize/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;iwritesize/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<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<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 "); +MODULE_DESCRIPTION("MTD NAND driver for rk29 device"); + diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c index b3f4f0312760..2910bac817b4 100644 --- a/fs/yaffs2/yaffs_fs.c +++ b/fs/yaffs2/yaffs_fs.c @@ -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 -- 2.34.1