diff options
Diffstat (limited to 'packages/kexecboot/linux-kexecboot-2.6.26/zylonite_mtd-r0.patch')
-rw-r--r-- | packages/kexecboot/linux-kexecboot-2.6.26/zylonite_mtd-r0.patch | 4093 |
1 files changed, 0 insertions, 4093 deletions
diff --git a/packages/kexecboot/linux-kexecboot-2.6.26/zylonite_mtd-r0.patch b/packages/kexecboot/linux-kexecboot-2.6.26/zylonite_mtd-r0.patch deleted file mode 100644 index cb5a9c5f72..0000000000 --- a/packages/kexecboot/linux-kexecboot-2.6.26/zylonite_mtd-r0.patch +++ /dev/null @@ -1,4093 +0,0 @@ -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 2007-10-09 21:31:38.000000000 +0100 -+++ linux-2.6.23/drivers/mtd/nand/Kconfig 2008-02-13 00:59:45.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 2007-10-09 21:31:38.000000000 +0100 -+++ linux-2.6.23/drivers/mtd/nand/Makefile 2008-02-13 00:59:45.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-13 00:59:45.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, µn1GbX8}, -+ { DFC_FLASH_Micron_1Gb_X_16, µn1GbX16}, -+ { 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-13 00:59:45.000000000 +0000 -+++ linux-2.6.23/arch/arm/mach-pxa/zylonite.c 2008-02-13 09:11:02.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,16 @@ - .resource = smc91x_resources, - }; - -+static struct platform_device nand_device = { -+ .name = "monahans-nand-flash", -+ .id = -1, -+}; -+ -+static struct platform_device touch_device = { -+ .name = "pxa2xx-touch", -+ .id = -1, -+}; -+ - #if defined(CONFIG_FB_PXA) || (CONFIG_FB_PXA_MODULES) - static void zylonite_backlight_power(int on) - { -@@ -96,7 +108,7 @@ - }; - - static struct pxafb_mode_info sharp_ls037_modes[] = { -- [0] = { -+ [1] = { - .pixclock = 158000, - .xres = 240, - .yres = 320, -@@ -109,8 +121,8 @@ - .lower_margin = 3, - .sync = 0, - }, -- [1] = { -- .pixclock = 39700, -+ [0] = { -+ .pixclock = 45000, - .xres = 480, - .yres = 640, - .bpp = 16, -@@ -137,6 +149,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 +186,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); -+ platform_device_register(&touch_device); - - 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-13 00:59:45.000000000 +0000 -+++ linux-2.6.23/arch/arm/mach-pxa/zylonite_pxa300.c 2008-02-13 14:01:13.000000000 +0000 -@@ -62,12 +62,12 @@ - GPIO110_UART3_RXD, - - /* AC97 */ -- GPIO23_AC97_nACRESET, -+ /*GPIO23_AC97_nACRESET, - GPIO24_AC97_SYSCLK, - GPIO29_AC97_BITCLK, - GPIO25_AC97_SDATA_IN_0, - GPIO27_AC97_SDATA_OUT, -- GPIO28_AC97_SYNC, -+ GPIO28_AC97_SYNC,*/ - - /* Keypad */ - GPIO107_KP_DKIN_0, -@@ -104,6 +104,41 @@ - /* 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), -+ -+ /* AC97 */ -+ MFP_CFG_X(GPIO23, AF1, DS03X, PULL_LOW), -+ MFP_CFG_X(GPIO27, AF1, DS03X, PULL_LOW), -+ MFP_CFG_X(GPIO28, AF1, DS03X, PULL_LOW), -+ MFP_CFG_X(GPIO29, AF1, DS03X, PULL_LOW), -+ MFP_CFG_X(GPIO25, AF1, DS03X, PULL_LOW), -+ -+ MFP_CFG_X(GPIO26, AF0, DS01X, PULL_LOW), /* Interrupt */ -+ MFP_CFG_X(GPIO24, AF0, DS03X, PULL_LOW), /*SYSCLK external */ -+ MFP_CFG_X(GPIO11, AF0, DS01X, PULL_LOW), - }; - - static mfp_cfg_t pxa310_mfp_cfg[] __initdata = { -@@ -163,6 +198,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 +212,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:59:45.000000000 +0000 -+++ linux-2.6.23/drivers/video/pxafb.c 2008-02-13 00:59:45.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:59:45.000000000 +0000 -+++ linux-2.6.23/include/asm-arm/arch-pxa/mfp-pxa300.h 2008-02-13 00:59:45.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) |