linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] nand prefetch-irq support and ecc layout chanage
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
@ 2010-04-16 11:32 ` Sukumar Ghorai
  2010-04-16 11:34 ` [PATCH 1/6] omap3: GPMC register definition at common location Sukumar Ghorai
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-04-16 11:32 UTC (permalink / raw)
  To: linux-mtd
  Cc: leochen, tony, vimal.newwork, Sukumar Ghorai, linux-omap,
	David.Woodhouse

   The main motivations behind this patch series are -
	1. support NAND I/O in irq mode.
	2. support of different ECC schema. 
	3. also to make ecc layout as like in romcode ecc layout

   The following set of patches applies on top of the master branch. And
   is dependent on the following patches not yet applied onto this branch.
	https://patchwork.kernel.org/patch/92220/
	https://patchwork.kernel.org/patch/92232/
	https://patchwork.kernel.org/patch/92221/
	https://patchwork.kernel.org/patch/92230/
	https://patchwork.kernel.org/patch/92224/
	https://patchwork.kernel.org/patch/92222/
	https://patchwork.kernel.org/patch/92223/
	https://patchwork.kernel.org/patch/92229/

Sukumar Ghorai (6):
	omap: NAND: Making ecc layout as compatible with romcode ecc 
	omap: NAND: ecc layout select from board file 
	omap-3630 NAND: enable NAND io in prefetch-irq mode 
	OMAP NAND: configurable fifo threshold to gain the throughput
	omap3: NAND Prefetch in IRQ mode support
	omap3: GPMC register definition at common location

 arch/arm/configs/omap_3630sdp_defconfig |    1 +
 arch/arm/configs/omap_zoom3_defconfig   |    1 +
 arch/arm/mach-omap2/board-sdp-flash.c   |    2 +
 arch/arm/mach-omap2/board-zoom-flash.c  |    2 +
 arch/arm/mach-omap2/gpmc.c              |   47 +-----
 arch/arm/plat-omap/include/plat/gpmc.h  |   41 ++++-
 arch/arm/plat-omap/include/plat/nand.h  |    5 +
 drivers/mtd/nand/Kconfig                |   14 ++-
 drivers/mtd/nand/omap2.c                |  275 +++++++++++++++++++++++++++----
 9 files changed, 309 insertions(+), 79 deletions(-)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH 1/6] omap3: GPMC register definition at common location
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
  2010-04-16 11:32 ` [PATCH 0/6] nand prefetch-irq support and ecc layout chanage Sukumar Ghorai
@ 2010-04-16 11:34 ` Sukumar Ghorai
  2010-04-16 11:35 ` [PATCH 2/6] omap3: NAND Prefetch in IRQ mode support Sukumar Ghorai
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-04-16 11:34 UTC (permalink / raw)
  To: linux-mtd
  Cc: Vimal Singh, leochen, tony, vimal.newwork, Sukumar Ghorai,
	linux-omap, David.Woodhouse

GPMC register definition move to common place in gpmc.h.

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
Signed-off-by: Vimal Singh <vimalsingh@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   38 +------------------------------
 arch/arm/plat-omap/include/plat/gpmc.h |   36 +++++++++++++++++++++++++++--
 drivers/mtd/nand/omap2.c               |   14 ++++-------
 3 files changed, 40 insertions(+), 48 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5bc3ca0..9c77af0
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -28,40 +28,6 @@
 
 #include <plat/sdrc.h>
 
-/* GPMC register offsets */
-#define GPMC_REVISION		0x00
-#define GPMC_SYSCONFIG		0x10
-#define GPMC_SYSSTATUS		0x14
-#define GPMC_IRQSTATUS		0x18
-#define GPMC_IRQENABLE		0x1c
-#define GPMC_TIMEOUT_CONTROL	0x40
-#define GPMC_ERR_ADDRESS	0x44
-#define GPMC_ERR_TYPE		0x48
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-#define GPMC_PREFETCH_CONFIG1	0x1e0
-#define GPMC_PREFETCH_CONFIG2	0x1e4
-#define GPMC_PREFETCH_CONTROL	0x1ec
-#define GPMC_PREFETCH_STATUS	0x1f0
-#define GPMC_ECC_CONFIG		0x1f4
-#define GPMC_ECC_CONTROL	0x1f8
-#define GPMC_ECC_SIZE_CONFIG	0x1fc
-
-#define GPMC_CS0		0x60
-#define GPMC_CS_SIZE		0x30
-
-#define GPMC_MEM_START		0x00000000
-#define GPMC_MEM_END		0x3FFFFFFF
-#define BOOT_ROM_SPACE		0x100000	/* 1MB */
-
-#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
-#define GPMC_SECTION_SHIFT	28		/* 128 MB */
-
-#define PREFETCH_FIFOTHRESHOLD	(0x40 << 8)
-#define CS_NUM_SHIFT		24
-#define ENABLE_PREFETCH		(0x1 << 7)
-#define DMA_MPU_MODE		2
-
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -112,7 +78,7 @@ void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	__raw_writel(val, reg_addr);
 }
 
@@ -120,7 +86,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	return __raw_readl(reg_addr);
 }
 
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 145838a..347d212 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -25,10 +25,40 @@
 #define GPMC_CS_NAND_ADDRESS	0x20
 #define GPMC_CS_NAND_DATA	0x24
 
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
+/* GPMC register offsets */
+#define GPMC_REVISION           0x00
+#define GPMC_SYSCONFIG          0x10
+#define GPMC_SYSSTATUS          0x14
+#define GPMC_IRQSTATUS          0x18
+#define GPMC_IRQENABLE          0x1c
+#define GPMC_TIMEOUT_CONTROL    0x40
+#define GPMC_ERR_ADDRESS        0x44
+#define GPMC_ERR_TYPE           0x48
+#define GPMC_CONFIG             0x50
+#define GPMC_STATUS             0x54
+#define GPMC_PREFETCH_CONFIG1   0x1e0
+#define GPMC_PREFETCH_CONFIG2   0x1e4
+#define GPMC_PREFETCH_CONTROL   0x1ec
+#define GPMC_PREFETCH_STATUS    0x1f0
+#define GPMC_ECC_CONFIG         0x1f4
+#define GPMC_ECC_CONTROL        0x1f8
+#define GPMC_ECC_SIZE_CONFIG    0x1fc
+#define GPMC_ECC1_RESULT        0x200
+
 #define GPMC_CS0_BASE		0x60
-#define GPMC_CS_SIZE		0x30
+#define GPMC_CS_SIZE            0x30
+
+#define GPMC_MEM_START          0x00000000
+#define GPMC_MEM_END            0x3FFFFFFF
+#define BOOT_ROM_SPACE          0x100000        /* 1MB */
+
+#define GPMC_CHUNK_SHIFT        24              /* 16 MB */
+#define GPMC_SECTION_SHIFT      28              /* 128 MB */
+
+#define PREFETCH_FIFOTHRESHOLD  (0x40 << 8)
+#define CS_NUM_SHIFT            24
+#define ENABLE_PREFETCH         (0x1 << 7)
+#define DMA_MPU_MODE            2
 
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index ad07d39..09a89f9
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -22,12 +22,6 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 
-#define GPMC_IRQ_STATUS		0x18
-#define GPMC_ECC_CONFIG		0x1F4
-#define GPMC_ECC_CONTROL	0x1F8
-#define GPMC_ECC_SIZE_CONFIG	0x1FC
-#define GPMC_ECC1_RESULT	0x200
-
 #define	DRIVER_NAME	"omap2-nand"
 
 #define	NAND_WP_OFF	0
@@ -36,6 +30,7 @@
 #define	GPMC_BUF_FULL	0x00000001
 #define	GPMC_BUF_EMPTY	0x00000000
 
+#ifdef CONFIG_MTD_NAND_OMAP_HWECC
 #define NAND_Ecc_P1e		(1 << 0)
 #define NAND_Ecc_P2e		(1 << 1)
 #define NAND_Ecc_P4e		(1 << 2)
@@ -102,6 +97,7 @@
 
 #define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
 #define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
+#endif /* CONFIG_MTD_NAND_OMAP_HWECC */
 
 #ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL };
@@ -856,20 +852,20 @@ static int omap_dev_ready(struct mtd_info *mtd)
 {
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
 
 	if ((val & 0x100) == 0x100) {
 		/* Clear IRQ Interrupt */
 		val |= 0x100;
 		val &= ~(0x0);
-		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQSTATUS);
 	} else {
 		unsigned int cnt = 0;
 		while (cnt++ < 0x1FF) {
 			if  ((val & 0x100) == 0x100)
 				return 0;
 			val = __raw_readl(info->gpmc_baseaddr +
-							GPMC_IRQ_STATUS);
+							GPMC_IRQSTATUS);
 		}
 	}
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 2/6] omap3: NAND Prefetch in IRQ mode support
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
  2010-04-16 11:32 ` [PATCH 0/6] nand prefetch-irq support and ecc layout chanage Sukumar Ghorai
  2010-04-16 11:34 ` [PATCH 1/6] omap3: GPMC register definition at common location Sukumar Ghorai
@ 2010-04-16 11:35 ` Sukumar Ghorai
  2010-04-16 11:35 ` [PATCH 3/6] OMAP NAND: configurable fifo threshold to gain the throughput Sukumar Ghorai
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-04-16 11:35 UTC (permalink / raw)
  To: linux-mtd
  Cc: Vimal Singh, leochen, tony, vimal.newwork, Sukumar Ghorai,
	linux-omap, David.Woodhouse

This patch enable prefetch-irq mode for NAND.

Signed-off-by: Vimal Singh <vimalsingh@ti.com>
Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/board-sdp-flash.c  |    1 +
 arch/arm/mach-omap2/board-zoom-flash.c |    1 +
 arch/arm/plat-omap/include/plat/nand.h |    1 +
 drivers/mtd/nand/Kconfig               |   14 +++-
 drivers/mtd/nand/omap2.c               |  180 +++++++++++++++++++++++++++++++-
 5 files changed, 191 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-omap2/board-sdp-flash.c b/arch/arm/mach-omap2/board-sdp-flash.c
index 57116e6..81b83ce
--- a/arch/arm/mach-omap2/board-sdp-flash.c
+++ b/arch/arm/mach-omap2/board-sdp-flash.c
@@ -151,6 +151,7 @@ static struct omap_nand_platform_data sdp_nand_data = {
 	.nand_setup	= NULL,
 	.gpmc_t		= &nand_timings,
 	.dma_channel	= -1,		/* disable DMA in OMAP NAND driver */
+	.gpmc_irq	= 20,
 	.dev_ready	= NULL,
 	.devsize	= 0,	/* '0' for 8-bit, '1' for 16-bit device */
 };
diff --git a/arch/arm/mach-omap2/board-zoom-flash.c b/arch/arm/mach-omap2/board-zoom-flash.c
index 55e173b..6a5dcf4 100644
--- a/arch/arm/mach-omap2/board-zoom-flash.c
+++ b/arch/arm/mach-omap2/board-zoom-flash.c
@@ -54,6 +54,7 @@ static struct omap_nand_platform_data zoom_nand_data = {
 	.nand_setup	= NULL,
 	.gpmc_t		= &nand_timings,
 	.dma_channel	= -1,	/* disable DMA in OMAP NAND driver */
+	.gpmc_irq	= 20,
 	.dev_ready	= NULL,
 	.devsize	= 1,	/* '0' for 8-bit, '1' for 16-bit device */
 };
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index 6ba88d2..8ba2e3e 100644
--- a/arch/arm/plat-omap/include/plat/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
@@ -20,6 +20,7 @@ struct omap_nand_platform_data {
 	int			(*nand_setup)(void);
 	int			(*dev_ready)(struct omap_nand_platform_data *);
 	int			dma_channel;
+	int			gpmc_irq;
 	unsigned long		phys_base;
 	void __iomem		*gpmc_cs_baseaddr;
 	void __iomem		*gpmc_baseaddr;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index b712aed..ee9abbd
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -94,6 +94,9 @@ config MTD_NAND_OMAP_PREFETCH
 	help
 	 The NAND device can be accessed for Read/Write using GPMC PREFETCH engine
 	 to improve the performance.
+	 GPMC PREFETCH can be configured eigther in MPU interrupt mode or in DMA
+	 interrupt mode. If not selected any of them prefetch will be used in
+	 polling mode.
 
 config MTD_NAND_OMAP_PREFETCH_DMA
 	depends on MTD_NAND_OMAP_PREFETCH
@@ -102,7 +105,16 @@ config MTD_NAND_OMAP_PREFETCH_DMA
 	help
 	 The GPMC PREFETCH engine can be configured eigther in MPU interrupt mode
 	 or in DMA interrupt mode.
-	 Say y for DMA mode or MPU mode will be used
+	 Say y for DMA mode
+
+config MTD_NAND_OMAP_PREFETCH_IRQ
+	depends on MTD_NAND_OMAP_PREFETCH && !MTD_NAND_OMAP_PREFETCH_DMA
+	bool "IRQ mode"
+	default n
+	help
+	 The GPMC PREFETCH engine can be configured eigther in MPU interrupt mode
+	 or in DMA interrupt mode.
+	 Say y for IRQ mode
 
 config MTD_NAND_IDS
 	tristate
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 09a89f9..de9b058 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -11,6 +11,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/sched.h>
 #include <linux/mtd/mtd.h>
@@ -111,17 +112,27 @@ module_param(use_prefetch, bool, 0);
 MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH");
 
 #ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+const int use_interrupt;
 static int use_dma = 1;
 
 /* "modprobe ... use_dma=0" etc */
 module_param(use_dma, bool, 0);
-MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA mode");
+#elif defined(CONFIG_MTD_NAND_OMAP_PREFETCH_IRQ)
+const int use_dma;
+static int use_interrupt = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_interrupt, bool, 0);
+MODULE_PARM_DESC(use_interrupt, "enable/disable use of IRQ mode");
 #else
 const int use_dma;
+const int use_interrupt;
 #endif
 #else
 const int use_prefetch;
 const int use_dma;
+const int use_interrupt;
 #endif
 
 struct omap_nand_info {
@@ -139,6 +150,8 @@ struct omap_nand_info {
 	void __iomem			*nand_pref_fifo_add;
 	struct completion		comp;
 	int				dma_ch;
+	int				gpmc_irq;
+	u_char				*buf;
 };
 
 /**
@@ -503,6 +516,141 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
 		omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
 }
 
+/*
+ * omap_nand_irq - GMPC irq handler
+ * @this_irq: gpmc irq number
+ * @dev: omap_nand_info structure pointer is passed here
+ */
+static irqreturn_t omap_nand_irq(int this_irq, void *dev)
+{
+	struct omap_nand_info *info = (struct omap_nand_info *) dev;
+	u32 irq_enb = 0, pref_status = 0, bytes = 0;
+	u32 irq_stats = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
+	u32 pref_config = __raw_readl(info->gpmc_baseaddr +
+					GPMC_PREFETCH_CONFIG1);
+
+	if (pref_config & 0x1) { /* checks for write operaiton */
+		if (irq_stats & 0x2)
+			goto done;
+
+		u32 *p = (u32 *) info->buf;
+		pref_status = gpmc_prefetch_status();
+		bytes = ((pref_status >> 24) & 0x7F);
+		iowrite32_rep(info->nand_pref_fifo_add, p, bytes >> 2);
+		info->buf = info->buf + bytes;
+
+	} else {
+		u32 *p = (u32 *) info->buf;
+		pref_status = gpmc_prefetch_status();
+		bytes = ((pref_status >> 24) & 0x7F);
+		ioread32_rep(info->nand_pref_fifo_add, p, bytes >> 2);
+		info->buf = info->buf + bytes;
+
+		if (irq_stats & 0x2)
+			goto done;
+	}
+	__raw_writel(irq_stats, info->gpmc_baseaddr + GPMC_IRQSTATUS);
+	irq_stats = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
+
+	return IRQ_HANDLED;
+
+done:
+	complete(&info->comp);
+	irq_enb = __raw_readl(info->gpmc_baseaddr + GPMC_IRQENABLE);
+	__raw_writel((irq_enb & ~0x3), info->gpmc_baseaddr + GPMC_IRQENABLE);
+	__raw_writel(irq_stats, info->gpmc_baseaddr + GPMC_IRQSTATUS);
+	irq_stats = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * omap_read_buf_irq_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct omap_nand_info *info = container_of(mtd,
+						struct omap_nand_info, mtd);
+	u32 irq_enb = __raw_readl(info->gpmc_baseaddr + GPMC_IRQENABLE);
+	int ret = 0;
+
+	if (len <= mtd->oobsize) {
+		omap_read_buf_pref(mtd, buf, len);
+		return;
+	}
+
+	info->buf = buf;
+	init_completion(&info->comp);
+
+	/*  configure and start prefetch transfer */
+	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
+	if (ret)
+		/* PFPW engine is busy, use cpu copy methode */
+		goto out_copy;
+
+	__raw_writel((irq_enb | 0x3), info->gpmc_baseaddr + GPMC_IRQENABLE);
+
+	/* setup and start DMA using dma_addr */
+	wait_for_completion(&info->comp);
+
+	/* disable and stop the PFPW engine */
+	gpmc_prefetch_reset();
+
+	return;
+out_copy:
+	if (info->nand.options & NAND_BUSWIDTH_16)
+		omap_read_buf16(mtd, buf, len);
+	else
+		omap_read_buf8(mtd, buf, len);
+}
+
+/*
+ * omap_write_buf_irq_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_irq_pref(struct mtd_info *mtd,
+					const u_char *buf, int len)
+{
+	struct omap_nand_info *info = container_of(mtd,
+						struct omap_nand_info, mtd);
+	u32 irq_enb = __raw_readl(info->gpmc_baseaddr + GPMC_IRQENABLE);
+	int ret = 0;
+
+	if (len <= mtd->oobsize) {
+		omap_write_buf_pref(mtd, buf, len);
+		return;
+	}
+
+	info->buf = (u_char *) buf;
+	init_completion(&info->comp);
+
+	/*  configure and start prefetch transfer */
+	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
+	if (ret)
+		/* PFPW engine is busy, use cpu copy methode */
+		goto out_copy;
+
+	__raw_writel((irq_enb | 0x3), info->gpmc_baseaddr + GPMC_IRQENABLE);
+
+	/* setup and start DMA using dma_addr */
+	wait_for_completion(&info->comp);
+
+	/* disable and stop the PFPW engine */
+	gpmc_prefetch_reset();
+
+	return;
+out_copy:
+	if (info->nand.options & NAND_BUSWIDTH_16)
+		omap_write_buf16(mtd, buf, len);
+	else
+		omap_write_buf8(mtd, buf, len);
+}
+
 /**
  * omap_verify_buf - Verify chip data against buffer
  * @mtd: MTD device structure
@@ -898,6 +1046,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->gpmc_cs		= pdata->cs;
 	info->gpmc_baseaddr	= pdata->gpmc_baseaddr;
 	info->gpmc_cs_baseaddr	= pdata->gpmc_cs_baseaddr;
+	info->gpmc_irq		= pdata->gpmc_irq;
 	info->phys_base		= pdata->phys_base;
 
 	info->mtd.priv		= &info->nand;
@@ -964,7 +1113,20 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 				info->nand.read_buf   = omap_read_buf_dma_pref;
 				info->nand.write_buf  = omap_write_buf_dma_pref;
 			}
+		} else if (use_interrupt) {
+			err = request_irq(info->gpmc_irq, omap_nand_irq,
+					IRQF_SHARED, info->mtd.name, info);
+			if (err) {
+				printk(KERN_INFO"failure requesting irq %i."
+						" Prefetch will work in mpu"
+						" poling mode.\n",
+						info->gpmc_irq);
+			} else {
+				info->nand.read_buf   = omap_read_buf_irq_pref;
+				info->nand.write_buf  = omap_write_buf_irq_pref;
+			}
 		}
+
 	} else {
 		if (info->nand.options & NAND_BUSWIDTH_16) {
 			info->nand.read_buf   = omap_read_buf16;
@@ -1056,11 +1218,19 @@ static int __init omap_nand_init(void)
 	/* This check is required if driver is being
 	 * loaded run time as a module
 	 */
-	if ((1 == use_dma) && (0 == use_prefetch)) {
-		printk(KERN_INFO"Wrong parameters: 'use_dma' can not be 1 "
-				"without use_prefetch'. Prefetch will not be"
-				" used in either mode (mpu or dma)\n");
+
+	if ((0 == use_prefetch) && (1 == (use_dma | use_interrupt))) {
+		printk(KERN_INFO "Wrong parameters: Neither 'dma' nor 'irq' "
+				"can used without 'use_prefetch' selected.\n");
+		printk(KERN_INFO "Prefetch will not be used in any mode: "
+				"poll, mpu or dma\n");
+	} else if ((1 == use_prefetch) && (1 == (use_interrupt & use_dma))) {
+			printk(KERN_INFO "Wrong parameters: Both DMA and IRQ"
+					" modes can not be used together.\n");
+			printk(KERN_INFO "It has to be selected at compile "
+					"time and same will be used.\n");
 	}
+
 	return platform_driver_register(&omap_nand_driver);
 }
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 3/6] OMAP NAND: configurable fifo threshold to gain the throughput
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
                   ` (2 preceding siblings ...)
  2010-04-16 11:35 ` [PATCH 2/6] omap3: NAND Prefetch in IRQ mode support Sukumar Ghorai
@ 2010-04-16 11:35 ` Sukumar Ghorai
  2010-04-16 12:45   ` Vimal Singh
  2010-04-16 11:35 ` [PATCH 4/6] omap-3630 NAND: enable NAND io in prefetch-irq mode Sukumar Ghorai
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 57+ messages in thread
From: Sukumar Ghorai @ 2010-04-16 11:35 UTC (permalink / raw)
  To: linux-mtd
  Cc: Vimal Singh, leochen, tony, vimal.newwork, Sukumar Ghorai,
	linux-omap, David.Woodhouse

  Configure the FIFO THREASHOLD value to 50% (32 bytes) to keep busy both
  filling and to drain out of FIFO at reading and writing.

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
Signed-off-by: Vimal Singh <vimalsingh@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |    9 ++++++---
 arch/arm/plat-omap/include/plat/gpmc.h |    7 +++++--
 drivers/mtd/nand/omap2.c               |   25 +++++++++++++------------
 3 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9c77af0..1380886 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -391,12 +391,15 @@ EXPORT_SYMBOL(gpmc_cs_free);
  * @u32_count: number of bytes to be transferred
  * @is_write: prefetch read(0) or write post(1) mode
  */
-int gpmc_prefetch_enable(int cs, int dma_mode,
+int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
 				unsigned int u32_count, int is_write)
 {
 	uint32_t prefetch_config1;
 
-	if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
+	if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) {
+		printk(KERN_ERR "PREFETCH Fifo Threshold is not supported\n");
+		return -1;
+	} else if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
 		/* Set the amount of bytes to be prefetched */
 		gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
 
@@ -404,7 +407,7 @@ int gpmc_prefetch_enable(int cs, int dma_mode,
 		 * enable the engine. Set which cs is has requested for.
 		 */
 		prefetch_config1 = ((cs << CS_NUM_SHIFT) |
-					PREFETCH_FIFOTHRESHOLD |
+					PREFETCH_FIFOTHRESHOLD(fifo_th) |
 					ENABLE_PREFETCH |
 					(dma_mode << DMA_MPU_MODE) |
 					(0x1 & is_write));
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 347d212..a36a046 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -55,10 +55,13 @@
 #define GPMC_CHUNK_SHIFT        24              /* 16 MB */
 #define GPMC_SECTION_SHIFT      28              /* 128 MB */
 
-#define PREFETCH_FIFOTHRESHOLD  (0x40 << 8)
+#define PREFETCH_FIFOTHRESHOLD_MAX	0x40
+#define PREFETCH_FIFOTHRESHOLD(val)	(val << 8)
 #define CS_NUM_SHIFT            24
 #define ENABLE_PREFETCH         (0x1 << 7)
 #define DMA_MPU_MODE            2
+#define PREFETCH_FIFOTHRESHOLD_READ	32 /* threashold size for read */
+#define PREFETCH_FIFOTHRESHOLD_WRITE	32 /* threashold size for write */
 
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
@@ -136,7 +139,7 @@ extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
 extern int gpmc_cs_set_reserved(int cs, int reserved);
 extern int gpmc_cs_reserved(int cs);
-extern int gpmc_prefetch_enable(int cs, int dma_mode,
+extern int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
 					unsigned int u32_count, int is_write);
 extern void gpmc_prefetch_reset(void);
 extern int gpmc_prefetch_status(void);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index de9b058..61c0c01
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -310,7 +310,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 	}
 
 	/* configure and start prefetch transfer */
-	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
+	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x40, 0x0, len, 0x0);
 	if (ret) {
 		/* PFPW engine is busy, use cpu copy method */
 		if (info->nand.options & NAND_BUSWIDTH_16)
@@ -354,7 +354,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 	}
 
 	/*  configure and start prefetch transfer */
-	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
+	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x40, 0x0, len, 0x1);
 	if (ret) {
 		/* PFPW engine is busy, use cpu copy method */
 		if (info->nand.options & NAND_BUSWIDTH_16)
@@ -405,10 +405,11 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 	dma_addr_t dma_addr;
 	int ret;
 
-	/* The fifo depth is 64 bytes. We have a sync at each frame and frame
-	 * length is 64 bytes.
+	/* The fifo depth is 64 bytes max.
+	 * But configure the FIFO-threahold to 32 to get a sync at each frame
+	 * and frame length is 32 bytes.
 	 */
-	int buf_len = len >> 6;
+	int buf_len = len >> 5;
 
 	if (addr >= high_memory) {
 		struct page *p1;
@@ -447,7 +448,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 					OMAP24XX_DMA_GPMC, OMAP_DMA_SRC_SYNC);
 	}
 	/*  configure and start prefetch transfer */
-	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x1, len, is_write);
+	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x20, 0x1, len, is_write);
 	if (ret)
 		/* PFPW engine is busy, use cpu copy methode */
 		goto out_copy;
@@ -524,6 +525,7 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
 static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 {
 	struct omap_nand_info *info = (struct omap_nand_info *) dev;
+	u32 *p = (u32 *) info->buf;
 	u32 irq_enb = 0, pref_status = 0, bytes = 0;
 	u32 irq_stats = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
 	u32 pref_config = __raw_readl(info->gpmc_baseaddr +
@@ -533,14 +535,11 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 		if (irq_stats & 0x2)
 			goto done;
 
-		u32 *p = (u32 *) info->buf;
-		pref_status = gpmc_prefetch_status();
-		bytes = ((pref_status >> 24) & 0x7F);
+		bytes = PREFETCH_FIFOTHRESHOLD_WRITE;
 		iowrite32_rep(info->nand_pref_fifo_add, p, bytes >> 2);
 		info->buf = info->buf + bytes;
 
 	} else {
-		u32 *p = (u32 *) info->buf;
 		pref_status = gpmc_prefetch_status();
 		bytes = ((pref_status >> 24) & 0x7F);
 		ioread32_rep(info->nand_pref_fifo_add, p, bytes >> 2);
@@ -586,7 +585,8 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
 	init_completion(&info->comp);
 
 	/*  configure and start prefetch transfer */
-	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
+	ret = gpmc_prefetch_enable(info->gpmc_cs,
+				PREFETCH_FIFOTHRESHOLD_READ, 0x0, len, 0x0);
 	if (ret)
 		/* PFPW engine is busy, use cpu copy methode */
 		goto out_copy;
@@ -630,7 +630,8 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
 	init_completion(&info->comp);
 
 	/*  configure and start prefetch transfer */
-	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
+	ret = gpmc_prefetch_enable(info->gpmc_cs,
+				PREFETCH_FIFOTHRESHOLD_WRITE, 0x0, len, 0x1);
 	if (ret)
 		/* PFPW engine is busy, use cpu copy methode */
 		goto out_copy;

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 4/6] omap-3630 NAND: enable NAND io in prefetch-irq mode
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
                   ` (3 preceding siblings ...)
  2010-04-16 11:35 ` [PATCH 3/6] OMAP NAND: configurable fifo threshold to gain the throughput Sukumar Ghorai
@ 2010-04-16 11:35 ` Sukumar Ghorai
  2010-04-16 11:35 ` [PATCH 5/6] omap: NAND: ecc layout select from board file Sukumar Ghorai
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-04-16 11:35 UTC (permalink / raw)
  To: linux-mtd
  Cc: leochen, tony, vimal.newwork, Sukumar Ghorai, linux-omap,
	David.Woodhouse

Update config file to enable NAND in prefetch IRQ mode for ZOOM3 and 3630SDP .

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/configs/omap_3630sdp_defconfig |    1 +
 arch/arm/configs/omap_zoom3_defconfig   |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/configs/omap_3630sdp_defconfig b/arch/arm/configs/omap_3630sdp_defconfig
index a623927..9dfce1a
--- a/arch/arm/configs/omap_3630sdp_defconfig
+++ b/arch/arm/configs/omap_3630sdp_defconfig
@@ -525,6 +525,7 @@ CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_OMAP2=y
 CONFIG_MTD_NAND_OMAP_PREFETCH=y
 # CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
+CONFIG_MTD_NAND_OMAP_PREFETCH_IRQ=y
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
diff --git a/arch/arm/configs/omap_zoom3_defconfig b/arch/arm/configs/omap_zoom3_defconfig
index 1a12e3e..27b16ed
--- a/arch/arm/configs/omap_zoom3_defconfig
+++ b/arch/arm/configs/omap_zoom3_defconfig
@@ -534,6 +534,7 @@ CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_OMAP2=y
 CONFIG_MTD_NAND_OMAP_PREFETCH=y
 # CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
+CONFIG_MTD_NAND_OMAP_PREFETCH_IRQ=y
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
-- 
1.5.4.7

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 5/6] omap: NAND: ecc layout select from board file
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
                   ` (4 preceding siblings ...)
  2010-04-16 11:35 ` [PATCH 4/6] omap-3630 NAND: enable NAND io in prefetch-irq mode Sukumar Ghorai
@ 2010-04-16 11:35 ` Sukumar Ghorai
  2010-04-16 11:35 ` [PATCH 6/6] omap: NAND: Making ecc layout as compatible with romcode ecc Sukumar Ghorai
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-04-16 11:35 UTC (permalink / raw)
  To: linux-mtd
  Cc: Vimal Singh, leochen, tony, vimal.newwork, Sukumar Ghorai,
	linux-omap, David.Woodhouse

    This patch makes it possible to select sw or hw (different layout options)
    ecc scheme supported by omap nand driver.  And hw ecc layout selected for
    sdp and zoom boards, by default.

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
Signed-off-by: Vimal Singh <vimalsingh@ti.com>
---
 arch/arm/mach-omap2/board-sdp-flash.c  |    1 +
 arch/arm/mach-omap2/board-zoom-flash.c |    1 +
 arch/arm/plat-omap/include/plat/nand.h |    4 ++++
 drivers/mtd/nand/omap2.c               |   28 ++++++++++++----------------
 4 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mach-omap2/board-sdp-flash.c b/arch/arm/mach-omap2/board-sdp-flash.c
index 81b83ce..437a1a4
--- a/arch/arm/mach-omap2/board-sdp-flash.c
+++ b/arch/arm/mach-omap2/board-sdp-flash.c
@@ -162,6 +162,7 @@ __init board_nand_init(struct flash_partitions sdp_nand_parts, u8 cs)
 	sdp_nand_data.cs		= cs;
 	sdp_nand_data.parts		= sdp_nand_parts.parts;
 	sdp_nand_data.nr_parts		= sdp_nand_parts.nr_parts;
+	sdp_nand_data.ecc_opt		= 0x1; /* HW ECC in default layout */
 	if (cpu_is_omap3630())
 		sdp_nand_data.devsize = 1; /* 0: 8-bit, 1: 16-bit device */
 
diff --git a/arch/arm/mach-omap2/board-zoom-flash.c b/arch/arm/mach-omap2/board-zoom-flash.c
index 6a5dcf4..1547bdb
--- a/arch/arm/mach-omap2/board-zoom-flash.c
+++ b/arch/arm/mach-omap2/board-zoom-flash.c
@@ -71,6 +71,7 @@ void __init zoom_flash_init(struct flash_partitions zoom_nand_parts[], int cs)
 	zoom_nand_data.cs		= cs;
 	zoom_nand_data.parts		= zoom_nand_parts[0].parts;
 	zoom_nand_data.nr_parts		= zoom_nand_parts[0].nr_parts;
+	zoom_nand_data.ecc_opt		= 0x1; /* HW ECC in default layout */
 	zoom_nand_data.gpmc_baseaddr	= (void *)(gpmc_base_add);
 	zoom_nand_data.gpmc_cs_baseaddr	= (void *)(gpmc_base_add +
 					GPMC_CS0_BASE +	cs * GPMC_CS_SIZE);
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index 8ba2e3e..b2ccd68
--- a/arch/arm/plat-omap/include/plat/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
@@ -25,6 +25,10 @@ struct omap_nand_platform_data {
 	void __iomem		*gpmc_cs_baseaddr;
 	void __iomem		*gpmc_baseaddr;
 	int			devsize;
+	int			ecc_opt; /* 0x0 - sw ecc
+					  * 0x1 - hw ecc default ecc layout
+					  * 0x2 - hw ecc in romcode layout
+					  */
 };
 
 /* size (4 KiB) for IO mapping */
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 61c0c01..207fb3c
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -31,7 +31,6 @@
 #define	GPMC_BUF_FULL	0x00000001
 #define	GPMC_BUF_EMPTY	0x00000000
 
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
 #define NAND_Ecc_P1e		(1 << 0)
 #define NAND_Ecc_P2e		(1 << 1)
 #define NAND_Ecc_P4e		(1 << 2)
@@ -98,7 +97,6 @@
 
 #define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
 #define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
-#endif /* CONFIG_MTD_NAND_OMAP_HWECC */
 
 #ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL };
@@ -673,7 +671,6 @@ static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len)
 	return 0;
 }
 
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
 /**
  * omap_hwecc_init - Initialize the HW ECC for NAND flash in GPMC controller
  * @mtd: MTD device structure
@@ -951,7 +948,6 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
 
 	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
 }
-#endif
 
 /**
  * omap_wait - wait until the command is done
@@ -1139,19 +1135,19 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	}
 	info->nand.verify_buf = omap_verify_buf;
 
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
-	info->nand.ecc.bytes		= 3;
-	info->nand.ecc.size		= 512;
-	info->nand.ecc.calculate	= omap_calculate_ecc;
-	info->nand.ecc.hwctl		= omap_enable_hwecc;
-	info->nand.ecc.correct		= omap_correct_data;
-	info->nand.ecc.mode		= NAND_ECC_HW;
+	if (pdata->ecc_opt & 0x3) {
+		info->nand.ecc.bytes		= 3;
+		info->nand.ecc.size		= 512;
+		info->nand.ecc.calculate	= omap_calculate_ecc;
+		info->nand.ecc.hwctl		= omap_enable_hwecc;
+		info->nand.ecc.correct		= omap_correct_data;
+		info->nand.ecc.mode		= NAND_ECC_HW;
 
-	/* init HW ECC */
-	omap_hwecc_init(&info->mtd);
-#else
-	info->nand.ecc.mode = NAND_ECC_SOFT;
-#endif
+		/* init HW ECC */
+		omap_hwecc_init(&info->mtd);
+	} else {
+		info->nand.ecc.mode = NAND_ECC_SOFT;
+	}
 
 	/* DIP switches on some boards change between 8 and 16 bit
 	 * bus widths for flash.  Try the other width if the first try fails.

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 6/6] omap: NAND: Making ecc layout as compatible with romcode ecc
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
                   ` (5 preceding siblings ...)
  2010-04-16 11:35 ` [PATCH 5/6] omap: NAND: ecc layout select from board file Sukumar Ghorai
@ 2010-04-16 11:35 ` Sukumar Ghorai
  2010-05-12  9:48 ` [PATCH 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-04-16 11:35 UTC (permalink / raw)
  To: linux-mtd
  Cc: leochen, tony, vimal.newwork, Sukumar Ghorai, linux-omap,
	David.Woodhouse

    This patch overrides nand ecc layout and bad block descriptor (for 8-bit
    device) to support hw ecc in romcode layout. So as to have in sync with ecc
    layout throughout; i.e. x-laod, u-boot and kernel.

    This patch also enables to use romcode ecc for spd and zoom, by default.

    This enables to flash x-load, u-boot, kernel, FS images from kernel itself
    and compatiable with other tools.

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/board-sdp-flash.c  |    2 +-
 arch/arm/mach-omap2/board-zoom-flash.c |    2 +-
 drivers/mtd/nand/omap2.c               |   42 ++++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/board-sdp-flash.c b/arch/arm/mach-omap2/board-sdp-flash.c
index 437a1a4..ac891ea
--- a/arch/arm/mach-omap2/board-sdp-flash.c
+++ b/arch/arm/mach-omap2/board-sdp-flash.c
@@ -162,7 +162,7 @@ __init board_nand_init(struct flash_partitions sdp_nand_parts, u8 cs)
 	sdp_nand_data.cs		= cs;
 	sdp_nand_data.parts		= sdp_nand_parts.parts;
 	sdp_nand_data.nr_parts		= sdp_nand_parts.nr_parts;
-	sdp_nand_data.ecc_opt		= 0x1; /* HW ECC in default layout */
+	sdp_nand_data.ecc_opt		= 0x2; /* HW ECC layout as in ROMCODE */
 	if (cpu_is_omap3630())
 		sdp_nand_data.devsize = 1; /* 0: 8-bit, 1: 16-bit device */
 
diff --git a/arch/arm/mach-omap2/board-zoom-flash.c b/arch/arm/mach-omap2/board-zoom-flash.c
index 1547bdb..53eeaa6
--- a/arch/arm/mach-omap2/board-zoom-flash.c
+++ b/arch/arm/mach-omap2/board-zoom-flash.c
@@ -71,7 +71,7 @@ void __init zoom_flash_init(struct flash_partitions zoom_nand_parts[], int cs)
 	zoom_nand_data.cs		= cs;
 	zoom_nand_data.parts		= zoom_nand_parts[0].parts;
 	zoom_nand_data.nr_parts		= zoom_nand_parts[0].nr_parts;
-	zoom_nand_data.ecc_opt		= 0x1; /* HW ECC in default layout */
+	zoom_nand_data.ecc_opt		= 0x2; /* HW ECC in romcode layout */
 	zoom_nand_data.gpmc_baseaddr	= (void *)(gpmc_base_add);
 	zoom_nand_data.gpmc_cs_baseaddr	= (void *)(gpmc_base_add +
 					GPMC_CS0_BASE +	cs * GPMC_CS_SIZE);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 207fb3c..f5d2c53
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -152,6 +152,39 @@ struct omap_nand_info {
 	u_char				*buf;
 };
 
+static struct nand_ecclayout hw_x8_romcode_oob_64 = {
+	.eccbytes = 12,
+	.eccpos = {
+		    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+		  },
+	.oobfree = {
+			{.offset = 13,
+			 .length = 51}
+		   }
+};
+
+/* Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks
+ */
+static uint8_t scan_ff_pattern[] = { 0xff };
+static struct nand_bbt_descr bb_descrip_flashbased = {
+	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+	.offs = 0,
+	.len = 1,
+	.pattern = scan_ff_pattern,
+};
+
+static struct nand_ecclayout hw_x16_romcode_oob_64 = {
+	.eccbytes = 12,
+	.eccpos = {
+		    2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
+		  },
+	.oobfree = {
+			{.offset = 14,
+			 .length = 50}
+		   }
+};
+
 /**
  * omap_nand_wp - This function enable or disable the Write Protect feature
  * @mtd: MTD device structure
@@ -1136,6 +1169,15 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->nand.verify_buf = omap_verify_buf;
 
 	if (pdata->ecc_opt & 0x3) {
+		if (pdata->ecc_opt == 0x2) {
+			if (info->nand.options & NAND_BUSWIDTH_16) {
+				info->nand.ecc.layout = &hw_x16_romcode_oob_64;
+			} else {
+				info->nand.ecc.layout = &hw_x8_romcode_oob_64;
+				info->nand.badblock_pattern =
+							&bb_descrip_flashbased;
+			}
+		}
 		info->nand.ecc.bytes		= 3;
 		info->nand.ecc.size		= 512;
 		info->nand.ecc.calculate	= omap_calculate_ecc;

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH 3/6] OMAP NAND: configurable fifo threshold to gain the throughput
  2010-04-16 11:35 ` [PATCH 3/6] OMAP NAND: configurable fifo threshold to gain the throughput Sukumar Ghorai
@ 2010-04-16 12:45   ` Vimal Singh
  0 siblings, 0 replies; 57+ messages in thread
From: Vimal Singh @ 2010-04-16 12:45 UTC (permalink / raw)
  To: Sukumar Ghorai
  Cc: Vimal Singh, leochen, tony, linux-mtd, linux-omap,
	David.Woodhouse

Hi Ghorai,

On Fri, Apr 16, 2010 at 5:05 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
[...]
> -       ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
> +       ret = gpmc_prefetch_enable(info->gpmc_cs, 0x40, 0x0, len, 0x0);

Use macros here too then.

>        if (ret) {
>                /* PFPW engine is busy, use cpu copy method */
>                if (info->nand.options & NAND_BUSWIDTH_16)
> @@ -354,7 +354,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
>        }
>
>        /*  configure and start prefetch transfer */
> -       ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
> +       ret = gpmc_prefetch_enable(info->gpmc_cs, 0x40, 0x0, len, 0x1);

here too

>        if (ret) {
>                /* PFPW engine is busy, use cpu copy method */
>                if (info->nand.options & NAND_BUSWIDTH_16)
> @@ -405,10 +405,11 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
>        dma_addr_t dma_addr;
>        int ret;
>
> -       /* The fifo depth is 64 bytes. We have a sync at each frame and frame
> -        * length is 64 bytes.
> +       /* The fifo depth is 64 bytes max.
> +        * But configure the FIFO-threahold to 32 to get a sync at each frame
> +        * and frame length is 32 bytes.
>         */
> -       int buf_len = len >> 6;
> +       int buf_len = len >> 5;
>
>        if (addr >= high_memory) {
>                struct page *p1;
> @@ -447,7 +448,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
>                                        OMAP24XX_DMA_GPMC, OMAP_DMA_SRC_SYNC);
>        }
>        /*  configure and start prefetch transfer */
> -       ret = gpmc_prefetch_enable(info->gpmc_cs, 0x1, len, is_write);
> +       ret = gpmc_prefetch_enable(info->gpmc_cs, 0x20, 0x1, len, is_write);
>        if (ret)
>                /* PFPW engine is busy, use cpu copy methode */
>                goto out_copy;
> @@ -524,6 +525,7 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
>  static irqreturn_t omap_nand_irq(int this_irq, void *dev)
>  {
>        struct omap_nand_info *info = (struct omap_nand_info *) dev;
> +       u32 *p = (u32 *) info->buf;
>        u32 irq_enb = 0, pref_status = 0, bytes = 0;
>        u32 irq_stats = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
>        u32 pref_config = __raw_readl(info->gpmc_baseaddr +
> @@ -533,14 +535,11 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
>                if (irq_stats & 0x2)
>                        goto done;
>
> -               u32 *p = (u32 *) info->buf;
> -               pref_status = gpmc_prefetch_status();
> -               bytes = ((pref_status >> 24) & 0x7F);
> +               bytes = PREFETCH_FIFOTHRESHOLD_WRITE;

By this, you are not really keeping prefetch the busyest.
you are filling only 'PREFETCH_FIFOTHRESHOLD_WRITE' bytes, while there
could be more free spaces.
Previous way of doing it was more efficent.

>                iowrite32_rep(info->nand_pref_fifo_add, p, bytes >> 2);
>                info->buf = info->buf + bytes;
>
>        } else {
> -               u32 *p = (u32 *) info->buf;
>                pref_status = gpmc_prefetch_status();
>                bytes = ((pref_status >> 24) & 0x7F);
>                ioread32_rep(info->nand_pref_fifo_add, p, bytes >> 2);
> @@ -586,7 +585,8 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
>        init_completion(&info->comp);
>
>        /*  configure and start prefetch transfer */
> -       ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
> +       ret = gpmc_prefetch_enable(info->gpmc_cs,
> +                               PREFETCH_FIFOTHRESHOLD_READ, 0x0, len, 0x0);
>        if (ret)
>                /* PFPW engine is busy, use cpu copy methode */
>                goto out_copy;
> @@ -630,7 +630,8 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
>        init_completion(&info->comp);
>
>        /*  configure and start prefetch transfer */
> -       ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
> +       ret = gpmc_prefetch_enable(info->gpmc_cs,
> +                               PREFETCH_FIFOTHRESHOLD_WRITE, 0x0, len, 0x1);

In case of write, in my experiments, fifo thresholed '24' was the best
compromise for throughput and cpu load.


Regards,
Vimal

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH 0/3] omap3 nand: cleanup exiting platform related code
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
                   ` (6 preceding siblings ...)
  2010-04-16 11:35 ` [PATCH 6/6] omap: NAND: Making ecc layout as compatible with romcode ecc Sukumar Ghorai
@ 2010-05-12  9:48 ` Sukumar Ghorai
  2010-05-12  9:48   ` [PATCH 1/3] omap3: GPMC register definition at common location Sukumar Ghorai
  2010-05-13 15:44   ` [PATCH 0/3] omap3 nand: cleanup exiting platform related code Tony Lindgren
  2010-05-14 15:23 ` [PATCH v2 0/2] " Sukumar Ghorai
                   ` (2 subsequent siblings)
  10 siblings, 2 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-12  9:48 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

   The following set of patches applies on top of master branch.
	http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git
   Patches verified on: omap3430-SDP, omap3630-sdp, zoom3 and beagle board

   And these are the patches required to address the following input -
     1. The NAND driver needs to stop tinkering with the GPMC registers
	The omap General Purpose Memory Controller (GPMC) registers are omap
        specific, and not driver specific. Tinkering with these registers can
        cause issues with the other devices on the GPMC.

     2. Passing hardcoded GPMC_CS0_BASE needs to go from the board files
	Passing hardcoded GPMC virtual addressess is sure way to mess up things.
        This should all become unnecessary once the NAND drivers stops messing
        with the GPMC registers directly.

Sukumar Ghorai (3):
	omap3: GPMC register definition at common location
	omap3 nand: cleanup for not to use GPMC virtual address
	omap3 nand: fix issue in board file to detect the nand

 arch/arm/mach-omap2/board-cm-t35.c         |   20 +----
 arch/arm/mach-omap2/board-devkit8000.c     |   25 +------
 arch/arm/mach-omap2/board-omap3beagle.c    |   24 +-----
 arch/arm/mach-omap2/board-omap3touchbook.c |   25 +------
 arch/arm/mach-omap2/board-overo.c          |   24 +-----
 arch/arm/mach-omap2/gpmc.c                 |   67 +++++-----------
 arch/arm/plat-omap/include/plat/gpmc.h     |   41 ++++++++-
 arch/arm/plat-omap/include/plat/nand.h     |    6 +-
 drivers/mtd/nand/omap2.c                   |  125 ++++++++++------------------
 9 files changed, 109 insertions(+), 248 deletions(-)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH 1/3] omap3: GPMC register definition at common location
  2010-05-12  9:48 ` [PATCH 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
@ 2010-05-12  9:48   ` Sukumar Ghorai
  2010-05-12  9:48     ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
                       ` (2 more replies)
  2010-05-13 15:44   ` [PATCH 0/3] omap3 nand: cleanup exiting platform related code Tony Lindgren
  1 sibling, 3 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-12  9:48 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

GPMC register definition move to common place in gpmc.h.

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   38 +------------------------------
 arch/arm/plat-omap/include/plat/gpmc.h |   36 +++++++++++++++++++++++++++--
 drivers/mtd/nand/omap2.c               |   14 ++++-------
 3 files changed, 40 insertions(+), 48 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5bc3ca0..9c77af0
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -28,40 +28,6 @@
 
 #include <plat/sdrc.h>
 
-/* GPMC register offsets */
-#define GPMC_REVISION		0x00
-#define GPMC_SYSCONFIG		0x10
-#define GPMC_SYSSTATUS		0x14
-#define GPMC_IRQSTATUS		0x18
-#define GPMC_IRQENABLE		0x1c
-#define GPMC_TIMEOUT_CONTROL	0x40
-#define GPMC_ERR_ADDRESS	0x44
-#define GPMC_ERR_TYPE		0x48
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-#define GPMC_PREFETCH_CONFIG1	0x1e0
-#define GPMC_PREFETCH_CONFIG2	0x1e4
-#define GPMC_PREFETCH_CONTROL	0x1ec
-#define GPMC_PREFETCH_STATUS	0x1f0
-#define GPMC_ECC_CONFIG		0x1f4
-#define GPMC_ECC_CONTROL	0x1f8
-#define GPMC_ECC_SIZE_CONFIG	0x1fc
-
-#define GPMC_CS0		0x60
-#define GPMC_CS_SIZE		0x30
-
-#define GPMC_MEM_START		0x00000000
-#define GPMC_MEM_END		0x3FFFFFFF
-#define BOOT_ROM_SPACE		0x100000	/* 1MB */
-
-#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
-#define GPMC_SECTION_SHIFT	28		/* 128 MB */
-
-#define PREFETCH_FIFOTHRESHOLD	(0x40 << 8)
-#define CS_NUM_SHIFT		24
-#define ENABLE_PREFETCH		(0x1 << 7)
-#define DMA_MPU_MODE		2
-
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -112,7 +78,7 @@ void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	__raw_writel(val, reg_addr);
 }
 
@@ -120,7 +86,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	return __raw_readl(reg_addr);
 }
 
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 145838a..347d212 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -25,10 +25,40 @@
 #define GPMC_CS_NAND_ADDRESS	0x20
 #define GPMC_CS_NAND_DATA	0x24
 
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
+/* GPMC register offsets */
+#define GPMC_REVISION           0x00
+#define GPMC_SYSCONFIG          0x10
+#define GPMC_SYSSTATUS          0x14
+#define GPMC_IRQSTATUS          0x18
+#define GPMC_IRQENABLE          0x1c
+#define GPMC_TIMEOUT_CONTROL    0x40
+#define GPMC_ERR_ADDRESS        0x44
+#define GPMC_ERR_TYPE           0x48
+#define GPMC_CONFIG             0x50
+#define GPMC_STATUS             0x54
+#define GPMC_PREFETCH_CONFIG1   0x1e0
+#define GPMC_PREFETCH_CONFIG2   0x1e4
+#define GPMC_PREFETCH_CONTROL   0x1ec
+#define GPMC_PREFETCH_STATUS    0x1f0
+#define GPMC_ECC_CONFIG         0x1f4
+#define GPMC_ECC_CONTROL        0x1f8
+#define GPMC_ECC_SIZE_CONFIG    0x1fc
+#define GPMC_ECC1_RESULT        0x200
+
 #define GPMC_CS0_BASE		0x60
-#define GPMC_CS_SIZE		0x30
+#define GPMC_CS_SIZE            0x30
+
+#define GPMC_MEM_START          0x00000000
+#define GPMC_MEM_END            0x3FFFFFFF
+#define BOOT_ROM_SPACE          0x100000        /* 1MB */
+
+#define GPMC_CHUNK_SHIFT        24              /* 16 MB */
+#define GPMC_SECTION_SHIFT      28              /* 128 MB */
+
+#define PREFETCH_FIFOTHRESHOLD  (0x40 << 8)
+#define CS_NUM_SHIFT            24
+#define ENABLE_PREFETCH         (0x1 << 7)
+#define DMA_MPU_MODE            2
 
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 7545568..258bf06
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -23,12 +23,6 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 
-#define GPMC_IRQ_STATUS		0x18
-#define GPMC_ECC_CONFIG		0x1F4
-#define GPMC_ECC_CONTROL	0x1F8
-#define GPMC_ECC_SIZE_CONFIG	0x1FC
-#define GPMC_ECC1_RESULT	0x200
-
 #define	DRIVER_NAME	"omap2-nand"
 
 #define	NAND_WP_OFF	0
@@ -37,6 +31,7 @@
 #define	GPMC_BUF_FULL	0x00000001
 #define	GPMC_BUF_EMPTY	0x00000000
 
+#ifdef CONFIG_MTD_NAND_OMAP_HWECC
 #define NAND_Ecc_P1e		(1 << 0)
 #define NAND_Ecc_P2e		(1 << 1)
 #define NAND_Ecc_P4e		(1 << 2)
@@ -103,6 +98,7 @@
 
 #define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
 #define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
+#endif /* CONFIG_MTD_NAND_OMAP_HWECC */
 
 #ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL };
@@ -854,20 +850,20 @@ static int omap_dev_ready(struct mtd_info *mtd)
 {
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
 
 	if ((val & 0x100) == 0x100) {
 		/* Clear IRQ Interrupt */
 		val |= 0x100;
 		val &= ~(0x0);
-		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQSTATUS);
 	} else {
 		unsigned int cnt = 0;
 		while (cnt++ < 0x1FF) {
 			if  ((val & 0x100) == 0x100)
 				return 0;
 			val = __raw_readl(info->gpmc_baseaddr +
-							GPMC_IRQ_STATUS);
+							GPMC_IRQSTATUS);
 		}
 	}
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-12  9:48   ` [PATCH 1/3] omap3: GPMC register definition at common location Sukumar Ghorai
@ 2010-05-12  9:48     ` Sukumar Ghorai
  2010-05-12  9:48       ` [PATCH 3/3] omap3 nand: fix issue in board file to detect the nand Sukumar Ghorai
  2010-05-13 15:41       ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Tony Lindgren
  2010-05-13  6:15     ` [PATCH 1/3] omap3: GPMC register definition at common location Mike Rapoport
  2010-05-13 15:41     ` Tony Lindgren
  2 siblings, 2 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-12  9:48 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

Necessary function added in GPMC module and used by nand driver. This is for
not to use GPMC address directly from nand driver. Also it was passing GPMC
base address from board files and that is removed.

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/board-cm-t35.c         |    4 -
 arch/arm/mach-omap2/board-devkit8000.c     |    9 --
 arch/arm/mach-omap2/board-omap3beagle.c    |    8 --
 arch/arm/mach-omap2/board-omap3touchbook.c |    9 --
 arch/arm/mach-omap2/board-overo.c          |    7 --
 arch/arm/mach-omap2/gpmc.c                 |   29 ++++---
 arch/arm/plat-omap/include/plat/gpmc.h     |    5 +-
 arch/arm/plat-omap/include/plat/nand.h     |    6 +-
 drivers/mtd/nand/omap2.c                   |  117 ++++++++++-----------------
 9 files changed, 67 insertions(+), 127 deletions(-)

diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index e679a2c..fb23122
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -61,8 +61,6 @@
 #define SB_T35_SMSC911X_GPIO	65
 
 #define NAND_BLOCK_SIZE		SZ_128K
-#define GPMC_CS0_BASE		0x60
-#define GPMC_CS0_BASE_ADDR	(OMAP34XX_GPMC_VIRT + GPMC_CS0_BASE)
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #include <linux/smsc911x.h>
@@ -223,8 +221,6 @@ static struct omap_nand_platform_data cm_t35_nand_data = {
 	.nr_parts		= ARRAY_SIZE(cm_t35_nand_partitions),
 	.dma_channel		= -1,	/* disable DMA in OMAP NAND driver */
 	.cs			= 0,
-	.gpmc_cs_baseaddr	= (void __iomem *)GPMC_CS0_BASE_ADDR,
-	.gpmc_baseaddr		= (void __iomem *)OMAP34XX_GPMC_VIRT,
 
 };
 
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 47e3af2..be50d18
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -58,9 +58,6 @@
 #include "mux.h"
 #include "hsmmc.h"
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 #define OMAP_DM9000_GPIO_IRQ	25
@@ -581,8 +578,6 @@ static void __init devkit8000_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -604,10 +599,6 @@ static void __init devkit8000_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		devkit8000_nand_data.cs = nandcs;
-		devkit8000_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		devkit8000_nand_data.gpmc_baseaddr = (void *)
-			(gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
 		if (platform_device_register(&devkit8000_nand_device) < 0)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 962d377..becaebe
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -47,9 +47,6 @@
 #include "mux.h"
 #include "hsmmc.h"
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 static struct mtd_partition omap3beagle_nand_partitions[] = {
@@ -377,8 +374,6 @@ static void __init omap3beagle_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -400,9 +395,6 @@ static void __init omap3beagle_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		omap3beagle_nand_data.cs = nandcs;
-		omap3beagle_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		omap3beagle_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
 		if (platform_device_register(&omap3beagle_nand_device) < 0)
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index 2504d41..d6f1b12
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -54,9 +54,6 @@
 
 #include <asm/setup.h>
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 #define OMAP3_AC_GPIO		136
@@ -459,8 +456,6 @@ static void __init omap3touchbook_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -482,10 +477,6 @@ static void __init omap3touchbook_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		omap3touchbook_nand_data.cs = nandcs;
-		omap3touchbook_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		omap3touchbook_nand_data.gpmc_baseaddr =
-						(void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
 		if (platform_device_register(&omap3touchbook_nand_device) < 0)
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 8848c7c..d843a0a
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -58,8 +58,6 @@
 #define OVERO_GPIO_USBH_NRESET	183
 
 #define NAND_BLOCK_SIZE SZ_128K
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
 
 #define OVERO_SMSC911X_CS      5
 #define OVERO_SMSC911X_GPIO    176
@@ -239,8 +237,6 @@ static void __init overo_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -262,9 +258,6 @@ static void __init overo_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		overo_nand_data.cs = nandcs;
-		overo_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		overo_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
 		if (platform_device_register(&overo_nand_device) < 0)
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9c77af0..9210e10
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -64,16 +64,32 @@ static void __iomem *gpmc_base;
 
 static struct clk *gpmc_l3_clk;
 
-static void gpmc_write_reg(int idx, u32 val)
+void gpmc_write_reg(int idx, u32 val)
 {
 	__raw_writel(val, gpmc_base + idx);
 }
 
-static u32 gpmc_read_reg(int idx)
+u32 gpmc_read_reg(int idx)
 {
 	return __raw_readl(gpmc_base + idx);
 }
 
+void gpmc_cs_write_byte(int cs, int idx, u32 val)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
+	__raw_writeb(val, reg_addr);
+}
+
+u8 gpmc_cs_read_byte(int cs, int idx)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
+	return __raw_readb(reg_addr);
+}
+
 void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
@@ -432,15 +448,6 @@ void gpmc_prefetch_reset(void)
 }
 EXPORT_SYMBOL(gpmc_prefetch_reset);
 
-/**
- * gpmc_prefetch_status - reads prefetch status of engine
- */
-int  gpmc_prefetch_status(void)
-{
-	return gpmc_read_reg(GPMC_PREFETCH_STATUS);
-}
-EXPORT_SYMBOL(gpmc_prefetch_status);
-
 static void __init gpmc_mem_init(void)
 {
 	int cs;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 347d212..c1e9807
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -128,8 +128,12 @@ extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
 extern unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns);
 extern unsigned long gpmc_get_fclk_period(void);
 
+extern void gpmc_write_reg(int idx, u32 val);
+extern u32 gpmc_read_reg(int idx);
 extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
 extern u32 gpmc_cs_read_reg(int cs, int idx);
+extern void gpmc_cs_write_byte(int cs, int idx, u32 val);
+extern u8 gpmc_cs_read_byte(int cs, int idx);
 extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk);
 extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
 extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
@@ -139,7 +143,6 @@ extern int gpmc_cs_reserved(int cs);
 extern int gpmc_prefetch_enable(int cs, int dma_mode,
 					unsigned int u32_count, int is_write);
 extern void gpmc_prefetch_reset(void);
-extern int gpmc_prefetch_status(void);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_init(void);
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index f8efd54..6562cd0
--- a/arch/arm/plat-omap/include/plat/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
@@ -21,13 +21,11 @@ struct omap_nand_platform_data {
 	int			(*dev_ready)(struct omap_nand_platform_data *);
 	int			dma_channel;
 	unsigned long		phys_base;
-	void __iomem		*gpmc_cs_baseaddr;
-	void __iomem		*gpmc_baseaddr;
 	int			devsize;
 };
 
-/* size (4 KiB) for IO mapping */
-#define	NAND_IO_SIZE	SZ_4K
+/* minimum size for IO mapping */
+#define	NAND_IO_SIZE	4
 
 #if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
 extern int gpmc_nand_init(struct omap_nand_platform_data *d);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 258bf06..f4f6f01
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -135,9 +135,6 @@ struct omap_nand_info {
 
 	int				gpmc_cs;
 	unsigned long			phys_base;
-	void __iomem			*gpmc_cs_baseaddr;
-	void __iomem			*gpmc_baseaddr;
-	void __iomem			*nand_pref_fifo_add;
 	struct completion		comp;
 	int				dma_ch;
 };
@@ -149,17 +146,14 @@ struct omap_nand_info {
  */
 static void omap_nand_wp(struct mtd_info *mtd, int mode)
 {
-	struct omap_nand_info *info = container_of(mtd,
-						struct omap_nand_info, mtd);
-
-	unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);
+	unsigned long config = gpmc_read_reg(GPMC_CONFIG);
 
 	if (mode)
 		config &= ~(NAND_WP_BIT);	/* WP is ON */
 	else
 		config |= (NAND_WP_BIT);	/* WP is OFF */
 
-	__raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
+	gpmc_write_reg(GPMC_CONFIG, config);
 }
 
 /**
@@ -177,31 +171,20 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
 	struct omap_nand_info *info = container_of(mtd,
 					struct omap_nand_info, mtd);
-	switch (ctrl) {
-	case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_COMMAND;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
 
-	case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_ADDRESS;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
+	if (cmd != NAND_CMD_NONE) {
+		if (ctrl & NAND_CLE) {
+			gpmc_cs_write_byte(info->gpmc_cs,
+					GPMC_CS_NAND_COMMAND, cmd);
 
-	case NAND_CTRL_CHANGE | NAND_NCE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-	}
+		} else if (ctrl & NAND_ALE) {
+			gpmc_cs_write_byte(info->gpmc_cs,
+					GPMC_CS_NAND_ADDRESS, cmd);
 
-	if (cmd != NAND_CMD_NONE)
-		__raw_writeb(cmd, info->nand.IO_ADDR_W);
+		} else /* NAND_NCE */
+			gpmc_cs_write_byte(info->gpmc_cs,
+					GPMC_CS_NAND_DATA, cmd);
+	}
 }
 
 /**
@@ -231,8 +214,9 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
 
 	while (len--) {
 		iowrite8(*p++, info->nand.IO_ADDR_W);
-		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
-						GPMC_STATUS) & GPMC_BUF_FULL));
+		while (GPMC_BUF_EMPTY ==
+				(gpmc_read_reg(GPMC_STATUS) & GPMC_BUF_FULL))
+			;
 	}
 }
 
@@ -267,8 +251,8 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
 	while (len--) {
 		iowrite16(*p++, info->nand.IO_ADDR_W);
 
-		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
-						GPMC_STATUS) & GPMC_BUF_FULL))
+		while (GPMC_BUF_EMPTY ==
+				(gpmc_read_reg(GPMC_STATUS) & GPMC_BUF_FULL))
 			;
 	}
 }
@@ -304,9 +288,9 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 			omap_read_buf8(mtd, buf, len);
 	} else {
 		do {
-			pfpw_status = gpmc_prefetch_status();
+			pfpw_status = gpmc_read_reg(GPMC_PREFETCH_STATUS);
 			r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
-			ioread32_rep(info->nand_pref_fifo_add, p, r_count);
+			ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
 			p += r_count;
 			len -= r_count << 2;
 		} while (len);
@@ -347,12 +331,12 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 		else
 			omap_write_buf8(mtd, buf, len);
 	} else {
-		pfpw_status = gpmc_prefetch_status();
+		pfpw_status = gpmc_read_reg(GPMC_PREFETCH_STATUS);
 		while (pfpw_status & 0x3FFF) {
 			w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
 			for (i = 0; (i < w_count) && len; i++, len -= 2)
-				iowrite16(*p++, info->nand_pref_fifo_add);
-			pfpw_status = gpmc_prefetch_status();
+				iowrite16(*p++, info->nand.IO_ADDR_W);
+			pfpw_status = gpmc_read_reg(GPMC_PREFETCH_STATUS);
 		}
 
 		/* disable and stop the PFPW engine */
@@ -444,7 +428,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 	/* setup and start DMA using dma_addr */
 	wait_for_completion(&info->comp);
 
-	while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
+	while (0x3fff & (prefetch_status = gpmc_read_reg(GPMC_PREFETCH_STATUS)))
 		;
 	/* disable and stop the PFPW engine */
 	gpmc_prefetch_reset();
@@ -498,7 +482,7 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
 		omap_write_buf_pref(mtd, buf, len);
 	else
 		/* start transfer in DMA mode */
-		omap_nand_dma_transfer(mtd, buf, len, 0x1);
+		omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
 }
 
 /**
@@ -529,22 +513,21 @@ static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len)
  */
 static void omap_hwecc_init(struct mtd_info *mtd)
 {
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-							mtd);
 	struct nand_chip *chip = mtd->priv;
 	unsigned long val = 0x0;
 
 	/* Read from ECC Control Register */
-	val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+	val = gpmc_read_reg(GPMC_ECC_CONTROL);
+
 	/* Clear all ECC | Enable Reg1 */
 	val = ((0x00000001<<8) | 0x00000001);
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+	gpmc_write_reg(GPMC_ECC_CONTROL, val);
 
 	/* Read from ECC Size Config Register */
-	val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
+	val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
 	/* ECCSIZE1=512 | Select eccResultsize[0-3] */
 	val = ((((chip->ecc.size >> 1) - 1) << 22) | (0x0000000F));
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
+	gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
 }
 
 /**
@@ -746,19 +729,14 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
 static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 				u_char *ecc_code)
 {
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-							mtd);
 	unsigned long val = 0x0;
-	unsigned long reg;
 
 	/* Start Reading from HW ECC1_Result = 0x200 */
-	reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT);
-	val = __raw_readl(reg);
+	val = gpmc_read_reg(GPMC_ECC1_RESULT);
 	*ecc_code++ = val;          /* P128e, ..., P1e */
 	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
 	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
 	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
-	reg += 4;
 
 	return 0;
 }
@@ -774,21 +752,21 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
 							mtd);
 	struct nand_chip *chip = mtd->priv;
 	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
-	unsigned long val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+	unsigned long val = gpmc_read_reg(GPMC_ECC_CONFIG);
 
 	switch (mode) {
 	case NAND_ECC_READ:
-		__raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+		gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
 		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
 		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
 		break;
 	case NAND_ECC_READSYN:
-		 __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+		 gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
 		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
 		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
 		break;
 	case NAND_ECC_WRITE:
-		__raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+		gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
 		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
 		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
 		break;
@@ -798,7 +776,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
 		break;
 	}
 
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+	gpmc_write_reg(GPMC_ECC_CONFIG, val);
 }
 #endif
 
@@ -827,14 +805,11 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 	else
 		timeo += (HZ * 20) / 1000;
 
-	this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_COMMAND;
-	this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA;
-
-	__raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W);
+	gpmc_cs_write_byte(info->gpmc_cs,
+		GPMC_CS_NAND_COMMAND, (NAND_CMD_STATUS & 0xFF));
 
 	while (time_before(jiffies, timeo)) {
-		status = __raw_readb(this->IO_ADDR_R);
+		status = gpmc_cs_read_byte(info->gpmc_cs, GPMC_CS_NAND_DATA);
 		if (status & NAND_STATUS_READY)
 			break;
 		cond_resched();
@@ -848,22 +823,19 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
  */
 static int omap_dev_ready(struct mtd_info *mtd)
 {
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-							mtd);
-	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
+	unsigned int val = gpmc_read_reg(GPMC_IRQSTATUS);
 
 	if ((val & 0x100) == 0x100) {
 		/* Clear IRQ Interrupt */
 		val |= 0x100;
 		val &= ~(0x0);
-		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQSTATUS);
+		gpmc_write_reg(GPMC_IRQSTATUS, val);
 	} else {
 		unsigned int cnt = 0;
 		while (cnt++ < 0x1FF) {
 			if  ((val & 0x100) == 0x100)
 				return 0;
-			val = __raw_readl(info->gpmc_baseaddr +
-							GPMC_IRQSTATUS);
+			val = gpmc_read_reg(GPMC_IRQSTATUS);
 		}
 	}
 
@@ -894,8 +866,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->pdev = pdev;
 
 	info->gpmc_cs		= pdata->cs;
-	info->gpmc_baseaddr	= pdata->gpmc_baseaddr;
-	info->gpmc_cs_baseaddr	= pdata->gpmc_cs_baseaddr;
 	info->phys_base		= pdata->phys_base;
 
 	info->mtd.priv		= &info->nand;
@@ -942,7 +912,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 
 	if (use_prefetch) {
 		/* copy the virtual address of nand base for fifo access */
-		info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
 
 		info->nand.read_buf   = omap_read_buf_pref;
 		info->nand.write_buf  = omap_write_buf_pref;
@@ -1032,7 +1001,7 @@ static int omap_nand_remove(struct platform_device *pdev)
 
 	/* Release NAND device, its internal structures and partitions */
 	nand_release(&info->mtd);
-	iounmap(info->nand_pref_fifo_add);
+	iounmap(info->nand.IO_ADDR_R);
 	kfree(&info->mtd);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 3/3] omap3 nand: fix issue in board file to detect the nand
  2010-05-12  9:48     ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
@ 2010-05-12  9:48       ` Sukumar Ghorai
  2010-05-13 15:41       ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Tony Lindgren
  1 sibling, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-12  9:48 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

Board file modified to pass the GMPC phys_base address to nand driver. This is
required to adopt the _prob function as in omap2.c

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/board-cm-t35.c         |   16 +---------------
 arch/arm/mach-omap2/board-devkit8000.c     |   16 +---------------
 arch/arm/mach-omap2/board-omap3beagle.c    |   16 +---------------
 arch/arm/mach-omap2/board-omap3touchbook.c |   16 +---------------
 arch/arm/mach-omap2/board-overo.c          |   17 +----------------
 5 files changed, 5 insertions(+), 76 deletions(-)

diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index fb23122..0544294
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -224,23 +224,9 @@ static struct omap_nand_platform_data cm_t35_nand_data = {
 
 };
 
-static struct resource cm_t35_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device cm_t35_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.num_resources	= 1,
-	.resource	= &cm_t35_nand_resource,
-	.dev		= {
-		.platform_data	= &cm_t35_nand_data,
-	},
-};
-
 static void __init cm_t35_init_nand(void)
 {
-	if (platform_device_register(&cm_t35_nand_device) < 0)
+	if (gpmc_nand_init(&cm_t35_nand_data) < 0)
 		pr_err("CM-T35: Unable to register NAND device\n");
 }
 #else
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index be50d18..a6fcb48
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -101,20 +101,6 @@ static struct omap_nand_platform_data devkit8000_nand_data = {
 	.dma_channel	= -1,		/* disable DMA in OMAP NAND driver */
 };
 
-static struct resource devkit8000_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device devkit8000_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &devkit8000_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &devkit8000_nand_resource,
-};
-
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
@@ -601,7 +587,7 @@ static void __init devkit8000_flash_init(void)
 		devkit8000_nand_data.cs = nandcs;
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&devkit8000_nand_device) < 0)
+		if (gpmc_nand_init(&devkit8000_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index becaebe..bf31b7c
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -89,20 +89,6 @@ static struct omap_nand_platform_data omap3beagle_nand_data = {
 	.dev_ready	= NULL,
 };
 
-static struct resource omap3beagle_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device omap3beagle_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &omap3beagle_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &omap3beagle_nand_resource,
-};
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
@@ -397,7 +383,7 @@ static void __init omap3beagle_flash_init(void)
 		omap3beagle_nand_data.cs = nandcs;
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&omap3beagle_nand_device) < 0)
+		if (gpmc_nand_init(&omap3beagle_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index d6f1b12..e8ad30c
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -103,20 +103,6 @@ static struct omap_nand_platform_data omap3touchbook_nand_data = {
 	.dev_ready	= NULL,
 };
 
-static struct resource omap3touchbook_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device omap3touchbook_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &omap3touchbook_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &omap3touchbook_nand_resource,
-};
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
@@ -479,7 +465,7 @@ static void __init omap3touchbook_flash_init(void)
 		omap3touchbook_nand_data.cs = nandcs;
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&omap3touchbook_nand_device) < 0)
+		if (gpmc_nand_init(&omap3touchbook_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index d843a0a..627edd3
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -217,21 +217,6 @@ static struct omap_nand_platform_data overo_nand_data = {
 	.dma_channel = -1,	/* disable DMA in OMAP NAND driver */
 };
 
-static struct resource overo_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device overo_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &overo_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &overo_nand_resource,
-};
-
-
 static void __init overo_flash_init(void)
 {
 	u8 cs = 0;
@@ -260,7 +245,7 @@ static void __init overo_flash_init(void)
 		overo_nand_data.cs = nandcs;
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&overo_nand_device) < 0)
+		if (gpmc_nand_init(&overo_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH 1/3] omap3: GPMC register definition at common location
  2010-05-12  9:48   ` [PATCH 1/3] omap3: GPMC register definition at common location Sukumar Ghorai
  2010-05-12  9:48     ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
@ 2010-05-13  6:15     ` Mike Rapoport
  2010-05-13 15:41     ` Tony Lindgren
  2 siblings, 0 replies; 57+ messages in thread
From: Mike Rapoport @ 2010-05-13  6:15 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, linux-omap

Sukumar Ghorai wrote:
> GPMC register definition move to common place in gpmc.h.
> 
> Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>

Looks Ok to me, just minor comments

> ---
>  arch/arm/mach-omap2/gpmc.c             |   38 +------------------------------
>  arch/arm/plat-omap/include/plat/gpmc.h |   36 +++++++++++++++++++++++++++--
>  drivers/mtd/nand/omap2.c               |   14 ++++-------
>  3 files changed, 40 insertions(+), 48 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
> index 5bc3ca0..9c77af0
> --- a/arch/arm/mach-omap2/gpmc.c
> +++ b/arch/arm/mach-omap2/gpmc.c
> @@ -28,40 +28,6 @@
>  
>  #include <plat/sdrc.h>
>  
> -/* GPMC register offsets */
> -#define GPMC_REVISION		0x00
> -#define GPMC_SYSCONFIG		0x10
> -#define GPMC_SYSSTATUS		0x14
> -#define GPMC_IRQSTATUS		0x18
> -#define GPMC_IRQENABLE		0x1c
> -#define GPMC_TIMEOUT_CONTROL	0x40
> -#define GPMC_ERR_ADDRESS	0x44
> -#define GPMC_ERR_TYPE		0x48
> -#define GPMC_CONFIG		0x50
> -#define GPMC_STATUS		0x54
> -#define GPMC_PREFETCH_CONFIG1	0x1e0
> -#define GPMC_PREFETCH_CONFIG2	0x1e4
> -#define GPMC_PREFETCH_CONTROL	0x1ec
> -#define GPMC_PREFETCH_STATUS	0x1f0
> -#define GPMC_ECC_CONFIG		0x1f4
> -#define GPMC_ECC_CONTROL	0x1f8
> -#define GPMC_ECC_SIZE_CONFIG	0x1fc
> -
> -#define GPMC_CS0		0x60
> -#define GPMC_CS_SIZE		0x30
> -
> -#define GPMC_MEM_START		0x00000000
> -#define GPMC_MEM_END		0x3FFFFFFF
> -#define BOOT_ROM_SPACE		0x100000	/* 1MB */
> -
> -#define GPMC_CHUNK_SHIFT	24		/* 16 MB */
> -#define GPMC_SECTION_SHIFT	28		/* 128 MB */
> -
> -#define PREFETCH_FIFOTHRESHOLD	(0x40 << 8)
> -#define CS_NUM_SHIFT		24
> -#define ENABLE_PREFETCH		(0x1 << 7)
> -#define DMA_MPU_MODE		2
> -
>  /* Structure to save gpmc cs context */
>  struct gpmc_cs_config {
>  	u32 config1;
> @@ -112,7 +78,7 @@ void gpmc_cs_write_reg(int cs, int idx, u32 val)
>  {
>  	void __iomem *reg_addr;
>  
> -	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> +	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
>  	__raw_writel(val, reg_addr);
>  }
>  
> @@ -120,7 +86,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
>  {
>  	void __iomem *reg_addr;
>  
> -	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> +	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
>  	return __raw_readl(reg_addr);
>  }
>  
> diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
> index 145838a..347d212 100644
> --- a/arch/arm/plat-omap/include/plat/gpmc.h
> +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> @@ -25,10 +25,40 @@
>  #define GPMC_CS_NAND_ADDRESS	0x20
>  #define GPMC_CS_NAND_DATA	0x24
>  
> -#define GPMC_CONFIG		0x50
> -#define GPMC_STATUS		0x54
> +/* GPMC register offsets */
> +#define GPMC_REVISION           0x00
> +#define GPMC_SYSCONFIG          0x10
> +#define GPMC_SYSSTATUS          0x14
> +#define GPMC_IRQSTATUS          0x18
> +#define GPMC_IRQENABLE          0x1c
> +#define GPMC_TIMEOUT_CONTROL    0x40
> +#define GPMC_ERR_ADDRESS        0x44
> +#define GPMC_ERR_TYPE           0x48
> +#define GPMC_CONFIG             0x50
> +#define GPMC_STATUS             0x54
> +#define GPMC_PREFETCH_CONFIG1   0x1e0
> +#define GPMC_PREFETCH_CONFIG2   0x1e4
> +#define GPMC_PREFETCH_CONTROL   0x1ec
> +#define GPMC_PREFETCH_STATUS    0x1f0
> +#define GPMC_ECC_CONFIG         0x1f4
> +#define GPMC_ECC_CONTROL        0x1f8
> +#define GPMC_ECC_SIZE_CONFIG    0x1fc
> +#define GPMC_ECC1_RESULT        0x200
> +
>  #define GPMC_CS0_BASE		0x60
> -#define GPMC_CS_SIZE		0x30
> +#define GPMC_CS_SIZE            0x30
> +
> +#define GPMC_MEM_START          0x00000000
> +#define GPMC_MEM_END            0x3FFFFFFF
> +#define BOOT_ROM_SPACE          0x100000        /* 1MB */
> +
> +#define GPMC_CHUNK_SHIFT        24              /* 16 MB */
> +#define GPMC_SECTION_SHIFT      28              /* 128 MB */
> +
> +#define PREFETCH_FIFOTHRESHOLD  (0x40 << 8)
> +#define CS_NUM_SHIFT            24
> +#define ENABLE_PREFETCH         (0x1 << 7)
> +#define DMA_MPU_MODE            2
>  
>  #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
>  #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> index 7545568..258bf06
> --- a/drivers/mtd/nand/omap2.c
> +++ b/drivers/mtd/nand/omap2.c
> @@ -23,12 +23,6 @@
>  #include <plat/gpmc.h>
>  #include <plat/nand.h>
>  
> -#define GPMC_IRQ_STATUS		0x18
> -#define GPMC_ECC_CONFIG		0x1F4
> -#define GPMC_ECC_CONTROL	0x1F8
> -#define GPMC_ECC_SIZE_CONFIG	0x1FC
> -#define GPMC_ECC1_RESULT	0x200
> -
>  #define	DRIVER_NAME	"omap2-nand"
>  
>  #define	NAND_WP_OFF	0
> @@ -37,6 +31,7 @@
>  #define	GPMC_BUF_FULL	0x00000001
>  #define	GPMC_BUF_EMPTY	0x00000000
>  
> +#ifdef CONFIG_MTD_NAND_OMAP_HWECC

This change does not seem related to the patch subject.

>  #define NAND_Ecc_P1e		(1 << 0)
>  #define NAND_Ecc_P2e		(1 << 1)
>  #define NAND_Ecc_P4e		(1 << 2)
> @@ -103,6 +98,7 @@
>  
>  #define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
>  #define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
> +#endif /* CONFIG_MTD_NAND_OMAP_HWECC */
>  
>  #ifdef CONFIG_MTD_PARTITIONS
>  static const char *part_probes[] = { "cmdlinepart", NULL };
> @@ -854,20 +850,20 @@ static int omap_dev_ready(struct mtd_info *mtd)
>  {
>  	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
>  							mtd);
> -	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS);
> +	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQSTATUS);
>  
>  	if ((val & 0x100) == 0x100) {
>  		/* Clear IRQ Interrupt */
>  		val |= 0x100;
>  		val &= ~(0x0);
> -		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS);
> +		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQSTATUS);
>  	} else {
>  		unsigned int cnt = 0;
>  		while (cnt++ < 0x1FF) {
>  			if  ((val & 0x100) == 0x100)
>  				return 0;
>  			val = __raw_readl(info->gpmc_baseaddr +
> -							GPMC_IRQ_STATUS);
> +							GPMC_IRQSTATUS);
>  		}
>  	}
>  


-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-12  9:48     ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
  2010-05-12  9:48       ` [PATCH 3/3] omap3 nand: fix issue in board file to detect the nand Sukumar Ghorai
@ 2010-05-13 15:41       ` Tony Lindgren
  2010-05-13 18:48         ` Ghorai, Sukumar
  1 sibling, 1 reply; 57+ messages in thread
From: Tony Lindgren @ 2010-05-13 15:41 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: sakoman, Artem.Bityutskiy, linux-omap, linux-mtd

* Sukumar Ghorai <s-ghorai@ti.com> [100512 02:43]:
> --- a/arch/arm/mach-omap2/gpmc.c
> +++ b/arch/arm/mach-omap2/gpmc.c
> @@ -64,16 +64,32 @@ static void __iomem *gpmc_base;
>  
>  static struct clk *gpmc_l3_clk;
>  
> -static void gpmc_write_reg(int idx, u32 val)
> +void gpmc_write_reg(int idx, u32 val)
>  {
>  	__raw_writel(val, gpmc_base + idx);
>  }
>  
> -static u32 gpmc_read_reg(int idx)
> +u32 gpmc_read_reg(int idx)
>  {
>  	return __raw_readl(gpmc_base + idx);
>  }
>  
> +void gpmc_cs_write_byte(int cs, int idx, u32 val)
> +{
> +	void __iomem *reg_addr;
> +
> +	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> +	__raw_writeb(val, reg_addr);
> +}
> +
> +u8 gpmc_cs_read_byte(int cs, int idx)
> +{
> +	void __iomem *reg_addr;
> +
> +	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> +	return __raw_readb(reg_addr);
> +}
> +

This will not improve the situation unfortunately.
We for sure don't want to export functions to mess
with the GPMC registers all over the place.

> @@ -432,15 +448,6 @@ void gpmc_prefetch_reset(void)
>  }
>  EXPORT_SYMBOL(gpmc_prefetch_reset);
>  
> -/**
> - * gpmc_prefetch_status - reads prefetch status of engine
> - */
> -int  gpmc_prefetch_status(void)
> -{
> -	return gpmc_read_reg(GPMC_PREFETCH_STATUS);
> -}
> -EXPORT_SYMBOL(gpmc_prefetch_status);
> -

And we don't want to remove GPMC functions like this,
instead we need to implement more functions like this
for the platform init code to use.

Regards,

Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 1/3] omap3: GPMC register definition at common location
  2010-05-12  9:48   ` [PATCH 1/3] omap3: GPMC register definition at common location Sukumar Ghorai
  2010-05-12  9:48     ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
  2010-05-13  6:15     ` [PATCH 1/3] omap3: GPMC register definition at common location Mike Rapoport
@ 2010-05-13 15:41     ` Tony Lindgren
  2 siblings, 0 replies; 57+ messages in thread
From: Tony Lindgren @ 2010-05-13 15:41 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: sakoman, Artem.Bityutskiy, linux-omap, linux-mtd

* Sukumar Ghorai <s-ghorai@ti.com> [100512 02:43]:
> --- a/arch/arm/plat-omap/include/plat/gpmc.h
> +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> @@ -25,10 +25,40 @@
>  #define GPMC_CS_NAND_ADDRESS	0x20
>  #define GPMC_CS_NAND_DATA	0x24
>  
> -#define GPMC_CONFIG		0x50
> -#define GPMC_STATUS		0x54
> +/* GPMC register offsets */
> +#define GPMC_REVISION           0x00
> +#define GPMC_SYSCONFIG          0x10
> +#define GPMC_SYSSTATUS          0x14
> +#define GPMC_IRQSTATUS          0x18
> +#define GPMC_IRQENABLE          0x1c
> +#define GPMC_TIMEOUT_CONTROL    0x40
> +#define GPMC_ERR_ADDRESS        0x44
> +#define GPMC_ERR_TYPE           0x48
> +#define GPMC_CONFIG             0x50
> +#define GPMC_STATUS             0x54
> +#define GPMC_PREFETCH_CONFIG1   0x1e0
> +#define GPMC_PREFETCH_CONFIG2   0x1e4
> +#define GPMC_PREFETCH_CONTROL   0x1ec
> +#define GPMC_PREFETCH_STATUS    0x1f0
> +#define GPMC_ECC_CONFIG         0x1f4
> +#define GPMC_ECC_CONTROL        0x1f8
> +#define GPMC_ECC_SIZE_CONFIG    0x1fc
> +#define GPMC_ECC1_RESULT        0x200
...

No thanks, that will just make the situation worse
leading into all the drivers messing with the GPMC
registers.

Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 0/3] omap3 nand: cleanup exiting platform related code
  2010-05-12  9:48 ` [PATCH 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
  2010-05-12  9:48   ` [PATCH 1/3] omap3: GPMC register definition at common location Sukumar Ghorai
@ 2010-05-13 15:44   ` Tony Lindgren
  1 sibling, 0 replies; 57+ messages in thread
From: Tony Lindgren @ 2010-05-13 15:44 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: sakoman, Artem.Bityutskiy, linux-omap, linux-mtd

* Sukumar Ghorai <s-ghorai@ti.com> [100512 02:43]:
>    The following set of patches applies on top of master branch.
> 	http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git
>    Patches verified on: omap3430-SDP, omap3630-sdp, zoom3 and beagle board
> 
>    And these are the patches required to address the following input -
>      1. The NAND driver needs to stop tinkering with the GPMC registers
> 	The omap General Purpose Memory Controller (GPMC) registers are omap
>         specific, and not driver specific. Tinkering with these registers can
>         cause issues with the other devices on the GPMC.
> 
>      2. Passing hardcoded GPMC_CS0_BASE needs to go from the board files
> 	Passing hardcoded GPMC virtual addressess is sure way to mess up things.
>         This should all become unnecessary once the NAND drivers stops messing
>         with the GPMC registers directly.

Thanks for working on this. I've made some comments to you patches
to do what's listed above.

Instead of exporting the GPMC registers, you should create new
functions into gpmc.c for the nand platform init code to use.

Regards,

Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-13 15:41       ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Tony Lindgren
@ 2010-05-13 18:48         ` Ghorai, Sukumar
  0 siblings, 0 replies; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-05-13 18:48 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: sakoman@gmail.com, Artem.Bityutskiy@nokia.com,
	linux-omap@vger.kernel.org, linux-mtd@lists.infradead.org

Tony,

> -----Original Message-----
> From: Tony Lindgren [mailto:tony@atomide.com]
> Sent: 2010-05-13 21:11
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> sakoman@gmail.com; mike@compulab.co.il; Artem.Bityutskiy@nokia.com
> Subject: Re: [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual
> address
> 
> * Sukumar Ghorai <s-ghorai@ti.com> [100512 02:43]:
> > --- a/arch/arm/mach-omap2/gpmc.c
> > +++ b/arch/arm/mach-omap2/gpmc.c
> > @@ -64,16 +64,32 @@ static void __iomem *gpmc_base;
> >
> >  static struct clk *gpmc_l3_clk;
> >
> > -static void gpmc_write_reg(int idx, u32 val)
> > +void gpmc_write_reg(int idx, u32 val)
> >  {
> >  	__raw_writel(val, gpmc_base + idx);
> >  }
> >
> > -static u32 gpmc_read_reg(int idx)
> > +u32 gpmc_read_reg(int idx)
> >  {
> >  	return __raw_readl(gpmc_base + idx);
> >  }
> >
> > +void gpmc_cs_write_byte(int cs, int idx, u32 val)
> > +{
> > +	void __iomem *reg_addr;
> > +
> > +	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> > +	__raw_writeb(val, reg_addr);
> > +}
> > +
> > +u8 gpmc_cs_read_byte(int cs, int idx)
> > +{
> > +	void __iomem *reg_addr;
> > +
> > +	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> > +	return __raw_readb(reg_addr);
> > +}
> > +
> 
> This will not improve the situation unfortunately.
> We for sure don't want to export functions to mess
> with the GPMC registers all over the place.
> 
> > @@ -432,15 +448,6 @@ void gpmc_prefetch_reset(void)
> >  }
> >  EXPORT_SYMBOL(gpmc_prefetch_reset);
> >
> > -/**
> > - * gpmc_prefetch_status - reads prefetch status of engine
> > - */
> > -int  gpmc_prefetch_status(void)
> > -{
> > -	return gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > -}
> > -EXPORT_SYMBOL(gpmc_prefetch_status);
> > -
> 
> And we don't want to remove GPMC functions like this,
> instead we need to implement more functions like this
> for the platform init code to use.

[Ghorai] 
1. NAND IO address needed by core NAND driver. So we can't move that access to GMPC.
2. And is it ok if we add functions as below and all need to be as EXPORT_SYMBOL too? 
get_gpmc_status()
get_gpmc_irq_status()
set_gpmc_irq_status()
set_gpmc_irq_enable()
get_gpmc_config
set_gpmc_config
get_gpmc_status()
get_gpmc_prefetch_config()
gpmc_prefetch_status 
set_gpmc_ecc_config
set_gpmc_ecc_contol
set_gpmc_ecc_size
get_gpmc_ecc_result

Regards,
Sukumar


> Regards,
> 
> Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v2 0/2] omap3 nand: cleanup exiting platform related code
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
                   ` (7 preceding siblings ...)
  2010-05-12  9:48 ` [PATCH 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
@ 2010-05-14 15:23 ` Sukumar Ghorai
  2010-05-14 15:23   ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
  2010-05-18 11:16 ` [PATCH v3 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
  2010-06-04  7:40 ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
  10 siblings, 1 reply; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-14 15:23 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

  v2:
   The following set of patches applies on top of master branch.
	http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git
   Patches verified on: omap3430-SDP, omap3630-sdp, zoom3 and beagle board

   And these are the patches required to address the following input -
     1. The NAND driver needs to stop tinkering with the GPMC registers
	The omap General Purpose Memory Controller (GPMC) registers are omap
        specific, and not driver specific. Tinkering with these registers can
        cause issues with the other devices on the GPMC.

     2. Passing hardcoded GPMC_CS0_BASE needs to go from the board files
	Passing hardcoded GPMC virtual addressess is sure way to mess up things.
        This should all become unnecessary once the NAND drivers stops messing
        with the GPMC registers directly.

  v1: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28164.html

Sukumar Ghorai (2):
	omap3 nand: cleanup for not to use GPMC virtual address
	omap3 nand: fix issue in board file to detect the nand

 arch/arm/mach-omap2/board-cm-t35.c         |   20 +---
 arch/arm/mach-omap2/board-devkit8000.c     |   25 +---
 arch/arm/mach-omap2/board-omap3beagle.c    |   24 +---
 arch/arm/mach-omap2/board-omap3touchbook.c |   25 +---
 arch/arm/mach-omap2/board-overo.c          |   24 +---
 arch/arm/mach-omap2/gpmc-nand.c            |   38 ++----
 arch/arm/mach-omap2/gpmc-onenand.c         |    2 +-
 arch/arm/mach-omap2/gpmc.c                 |  244 ++++++++++++++++++++++++----
 arch/arm/plat-omap/include/plat/gpmc.h     |   36 ++++-
 arch/arm/plat-omap/include/plat/nand.h     |    6 +-
 drivers/mtd/nand/omap2.c                   |  190 ++++++----------------
 11 files changed, 306 insertions(+), 328 deletions(-)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-14 15:23 ` [PATCH v2 0/2] " Sukumar Ghorai
@ 2010-05-14 15:23   ` Sukumar Ghorai
  2010-05-14 15:23     ` [PATCH v2 2/2] omap3 nand: fix issue in board file to detect the nand Sukumar Ghorai
                       ` (3 more replies)
  0 siblings, 4 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-14 15:23 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

Necessary function added in GPMC module and used by nand driver. This is for
not to use GPMC address directly from nand driver. Also it was passing GPMC
base address from board files and that is removed.

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/board-cm-t35.c         |    4 -
 arch/arm/mach-omap2/board-devkit8000.c     |    9 -
 arch/arm/mach-omap2/board-omap3beagle.c    |    8 -
 arch/arm/mach-omap2/board-omap3touchbook.c |    9 -
 arch/arm/mach-omap2/board-overo.c          |    7 -
 arch/arm/mach-omap2/gpmc-nand.c            |   38 ++----
 arch/arm/mach-omap2/gpmc-onenand.c         |    2 +-
 arch/arm/mach-omap2/gpmc.c                 |  244 ++++++++++++++++++++++++----
 arch/arm/plat-omap/include/plat/gpmc.h     |   36 ++++-
 arch/arm/plat-omap/include/plat/nand.h     |    6 +-
 drivers/mtd/nand/omap2.c                   |  190 ++++++----------------
 11 files changed, 301 insertions(+), 252 deletions(-)

diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index f4e8063..87bed2a
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -61,8 +61,6 @@
 #define SB_T35_SMSC911X_GPIO	65
 
 #define NAND_BLOCK_SIZE		SZ_128K
-#define GPMC_CS0_BASE		0x60
-#define GPMC_CS0_BASE_ADDR	(OMAP34XX_GPMC_VIRT + GPMC_CS0_BASE)
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #include <linux/smsc911x.h>
@@ -223,8 +221,6 @@ static struct omap_nand_platform_data cm_t35_nand_data = {
 	.nr_parts		= ARRAY_SIZE(cm_t35_nand_partitions),
 	.dma_channel		= -1,	/* disable DMA in OMAP NAND driver */
 	.cs			= 0,
-	.gpmc_cs_baseaddr	= (void __iomem *)GPMC_CS0_BASE_ADDR,
-	.gpmc_baseaddr		= (void __iomem *)OMAP34XX_GPMC_VIRT,
 
 };
 
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 6d910df..ef9b677
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -58,9 +58,6 @@
 #include "mux.h"
 #include "hsmmc.h"
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 #define OMAP_DM9000_GPIO_IRQ	25
@@ -581,8 +578,6 @@ static void __init devkit8000_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -604,10 +599,6 @@ static void __init devkit8000_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		devkit8000_nand_data.cs = nandcs;
-		devkit8000_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		devkit8000_nand_data.gpmc_baseaddr = (void *)
-			(gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
 		if (platform_device_register(&devkit8000_nand_device) < 0)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 5df89f6..e90dd2a
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -47,9 +47,6 @@
 #include "mux.h"
 #include "hsmmc.h"
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 static struct mtd_partition omap3beagle_nand_partitions[] = {
@@ -377,8 +374,6 @@ static void __init omap3beagle_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -400,9 +395,6 @@ static void __init omap3beagle_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		omap3beagle_nand_data.cs = nandcs;
-		omap3beagle_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		omap3beagle_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
 		if (platform_device_register(&omap3beagle_nand_device) < 0)
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index c59050d..4a6c984
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -54,9 +54,6 @@
 
 #include <asm/setup.h>
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 #define OMAP3_AC_GPIO		136
@@ -459,8 +456,6 @@ static void __init omap3touchbook_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -482,10 +477,6 @@ static void __init omap3touchbook_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		omap3touchbook_nand_data.cs = nandcs;
-		omap3touchbook_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		omap3touchbook_nand_data.gpmc_baseaddr =
-						(void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
 		if (platform_device_register(&omap3touchbook_nand_device) < 0)
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 24b32d7..a9151fb
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -58,8 +58,6 @@
 #define OVERO_GPIO_USBH_NRESET	183
 
 #define NAND_BLOCK_SIZE SZ_128K
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
 
 #define OVERO_SMSC911X_CS      5
 #define OVERO_SMSC911X_GPIO    176
@@ -251,8 +249,6 @@ static void __init overo_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -274,9 +270,6 @@ static void __init overo_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		overo_nand_data.cs = nandcs;
-		overo_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		overo_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
 		if (platform_device_register(&overo_nand_device) < 0)
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index e57fb29..8aa74be
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -19,8 +19,6 @@
 #include <plat/board.h>
 #include <plat/gpmc.h>
 
-#define WR_RD_PIN_MONITORING	0x00600000
-
 static struct omap_nand_platform_data *gpmc_nand_data;
 
 static struct resource gpmc_nand_resource = {
@@ -71,10 +69,10 @@ static int omap2_nand_gpmc_retime(void)
 	t.wr_cycle  = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);
 
 	/* Configure GPMC */
-	gpmc_cs_write_reg(gpmc_nand_data->cs, GPMC_CS_CONFIG1,
-			GPMC_CONFIG1_DEVICESIZE(gpmc_nand_data->devsize) |
-			GPMC_CONFIG1_DEVICETYPE_NAND);
-
+	gpmc_hwcontrol(1, gpmc_nand_data->cs,
+			GPMC_CONFIG_DEV_SIZE, gpmc_nand_data->devsize, NULL);
+	gpmc_hwcontrol(1, gpmc_nand_data->cs,
+			GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND, NULL);
 	err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
 	if (err)
 		return err;
@@ -82,27 +80,13 @@ static int omap2_nand_gpmc_retime(void)
 	return 0;
 }
 
-static int gpmc_nand_setup(void)
-{
-	struct device *dev = &gpmc_nand_device.dev;
-
-	/* Set timings in GPMC */
-	if (omap2_nand_gpmc_retime() < 0) {
-		dev_err(dev, "Unable to set gpmc timings\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
 {
-	unsigned int val;
 	int err	= 0;
 	struct device *dev = &gpmc_nand_device.dev;
 
 	gpmc_nand_data = _nand_data;
-	gpmc_nand_data->nand_setup = gpmc_nand_setup;
+	gpmc_nand_data->nand_setup = omap2_nand_gpmc_retime;
 	gpmc_nand_device.dev.platform_data = gpmc_nand_data;
 
 	err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
@@ -112,19 +96,17 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
 		return err;
 	}
 
-	err = gpmc_nand_setup();
+	 /* Set timings in GPMC */
+	err = omap2_nand_gpmc_retime();
 	if (err < 0) {
-		dev_err(dev, "NAND platform setup failed: %d\n", err);
+		dev_err(dev, "Unable to set gpmc timings: %d\n", err);
 		return err;
 	}
 
 	/* Enable RD PIN Monitoring Reg */
 	if (gpmc_nand_data->dev_ready) {
-		val  = gpmc_cs_read_reg(gpmc_nand_data->cs,
-						 GPMC_CS_CONFIG1);
-		val |= WR_RD_PIN_MONITORING;
-		gpmc_cs_write_reg(gpmc_nand_data->cs,
-						GPMC_CS_CONFIG1, val);
+		gpmc_hwcontrol(1, gpmc_nand_data->cs,
+						GPMC_CONFIG_RDY_BSY, 1, NULL);
 	}
 
 	err = platform_device_register(&gpmc_nand_device);
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 7bb6922..5d66817
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -301,7 +301,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
 				(GPMC_CONFIG1_WAIT_READ_MON |
 				 GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
 			  GPMC_CONFIG1_DEVICESIZE_16 |
-			  GPMC_CONFIG1_DEVICETYPE_NOR |
+			  GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NOR) |
 			  GPMC_CONFIG1_MUXADDDATA);
 
 	err = gpmc_cs_set_timings(cs, &t);
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5bc3ca0..a3fd1ed
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -29,27 +29,27 @@
 #include <plat/sdrc.h>
 
 /* GPMC register offsets */
-#define GPMC_REVISION		0x00
-#define GPMC_SYSCONFIG		0x10
-#define GPMC_SYSSTATUS		0x14
-#define GPMC_IRQSTATUS		0x18
-#define GPMC_IRQENABLE		0x1c
-#define GPMC_TIMEOUT_CONTROL	0x40
-#define GPMC_ERR_ADDRESS	0x44
-#define GPMC_ERR_TYPE		0x48
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-#define GPMC_PREFETCH_CONFIG1	0x1e0
-#define GPMC_PREFETCH_CONFIG2	0x1e4
-#define GPMC_PREFETCH_CONTROL	0x1ec
-#define GPMC_PREFETCH_STATUS	0x1f0
-#define GPMC_ECC_CONFIG		0x1f4
-#define GPMC_ECC_CONTROL	0x1f8
-#define GPMC_ECC_SIZE_CONFIG	0x1fc
-
-#define GPMC_CS0		0x60
-#define GPMC_CS_SIZE		0x30
-
+#define GPMC_REVISION           0x00
+#define GPMC_SYSCONFIG          0x10
+#define GPMC_SYSSTATUS          0x14
+#define GPMC_IRQSTATUS          0x18
+#define GPMC_IRQENABLE          0x1c
+#define GPMC_TIMEOUT_CONTROL    0x40
+#define GPMC_ERR_ADDRESS        0x44
+#define GPMC_ERR_TYPE           0x48
+#define GPMC_CONFIG             0x50
+#define GPMC_STATUS             0x54
+#define GPMC_PREFETCH_CONFIG1   0x1e0
+#define GPMC_PREFETCH_CONFIG2   0x1e4
+#define GPMC_PREFETCH_CONTROL   0x1ec
+#define GPMC_PREFETCH_STATUS    0x1f0
+#define GPMC_ECC_CONFIG         0x1f4
+#define GPMC_ECC_CONTROL        0x1f8
+#define GPMC_ECC_SIZE_CONFIG    0x1fc
+#define GPMC_ECC1_RESULT        0x200
+
+#define GPMC_CS0_BASE		0x60
+#define GPMC_CS_SIZE            0x30
 #define GPMC_MEM_START		0x00000000
 #define GPMC_MEM_END		0x3FFFFFFF
 #define BOOT_ROM_SPACE		0x100000	/* 1MB */
@@ -108,11 +108,27 @@ static u32 gpmc_read_reg(int idx)
 	return __raw_readl(gpmc_base + idx);
 }
 
+static void gpmc_cs_write_byte(int cs, int idx, u8 val)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
+	__raw_writeb(val, reg_addr);
+}
+
+static u8 gpmc_cs_read_byte(int cs, int idx)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
+	return __raw_readb(reg_addr);
+}
+
 void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	__raw_writel(val, reg_addr);
 }
 
@@ -120,7 +136,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	return __raw_readl(reg_addr);
 }
 
@@ -419,6 +435,96 @@ void gpmc_cs_free(int cs)
 EXPORT_SYMBOL(gpmc_cs_free);
 
 /**
+ * gpmc_hwcontrol - hardware specific access (read/ write) to control
+ * @write: need 1 for configure; 0 for reading the complete register
+ * @cs: chip select number
+ * @cmd: Command type
+ * @wval: value/information to write
+ * @rval: pointer to get the value back
+ */
+int gpmc_hwcontrol(int write, int cs, int cmd, int wval, int *rval)
+{
+	u32 reg = 0;
+	u32 regval = 0;
+
+	switch (cmd) {
+
+	case GPMC_GET_SET_STATUS:
+		reg = GPMC_STATUS;
+		if (write)
+			gpmc_write_reg(GPMC_STATUS, regval);
+		break;
+
+	case GPMC_GET_SET_IRQ_STATUS:
+		reg = GPMC_IRQSTATUS;
+		if (write)
+			gpmc_write_reg(GPMC_IRQSTATUS, regval);
+		break;
+
+	case GPMC_GET_PREF_STATUS:
+		reg = GPMC_PREFETCH_STATUS;
+		break;
+
+	case GPMC_CONFIG_WP:
+		reg = GPMC_CONFIG;
+		regval = gpmc_read_reg(GPMC_CONFIG);
+	    if (wval)
+			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
+		else
+			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
+		gpmc_write_reg(reg, regval);
+		break;
+
+	case GPMC_CONFIG_RDY_BSY:
+		#define WR_RD_PIN_MONITORING    0x00600000
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= WR_RD_PIN_MONITORING;
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_CONFIG_DEV_SIZE:
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= GPMC_CONFIG1_DEVICESIZE(wval);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_CONFIG_DEV_TYPE:
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= GPMC_CONFIG1_DEVICETYPE(wval);
+		if (wval == GPMC_DEVICETYPE_NOR)
+			regval |= GPMC_CONFIG1_MUXADDDATA;
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_NAND_COMMAND:
+		gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
+		break;
+
+	case GPMC_NAND_ADDRESS:
+		gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
+		break;
+
+	case GPMC_NAND_DATA:
+		if (write)
+			gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
+		else
+			*rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
+		break;
+
+	default:
+		dump_stack();
+		printk(KERN_ERR "not supported\n");
+		return -1;
+	}
+
+	if (!write && reg)
+		*rval = gpmc_read_reg(reg);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpmc_hwcontrol);
+
+/**
  * gpmc_prefetch_enable - configures and starts prefetch transfer
  * @cs: nand cs (chip select) number
  * @dma_mode: dma mode enable (1) or disable (0)
@@ -466,15 +572,6 @@ void gpmc_prefetch_reset(void)
 }
 EXPORT_SYMBOL(gpmc_prefetch_reset);
 
-/**
- * gpmc_prefetch_status - reads prefetch status of engine
- */
-int  gpmc_prefetch_status(void)
-{
-	return gpmc_read_reg(GPMC_PREFETCH_STATUS);
-}
-EXPORT_SYMBOL(gpmc_prefetch_status);
-
 static void __init gpmc_mem_init(void)
 {
 	int cs;
@@ -615,3 +712,86 @@ void omap3_gpmc_restore_context(void)
 	}
 }
 #endif /* CONFIG_ARCH_OMAP3 */
+
+/**
+ * gmpc_ecc_init - Initialize the HW ECC for NAND flash in GPMC controller
+ * @cs: Chip select number
+ * @ecc_size: bytes for which ECC will be generated
+ */
+void gpmc_ecc_init(int cs, int ecc_size)
+{
+	unsigned int val = 0x0;
+
+	/* Read from ECC Control Register */
+	val = gpmc_read_reg(GPMC_ECC_CONTROL);
+
+	/* Clear all ECC | Enable Reg1 */
+	val = ((0x00000001<<8) | 0x00000001);
+	gpmc_write_reg(GPMC_ECC_CONTROL, val);
+
+	/* Read from ECC Size Config Register */
+	val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
+	/* ECCSIZE1=512 | Select eccResultsize[0-3] */
+	val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
+	gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
+}
+
+/**
+ * gpmc_calcuate_ecc - Generate non-inverted ECC bytes.
+ * @cs: Chip select number
+ * @dat: The pointer to data on which ecc is computed
+ * @ecc_code: The ecc_code buffer
+ *
+ * Using noninverted ECC can be considered ugly since writing a blank
+ * page ie. padding will clear the ECC bytes. This is no problem as long
+ * nobody is trying to write data on the seemingly unused page. Reading
+ * an erased page will produce an ECC mismatch between generated and read
+ * ECC bytes that has to be dealt with separately.
+ */
+int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
+{
+	unsigned int val = 0x0;
+
+	/* Start Reading from HW ECC1_Result = 0x200 */
+	val = gpmc_read_reg(GPMC_ECC1_RESULT);
+	*ecc_code++ = val;          /* P128e, ..., P1e */
+	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
+	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
+
+	return 0;
+}
+
+/**
+ * gpmc_enable_hwecc - This function enables the hardware ecc functionality
+ * @cs: Chip select number
+ * @mode: Read/Write mode
+ * @dev_width: device bus width
+ */
+void gpmc_enable_hwecc(int cs, int mode, int dev_width)
+{
+	unsigned int val = gpmc_read_reg(GPMC_ECC_CONFIG);
+
+	switch (mode) {
+	case GPMC_ECC_READ:
+		gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
+		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+		val = (dev_width << 7) | (cs << 1) | (0x1);
+		break;
+	case GPMC_ECC_READSYN:
+		 gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
+		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+		val = (dev_width << 7) | (cs << 1) | (0x1);
+		break;
+	case GPMC_ECC_WRITE:
+		gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
+		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+		val = (dev_width << 7) | (cs << 1) | (0x1);
+		break;
+	default:
+		printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode);
+		break;
+	}
+
+	gpmc_write_reg(GPMC_ECC_CONFIG, val);
+}
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 145838a..56e1407
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -25,10 +25,22 @@
 #define GPMC_CS_NAND_ADDRESS	0x20
 #define GPMC_CS_NAND_DATA	0x24
 
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-#define GPMC_CS0_BASE		0x60
-#define GPMC_CS_SIZE		0x30
+/* Control Commands */
+#define GPMC_GET_SET_STATUS	0x00000001
+#define GPMC_CONFIG_WP		0x00000002
+#define GPMC_CONFIG_RDY_BSY	0x00000003
+#define GPMC_CONFIG_DEV_SIZE	0x00000004
+#define GPMC_CONFIG_DEV_TYPE    0x00000005
+#define GPMC_NAND_COMMAND	0x00000006
+#define GPMC_NAND_ADDRESS	0x00000007
+#define GPMC_NAND_DATA		0x00000008
+#define GPMC_GET_PREF_STATUS	0x00000009
+#define GPMC_GET_SET_IRQ_STATUS	0x0000000a
+
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
 
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
@@ -44,10 +56,7 @@
 #define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
 #define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
-#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
 #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
-#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_DEVICETYPE_NAND    GPMC_CONFIG1_DEVICETYPE(2)
 #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
 #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
 #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
@@ -56,6 +65,12 @@
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 #define GPMC_CONFIG7_CSVALID		(1 << 6)
 
+#define GPMC_DEVICETYPE_NOR	0
+#define GPMC_DEVICETYPE_NAND	2
+#define GPMC_CONFIG_WRITEPROTECT	0x00000010
+#define GPMC_CONFIG1_DEVICESIZE_16	GPMC_CONFIG1_DEVICESIZE(1)
+
+
 /*
  * Note that all values in this struct are in nanoseconds, while
  * the register values are in gpmc_fck cycles.
@@ -109,9 +124,14 @@ extern int gpmc_cs_reserved(int cs);
 extern int gpmc_prefetch_enable(int cs, int dma_mode,
 					unsigned int u32_count, int is_write);
 extern void gpmc_prefetch_reset(void);
-extern int gpmc_prefetch_status(void);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_init(void);
+extern int gpmc_hwcontrol(int write, int cs, int cmd, int wval, int *rval);
+
+void gpmc_ecc_init(int cs, int ecc_size);
+void gpmc_enable_hwecc(int cs, int mode, int dev_width);
+int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
+
 
 #endif
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index f8efd54..6562cd0
--- a/arch/arm/plat-omap/include/plat/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
@@ -21,13 +21,11 @@ struct omap_nand_platform_data {
 	int			(*dev_ready)(struct omap_nand_platform_data *);
 	int			dma_channel;
 	unsigned long		phys_base;
-	void __iomem		*gpmc_cs_baseaddr;
-	void __iomem		*gpmc_baseaddr;
 	int			devsize;
 };
 
-/* size (4 KiB) for IO mapping */
-#define	NAND_IO_SIZE	SZ_4K
+/* minimum size for IO mapping */
+#define	NAND_IO_SIZE	4
 
 #if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
 extern int gpmc_nand_init(struct omap_nand_platform_data *d);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 7545568..1858c42
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -23,12 +23,6 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 
-#define GPMC_IRQ_STATUS		0x18
-#define GPMC_ECC_CONFIG		0x1F4
-#define GPMC_ECC_CONTROL	0x1F8
-#define GPMC_ECC_SIZE_CONFIG	0x1FC
-#define GPMC_ECC1_RESULT	0x200
-
 #define	DRIVER_NAME	"omap2-nand"
 
 #define	NAND_WP_OFF	0
@@ -37,6 +31,7 @@
 #define	GPMC_BUF_FULL	0x00000001
 #define	GPMC_BUF_EMPTY	0x00000000
 
+#ifdef CONFIG_MTD_NAND_OMAP_HWECC
 #define NAND_Ecc_P1e		(1 << 0)
 #define NAND_Ecc_P2e		(1 << 1)
 #define NAND_Ecc_P4e		(1 << 2)
@@ -103,6 +98,7 @@
 
 #define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
 #define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
+#endif /* CONFIG_MTD_NAND_OMAP_HWECC */
 
 #ifdef CONFIG_MTD_PARTITIONS
 static const char *part_probes[] = { "cmdlinepart", NULL };
@@ -139,34 +135,11 @@ struct omap_nand_info {
 
 	int				gpmc_cs;
 	unsigned long			phys_base;
-	void __iomem			*gpmc_cs_baseaddr;
-	void __iomem			*gpmc_baseaddr;
-	void __iomem			*nand_pref_fifo_add;
 	struct completion		comp;
 	int				dma_ch;
 };
 
 /**
- * omap_nand_wp - This function enable or disable the Write Protect feature
- * @mtd: MTD device structure
- * @mode: WP ON/OFF
- */
-static void omap_nand_wp(struct mtd_info *mtd, int mode)
-{
-	struct omap_nand_info *info = container_of(mtd,
-						struct omap_nand_info, mtd);
-
-	unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);
-
-	if (mode)
-		config &= ~(NAND_WP_BIT);	/* WP is ON */
-	else
-		config |= (NAND_WP_BIT);	/* WP is OFF */
-
-	__raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
-}
-
-/**
  * omap_hwcontrol - hardware specific access to control-lines
  * @mtd: MTD device structure
  * @cmd: command to device
@@ -181,31 +154,20 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
 	struct omap_nand_info *info = container_of(mtd,
 					struct omap_nand_info, mtd);
-	switch (ctrl) {
-	case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_COMMAND;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-
-	case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_ADDRESS;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-
-	case NAND_CTRL_CHANGE | NAND_NCE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-	}
 
-	if (cmd != NAND_CMD_NONE)
-		__raw_writeb(cmd, info->nand.IO_ADDR_W);
+	if (cmd != NAND_CMD_NONE) {
+		if (ctrl & NAND_CLE) {
+			gpmc_hwcontrol(1, info->gpmc_cs,
+					GPMC_NAND_COMMAND, cmd, NULL);
+
+		} else if (ctrl & NAND_ALE) {
+			gpmc_hwcontrol(1, info->gpmc_cs,
+					GPMC_NAND_ADDRESS, cmd, NULL);
+
+		} else /* NAND_NCE */
+			gpmc_hwcontrol(1, info->gpmc_cs,
+					GPMC_NAND_DATA, cmd, NULL);
+	}
 }
 
 /**
@@ -229,14 +191,15 @@ static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
  */
 static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
 {
-	struct omap_nand_info *info = container_of(mtd,
-						struct omap_nand_info, mtd);
+	u32	status;
+	struct nand_chip *nand = mtd->priv;
 	u_char *p = (u_char *)buf;
 
 	while (len--) {
-		iowrite8(*p++, info->nand.IO_ADDR_W);
-		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
-						GPMC_STATUS) & GPMC_BUF_FULL));
+		iowrite8(*p++, nand->IO_ADDR_W);
+		gpmc_hwcontrol(0, 0, GPMC_GET_SET_STATUS, 0, &status);
+		while (GPMC_BUF_EMPTY == (status & GPMC_BUF_FULL))
+			;
 	}
 }
 
@@ -261,18 +224,17 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
  */
 static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
 {
-	struct omap_nand_info *info = container_of(mtd,
-						struct omap_nand_info, mtd);
+	u32     status;
+	struct nand_chip *nand = mtd->priv;
 	u16 *p = (u16 *) buf;
 
 	/* FIXME try bursts of writesw() or DMA ... */
 	len >>= 1;
 
 	while (len--) {
-		iowrite16(*p++, info->nand.IO_ADDR_W);
-
-		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
-						GPMC_STATUS) & GPMC_BUF_FULL))
+		iowrite16(*p++, nand->IO_ADDR_W);
+		gpmc_hwcontrol(0, 0, GPMC_GET_SET_STATUS, 0, &status);
+		while (GPMC_BUF_EMPTY == (status & GPMC_BUF_FULL))
 			;
 	}
 }
@@ -308,9 +270,10 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 			omap_read_buf8(mtd, buf, len);
 	} else {
 		do {
-			pfpw_status = gpmc_prefetch_status();
+			gpmc_hwcontrol(0, info->gpmc_cs,
+					GPMC_GET_PREF_STATUS, 0, &pfpw_status);
 			r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
-			ioread32_rep(info->nand_pref_fifo_add, p, r_count);
+			ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
 			p += r_count;
 			len -= r_count << 2;
 		} while (len);
@@ -351,12 +314,13 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 		else
 			omap_write_buf8(mtd, buf, len);
 	} else {
-		pfpw_status = gpmc_prefetch_status();
+		gpmc_hwcontrol(0, 0, GPMC_GET_PREF_STATUS, 0, &pfpw_status);
 		while (pfpw_status & 0x3FFF) {
 			w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
 			for (i = 0; (i < w_count) && len; i++, len -= 2)
-				iowrite16(*p++, info->nand_pref_fifo_add);
-			pfpw_status = gpmc_prefetch_status();
+				iowrite16(*p++, info->nand.IO_ADDR_W);
+			gpmc_hwcontrol(0, 0,
+					GPMC_GET_PREF_STATUS, 0, &pfpw_status);
 		}
 
 		/* disable and stop the PFPW engine */
@@ -448,7 +412,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 	/* setup and start DMA using dma_addr */
 	wait_for_completion(&info->comp);
 
-	while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
+	while (0x3fff & (prefetch_status = gpmc_read_reg(GPMC_PREFETCH_STATUS)))
 		;
 	/* disable and stop the PFPW engine */
 	gpmc_prefetch_reset();
@@ -502,7 +466,7 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
 		omap_write_buf_pref(mtd, buf, len);
 	else
 		/* start transfer in DMA mode */
-		omap_nand_dma_transfer(mtd, buf, len, 0x1);
+		omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
 }
 
 /**
@@ -535,22 +499,8 @@ static void omap_hwecc_init(struct mtd_info *mtd)
 {
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	struct nand_chip *chip = mtd->priv;
-	unsigned long val = 0x0;
-
-	/* Read from ECC Control Register */
-	val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-	/* Clear all ECC | Enable Reg1 */
-	val = ((0x00000001<<8) | 0x00000001);
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-
-	/* Read from ECC Size Config Register */
-	val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
-	/* ECCSIZE1=512 | Select eccResultsize[0-3] */
-	val = ((((chip->ecc.size >> 1) - 1) << 22) | (0x0000000F));
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
+	gpmc_ecc_init(info->gpmc_cs, info->nand.ecc.size);
 }
-
 /**
  * gen_true_ecc - This function will generate true ECC value
  * @ecc_buf: buffer to store ecc code
@@ -752,21 +702,8 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 {
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	unsigned long val = 0x0;
-	unsigned long reg;
-
-	/* Start Reading from HW ECC1_Result = 0x200 */
-	reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT);
-	val = __raw_readl(reg);
-	*ecc_code++ = val;          /* P128e, ..., P1e */
-	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
-	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
-	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
-	reg += 4;
-
-	return 0;
+	return gpmc_calculate_ecc(info->gpmc_cs, dat, ecc_code);
 }
-
 /**
  * omap_enable_hwecc - This function enables the hardware ecc functionality
  * @mtd: MTD device structure
@@ -778,32 +715,10 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
 							mtd);
 	struct nand_chip *chip = mtd->priv;
 	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
-	unsigned long val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONFIG);
-
-	switch (mode) {
-	case NAND_ECC_READ:
-		__raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	case NAND_ECC_READSYN:
-		 __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	case NAND_ECC_WRITE:
-		__raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	default:
-		DEBUG(MTD_DEBUG_LEVEL0, "Error: Unrecognized Mode[%d]!\n",
-					mode);
-		break;
-	}
 
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+	gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width);
 }
+
 #endif
 
 /**
@@ -831,14 +746,10 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 	else
 		timeo += (HZ * 20) / 1000;
 
-	this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_COMMAND;
-	this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA;
-
-	__raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W);
-
+	gpmc_hwcontrol(1, info->gpmc_cs,
+			GPMC_NAND_COMMAND, (NAND_CMD_STATUS & 0xFF), NULL);
 	while (time_before(jiffies, timeo)) {
-		status = __raw_readb(this->IO_ADDR_R);
+		gpmc_hwcontrol(0, info->gpmc_cs, GPMC_NAND_DATA, 0, &status);
 		if (status & NAND_STATUS_READY)
 			break;
 		cond_resched();
@@ -852,22 +763,20 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
  */
 static int omap_dev_ready(struct mtd_info *mtd)
 {
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-							mtd);
-	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+	unsigned int val = 0;
 
+	gpmc_hwcontrol(0, 0, GPMC_GET_SET_IRQ_STATUS, 0, &val);
 	if ((val & 0x100) == 0x100) {
 		/* Clear IRQ Interrupt */
 		val |= 0x100;
 		val &= ~(0x0);
-		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+		gpmc_hwcontrol(1, 0, GPMC_GET_SET_IRQ_STATUS, val, NULL);
 	} else {
 		unsigned int cnt = 0;
 		while (cnt++ < 0x1FF) {
 			if  ((val & 0x100) == 0x100)
 				return 0;
-			val = __raw_readl(info->gpmc_baseaddr +
-							GPMC_IRQ_STATUS);
+			gpmc_hwcontrol(0, 0, GPMC_GET_SET_IRQ_STATUS, 0, &val);
 		}
 	}
 
@@ -898,8 +807,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->pdev = pdev;
 
 	info->gpmc_cs		= pdata->cs;
-	info->gpmc_baseaddr	= pdata->gpmc_baseaddr;
-	info->gpmc_cs_baseaddr	= pdata->gpmc_cs_baseaddr;
 	info->phys_base		= pdata->phys_base;
 
 	info->mtd.priv		= &info->nand;
@@ -910,7 +817,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->nand.options	|= NAND_SKIP_BBTSCAN;
 
 	/* NAND write protect off */
-	omap_nand_wp(&info->mtd, NAND_WP_OFF);
+	gpmc_hwcontrol(1, info->gpmc_cs, GPMC_CONFIG_WP, 0, NULL);
 
 	if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
 				pdev->dev.driver->name)) {
@@ -946,7 +853,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 
 	if (use_prefetch) {
 		/* copy the virtual address of nand base for fifo access */
-		info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
 
 		info->nand.read_buf   = omap_read_buf_pref;
 		info->nand.write_buf  = omap_write_buf_pref;
@@ -1036,7 +942,7 @@ static int omap_nand_remove(struct platform_device *pdev)
 
 	/* Release NAND device, its internal structures and partitions */
 	nand_release(&info->mtd);
-	iounmap(info->nand_pref_fifo_add);
+	iounmap(info->nand.IO_ADDR_R);
 	kfree(&info->mtd);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v2 2/2] omap3 nand: fix issue in board file to detect the nand
  2010-05-14 15:23   ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
@ 2010-05-14 15:23     ` Sukumar Ghorai
  2010-05-14 15:28     ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Tony Lindgren
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-14 15:23 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

Board file modified to pass the GMPC phys_base address to nand driver. This is
required to adopt the _prob function as in omap2.c

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/board-cm-t35.c         |   16 +---------------
 arch/arm/mach-omap2/board-devkit8000.c     |   16 +---------------
 arch/arm/mach-omap2/board-omap3beagle.c    |   16 +---------------
 arch/arm/mach-omap2/board-omap3touchbook.c |   16 +---------------
 arch/arm/mach-omap2/board-overo.c          |   17 +----------------
 5 files changed, 5 insertions(+), 76 deletions(-)

diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index fb23122..0544294
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -224,23 +224,9 @@ static struct omap_nand_platform_data cm_t35_nand_data = {
 
 };
 
-static struct resource cm_t35_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device cm_t35_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.num_resources	= 1,
-	.resource	= &cm_t35_nand_resource,
-	.dev		= {
-		.platform_data	= &cm_t35_nand_data,
-	},
-};
-
 static void __init cm_t35_init_nand(void)
 {
-	if (platform_device_register(&cm_t35_nand_device) < 0)
+	if (gpmc_nand_init(&cm_t35_nand_data) < 0)
 		pr_err("CM-T35: Unable to register NAND device\n");
 }
 #else
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index ca4e409..9a8135d
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -101,20 +101,6 @@ static struct omap_nand_platform_data devkit8000_nand_data = {
 	.dma_channel	= -1,		/* disable DMA in OMAP NAND driver */
 };
 
-static struct resource devkit8000_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device devkit8000_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &devkit8000_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &devkit8000_nand_resource,
-};
-
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
@@ -601,7 +587,7 @@ static void __init devkit8000_flash_init(void)
 		devkit8000_nand_data.cs = nandcs;
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&devkit8000_nand_device) < 0)
+		if (gpmc_nand_init(&devkit8000_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index becaebe..bf31b7c
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -89,20 +89,6 @@ static struct omap_nand_platform_data omap3beagle_nand_data = {
 	.dev_ready	= NULL,
 };
 
-static struct resource omap3beagle_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device omap3beagle_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &omap3beagle_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &omap3beagle_nand_resource,
-};
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
@@ -397,7 +383,7 @@ static void __init omap3beagle_flash_init(void)
 		omap3beagle_nand_data.cs = nandcs;
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&omap3beagle_nand_device) < 0)
+		if (gpmc_nand_init(&omap3beagle_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index d6f1b12..e8ad30c
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -103,20 +103,6 @@ static struct omap_nand_platform_data omap3touchbook_nand_data = {
 	.dev_ready	= NULL,
 };
 
-static struct resource omap3touchbook_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device omap3touchbook_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &omap3touchbook_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &omap3touchbook_nand_resource,
-};
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
@@ -479,7 +465,7 @@ static void __init omap3touchbook_flash_init(void)
 		omap3touchbook_nand_data.cs = nandcs;
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&omap3touchbook_nand_device) < 0)
+		if (gpmc_nand_init(&omap3touchbook_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index bf2ec32..cddc7ad
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -229,21 +229,6 @@ static struct omap_nand_platform_data overo_nand_data = {
 	.dma_channel = -1,	/* disable DMA in OMAP NAND driver */
 };
 
-static struct resource overo_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device overo_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &overo_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &overo_nand_resource,
-};
-
-
 static void __init overo_flash_init(void)
 {
 	u8 cs = 0;
@@ -272,7 +257,7 @@ static void __init overo_flash_init(void)
 		overo_nand_data.cs = nandcs;
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&overo_nand_device) < 0)
+		if (gpmc_nand_init(&overo_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-14 15:23   ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
  2010-05-14 15:23     ` [PATCH v2 2/2] omap3 nand: fix issue in board file to detect the nand Sukumar Ghorai
@ 2010-05-14 15:28     ` Tony Lindgren
  2010-05-14 18:02     ` Vimal Singh
  2010-05-14 23:58     ` Tony Lindgren
  3 siblings, 0 replies; 57+ messages in thread
From: Tony Lindgren @ 2010-05-14 15:28 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: sakoman, Artem.Bityutskiy, linux-omap, linux-mtd

* Sukumar Ghorai <s-ghorai@ti.com> [100514 08:18]:
> Necessary function added in GPMC module and used by nand driver. This is for
> not to use GPMC address directly from nand driver. Also it was passing GPMC
> base address from board files and that is removed.

Great, this is starting to look good! I'll take a closer look today, some
quick comments below.
 
> --- a/arch/arm/mach-omap2/gpmc.c
> +++ b/arch/arm/mach-omap2/gpmc.c
> @@ -29,27 +29,27 @@
>  #include <plat/sdrc.h>
>  
>  /* GPMC register offsets */
> -#define GPMC_REVISION		0x00
> -#define GPMC_SYSCONFIG		0x10
> -#define GPMC_SYSSTATUS		0x14
> -#define GPMC_IRQSTATUS		0x18
> -#define GPMC_IRQENABLE		0x1c
> -#define GPMC_TIMEOUT_CONTROL	0x40
> -#define GPMC_ERR_ADDRESS	0x44
> -#define GPMC_ERR_TYPE		0x48
> -#define GPMC_CONFIG		0x50
> -#define GPMC_STATUS		0x54
> -#define GPMC_PREFETCH_CONFIG1	0x1e0
> -#define GPMC_PREFETCH_CONFIG2	0x1e4
> -#define GPMC_PREFETCH_CONTROL	0x1ec
> -#define GPMC_PREFETCH_STATUS	0x1f0
> -#define GPMC_ECC_CONFIG		0x1f4
> -#define GPMC_ECC_CONTROL	0x1f8
> -#define GPMC_ECC_SIZE_CONFIG	0x1fc
> -
> -#define GPMC_CS0		0x60
> -#define GPMC_CS_SIZE		0x30
> -
> +#define GPMC_REVISION           0x00
> +#define GPMC_SYSCONFIG          0x10
> +#define GPMC_SYSSTATUS          0x14
> +#define GPMC_IRQSTATUS          0x18
> +#define GPMC_IRQENABLE          0x1c
> +#define GPMC_TIMEOUT_CONTROL    0x40
> +#define GPMC_ERR_ADDRESS        0x44
> +#define GPMC_ERR_TYPE           0x48
> +#define GPMC_CONFIG             0x50
> +#define GPMC_STATUS             0x54
> +#define GPMC_PREFETCH_CONFIG1   0x1e0
> +#define GPMC_PREFETCH_CONFIG2   0x1e4
> +#define GPMC_PREFETCH_CONTROL   0x1ec
> +#define GPMC_PREFETCH_STATUS    0x1f0
> +#define GPMC_ECC_CONFIG         0x1f4
> +#define GPMC_ECC_CONTROL        0x1f8
> +#define GPMC_ECC_SIZE_CONFIG    0x1fc
> +#define GPMC_ECC1_RESULT        0x200
> +
> +#define GPMC_CS0_BASE		0x60
> +#define GPMC_CS_SIZE            0x30
>  #define GPMC_MEM_START		0x00000000
>  #define GPMC_MEM_END		0x3FFFFFFF
>  #define BOOT_ROM_SPACE		0x100000	/* 1MB */

These defines should not be modified that much, looks like some spaces
sneaked in instead of tabs?

Maybe also split this patch into two: First add the new functions,
then remove and convert everything to use the new functions.

Regards,

Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-14 15:23   ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
  2010-05-14 15:23     ` [PATCH v2 2/2] omap3 nand: fix issue in board file to detect the nand Sukumar Ghorai
  2010-05-14 15:28     ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Tony Lindgren
@ 2010-05-14 18:02     ` Vimal Singh
  2010-05-17  4:22       ` Ghorai, Sukumar
  2010-05-14 23:58     ` Tony Lindgren
  3 siblings, 1 reply; 57+ messages in thread
From: Vimal Singh @ 2010-05-14 18:02 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: tony, Artem.Bityutskiy, linux-omap, sakoman, linux-mtd

On Fri, May 14, 2010 at 8:53 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
[...]

> diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
> index 7bb6922..5d66817
> --- a/arch/arm/mach-omap2/gpmc-onenand.c
> +++ b/arch/arm/mach-omap2/gpmc-onenand.c
> @@ -301,7 +301,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
>                                (GPMC_CONFIG1_WAIT_READ_MON |
>                                 GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
>                          GPMC_CONFIG1_DEVICESIZE_16 |
> -                         GPMC_CONFIG1_DEVICETYPE_NOR |
> +                         GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NOR) |
>                          GPMC_CONFIG1_MUXADDDATA);

Please do not dp OneNAND changes in NAND patch.

> diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
> index 5bc3ca0..a3fd1ed
> --- a/arch/arm/mach-omap2/gpmc.c
> +++ b/arch/arm/mach-omap2/gpmc.c
> @@ -29,27 +29,27 @@
>  #include <plat/sdrc.h>
>
>  /* GPMC register offsets */
> -#define GPMC_REVISION          0x00
> -#define GPMC_SYSCONFIG         0x10
> -#define GPMC_SYSSTATUS         0x14
> -#define GPMC_IRQSTATUS         0x18
> -#define GPMC_IRQENABLE         0x1c
> -#define GPMC_TIMEOUT_CONTROL   0x40
> -#define GPMC_ERR_ADDRESS       0x44
> -#define GPMC_ERR_TYPE          0x48
> -#define GPMC_CONFIG            0x50
> -#define GPMC_STATUS            0x54
> -#define GPMC_PREFETCH_CONFIG1  0x1e0
> -#define GPMC_PREFETCH_CONFIG2  0x1e4
> -#define GPMC_PREFETCH_CONTROL  0x1ec
> -#define GPMC_PREFETCH_STATUS   0x1f0
> -#define GPMC_ECC_CONFIG                0x1f4
> -#define GPMC_ECC_CONTROL       0x1f8
> -#define GPMC_ECC_SIZE_CONFIG   0x1fc
> -
> -#define GPMC_CS0               0x60
> -#define GPMC_CS_SIZE           0x30
> -
> +#define GPMC_REVISION           0x00
> +#define GPMC_SYSCONFIG          0x10
> +#define GPMC_SYSSTATUS          0x14
> +#define GPMC_IRQSTATUS          0x18
> +#define GPMC_IRQENABLE          0x1c
> +#define GPMC_TIMEOUT_CONTROL    0x40
> +#define GPMC_ERR_ADDRESS        0x44
> +#define GPMC_ERR_TYPE           0x48
> +#define GPMC_CONFIG             0x50
> +#define GPMC_STATUS             0x54
> +#define GPMC_PREFETCH_CONFIG1   0x1e0
> +#define GPMC_PREFETCH_CONFIG2   0x1e4
> +#define GPMC_PREFETCH_CONTROL   0x1ec
> +#define GPMC_PREFETCH_STATUS    0x1f0
> +#define GPMC_ECC_CONFIG         0x1f4
> +#define GPMC_ECC_CONTROL        0x1f8
> +#define GPMC_ECC_SIZE_CONFIG    0x1fc
> +#define GPMC_ECC1_RESULT        0x200
> +
> +#define GPMC_CS0_BASE          0x60
> +#define GPMC_CS_SIZE            0x30
>  #define GPMC_MEM_START         0x00000000
>  #define GPMC_MEM_END           0x3FFFFFFF
>  #define BOOT_ROM_SPACE         0x100000        /* 1MB */
> @@ -108,11 +108,27 @@ static u32 gpmc_read_reg(int idx)
>        return __raw_readl(gpmc_base + idx);
>  }
>
> +static void gpmc_cs_write_byte(int cs, int idx, u8 val)
> +{
> +       void __iomem *reg_addr;
> +
> +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> +       __raw_writeb(val, reg_addr);
> +}
> +
> +static u8 gpmc_cs_read_byte(int cs, int idx)
> +{
> +       void __iomem *reg_addr;
> +
> +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> +       return __raw_readb(reg_addr);
> +}
> +

I do not think we need these functions.

>  void gpmc_cs_write_reg(int cs, int idx, u32 val)
>  {
>        void __iomem *reg_addr;
>
> -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
>        __raw_writel(val, reg_addr);
>  }
>
> @@ -120,7 +136,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
>  {
>        void __iomem *reg_addr;
>
> -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
>        return __raw_readl(reg_addr);
>  }
>
> @@ -419,6 +435,96 @@ void gpmc_cs_free(int cs)
>  EXPORT_SYMBOL(gpmc_cs_free);
>
>  /**
> + * gpmc_hwcontrol - hardware specific access (read/ write) to control
> + * @write: need 1 for configure; 0 for reading the complete register
> + * @cs: chip select number
> + * @cmd: Command type
> + * @wval: value/information to write
> + * @rval: pointer to get the value back
> + */
> +int gpmc_hwcontrol(int write, int cs, int cmd, int wval, int *rval)
> +{
> +       u32 reg = 0;
> +       u32 regval = 0;
> +
> +       switch (cmd) {
> +
> +       case GPMC_GET_SET_STATUS:
> +               reg = GPMC_STATUS;
> +               if (write)
> +                       gpmc_write_reg(GPMC_STATUS, regval);
> +               break;
> +
> +       case GPMC_GET_SET_IRQ_STATUS:
> +               reg = GPMC_IRQSTATUS;
> +               if (write)
> +                       gpmc_write_reg(GPMC_IRQSTATUS, regval);
> +               break;
> +
> +       case GPMC_GET_PREF_STATUS:
> +               reg = GPMC_PREFETCH_STATUS;
> +               break;
> +
> +       case GPMC_CONFIG_WP:
> +               reg = GPMC_CONFIG;
> +               regval = gpmc_read_reg(GPMC_CONFIG);
> +           if (wval)
> +                       regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
> +               else
> +                       regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
> +               gpmc_write_reg(reg, regval);
> +               break;
> +
> +       case GPMC_CONFIG_RDY_BSY:
> +               #define WR_RD_PIN_MONITORING    0x00600000
> +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +               regval |= WR_RD_PIN_MONITORING;
> +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +               break;
> +
> +       case GPMC_CONFIG_DEV_SIZE:
> +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +               regval |= GPMC_CONFIG1_DEVICESIZE(wval);
> +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +               break;
> +
> +       case GPMC_CONFIG_DEV_TYPE:
> +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +               regval |= GPMC_CONFIG1_DEVICETYPE(wval);
> +               if (wval == GPMC_DEVICETYPE_NOR)
> +                       regval |= GPMC_CONFIG1_MUXADDDATA;
> +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +               break;
> +
> +       case GPMC_NAND_COMMAND:
> +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
> +               break;
> +
> +       case GPMC_NAND_ADDRESS:
> +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
> +               break;
> +
> +       case GPMC_NAND_DATA:
> +               if (write)
> +                       gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
> +               else
> +                       *rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
> +               break;
> +
> +       default:
> +               dump_stack();
> +               printk(KERN_ERR "not supported\n");
> +               return -1;
> +       }
> +
> +       if (!write && reg)
> +               *rval = gpmc_read_reg(reg);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(gpmc_hwcontrol);
> +
> +/**
>  * gpmc_prefetch_enable - configures and starts prefetch transfer
>  * @cs: nand cs (chip select) number
>  * @dma_mode: dma mode enable (1) or disable (0)
> @@ -466,15 +572,6 @@ void gpmc_prefetch_reset(void)
>  }
>  EXPORT_SYMBOL(gpmc_prefetch_reset);
>
> -/**
> - * gpmc_prefetch_status - reads prefetch status of engine
> - */
> -int  gpmc_prefetch_status(void)
> -{
> -       return gpmc_read_reg(GPMC_PREFETCH_STATUS);
> -}
> -EXPORT_SYMBOL(gpmc_prefetch_status);
> -
>  static void __init gpmc_mem_init(void)
>  {
>        int cs;
> @@ -615,3 +712,86 @@ void omap3_gpmc_restore_context(void)
>        }
>  }
>  #endif /* CONFIG_ARCH_OMAP3 */
> +
> +/**
> + * gmpc_ecc_init - Initialize the HW ECC for NAND flash in GPMC controller
> + * @cs: Chip select number
> + * @ecc_size: bytes for which ECC will be generated
> + */
> +void gpmc_ecc_init(int cs, int ecc_size)
> +{
> +       unsigned int val = 0x0;
> +
> +       /* Read from ECC Control Register */
> +       val = gpmc_read_reg(GPMC_ECC_CONTROL);
> +
> +       /* Clear all ECC | Enable Reg1 */
> +       val = ((0x00000001<<8) | 0x00000001);
> +       gpmc_write_reg(GPMC_ECC_CONTROL, val);
> +
> +       /* Read from ECC Size Config Register */
> +       val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
> +       /* ECCSIZE1=512 | Select eccResultsize[0-3] */
> +       val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
> +       gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
> +}
> +
> +/**
> + * gpmc_calcuate_ecc - Generate non-inverted ECC bytes.
> + * @cs: Chip select number
> + * @dat: The pointer to data on which ecc is computed
> + * @ecc_code: The ecc_code buffer
> + *
> + * Using noninverted ECC can be considered ugly since writing a blank
> + * page ie. padding will clear the ECC bytes. This is no problem as long
> + * nobody is trying to write data on the seemingly unused page. Reading
> + * an erased page will produce an ECC mismatch between generated and read
> + * ECC bytes that has to be dealt with separately.
> + */
> +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
> +{
> +       unsigned int val = 0x0;
> +
> +       /* Start Reading from HW ECC1_Result = 0x200 */
> +       val = gpmc_read_reg(GPMC_ECC1_RESULT);
> +       *ecc_code++ = val;          /* P128e, ..., P1e */
> +       *ecc_code++ = val >> 16;    /* P128o, ..., P1o */
> +       /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
> +       *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
> +
> +       return 0;
> +}
> +
> +/**
> + * gpmc_enable_hwecc - This function enables the hardware ecc functionality
> + * @cs: Chip select number
> + * @mode: Read/Write mode
> + * @dev_width: device bus width
> + */
> +void gpmc_enable_hwecc(int cs, int mode, int dev_width)
> +{
> +       unsigned int val = gpmc_read_reg(GPMC_ECC_CONFIG);
> +
> +       switch (mode) {
> +       case GPMC_ECC_READ:
> +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> +               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> +               val = (dev_width << 7) | (cs << 1) | (0x1);
> +               break;
> +       case GPMC_ECC_READSYN:
> +                gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
> +               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> +               val = (dev_width << 7) | (cs << 1) | (0x1);
> +               break;
> +       case GPMC_ECC_WRITE:
> +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> +               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> +               val = (dev_width << 7) | (cs << 1) | (0x1);
> +               break;
> +       default:
> +               printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode);
> +               break;
> +       }
> +
> +       gpmc_write_reg(GPMC_ECC_CONFIG, val);
> +}
> diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
> index 145838a..56e1407
> --- a/arch/arm/plat-omap/include/plat/gpmc.h
> +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> @@ -25,10 +25,22 @@
>  #define GPMC_CS_NAND_ADDRESS   0x20
>  #define GPMC_CS_NAND_DATA      0x24
>
> -#define GPMC_CONFIG            0x50
> -#define GPMC_STATUS            0x54
> -#define GPMC_CS0_BASE          0x60
> -#define GPMC_CS_SIZE           0x30
> +/* Control Commands */
> +#define GPMC_GET_SET_STATUS    0x00000001
> +#define GPMC_CONFIG_WP         0x00000002
> +#define GPMC_CONFIG_RDY_BSY    0x00000003
> +#define GPMC_CONFIG_DEV_SIZE   0x00000004
> +#define GPMC_CONFIG_DEV_TYPE    0x00000005
> +#define GPMC_NAND_COMMAND      0x00000006
> +#define GPMC_NAND_ADDRESS      0x00000007
> +#define GPMC_NAND_DATA         0x00000008
> +#define GPMC_GET_PREF_STATUS   0x00000009
> +#define GPMC_GET_SET_IRQ_STATUS        0x0000000a
> +
> +/* ECC commands */
> +#define GPMC_ECC_READ          0 /* Reset Hardware ECC for read */
> +#define GPMC_ECC_WRITE         1 /* Reset Hardware ECC for write */
> +#define GPMC_ECC_READSYN       2 /* Reset before syndrom is read back */
>
>  #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
>  #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
> @@ -44,10 +56,7 @@
>  #define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
>  #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
>  #define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
> -#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
>  #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
> -#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
> -#define GPMC_CONFIG1_DEVICETYPE_NAND    GPMC_CONFIG1_DEVICETYPE(2)
>  #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
>  #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
>  #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
> @@ -56,6 +65,12 @@
>  #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
>  #define GPMC_CONFIG7_CSVALID           (1 << 6)
>
> +#define GPMC_DEVICETYPE_NOR    0
> +#define GPMC_DEVICETYPE_NAND   2
> +#define GPMC_CONFIG_WRITEPROTECT       0x00000010
> +#define GPMC_CONFIG1_DEVICESIZE_16     GPMC_CONFIG1_DEVICESIZE(1)
> +
> +
>  /*
>  * Note that all values in this struct are in nanoseconds, while
>  * the register values are in gpmc_fck cycles.
> @@ -109,9 +124,14 @@ extern int gpmc_cs_reserved(int cs);
>  extern int gpmc_prefetch_enable(int cs, int dma_mode,
>                                        unsigned int u32_count, int is_write);
>  extern void gpmc_prefetch_reset(void);
> -extern int gpmc_prefetch_status(void);
>  extern void omap3_gpmc_save_context(void);
>  extern void omap3_gpmc_restore_context(void);
>  extern void gpmc_init(void);
> +extern int gpmc_hwcontrol(int write, int cs, int cmd, int wval, int *rval);
> +
> +void gpmc_ecc_init(int cs, int ecc_size);
> +void gpmc_enable_hwecc(int cs, int mode, int dev_width);
> +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
> +
>
>  #endif
> diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
> index f8efd54..6562cd0
> --- a/arch/arm/plat-omap/include/plat/nand.h
> +++ b/arch/arm/plat-omap/include/plat/nand.h
> @@ -21,13 +21,11 @@ struct omap_nand_platform_data {
>        int                     (*dev_ready)(struct omap_nand_platform_data *);
>        int                     dma_channel;
>        unsigned long           phys_base;
> -       void __iomem            *gpmc_cs_baseaddr;
> -       void __iomem            *gpmc_baseaddr;
>        int                     devsize;
>  };
>
> -/* size (4 KiB) for IO mapping */
> -#define        NAND_IO_SIZE    SZ_4K
> +/* minimum size for IO mapping */
> +#define        NAND_IO_SIZE    4
>
>  #if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
>  extern int gpmc_nand_init(struct omap_nand_platform_data *d);
> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> index 7545568..1858c42
> --- a/drivers/mtd/nand/omap2.c
> +++ b/drivers/mtd/nand/omap2.c
> @@ -23,12 +23,6 @@
>  #include <plat/gpmc.h>
>  #include <plat/nand.h>
>
> -#define GPMC_IRQ_STATUS                0x18
> -#define GPMC_ECC_CONFIG                0x1F4
> -#define GPMC_ECC_CONTROL       0x1F8
> -#define GPMC_ECC_SIZE_CONFIG   0x1FC
> -#define GPMC_ECC1_RESULT       0x200
> -
>  #define        DRIVER_NAME     "omap2-nand"
>
>  #define        NAND_WP_OFF     0
> @@ -37,6 +31,7 @@
>  #define        GPMC_BUF_FULL   0x00000001
>  #define        GPMC_BUF_EMPTY  0x00000000
>
> +#ifdef CONFIG_MTD_NAND_OMAP_HWECC
>  #define NAND_Ecc_P1e           (1 << 0)
>  #define NAND_Ecc_P2e           (1 << 1)
>  #define NAND_Ecc_P4e           (1 << 2)
> @@ -103,6 +98,7 @@
>
>  #define P4e_s(a)       (TF(a & NAND_Ecc_P4e)           << 0)
>  #define P4o_s(a)       (TF(a & NAND_Ecc_P4o)           << 1)
> +#endif /* CONFIG_MTD_NAND_OMAP_HWECC */

Why this ifdef macro?

>
>  #ifdef CONFIG_MTD_PARTITIONS
>  static const char *part_probes[] = { "cmdlinepart", NULL };
> @@ -139,34 +135,11 @@ struct omap_nand_info {
>
>        int                             gpmc_cs;
>        unsigned long                   phys_base;
> -       void __iomem                    *gpmc_cs_baseaddr;
> -       void __iomem                    *gpmc_baseaddr;
> -       void __iomem                    *nand_pref_fifo_add;
>        struct completion               comp;
>        int                             dma_ch;
>  };
>
>  /**
> - * omap_nand_wp - This function enable or disable the Write Protect feature
> - * @mtd: MTD device structure
> - * @mode: WP ON/OFF
> - */
> -static void omap_nand_wp(struct mtd_info *mtd, int mode)
> -{
> -       struct omap_nand_info *info = container_of(mtd,
> -                                               struct omap_nand_info, mtd);
> -
> -       unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);
> -
> -       if (mode)
> -               config &= ~(NAND_WP_BIT);       /* WP is ON */
> -       else
> -               config |= (NAND_WP_BIT);        /* WP is OFF */
> -
> -       __raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
> -}
> -
> -/**
>  * omap_hwcontrol - hardware specific access to control-lines
>  * @mtd: MTD device structure
>  * @cmd: command to device
> @@ -181,31 +154,20 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
>  {
>        struct omap_nand_info *info = container_of(mtd,
>                                        struct omap_nand_info, mtd);
> -       switch (ctrl) {
> -       case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
> -               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
> -                                               GPMC_CS_NAND_COMMAND;
> -               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
> -                                               GPMC_CS_NAND_DATA;
> -               break;
> -
> -       case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
> -               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
> -                                               GPMC_CS_NAND_ADDRESS;
> -               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
> -                                               GPMC_CS_NAND_DATA;
> -               break;
> -
> -       case NAND_CTRL_CHANGE | NAND_NCE:
> -               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
> -                                               GPMC_CS_NAND_DATA;
> -               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
> -                                               GPMC_CS_NAND_DATA;
> -               break;
> -       }
>
> -       if (cmd != NAND_CMD_NONE)
> -               __raw_writeb(cmd, info->nand.IO_ADDR_W);
> +       if (cmd != NAND_CMD_NONE) {
> +               if (ctrl & NAND_CLE) {
> +                       gpmc_hwcontrol(1, info->gpmc_cs,
> +                                       GPMC_NAND_COMMAND, cmd, NULL);
> +
> +               } else if (ctrl & NAND_ALE) {
> +                       gpmc_hwcontrol(1, info->gpmc_cs,
> +                                       GPMC_NAND_ADDRESS, cmd, NULL);
> +
> +               } else /* NAND_NCE */
> +                       gpmc_hwcontrol(1, info->gpmc_cs,
> +                                       GPMC_NAND_DATA, cmd, NULL);
> +       }
>  }
>
>  /**
> @@ -229,14 +191,15 @@ static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
>  */
>  static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
>  {
> -       struct omap_nand_info *info = container_of(mtd,
> -                                               struct omap_nand_info, mtd);
> +       u32     status;
> +       struct nand_chip *nand = mtd->priv;
>        u_char *p = (u_char *)buf;
>
>        while (len--) {
> -               iowrite8(*p++, info->nand.IO_ADDR_W);
> -               while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
> -                                               GPMC_STATUS) & GPMC_BUF_FULL));
> +               iowrite8(*p++, nand->IO_ADDR_W);
> +               gpmc_hwcontrol(0, 0, GPMC_GET_SET_STATUS, 0, &status);
If I am not mistaking, 2nd argument is 'cs', correct? And then, why
are you hard coding this?
Different boards will have NAND chip present at different 'cs'.
Please have a look at uses of 'gpmc_hwcontrol' elsewhere as well for this.

Again, say, you got '(status & GPMC_BUF_FULL) != GPMC_BUF_EMPTY', then:

> +               while (GPMC_BUF_EMPTY == (status & GPMC_BUF_FULL))
> +                       ;

You got in an infinite loop here?

>        }
>  }
>
> @@ -261,18 +224,17 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
>  */
>  static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
>  {
> -       struct omap_nand_info *info = container_of(mtd,
> -                                               struct omap_nand_info, mtd);
> +       u32     status;
> +       struct nand_chip *nand = mtd->priv;
>        u16 *p = (u16 *) buf;
>
>        /* FIXME try bursts of writesw() or DMA ... */
>        len >>= 1;
>
>        while (len--) {
> -               iowrite16(*p++, info->nand.IO_ADDR_W);
> -
> -               while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
> -                                               GPMC_STATUS) & GPMC_BUF_FULL))
> +               iowrite16(*p++, nand->IO_ADDR_W);
> +               gpmc_hwcontrol(0, 0, GPMC_GET_SET_STATUS, 0, &status);
> +               while (GPMC_BUF_EMPTY == (status & GPMC_BUF_FULL))

same as above.


-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-14 15:23   ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
                       ` (2 preceding siblings ...)
  2010-05-14 18:02     ` Vimal Singh
@ 2010-05-14 23:58     ` Tony Lindgren
  2010-05-17  5:48       ` Ghorai, Sukumar
  3 siblings, 1 reply; 57+ messages in thread
From: Tony Lindgren @ 2010-05-14 23:58 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: sakoman, Artem.Bityutskiy, linux-omap, linux-mtd

Few more comments below.

* Sukumar Ghorai <s-ghorai@ti.com> [100514 08:18]:
> +
> +/**
> + * gmpc_ecc_init - Initialize the HW ECC for NAND flash in GPMC controller
> + * @cs: Chip select number
> + * @ecc_size: bytes for which ECC will be generated
> + */
> +void gpmc_ecc_init(int cs, int ecc_size)
> +{
> +	unsigned int val = 0x0;
> +
> +	/* Read from ECC Control Register */
> +	val = gpmc_read_reg(GPMC_ECC_CONTROL);
> +
> +	/* Clear all ECC | Enable Reg1 */
> +	val = ((0x00000001<<8) | 0x00000001);
> +	gpmc_write_reg(GPMC_ECC_CONTROL, val);
> +
> +	/* Read from ECC Size Config Register */
> +	val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
> +	/* ECCSIZE1=512 | Select eccResultsize[0-3] */
> +	val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
> +	gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
> +}

There should be some locking as only one chipselect can use
the ECC or prefetch engine at a time. If you have NAND in
two chipselects, bad things would happen..

Maybe something like:

int gpmc_ecc_request(int cs);
void gpmc_ecc_free(int cs);
int gpmc_prefetch_request(int cs);
void gpmc_prefetch_free(int cs);

Other than that, looks like a good clean-up so we can easily
add the platform init code for all the board files.

Regards,

Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-14 18:02     ` Vimal Singh
@ 2010-05-17  4:22       ` Ghorai, Sukumar
  2010-05-17 14:26         ` Vimal Singh
  0 siblings, 1 reply; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-05-17  4:22 UTC (permalink / raw)
  To: Vimal Singh
  Cc: tony@atomide.com, Artem.Bityutskiy@nokia.com,
	linux-omap@vger.kernel.org, sakoman@gmail.com,
	linux-mtd@lists.infradead.org

Vimal,

> -----Original Message-----
> From: Vimal Singh [mailto:vimal.newwork@gmail.com]
> Sent: 2010-05-14 23:33
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; Artem.Bityutskiy@nokia.com;
> tony@atomide.com; sakoman@gmail.com; linux-mtd@lists.infradead.org
> Subject: Re: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC
> virtual address
>
> On Fri, May 14, 2010 at 8:53 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> [...]
>
> > diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-
> omap2/gpmc-onenand.c
> > index 7bb6922..5d66817
> > --- a/arch/arm/mach-omap2/gpmc-onenand.c
> > +++ b/arch/arm/mach-omap2/gpmc-onenand.c
> > @@ -301,7 +301,7 @@ static int omap2_onenand_set_sync_mode(struct
> omap_onenand_platform_data *cfg,
> >                                (GPMC_CONFIG1_WAIT_READ_MON |
> >                                 GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
> >                          GPMC_CONFIG1_DEVICESIZE_16 |
> > -                         GPMC_CONFIG1_DEVICETYPE_NOR |
> > +                         GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NOR) |
> >                          GPMC_CONFIG1_MUXADDDATA);
>
> Please do not dp OneNAND changes in NAND patch.
[Ghorai] I agree.
>
> > diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
> > index 5bc3ca0..a3fd1ed
> > --- a/arch/arm/mach-omap2/gpmc.c
> > +++ b/arch/arm/mach-omap2/gpmc.c
> > @@ -29,27 +29,27 @@
> >  #include <plat/sdrc.h>
> >
> >  /* GPMC register offsets */
> > -#define GPMC_REVISION          0x00
> > -#define GPMC_SYSCONFIG         0x10
> > -#define GPMC_SYSSTATUS         0x14
> > -#define GPMC_IRQSTATUS         0x18
> > -#define GPMC_IRQENABLE         0x1c
> > -#define GPMC_TIMEOUT_CONTROL   0x40
> > -#define GPMC_ERR_ADDRESS       0x44
> > -#define GPMC_ERR_TYPE          0x48
> > -#define GPMC_CONFIG            0x50
> > -#define GPMC_STATUS            0x54
> > -#define GPMC_PREFETCH_CONFIG1  0x1e0
> > -#define GPMC_PREFETCH_CONFIG2  0x1e4
> > -#define GPMC_PREFETCH_CONTROL  0x1ec
> > -#define GPMC_PREFETCH_STATUS   0x1f0
> > -#define GPMC_ECC_CONFIG                0x1f4
> > -#define GPMC_ECC_CONTROL       0x1f8
> > -#define GPMC_ECC_SIZE_CONFIG   0x1fc
> > -
> > -#define GPMC_CS0               0x60
> > -#define GPMC_CS_SIZE           0x30
> > -
> > +#define GPMC_REVISION           0x00
> > +#define GPMC_SYSCONFIG          0x10
> > +#define GPMC_SYSSTATUS          0x14
> > +#define GPMC_IRQSTATUS          0x18
> > +#define GPMC_IRQENABLE          0x1c
> > +#define GPMC_TIMEOUT_CONTROL    0x40
> > +#define GPMC_ERR_ADDRESS        0x44
> > +#define GPMC_ERR_TYPE           0x48
> > +#define GPMC_CONFIG             0x50
> > +#define GPMC_STATUS             0x54
> > +#define GPMC_PREFETCH_CONFIG1   0x1e0
> > +#define GPMC_PREFETCH_CONFIG2   0x1e4
> > +#define GPMC_PREFETCH_CONTROL   0x1ec
> > +#define GPMC_PREFETCH_STATUS    0x1f0
> > +#define GPMC_ECC_CONFIG         0x1f4
> > +#define GPMC_ECC_CONTROL        0x1f8
> > +#define GPMC_ECC_SIZE_CONFIG    0x1fc
> > +#define GPMC_ECC1_RESULT        0x200
> > +
> > +#define GPMC_CS0_BASE          0x60
> > +#define GPMC_CS_SIZE            0x30
> >  #define GPMC_MEM_START         0x00000000
> >  #define GPMC_MEM_END           0x3FFFFFFF
> >  #define BOOT_ROM_SPACE         0x100000        /* 1MB */
> > @@ -108,11 +108,27 @@ static u32 gpmc_read_reg(int idx)
> >        return __raw_readl(gpmc_base + idx);
> >  }
> >
> > +static void gpmc_cs_write_byte(int cs, int idx, u8 val)
> > +{
> > +       void __iomem *reg_addr;
> > +
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> idx;
> > +       __raw_writeb(val, reg_addr);
> > +}
> > +
> > +static u8 gpmc_cs_read_byte(int cs, int idx)
> > +{
> > +       void __iomem *reg_addr;
> > +
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> idx;
> > +       return __raw_readb(reg_addr);
> > +}
> > +
>
> I do not think we need these functions.
[Ghorai] This is used in gpmc_hwcontrol() and to get the nand status from omap2.c.

>
> >  void gpmc_cs_write_reg(int cs, int idx, u32 val)
> >  {
> >        void __iomem *reg_addr;
> >
> > -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> idx;
> >        __raw_writel(val, reg_addr);
> >  }
> >
> > @@ -120,7 +136,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
> >  {
> >        void __iomem *reg_addr;
> >
> > -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> idx;
> >        return __raw_readl(reg_addr);
> >  }
> >
> > @@ -419,6 +435,96 @@ void gpmc_cs_free(int cs)
> >  EXPORT_SYMBOL(gpmc_cs_free);
> >
> >  /**
> > + * gpmc_hwcontrol - hardware specific access (read/ write) to control
> > + * @write: need 1 for configure; 0 for reading the complete register
> > + * @cs: chip select number
> > + * @cmd: Command type
> > + * @wval: value/information to write
> > + * @rval: pointer to get the value back
> > + */
> > +int gpmc_hwcontrol(int write, int cs, int cmd, int wval, int *rval)
> > +{
> > +       u32 reg = 0;
> > +       u32 regval = 0;
> > +
> > +       switch (cmd) {
> > +
> > +       case GPMC_GET_SET_STATUS:
> > +               reg = GPMC_STATUS;
> > +               if (write)
> > +                       gpmc_write_reg(GPMC_STATUS, regval);
> > +               break;
> > +
> > +       case GPMC_GET_SET_IRQ_STATUS:
> > +               reg = GPMC_IRQSTATUS;
> > +               if (write)
> > +                       gpmc_write_reg(GPMC_IRQSTATUS, regval);
> > +               break;
> > +
> > +       case GPMC_GET_PREF_STATUS:
> > +               reg = GPMC_PREFETCH_STATUS;
> > +               break;
> > +
> > +       case GPMC_CONFIG_WP:
> > +               reg = GPMC_CONFIG;
> > +               regval = gpmc_read_reg(GPMC_CONFIG);
> > +           if (wval)
> > +                       regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON
> */
> > +               else
> > +                       regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is
> OFF */
> > +               gpmc_write_reg(reg, regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_RDY_BSY:
> > +               #define WR_RD_PIN_MONITORING    0x00600000
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= WR_RD_PIN_MONITORING;
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_DEV_SIZE:
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= GPMC_CONFIG1_DEVICESIZE(wval);
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_DEV_TYPE:
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= GPMC_CONFIG1_DEVICETYPE(wval);
> > +               if (wval == GPMC_DEVICETYPE_NOR)
> > +                       regval |= GPMC_CONFIG1_MUXADDDATA;
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> > +
> > +       case GPMC_NAND_COMMAND:
> > +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
> > +               break;
> > +
> > +       case GPMC_NAND_ADDRESS:
> > +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
> > +               break;
> > +
> > +       case GPMC_NAND_DATA:
> > +               if (write)
> > +                       gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
> > +               else
> > +                       *rval = gpmc_cs_read_byte(cs,
> GPMC_CS_NAND_DATA);
> > +               break;
> > +
> > +       default:
> > +               dump_stack();
> > +               printk(KERN_ERR "not supported\n");
> > +               return -1;
> > +       }
> > +
> > +       if (!write && reg)
> > +               *rval = gpmc_read_reg(reg);
> > +
> > +       return 0;
> > +}
> > +EXPORT_SYMBOL(gpmc_hwcontrol);
> > +
> > +/**
> >  * gpmc_prefetch_enable - configures and starts prefetch transfer
> >  * @cs: nand cs (chip select) number
> >  * @dma_mode: dma mode enable (1) or disable (0)
> > @@ -466,15 +572,6 @@ void gpmc_prefetch_reset(void)
> >  }
> >  EXPORT_SYMBOL(gpmc_prefetch_reset);
> >
> > -/**
> > - * gpmc_prefetch_status - reads prefetch status of engine
> > - */
> > -int  gpmc_prefetch_status(void)
> > -{
> > -       return gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > -}
> > -EXPORT_SYMBOL(gpmc_prefetch_status);
> > -
> >  static void __init gpmc_mem_init(void)
> >  {
> >        int cs;
> > @@ -615,3 +712,86 @@ void omap3_gpmc_restore_context(void)
> >        }
> >  }
> >  #endif /* CONFIG_ARCH_OMAP3 */
> > +
> > +/**
> > + * gmpc_ecc_init - Initialize the HW ECC for NAND flash in GPMC
> controller
> > + * @cs: Chip select number
> > + * @ecc_size: bytes for which ECC will be generated
> > + */
> > +void gpmc_ecc_init(int cs, int ecc_size)
> > +{
> > +       unsigned int val = 0x0;
> > +
> > +       /* Read from ECC Control Register */
> > +       val = gpmc_read_reg(GPMC_ECC_CONTROL);
> > +
> > +       /* Clear all ECC | Enable Reg1 */
> > +       val = ((0x00000001<<8) | 0x00000001);
> > +       gpmc_write_reg(GPMC_ECC_CONTROL, val);
> > +
> > +       /* Read from ECC Size Config Register */
> > +       val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
> > +       /* ECCSIZE1=512 | Select eccResultsize[0-3] */
> > +       val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
> > +       gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
> > +}
> > +
> > +/**
> > + * gpmc_calcuate_ecc - Generate non-inverted ECC bytes.
> > + * @cs: Chip select number
> > + * @dat: The pointer to data on which ecc is computed
> > + * @ecc_code: The ecc_code buffer
> > + *
> > + * Using noninverted ECC can be considered ugly since writing a blank
> > + * page ie. padding will clear the ECC bytes. This is no problem as
> long
> > + * nobody is trying to write data on the seemingly unused page. Reading
> > + * an erased page will produce an ECC mismatch between generated and
> read
> > + * ECC bytes that has to be dealt with separately.
> > + */
> > +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
> > +{
> > +       unsigned int val = 0x0;
> > +
> > +       /* Start Reading from HW ECC1_Result = 0x200 */
> > +       val = gpmc_read_reg(GPMC_ECC1_RESULT);
> > +       *ecc_code++ = val;          /* P128e, ..., P1e */
> > +       *ecc_code++ = val >> 16;    /* P128o, ..., P1o */
> > +       /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
> > +       *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * gpmc_enable_hwecc - This function enables the hardware ecc
> functionality
> > + * @cs: Chip select number
> > + * @mode: Read/Write mode
> > + * @dev_width: device bus width
> > + */
> > +void gpmc_enable_hwecc(int cs, int mode, int dev_width)
> > +{
> > +       unsigned int val = gpmc_read_reg(GPMC_ECC_CONFIG);
> > +
> > +       switch (mode) {
> > +       case GPMC_ECC_READ:
> > +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> > +               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> > +               val = (dev_width << 7) | (cs << 1) | (0x1);
> > +               break;
> > +       case GPMC_ECC_READSYN:
> > +                gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
> > +               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> > +               val = (dev_width << 7) | (cs << 1) | (0x1);
> > +               break;
> > +       case GPMC_ECC_WRITE:
> > +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> > +               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> > +               val = (dev_width << 7) | (cs << 1) | (0x1);
> > +               break;
> > +       default:
> > +               printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n",
> mode);
> > +               break;
> > +       }
> > +
> > +       gpmc_write_reg(GPMC_ECC_CONFIG, val);
> > +}
> > diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-
> omap/include/plat/gpmc.h
> > index 145838a..56e1407
> > --- a/arch/arm/plat-omap/include/plat/gpmc.h
> > +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> > @@ -25,10 +25,22 @@
> >  #define GPMC_CS_NAND_ADDRESS   0x20
> >  #define GPMC_CS_NAND_DATA      0x24
> >
> > -#define GPMC_CONFIG            0x50
> > -#define GPMC_STATUS            0x54
> > -#define GPMC_CS0_BASE          0x60
> > -#define GPMC_CS_SIZE           0x30
> > +/* Control Commands */
> > +#define GPMC_GET_SET_STATUS    0x00000001
> > +#define GPMC_CONFIG_WP         0x00000002
> > +#define GPMC_CONFIG_RDY_BSY    0x00000003
> > +#define GPMC_CONFIG_DEV_SIZE   0x00000004
> > +#define GPMC_CONFIG_DEV_TYPE    0x00000005
> > +#define GPMC_NAND_COMMAND      0x00000006
> > +#define GPMC_NAND_ADDRESS      0x00000007
> > +#define GPMC_NAND_DATA         0x00000008
> > +#define GPMC_GET_PREF_STATUS   0x00000009
> > +#define GPMC_GET_SET_IRQ_STATUS        0x0000000a
> > +
> > +/* ECC commands */
> > +#define GPMC_ECC_READ          0 /* Reset Hardware ECC for read */
> > +#define GPMC_ECC_WRITE         1 /* Reset Hardware ECC for write */
> > +#define GPMC_ECC_READSYN       2 /* Reset before syndrom is read back
> */
> >
> >  #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
> >  #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
> > @@ -44,10 +56,7 @@
> >  #define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
> >  #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
> >  #define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
> > -#define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
> >  #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
> > -#define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
> > -#define GPMC_CONFIG1_DEVICETYPE_NAND    GPMC_CONFIG1_DEVICETYPE(2)
> >  #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
> >  #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
> >  #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
> > @@ -56,6 +65,12 @@
> >  #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
> >  #define GPMC_CONFIG7_CSVALID           (1 << 6)
> >
> > +#define GPMC_DEVICETYPE_NOR    0
> > +#define GPMC_DEVICETYPE_NAND   2
> > +#define GPMC_CONFIG_WRITEPROTECT       0x00000010
> > +#define GPMC_CONFIG1_DEVICESIZE_16     GPMC_CONFIG1_DEVICESIZE(1)
> > +
> > +
> >  /*
> >  * Note that all values in this struct are in nanoseconds, while
> >  * the register values are in gpmc_fck cycles.
> > @@ -109,9 +124,14 @@ extern int gpmc_cs_reserved(int cs);
> >  extern int gpmc_prefetch_enable(int cs, int dma_mode,
> >                                        unsigned int u32_count, int
> is_write);
> >  extern void gpmc_prefetch_reset(void);
> > -extern int gpmc_prefetch_status(void);
> >  extern void omap3_gpmc_save_context(void);
> >  extern void omap3_gpmc_restore_context(void);
> >  extern void gpmc_init(void);
> > +extern int gpmc_hwcontrol(int write, int cs, int cmd, int wval, int
> *rval);
> > +
> > +void gpmc_ecc_init(int cs, int ecc_size);
> > +void gpmc_enable_hwecc(int cs, int mode, int dev_width);
> > +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
> > +
> >
> >  #endif
> > diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-
> omap/include/plat/nand.h
> > index f8efd54..6562cd0
> > --- a/arch/arm/plat-omap/include/plat/nand.h
> > +++ b/arch/arm/plat-omap/include/plat/nand.h
> > @@ -21,13 +21,11 @@ struct omap_nand_platform_data {
> >        int                     (*dev_ready)(struct
> omap_nand_platform_data *);
> >        int                     dma_channel;
> >        unsigned long           phys_base;
> > -       void __iomem            *gpmc_cs_baseaddr;
> > -       void __iomem            *gpmc_baseaddr;
> >        int                     devsize;
> >  };
> >
> > -/* size (4 KiB) for IO mapping */
> > -#define        NAND_IO_SIZE    SZ_4K
> > +/* minimum size for IO mapping */
> > +#define        NAND_IO_SIZE    4
> >
> >  #if defined(CONFIG_MTD_NAND_OMAP2) ||
> defined(CONFIG_MTD_NAND_OMAP2_MODULE)
> >  extern int gpmc_nand_init(struct omap_nand_platform_data *d);
> > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> > index 7545568..1858c42
> > --- a/drivers/mtd/nand/omap2.c
> > +++ b/drivers/mtd/nand/omap2.c
> > @@ -23,12 +23,6 @@
> >  #include <plat/gpmc.h>
> >  #include <plat/nand.h>
> >
> > -#define GPMC_IRQ_STATUS                0x18
> > -#define GPMC_ECC_CONFIG                0x1F4
> > -#define GPMC_ECC_CONTROL       0x1F8
> > -#define GPMC_ECC_SIZE_CONFIG   0x1FC
> > -#define GPMC_ECC1_RESULT       0x200
> > -
> >  #define        DRIVER_NAME     "omap2-nand"
> >
> >  #define        NAND_WP_OFF     0
> > @@ -37,6 +31,7 @@
> >  #define        GPMC_BUF_FULL   0x00000001
> >  #define        GPMC_BUF_EMPTY  0x00000000
> >
> > +#ifdef CONFIG_MTD_NAND_OMAP_HWECC
> >  #define NAND_Ecc_P1e           (1 << 0)
> >  #define NAND_Ecc_P2e           (1 << 1)
> >  #define NAND_Ecc_P4e           (1 << 2)
> > @@ -103,6 +98,7 @@
> >
> >  #define P4e_s(a)       (TF(a & NAND_Ecc_P4e)           << 0)
> >  #define P4o_s(a)       (TF(a & NAND_Ecc_P4o)           << 1)
> > +#endif /* CONFIG_MTD_NAND_OMAP_HWECC */
>
> Why this ifdef macro?
>
> >
> >  #ifdef CONFIG_MTD_PARTITIONS
> >  static const char *part_probes[] = { "cmdlinepart", NULL };
> > @@ -139,34 +135,11 @@ struct omap_nand_info {
> >
> >        int                             gpmc_cs;
> >        unsigned long                   phys_base;
> > -       void __iomem                    *gpmc_cs_baseaddr;
> > -       void __iomem                    *gpmc_baseaddr;
> > -       void __iomem                    *nand_pref_fifo_add;
> >        struct completion               comp;
> >        int                             dma_ch;
> >  };
> >
> >  /**
> > - * omap_nand_wp - This function enable or disable the Write Protect
> feature
> > - * @mtd: MTD device structure
> > - * @mode: WP ON/OFF
> > - */
> > -static void omap_nand_wp(struct mtd_info *mtd, int mode)
> > -{
> > -       struct omap_nand_info *info = container_of(mtd,
> > -                                               struct omap_nand_info,
> mtd);
> > -
> > -       unsigned long config = __raw_readl(info->gpmc_baseaddr +
> GPMC_CONFIG);
> > -
> > -       if (mode)
> > -               config &= ~(NAND_WP_BIT);       /* WP is ON */
> > -       else
> > -               config |= (NAND_WP_BIT);        /* WP is OFF */
> > -
> > -       __raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
> > -}
> > -
> > -/**
> >  * omap_hwcontrol - hardware specific access to control-lines
> >  * @mtd: MTD device structure
> >  * @cmd: command to device
> > @@ -181,31 +154,20 @@ static void omap_hwcontrol(struct mtd_info *mtd,
> int cmd, unsigned int ctrl)
> >  {
> >        struct omap_nand_info *info = container_of(mtd,
> >                                        struct omap_nand_info, mtd);
> > -       switch (ctrl) {
> > -       case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
> > -               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
> > -                                               GPMC_CS_NAND_COMMAND;
> > -               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
> > -                                               GPMC_CS_NAND_DATA;
> > -               break;
> > -
> > -       case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
> > -               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
> > -                                               GPMC_CS_NAND_ADDRESS;
> > -               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
> > -                                               GPMC_CS_NAND_DATA;
> > -               break;
> > -
> > -       case NAND_CTRL_CHANGE | NAND_NCE:
> > -               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
> > -                                               GPMC_CS_NAND_DATA;
> > -               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
> > -                                               GPMC_CS_NAND_DATA;
> > -               break;
> > -       }
> >
> > -       if (cmd != NAND_CMD_NONE)
> > -               __raw_writeb(cmd, info->nand.IO_ADDR_W);
> > +       if (cmd != NAND_CMD_NONE) {
> > +               if (ctrl & NAND_CLE) {
> > +                       gpmc_hwcontrol(1, info->gpmc_cs,
> > +                                       GPMC_NAND_COMMAND, cmd, NULL);
> > +
> > +               } else if (ctrl & NAND_ALE) {
> > +                       gpmc_hwcontrol(1, info->gpmc_cs,
> > +                                       GPMC_NAND_ADDRESS, cmd, NULL);
> > +
> > +               } else /* NAND_NCE */
> > +                       gpmc_hwcontrol(1, info->gpmc_cs,
> > +                                       GPMC_NAND_DATA, cmd, NULL);
> > +       }
> >  }
> >
> >  /**
> > @@ -229,14 +191,15 @@ static void omap_read_buf8(struct mtd_info *mtd,
> u_char *buf, int len)
> >  */
> >  static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf,
> int len)
> >  {
> > -       struct omap_nand_info *info = container_of(mtd,
> > -                                               struct omap_nand_info,
> mtd);
> > +       u32     status;
> > +       struct nand_chip *nand = mtd->priv;
> >        u_char *p = (u_char *)buf;
> >
> >        while (len--) {
> > -               iowrite8(*p++, info->nand.IO_ADDR_W);
> > -               while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
> > -                                               GPMC_STATUS) &
> GPMC_BUF_FULL));
> > +               iowrite8(*p++, nand->IO_ADDR_W);
> > +               gpmc_hwcontrol(0, 0, GPMC_GET_SET_STATUS, 0, &status);
> If I am not mistaking, 2nd argument is 'cs', correct? And then, why
> are you hard coding this?
> Different boards will have NAND chip present at different 'cs'.
> Please have a look at uses of 'gpmc_hwcontrol' elsewhere as well for this.
[Ghorai] I agree.
>
> Again, say, you got '(status & GPMC_BUF_FULL) != GPMC_BUF_EMPTY', then:
>
> > +               while (GPMC_BUF_EMPTY == (status & GPMC_BUF_FULL))
> > +                       ;
>
> You got in an infinite loop here?
[Ghorai] if you see carefully this is same as existing code. Let me check if any better solution.
>
> >        }
> >  }
> >
> > @@ -261,18 +224,17 @@ static void omap_read_buf16(struct mtd_info *mtd,
> u_char *buf, int len)
> >  */
> >  static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf,
> int len)
> >  {
> > -       struct omap_nand_info *info = container_of(mtd,
> > -                                               struct omap_nand_info,
> mtd);
> > +       u32     status;
> > +       struct nand_chip *nand = mtd->priv;
> >        u16 *p = (u16 *) buf;
> >
> >        /* FIXME try bursts of writesw() or DMA ... */
> >        len >>= 1;
> >
> >        while (len--) {
> > -               iowrite16(*p++, info->nand.IO_ADDR_W);
> > -
> > -               while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
> > -                                               GPMC_STATUS) &
> GPMC_BUF_FULL))
> > +               iowrite16(*p++, nand->IO_ADDR_W);
> > +               gpmc_hwcontrol(0, 0, GPMC_GET_SET_STATUS, 0, &status);
> > +               while (GPMC_BUF_EMPTY == (status & GPMC_BUF_FULL))
>
> same as above.
[Ghorai] if you see carefully this is same as existing code. Let me check if any better solution.
>
>
> --
> Regards,
> Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-14 23:58     ` Tony Lindgren
@ 2010-05-17  5:48       ` Ghorai, Sukumar
  0 siblings, 0 replies; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-05-17  5:48 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: sakoman@gmail.com, Artem.Bityutskiy@nokia.com,
	linux-omap@vger.kernel.org, linux-mtd@lists.infradead.org

Tony,

> -----Original Message-----
> From: Tony Lindgren [mailto:tony@atomide.com]
> Sent: 2010-05-15 05:29
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> sakoman@gmail.com; mike@compulab.co.il; Artem.Bityutskiy@nokia.com
> Subject: Re: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC
> virtual address
> 
> Few more comments below.
> 
> * Sukumar Ghorai <s-ghorai@ti.com> [100514 08:18]:
> > +
> > +/**
> > + * gmpc_ecc_init - Initialize the HW ECC for NAND flash in GPMC
> controller
> > + * @cs: Chip select number
> > + * @ecc_size: bytes for which ECC will be generated
> > + */
> > +void gpmc_ecc_init(int cs, int ecc_size)
> > +{
> > +	unsigned int val = 0x0;
> > +
> > +	/* Read from ECC Control Register */
> > +	val = gpmc_read_reg(GPMC_ECC_CONTROL);
> > +
> > +	/* Clear all ECC | Enable Reg1 */
> > +	val = ((0x00000001<<8) | 0x00000001);
> > +	gpmc_write_reg(GPMC_ECC_CONTROL, val);
> > +
> > +	/* Read from ECC Size Config Register */
> > +	val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
> > +	/* ECCSIZE1=512 | Select eccResultsize[0-3] */
> > +	val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
> > +	gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
> > +}
> 
> There should be some locking as only one chipselect can use
> the ECC or prefetch engine at a time. If you have NAND in
> two chipselects, bad things would happen..
> 
> Maybe something like:
> 
> int gpmc_ecc_request(int cs);
> void gpmc_ecc_free(int cs);
> int gpmc_prefetch_request(int cs);
> void gpmc_prefetch_free(int cs);
> 
> Other than that, looks like a good clean-up so we can easily
> add the platform init code for all the board files.
[Ghorai] agreed.. and -
1). Adding one flag/variable for prefetch enable/reset request
2). Adding another flag/variable for ecc int/reset request

Regards,
Ghorai

> 
> Regards,
> 
> Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-17  4:22       ` Ghorai, Sukumar
@ 2010-05-17 14:26         ` Vimal Singh
  2010-05-17 14:34           ` Ghorai, Sukumar
  0 siblings, 1 reply; 57+ messages in thread
From: Vimal Singh @ 2010-05-17 14:26 UTC (permalink / raw)
  To: Ghorai, Sukumar
  Cc: tony@atomide.com, Artem.Bityutskiy@nokia.com,
	linux-omap@vger.kernel.org, sakoman@gmail.com,
	linux-mtd@lists.infradead.org

On Mon, May 17, 2010 at 9:52 AM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
[...]
>> > @@ -108,11 +108,27 @@ static u32 gpmc_read_reg(int idx)
>> >        return __raw_readl(gpmc_base + idx);
>> >  }
>> >
>> > +static void gpmc_cs_write_byte(int cs, int idx, u8 val)
>> > +{
>> > +       void __iomem *reg_addr;
>> > +
>> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
>> idx;
>> > +       __raw_writeb(val, reg_addr);
>> > +}
>> > +
>> > +static u8 gpmc_cs_read_byte(int cs, int idx)
>> > +{
>> > +       void __iomem *reg_addr;
>> > +
>> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
>> idx;
>> > +       return __raw_readb(reg_addr);
>> > +}
>> > +
>>
>> I do not think we need these functions.
> [Ghorai] This is used in gpmc_hwcontrol() and to get the nand status from omap2.c.

Yes, I can see that. But I think you should read complete register
(32-bits) and the manipulate them accordingly.

>
[...]
>> > @@ -229,14 +191,15 @@ static void omap_read_buf8(struct mtd_info *mtd,
>> u_char *buf, int len)
>> >  */
>> >  static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf,
>> int len)
>> >  {
>> > -       struct omap_nand_info *info = container_of(mtd,
>> > -                                               struct omap_nand_info,
>> mtd);
>> > +       u32     status;
>> > +       struct nand_chip *nand = mtd->priv;
>> >        u_char *p = (u_char *)buf;
>> >
>> >        while (len--) {
>> > -               iowrite8(*p++, info->nand.IO_ADDR_W);
>> > -               while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
>> > -                                               GPMC_STATUS) &
>> GPMC_BUF_FULL));
>> > +               iowrite8(*p++, nand->IO_ADDR_W);
>> > +               gpmc_hwcontrol(0, 0, GPMC_GET_SET_STATUS, 0, &status);
>> If I am not mistaking, 2nd argument is 'cs', correct? And then, why
>> are you hard coding this?
>> Different boards will have NAND chip present at different 'cs'.
>> Please have a look at uses of 'gpmc_hwcontrol' elsewhere as well for this.
> [Ghorai] I agree.
>>
>> Again, say, you got '(status & GPMC_BUF_FULL) != GPMC_BUF_EMPTY', then:
>>
>> > +               while (GPMC_BUF_EMPTY == (status & GPMC_BUF_FULL))
>> > +                       ;
>>
>> You got in an infinite loop here?
> [Ghorai] if you see carefully this is same as existing code. Let me check if any better solution.

No. Look carefully. In previous code 'gpmc status' was being read in
each loop, while in your code you read it once and then you never look
for updated value.
That's why your code is going into infinite loop


-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address
  2010-05-17 14:26         ` Vimal Singh
@ 2010-05-17 14:34           ` Ghorai, Sukumar
  0 siblings, 0 replies; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-05-17 14:34 UTC (permalink / raw)
  To: Vimal Singh
  Cc: tony@atomide.com, Artem.Bityutskiy@nokia.com,
	linux-omap@vger.kernel.org, sakoman@gmail.com,
	linux-mtd@lists.infradead.org



> -----Original Message-----
> From: Vimal Singh [mailto:vimal.newwork@gmail.com]
> Sent: 2010-05-17 19:57
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; Artem.Bityutskiy@nokia.com;
> tony@atomide.com; sakoman@gmail.com; linux-mtd@lists.infradead.org
> Subject: Re: [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC
> virtual address
> 
> On Mon, May 17, 2010 at 9:52 AM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
> [...]
> >> > @@ -108,11 +108,27 @@ static u32 gpmc_read_reg(int idx)
> >> >        return __raw_readl(gpmc_base + idx);
> >> >  }
> >> >
> >> > +static void gpmc_cs_write_byte(int cs, int idx, u8 val)
> >> > +{
> >> > +       void __iomem *reg_addr;
> >> > +
> >> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> >> idx;
> >> > +       __raw_writeb(val, reg_addr);
> >> > +}
> >> > +
> >> > +static u8 gpmc_cs_read_byte(int cs, int idx)
> >> > +{
> >> > +       void __iomem *reg_addr;
> >> > +
> >> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> >> idx;
> >> > +       return __raw_readb(reg_addr);
> >> > +}
> >> > +
> >>
> >> I do not think we need these functions.
> > [Ghorai] This is used in gpmc_hwcontrol() and to get the nand status
> from omap2.c.
> 
> Yes, I can see that. But I think you should read complete register
> (32-bits) and the manipulate them accordingly.
> 
> >
> [...]
> >> > @@ -229,14 +191,15 @@ static void omap_read_buf8(struct mtd_info
> *mtd,
> >> u_char *buf, int len)
> >> >  */
> >> >  static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf,
> >> int len)
> >> >  {
> >> > -       struct omap_nand_info *info = container_of(mtd,
> >> > -                                               struct
> omap_nand_info,
> >> mtd);
> >> > +       u32     status;
> >> > +       struct nand_chip *nand = mtd->priv;
> >> >        u_char *p = (u_char *)buf;
> >> >
> >> >        while (len--) {
> >> > -               iowrite8(*p++, info->nand.IO_ADDR_W);
> >> > -               while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
> >> > -                                               GPMC_STATUS) &
> >> GPMC_BUF_FULL));
> >> > +               iowrite8(*p++, nand->IO_ADDR_W);
> >> > +               gpmc_hwcontrol(0, 0, GPMC_GET_SET_STATUS, 0,
> &status);
> >> If I am not mistaking, 2nd argument is 'cs', correct? And then, why
> >> are you hard coding this?
> >> Different boards will have NAND chip present at different 'cs'.
> >> Please have a look at uses of 'gpmc_hwcontrol' elsewhere as well for
> this.
> > [Ghorai] I agree.
> >>
> >> Again, say, you got '(status & GPMC_BUF_FULL) != GPMC_BUF_EMPTY', then:
> >>
> >> > +               while (GPMC_BUF_EMPTY == (status & GPMC_BUF_FULL))
> >> > +                       ;
> >>
> >> You got in an infinite loop here?
> > [Ghorai] if you see carefully this is same as existing code. Let me
> check if any better solution.
> 
> No. Look carefully. In previous code 'gpmc status' was being read in
> each loop, while in your code you read it once and then you never look
> for updated value.
> That's why your code is going into infinite loop
[Ghorai] ok. thanks
> 
> 
> --
> Regards,
> Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v3 0/3] omap3 nand: cleanup exiting platform related code
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
                   ` (8 preceding siblings ...)
  2010-05-14 15:23 ` [PATCH v2 0/2] " Sukumar Ghorai
@ 2010-05-18 11:16 ` Sukumar Ghorai
  2010-05-18 11:16   ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
  2010-06-04  7:40 ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
  10 siblings, 1 reply; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-18 11:16 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

   The following set of patches applies on top of for-next branch.
	http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git
   Patches verified on: omap3430-SDP, omap3630-sdp, zoom3 and beagle board

   And these are the patches required to address the following input -
     1. The NAND driver needs to stop tinkering with the GPMC registers
	The omap General Purpose Memory Controller (GPMC) registers are omap
        specific, and not driver specific. Tinkering with these registers can
        cause issues with the other devices on the GPMC.

     2. Passing hardcoded GPMC_CS0_BASE needs to go from the board files
	Passing hardcoded GPMC virtual addressess is sure way to mess up things.
        This should all become unnecessary once the NAND drivers stops messing
        with the GPMC registers directly.

  v2: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28467.html
	Few functionality was missing  like - There should be some locking 
	as only one chipselect can use the ECC or prefetch engine at a time. 
	If you have NAND in two chipselects, bad things would happen.
	
  v1: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28164.html
	Additionally, it was needed to implement more functions for the
	platform init code to use.


Sukumar Ghorai (3):
	omap3 gpmc: functionality enhancement
	omap3 nand: cleanup virtual address usages
	omap3 nand: fix issue in board file to detect nand

 arch/arm/mach-omap2/board-cm-t35.c         |   20 +---
 arch/arm/mach-omap2/board-devkit8000.c     |   25 +---
 arch/arm/mach-omap2/board-omap3beagle.c    |   24 +---
 arch/arm/mach-omap2/board-omap3touchbook.c |   25 +---
 arch/arm/mach-omap2/board-overo.c          |   24 +---
 arch/arm/mach-omap2/gpmc-nand.c            |   39 ++----
 arch/arm/mach-omap2/gpmc.c                 |    9 -
 arch/arm/plat-omap/include/plat/gpmc.h     |    7 +-
 arch/arm/plat-omap/include/plat/nand.h     |    6 +-
 drivers/mtd/nand/omap2.c                   |  242 +++++++++-------------------
 10 files changed, 93 insertions(+), 328 deletions(-)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-18 11:16 ` [PATCH v3 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
@ 2010-05-18 11:16   ` Sukumar Ghorai
  2010-05-18 11:16     ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
  2010-05-19 14:46     ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Vimal Singh
  0 siblings, 2 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-18 11:16 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

few functions added in gpmc module and to be used by other drivers like NAND.
E.g.: - ioctl function
      - ecc functions

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |  246 +++++++++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/gpmc.h |   35 ++++-
 drivers/mtd/nand/omap2.c               |    4 +-
 3 files changed, 274 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5bc3ca0..7e6d821
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -46,8 +46,9 @@
 #define GPMC_ECC_CONFIG		0x1f4
 #define GPMC_ECC_CONTROL	0x1f8
 #define GPMC_ECC_SIZE_CONFIG	0x1fc
+#define GPMC_ECC1_RESULT        0x200
 
-#define GPMC_CS0		0x60
+#define GPMC_CS0_BASE		0x60
 #define GPMC_CS_SIZE		0x30
 
 #define GPMC_MEM_START		0x00000000
@@ -92,7 +93,9 @@ struct omap3_gpmc_regs {
 static struct resource	gpmc_mem_root;
 static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
-static unsigned		gpmc_cs_map;
+static unsigned	int gpmc_cs_map;	/* flag for cs which are initialized */
+static int gpmc_pref_used = -EINVAL;	/* cs using prefetch engine */
+static int gpmc_ecc_used = -EINVAL;	/* cs using ecc engine */
 
 static void __iomem *gpmc_base;
 
@@ -108,11 +111,27 @@ static u32 gpmc_read_reg(int idx)
 	return __raw_readl(gpmc_base + idx);
 }
 
+static void gpmc_cs_write_byte(int cs, int idx, u8 val)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
+	__raw_writeb(val, reg_addr);
+}
+
+static u8 gpmc_cs_read_byte(int cs, int idx)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
+	return __raw_readb(reg_addr);
+}
+
 void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	__raw_writel(val, reg_addr);
 }
 
@@ -120,7 +139,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	return __raw_readl(reg_addr);
 }
 
@@ -419,8 +438,100 @@ void gpmc_cs_free(int cs)
 EXPORT_SYMBOL(gpmc_cs_free);
 
 /**
+ * gpmc_hwcontrol - hardware specific access (read/ write) control
+ * @cs: chip select number
+ * @cmd: command type
+ * @write: 1 for write; 0 for read
+ * @wval: value to write
+ * @rval: read pointer
+ */
+int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval)
+{
+	u32 regval = 0;
+
+	if (!write && !rval)
+		return -EINVAL;
+
+	switch (cmd) {
+	case GPMC_STATUS_BUFFER:
+		regval = gpmc_read_reg(GPMC_STATUS);
+		/* 1 : buffer is available to write */
+		*rval = regval & GPMC_STATUS_BUFF_EMPTY;
+		break;
+
+	case GPMC_GET_SET_IRQ_STATUS:
+		if (write)
+			gpmc_write_reg(GPMC_IRQSTATUS, wval);
+		else
+			*rval = gpmc_read_reg(GPMC_IRQSTATUS);
+		break;
+
+	case GPMC_PREFETCH_FIFO_CNT:
+		regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
+		*rval = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
+		break;
+
+	case GPMC_PREFETCH_COUNT:
+		regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
+		*rval = GPMC_PREFETCH_STATUS_COUNT(regval);
+		break;
+
+	case GPMC_CONFIG_WP:
+		regval = gpmc_read_reg(GPMC_CONFIG);
+		if (wval)
+			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
+		else
+			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
+		gpmc_write_reg(GPMC_CONFIG, regval);
+		break;
+
+	case GPMC_CONFIG_RDY_BSY:
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= WR_RD_PIN_MONITORING;
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_CONFIG_DEV_SIZE:
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= GPMC_CONFIG1_DEVICESIZE(wval);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_CONFIG_DEV_TYPE:
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= GPMC_CONFIG1_DEVICETYPE(wval);
+		if (wval == GPMC_DEVICETYPE_NOR)
+			regval |= GPMC_CONFIG1_MUXADDDATA;
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_NAND_COMMAND:
+		gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
+		break;
+
+	case GPMC_NAND_ADDRESS:
+		gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
+		break;
+
+	case GPMC_NAND_DATA:
+		if (write)
+			gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
+		else
+			*rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
+		break;
+
+	default:
+		printk(KERN_ERR "gpmc_hwcontrol: Not supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(gpmc_hwcontrol);
+
+/**
  * gpmc_prefetch_enable - configures and starts prefetch transfer
- * @cs: nand cs (chip select) number
+ * @cs: cs (chip select) number
  * @dma_mode: dma mode enable (1) or disable (0)
  * @u32_count: number of bytes to be transferred
  * @is_write: prefetch read(0) or write post(1) mode
@@ -430,6 +541,11 @@ int gpmc_prefetch_enable(int cs, int dma_mode,
 {
 	uint32_t prefetch_config1;
 
+	if (gpmc_pref_used == -EINVAL)
+		gpmc_pref_used = cs;
+	else
+		return -EBUSY;
+
 	if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
 		/* Set the amount of bytes to be prefetched */
 		gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
@@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
 /**
  * gpmc_prefetch_reset - disables and stops the prefetch engine
  */
-void gpmc_prefetch_reset(void)
+int gpmc_prefetch_reset(int cs)
 {
+	if (gpmc_pref_used == cs)
+		gpmc_pref_used = -EINVAL;
+	else
+		return -EINVAL;
+
 	/* Stop the PFPW engine */
 	gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
 
 	/* Reset/disable the PFPW engine */
 	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
+
+	return 0;
 }
 EXPORT_SYMBOL(gpmc_prefetch_reset);
 
@@ -615,3 +738,114 @@ void omap3_gpmc_restore_context(void)
 	}
 }
 #endif /* CONFIG_ARCH_OMAP3 */
+
+/**
+ * gpmc_ecc_init - initialize hw ecc for device in GPMC controller
+ * @cs: chip select number
+ * @ecc_size: number of bytes for ecc generation
+ */
+
+int gpmc_ecc_init(int cs, int ecc_size)
+{
+	unsigned int val = 0x0;
+
+	/* check if ecc engine already by another cs */
+	if (gpmc_ecc_used == -EINVAL)
+		gpmc_ecc_used = cs;
+	else
+		return -EBUSY;
+
+	/* read ecc control register */
+	val = gpmc_read_reg(GPMC_ECC_CONTROL);
+
+	/* clear ecc and enable bits */
+	val = ((0x00000001<<8) | 0x00000001);
+	gpmc_write_reg(GPMC_ECC_CONTROL, val);
+
+	/* Read from ECC Size Config Register */
+	val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
+
+	/* program ecc and result sizes */
+	val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
+	gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
+
+	return 0;
+}
+
+/**
+ * gpmc_calculate_ecc - generate non-inverted ecc bytes
+ * @cs: chip select number
+ * @dat: data pointer over which ecc is computed
+ * @ecc_code: ecc code buffer
+ *
+ * Using non-inverted ECC is considered ugly since writing a blank
+ * page (padding) will clear the ECC bytes. This is not a problem as long
+ * no one is trying to write data on the seemingly unused page. Reading
+ * an erased page will produce an ECC mismatch between generated and read
+ * ECC bytes that has to be dealt with separately.
+ */
+int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
+{
+	unsigned int val = 0x0;
+
+	if (gpmc_ecc_used != cs)
+		return -EINVAL;
+
+	/* read ecc result */
+	val = gpmc_read_reg(GPMC_ECC1_RESULT);
+	*ecc_code++ = val;          /* P128e, ..., P1e */
+	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
+	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
+
+	return 0;
+}
+
+/**
+ * gpmc_enable_hwecc - enable hardware ecc functionality
+ * @cs: chip select number
+ * @mode: read/write mode
+ * @dev_width: device bus width(1 for x16, 0 for x8)
+ */
+int gpmc_enable_hwecc(int cs, int mode, int dev_width)
+{
+	unsigned int val;
+
+	if (gpmc_ecc_used != cs)
+		return -EINVAL;
+
+	switch (mode) {
+	case GPMC_ECC_READ:
+		gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
+		break;
+	case GPMC_ECC_READSYN:
+		 gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
+		break;
+	case GPMC_ECC_WRITE:
+		gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
+		break;
+	default:
+		printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode);
+		break;
+	}
+
+	/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+	val = (dev_width << 7) | (cs << 1) | (0x1);
+	gpmc_write_reg(GPMC_ECC_CONFIG, val);
+	return 0;
+}
+
+/**
+ * gmpc_ecc_reset - release the HW ECC in GPMC controller
+ * @cs: Chip select number
+ */
+int gpmc_ecc_reset(int cs)
+{
+	if (gpmc_ecc_used == cs)
+		gpmc_ecc_used = -EINVAL;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 145838a..67a3442
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -27,8 +27,24 @@
 
 #define GPMC_CONFIG		0x50
 #define GPMC_STATUS		0x54
-#define GPMC_CS0_BASE		0x60
-#define GPMC_CS_SIZE		0x30
+
+/* Control Commands */
+#define GPMC_CONFIG_WP		0x00000001
+#define GPMC_CONFIG_RDY_BSY	0x00000002
+#define GPMC_CONFIG_DEV_SIZE	0x00000003
+#define GPMC_CONFIG_DEV_TYPE	0x00000004
+#define GPMC_NAND_COMMAND	0x00000005
+#define GPMC_NAND_ADDRESS	0x00000006
+#define GPMC_NAND_DATA		0x00000007
+#define GPMC_STATUS_BUFFER	0x00000008 /* 1: buffer is available to write */
+#define GPMC_PREFETCH_FIFO_CNT	0x00000009 /* bytes available in FIFO for r/w */
+#define GPMC_PREFETCH_COUNT	0x0000000A /* remaining bytes to be read/write*/
+#define GPMC_GET_SET_IRQ_STATUS	0x0000000B
+
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
 
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
@@ -56,6 +72,14 @@
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 #define GPMC_CONFIG7_CSVALID		(1 << 6)
 
+#define GPMC_DEVICETYPE_NOR		0
+#define GPMC_DEVICETYPE_NAND		2
+#define GPMC_CONFIG_WRITEPROTECT	0x00000010
+#define GPMC_STATUS_BUFF_EMPTY		0x00000001
+#define WR_RD_PIN_MONITORING		0x00600000
+#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)	((val & 0x7f000000) >> 24)
+#define GPMC_PREFETCH_STATUS_COUNT(val)	(val & 0x00003fff)
+
 /*
  * Note that all values in this struct are in nanoseconds, while
  * the register values are in gpmc_fck cycles.
@@ -108,10 +132,15 @@ extern int gpmc_cs_set_reserved(int cs, int reserved);
 extern int gpmc_cs_reserved(int cs);
 extern int gpmc_prefetch_enable(int cs, int dma_mode,
 					unsigned int u32_count, int is_write);
-extern void gpmc_prefetch_reset(void);
+extern int gpmc_prefetch_reset(int cs);
 extern int gpmc_prefetch_status(void);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_init(void);
+extern int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval);
 
+int gpmc_ecc_init(int cs, int ecc_size);
+int gpmc_enable_hwecc(int cs, int mode, int dev_width);
+int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
+int gpmc_ecc_reset(int cs);
 #endif
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 7545568..206406b
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -316,7 +316,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 		} while (len);
 
 		/* disable and stop the PFPW engine */
-		gpmc_prefetch_reset();
+		gpmc_prefetch_reset(info->gpmc_cs);
 	}
 }
 
@@ -360,7 +360,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 		}
 
 		/* disable and stop the PFPW engine */
-		gpmc_prefetch_reset();
+		gpmc_prefetch_reset(info->gpmc_cs);
 	}
 }
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v3 2/3] omap3 nand: cleanup virtual address usages
  2010-05-18 11:16   ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
@ 2010-05-18 11:16     ` Sukumar Ghorai
  2010-05-18 11:16       ` [PATCH v3 3/3] omap3 nand: fix issue in board file to detect nand Sukumar Ghorai
  2010-05-19 15:30       ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Vimal Singh
  2010-05-19 14:46     ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Vimal Singh
  1 sibling, 2 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-18 11:16 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

This patch removes direct reference of gpmc address from generic nand platform code.
Nand platform code now uses wrapper functions which are implemented in gpmc module. 

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c        |   39 ++----
 arch/arm/mach-omap2/gpmc.c             |    9 --
 arch/arm/plat-omap/include/plat/gpmc.h |    7 +-
 arch/arm/plat-omap/include/plat/nand.h |    6 +-
 drivers/mtd/nand/omap2.c               |  242 ++++++++++----------------------
 5 files changed, 88 insertions(+), 215 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index e57fb29..80f5d94
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -19,8 +19,6 @@
 #include <plat/board.h>
 #include <plat/gpmc.h>
 
-#define WR_RD_PIN_MONITORING	0x00600000
-
 static struct omap_nand_platform_data *gpmc_nand_data;
 
 static struct resource gpmc_nand_resource = {
@@ -71,10 +69,10 @@ static int omap2_nand_gpmc_retime(void)
 	t.wr_cycle  = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);
 
 	/* Configure GPMC */
-	gpmc_cs_write_reg(gpmc_nand_data->cs, GPMC_CS_CONFIG1,
-			GPMC_CONFIG1_DEVICESIZE(gpmc_nand_data->devsize) |
-			GPMC_CONFIG1_DEVICETYPE_NAND);
-
+	gpmc_hwcontrol(gpmc_nand_data->cs,
+			GPMC_CONFIG_DEV_SIZE, 1, gpmc_nand_data->devsize, NULL);
+	gpmc_hwcontrol(gpmc_nand_data->cs,
+			GPMC_CONFIG_DEV_TYPE, 1, GPMC_DEVICETYPE_NAND, NULL);
 	err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
 	if (err)
 		return err;
@@ -82,27 +80,13 @@ static int omap2_nand_gpmc_retime(void)
 	return 0;
 }
 
-static int gpmc_nand_setup(void)
-{
-	struct device *dev = &gpmc_nand_device.dev;
-
-	/* Set timings in GPMC */
-	if (omap2_nand_gpmc_retime() < 0) {
-		dev_err(dev, "Unable to set gpmc timings\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
 {
-	unsigned int val;
 	int err	= 0;
 	struct device *dev = &gpmc_nand_device.dev;
 
 	gpmc_nand_data = _nand_data;
-	gpmc_nand_data->nand_setup = gpmc_nand_setup;
+	gpmc_nand_data->nand_setup = omap2_nand_gpmc_retime;
 	gpmc_nand_device.dev.platform_data = gpmc_nand_data;
 
 	err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
@@ -112,19 +96,17 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
 		return err;
 	}
 
-	err = gpmc_nand_setup();
+	 /* Set timings in GPMC */
+	err = omap2_nand_gpmc_retime();
 	if (err < 0) {
-		dev_err(dev, "NAND platform setup failed: %d\n", err);
+		dev_err(dev, "Unable to set gpmc timings: %d\n", err);
 		return err;
 	}
 
 	/* Enable RD PIN Monitoring Reg */
 	if (gpmc_nand_data->dev_ready) {
-		val  = gpmc_cs_read_reg(gpmc_nand_data->cs,
-						 GPMC_CS_CONFIG1);
-		val |= WR_RD_PIN_MONITORING;
-		gpmc_cs_write_reg(gpmc_nand_data->cs,
-						GPMC_CS_CONFIG1, val);
+		gpmc_hwcontrol(gpmc_nand_data->cs,
+					GPMC_CONFIG_RDY_BSY, 1, 1, NULL);
 	}
 
 	err = platform_device_register(&gpmc_nand_device);
@@ -140,3 +122,4 @@ out_free_cs:
 
 	return err;
 }
+
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index f414aeb..cbe0efb
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -589,15 +589,6 @@ int gpmc_prefetch_reset(int cs)
 }
 EXPORT_SYMBOL(gpmc_prefetch_reset);
 
-/**
- * gpmc_prefetch_status - reads prefetch status of engine
- */
-int  gpmc_prefetch_status(void)
-{
-	return gpmc_read_reg(GPMC_PREFETCH_STATUS);
-}
-EXPORT_SYMBOL(gpmc_prefetch_status);
-
 static void __init gpmc_mem_init(void)
 {
 	int cs;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 67a3442..2386ff6
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -25,9 +25,6 @@
 #define GPMC_CS_NAND_ADDRESS	0x20
 #define GPMC_CS_NAND_DATA	0x24
 
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-
 /* Control Commands */
 #define GPMC_CONFIG_WP		0x00000001
 #define GPMC_CONFIG_RDY_BSY	0x00000002
@@ -63,7 +60,6 @@
 #define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
 #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
 #define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_DEVICETYPE_NAND    GPMC_CONFIG1_DEVICETYPE(2)
 #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
 #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
 #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
@@ -77,7 +73,7 @@
 #define GPMC_CONFIG_WRITEPROTECT	0x00000010
 #define GPMC_STATUS_BUFF_EMPTY		0x00000001
 #define WR_RD_PIN_MONITORING		0x00600000
-#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)	((val & 0x7f000000) >> 24)
+#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)	((val >> 24) & 0x7F)
 #define GPMC_PREFETCH_STATUS_COUNT(val)	(val & 0x00003fff)
 
 /*
@@ -133,7 +129,6 @@ extern int gpmc_cs_reserved(int cs);
 extern int gpmc_prefetch_enable(int cs, int dma_mode,
 					unsigned int u32_count, int is_write);
 extern int gpmc_prefetch_reset(int cs);
-extern int gpmc_prefetch_status(void);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_init(void);
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index f8efd54..6562cd0
--- a/arch/arm/plat-omap/include/plat/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
@@ -21,13 +21,11 @@ struct omap_nand_platform_data {
 	int			(*dev_ready)(struct omap_nand_platform_data *);
 	int			dma_channel;
 	unsigned long		phys_base;
-	void __iomem		*gpmc_cs_baseaddr;
-	void __iomem		*gpmc_baseaddr;
 	int			devsize;
 };
 
-/* size (4 KiB) for IO mapping */
-#define	NAND_IO_SIZE	SZ_4K
+/* minimum size for IO mapping */
+#define	NAND_IO_SIZE	4
 
 #if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
 extern int gpmc_nand_init(struct omap_nand_platform_data *d);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 206406b..e2302a7
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -23,20 +23,8 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 
-#define GPMC_IRQ_STATUS		0x18
-#define GPMC_ECC_CONFIG		0x1F4
-#define GPMC_ECC_CONTROL	0x1F8
-#define GPMC_ECC_SIZE_CONFIG	0x1FC
-#define GPMC_ECC1_RESULT	0x200
-
 #define	DRIVER_NAME	"omap2-nand"
 
-#define	NAND_WP_OFF	0
-#define NAND_WP_BIT	0x00000010
-
-#define	GPMC_BUF_FULL	0x00000001
-#define	GPMC_BUF_EMPTY	0x00000000
-
 #define NAND_Ecc_P1e		(1 << 0)
 #define NAND_Ecc_P2e		(1 << 1)
 #define NAND_Ecc_P4e		(1 << 2)
@@ -139,34 +127,11 @@ struct omap_nand_info {
 
 	int				gpmc_cs;
 	unsigned long			phys_base;
-	void __iomem			*gpmc_cs_baseaddr;
-	void __iomem			*gpmc_baseaddr;
-	void __iomem			*nand_pref_fifo_add;
 	struct completion		comp;
 	int				dma_ch;
 };
 
 /**
- * omap_nand_wp - This function enable or disable the Write Protect feature
- * @mtd: MTD device structure
- * @mode: WP ON/OFF
- */
-static void omap_nand_wp(struct mtd_info *mtd, int mode)
-{
-	struct omap_nand_info *info = container_of(mtd,
-						struct omap_nand_info, mtd);
-
-	unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);
-
-	if (mode)
-		config &= ~(NAND_WP_BIT);	/* WP is ON */
-	else
-		config |= (NAND_WP_BIT);	/* WP is OFF */
-
-	__raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
-}
-
-/**
  * omap_hwcontrol - hardware specific access to control-lines
  * @mtd: MTD device structure
  * @cmd: command to device
@@ -181,31 +146,20 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
 	struct omap_nand_info *info = container_of(mtd,
 					struct omap_nand_info, mtd);
-	switch (ctrl) {
-	case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_COMMAND;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-
-	case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_ADDRESS;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-
-	case NAND_CTRL_CHANGE | NAND_NCE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-	}
 
-	if (cmd != NAND_CMD_NONE)
-		__raw_writeb(cmd, info->nand.IO_ADDR_W);
+	if (cmd != NAND_CMD_NONE) {
+		if (ctrl & NAND_CLE)
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_NAND_COMMAND, 1, cmd, NULL);
+
+		else if (ctrl & NAND_ALE)
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_NAND_ADDRESS, 1, cmd, NULL);
+
+		else /* NAND_NCE */
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_NAND_DATA, 1, cmd, NULL);
+	}
 }
 
 /**
@@ -232,11 +186,15 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
 	u_char *p = (u_char *)buf;
+	u32	status = 0;
 
 	while (len--) {
 		iowrite8(*p++, info->nand.IO_ADDR_W);
-		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
-						GPMC_STATUS) & GPMC_BUF_FULL));
+		/* wait until buffer is available for write */
+		do {
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_STATUS_BUFFER, 0, 0, &status);
+		} while (!status);
 	}
 }
 
@@ -264,16 +222,17 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
 	u16 *p = (u16 *) buf;
-
+	u32	status = 0;
 	/* FIXME try bursts of writesw() or DMA ... */
 	len >>= 1;
 
 	while (len--) {
 		iowrite16(*p++, info->nand.IO_ADDR_W);
-
-		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
-						GPMC_STATUS) & GPMC_BUF_FULL))
-			;
+		/* wait until buffer is available for write */
+		do {
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_STATUS_BUFFER, 0, 0, &status);
+		} while (!status);
 	}
 }
 
@@ -287,16 +246,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 {
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
-	uint32_t pfpw_status = 0, r_count = 0;
+	u32 r_count = 0;
 	int ret = 0;
-	u32 *p = (u32 *)buf;
+	u32 *p;
 
 	/* take care of subpage reads */
 	for (; len % 4 != 0; ) {
 		*buf++ = __raw_readb(info->nand.IO_ADDR_R);
 		len--;
 	}
-	p = (u32 *) buf;
 
 	/* configure and start prefetch transfer */
 	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
@@ -307,17 +265,18 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 		else
 			omap_read_buf8(mtd, buf, len);
 	} else {
+		p = (u32 *) buf;
 		do {
-			pfpw_status = gpmc_prefetch_status();
-			r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
-			ioread32_rep(info->nand_pref_fifo_add, p, r_count);
+			gpmc_hwcontrol(info->gpmc_cs,
+				GPMC_PREFETCH_FIFO_CNT, 0, 0, &r_count);
+			r_count = r_count >> 2;
+			ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
 			p += r_count;
-			len -= r_count << 2;
+			len -= (r_count << 2);
 		} while (len);
-
-		/* disable and stop the PFPW engine */
-		gpmc_prefetch_reset(info->gpmc_cs);
 	}
+	/* disable and stop the PFPW engine */
+	gpmc_prefetch_reset(info->gpmc_cs);
 }
 
 /**
@@ -331,13 +290,13 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 {
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
-	uint32_t pfpw_status = 0, w_count = 0;
+	uint32_t pref_count = 0, w_count = 0;
 	int i = 0, ret = 0;
-	u16 *p = (u16 *) buf;
+	u16 *p;
 
 	/* take care of subpage writes */
 	if (len % 2 != 0) {
-		writeb(*buf, info->nand.IO_ADDR_R);
+		writeb(*buf, info->nand.IO_ADDR_W);
 		p = (u16 *)(buf + 1);
 		len--;
 	}
@@ -351,17 +310,22 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 		else
 			omap_write_buf8(mtd, buf, len);
 	} else {
-		pfpw_status = gpmc_prefetch_status();
-		while (pfpw_status & 0x3FFF) {
-			w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
+		p = (u16 *) buf;
+		while (len) {
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_PREFETCH_FIFO_CNT, 0, 0, &w_count);
+			w_count = w_count >> 1;
 			for (i = 0; (i < w_count) && len; i++, len -= 2)
-				iowrite16(*p++, info->nand_pref_fifo_add);
-			pfpw_status = gpmc_prefetch_status();
+				iowrite16(*p++, info->nand.IO_ADDR_W);
 		}
-
-		/* disable and stop the PFPW engine */
-		gpmc_prefetch_reset(info->gpmc_cs);
+		/* wait for data to flushed-out before reset the prefetch */
+		do {
+			gpmc_hwcontrol(info->gpmc_cs,
+				GPMC_PREFETCH_COUNT, 0, 0, &pref_count);
+		} while (pref_count);
 	}
+	/* disable and stop the PFPW engine */
+	gpmc_prefetch_reset(info->gpmc_cs);
 }
 
 #ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
@@ -448,8 +412,10 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 	/* setup and start DMA using dma_addr */
 	wait_for_completion(&info->comp);
 
-	while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
-		;
+	do {
+		gpmc_hwcontrol(info->gpmc_cs,
+				GPMC_PREFETCH_COUNT, 0, 0, &prefetch_status);
+	} while (prefetch_status);
 	/* disable and stop the PFPW engine */
 	gpmc_prefetch_reset();
 
@@ -502,7 +468,7 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
 		omap_write_buf_pref(mtd, buf, len);
 	else
 		/* start transfer in DMA mode */
-		omap_nand_dma_transfer(mtd, buf, len, 0x1);
+		omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
 }
 
 /**
@@ -528,30 +494,6 @@ static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len)
 
 #ifdef CONFIG_MTD_NAND_OMAP_HWECC
 /**
- * omap_hwecc_init - Initialize the HW ECC for NAND flash in GPMC controller
- * @mtd: MTD device structure
- */
-static void omap_hwecc_init(struct mtd_info *mtd)
-{
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-							mtd);
-	struct nand_chip *chip = mtd->priv;
-	unsigned long val = 0x0;
-
-	/* Read from ECC Control Register */
-	val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-	/* Clear all ECC | Enable Reg1 */
-	val = ((0x00000001<<8) | 0x00000001);
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-
-	/* Read from ECC Size Config Register */
-	val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
-	/* ECCSIZE1=512 | Select eccResultsize[0-3] */
-	val = ((((chip->ecc.size >> 1) - 1) << 22) | (0x0000000F));
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
-}
-
-/**
  * gen_true_ecc - This function will generate true ECC value
  * @ecc_buf: buffer to store ecc code
  *
@@ -752,19 +694,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 {
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	unsigned long val = 0x0;
-	unsigned long reg;
-
-	/* Start Reading from HW ECC1_Result = 0x200 */
-	reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT);
-	val = __raw_readl(reg);
-	*ecc_code++ = val;          /* P128e, ..., P1e */
-	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
-	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
-	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
-	reg += 4;
-
-	return 0;
+	return gpmc_calculate_ecc(info->gpmc_cs, dat, ecc_code);
 }
 
 /**
@@ -778,32 +708,10 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
 							mtd);
 	struct nand_chip *chip = mtd->priv;
 	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
-	unsigned long val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONFIG);
-
-	switch (mode) {
-	case NAND_ECC_READ:
-		__raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	case NAND_ECC_READSYN:
-		 __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	case NAND_ECC_WRITE:
-		__raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	default:
-		DEBUG(MTD_DEBUG_LEVEL0, "Error: Unrecognized Mode[%d]!\n",
-					mode);
-		break;
-	}
 
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+	gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width);
 }
+
 #endif
 
 /**
@@ -831,14 +739,10 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 	else
 		timeo += (HZ * 20) / 1000;
 
-	this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_COMMAND;
-	this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA;
-
-	__raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W);
-
+	gpmc_hwcontrol(info->gpmc_cs,
+			GPMC_NAND_COMMAND, 1,  (NAND_CMD_STATUS & 0xFF), NULL);
 	while (time_before(jiffies, timeo)) {
-		status = __raw_readb(this->IO_ADDR_R);
+		gpmc_hwcontrol(info->gpmc_cs, GPMC_NAND_DATA, 0,  0, &status);
 		if (status & NAND_STATUS_READY)
 			break;
 		cond_resched();
@@ -852,22 +756,24 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
  */
 static int omap_dev_ready(struct mtd_info *mtd)
 {
+	unsigned int val = 0;
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS);
 
+	gpmc_hwcontrol(info->gpmc_cs, GPMC_GET_SET_IRQ_STATUS, 0, 0, &val);
 	if ((val & 0x100) == 0x100) {
 		/* Clear IRQ Interrupt */
 		val |= 0x100;
 		val &= ~(0x0);
-		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+		gpmc_hwcontrol(info->gpmc_cs,
+			GPMC_GET_SET_IRQ_STATUS, 1, val, NULL);
 	} else {
 		unsigned int cnt = 0;
 		while (cnt++ < 0x1FF) {
 			if  ((val & 0x100) == 0x100)
 				return 0;
-			val = __raw_readl(info->gpmc_baseaddr +
-							GPMC_IRQ_STATUS);
+			gpmc_hwcontrol(info->gpmc_cs,
+				GPMC_GET_SET_IRQ_STATUS, 0, 0, &val);
 		}
 	}
 
@@ -898,8 +804,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->pdev = pdev;
 
 	info->gpmc_cs		= pdata->cs;
-	info->gpmc_baseaddr	= pdata->gpmc_baseaddr;
-	info->gpmc_cs_baseaddr	= pdata->gpmc_cs_baseaddr;
 	info->phys_base		= pdata->phys_base;
 
 	info->mtd.priv		= &info->nand;
@@ -910,7 +814,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->nand.options	|= NAND_SKIP_BBTSCAN;
 
 	/* NAND write protect off */
-	omap_nand_wp(&info->mtd, NAND_WP_OFF);
+	gpmc_hwcontrol(info->gpmc_cs, GPMC_CONFIG_WP, 1, 0, NULL);
 
 	if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
 				pdev->dev.driver->name)) {
@@ -946,7 +850,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 
 	if (use_prefetch) {
 		/* copy the virtual address of nand base for fifo access */
-		info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
 
 		info->nand.read_buf   = omap_read_buf_pref;
 		info->nand.write_buf  = omap_write_buf_pref;
@@ -987,7 +890,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->nand.ecc.mode		= NAND_ECC_HW;
 
 	/* init HW ECC */
-	omap_hwecc_init(&info->mtd);
+	gpmc_ecc_init(info->gpmc_cs, info->nand.ecc.size);
 #else
 	info->nand.ecc.mode = NAND_ECC_SOFT;
 #endif
@@ -1034,9 +937,12 @@ static int omap_nand_remove(struct platform_device *pdev)
 	if (use_dma)
 		omap_free_dma(info->dma_ch);
 
+	/* reset/ releae the ecc module */
+	gpmc_ecc_reset(info->gpmc_cs);
+
 	/* Release NAND device, its internal structures and partitions */
 	nand_release(&info->mtd);
-	iounmap(info->nand_pref_fifo_add);
+	iounmap(info->nand.IO_ADDR_R);
 	kfree(&info->mtd);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v3 3/3] omap3 nand: fix issue in board file to detect nand
  2010-05-18 11:16     ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
@ 2010-05-18 11:16       ` Sukumar Ghorai
  2010-05-19 15:30       ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Vimal Singh
  1 sibling, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-05-18 11:16 UTC (permalink / raw)
  To: linux-omap; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, Sukumar Ghorai

Board file modified for not to provide gpmc phys_base address to nand driver.
The gpmc_nand_init funciton is now used to detect the nand and required to
adopt _prob function as in nand/omap2.c

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/board-cm-t35.c         |   20 +-------------------
 arch/arm/mach-omap2/board-devkit8000.c     |   25 +------------------------
 arch/arm/mach-omap2/board-omap3beagle.c    |   24 +-----------------------
 arch/arm/mach-omap2/board-omap3touchbook.c |   25 +------------------------
 arch/arm/mach-omap2/board-overo.c          |   24 +-----------------------
 5 files changed, 5 insertions(+), 113 deletions(-)

diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index f4e8063..8a41268
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -61,8 +61,6 @@
 #define SB_T35_SMSC911X_GPIO	65
 
 #define NAND_BLOCK_SIZE		SZ_128K
-#define GPMC_CS0_BASE		0x60
-#define GPMC_CS0_BASE_ADDR	(OMAP34XX_GPMC_VIRT + GPMC_CS0_BASE)
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #include <linux/smsc911x.h>
@@ -223,28 +221,12 @@ static struct omap_nand_platform_data cm_t35_nand_data = {
 	.nr_parts		= ARRAY_SIZE(cm_t35_nand_partitions),
 	.dma_channel		= -1,	/* disable DMA in OMAP NAND driver */
 	.cs			= 0,
-	.gpmc_cs_baseaddr	= (void __iomem *)GPMC_CS0_BASE_ADDR,
-	.gpmc_baseaddr		= (void __iomem *)OMAP34XX_GPMC_VIRT,
 
 };
 
-static struct resource cm_t35_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device cm_t35_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.num_resources	= 1,
-	.resource	= &cm_t35_nand_resource,
-	.dev		= {
-		.platform_data	= &cm_t35_nand_data,
-	},
-};
-
 static void __init cm_t35_init_nand(void)
 {
-	if (platform_device_register(&cm_t35_nand_device) < 0)
+	if (gpmc_nand_init(&cm_t35_nand_data) < 0)
 		pr_err("CM-T35: Unable to register NAND device\n");
 }
 #else
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 6d910df..b172414
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -58,9 +58,6 @@
 #include "mux.h"
 #include "hsmmc.h"
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 #define OMAP_DM9000_GPIO_IRQ	25
@@ -104,20 +101,6 @@ static struct omap_nand_platform_data devkit8000_nand_data = {
 	.dma_channel	= -1,		/* disable DMA in OMAP NAND driver */
 };
 
-static struct resource devkit8000_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device devkit8000_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &devkit8000_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &devkit8000_nand_resource,
-};
-
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
@@ -581,8 +564,6 @@ static void __init devkit8000_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -604,13 +585,9 @@ static void __init devkit8000_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		devkit8000_nand_data.cs = nandcs;
-		devkit8000_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		devkit8000_nand_data.gpmc_baseaddr = (void *)
-			(gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&devkit8000_nand_device) < 0)
+		if (gpmc_nand_init(&devkit8000_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 5df89f6..9ec3ef8 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -47,9 +47,6 @@
 #include "mux.h"
 #include "hsmmc.h"
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 static struct mtd_partition omap3beagle_nand_partitions[] = {
@@ -92,20 +89,6 @@ static struct omap_nand_platform_data omap3beagle_nand_data = {
 	.dev_ready	= NULL,
 };
 
-static struct resource omap3beagle_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device omap3beagle_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &omap3beagle_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &omap3beagle_nand_resource,
-};
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
@@ -377,8 +360,6 @@ static void __init omap3beagle_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -400,12 +381,9 @@ static void __init omap3beagle_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		omap3beagle_nand_data.cs = nandcs;
-		omap3beagle_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		omap3beagle_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&omap3beagle_nand_device) < 0)
+		if (gpmc_nand_init(&omap3beagle_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index c59050d..29dd266
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -54,9 +54,6 @@
 
 #include <asm/setup.h>
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 #define OMAP3_AC_GPIO		136
@@ -106,20 +103,6 @@ static struct omap_nand_platform_data omap3touchbook_nand_data = {
 	.dev_ready	= NULL,
 };
 
-static struct resource omap3touchbook_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device omap3touchbook_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &omap3touchbook_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &omap3touchbook_nand_resource,
-};
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
@@ -459,8 +442,6 @@ static void __init omap3touchbook_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -482,13 +463,9 @@ static void __init omap3touchbook_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		omap3touchbook_nand_data.cs = nandcs;
-		omap3touchbook_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		omap3touchbook_nand_data.gpmc_baseaddr =
-						(void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&omap3touchbook_nand_device) < 0)
+		if (gpmc_nand_init(&omap3touchbook_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 24b32d7..df0fb0d
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -58,8 +58,6 @@
 #define OVERO_GPIO_USBH_NRESET	183
 
 #define NAND_BLOCK_SIZE SZ_128K
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
 
 #define OVERO_SMSC911X_CS      5
 #define OVERO_SMSC911X_GPIO    176
@@ -231,28 +229,11 @@ static struct omap_nand_platform_data overo_nand_data = {
 	.dma_channel = -1,	/* disable DMA in OMAP NAND driver */
 };
 
-static struct resource overo_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device overo_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &overo_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &overo_nand_resource,
-};
-
-
 static void __init overo_flash_init(void)
 {
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -274,12 +255,9 @@ static void __init overo_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		overo_nand_data.cs = nandcs;
-		overo_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		overo_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&overo_nand_device) < 0)
+		if (gpmc_nand_init(&overo_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-18 11:16   ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
  2010-05-18 11:16     ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
@ 2010-05-19 14:46     ` Vimal Singh
  2010-05-19 15:14       ` Peter Barada
  2010-05-19 15:48       ` Peter Barada
  1 sibling, 2 replies; 57+ messages in thread
From: Vimal Singh @ 2010-05-19 14:46 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, linux-omap

On Tue, May 18, 2010 at 4:46 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> few functions added in gpmc module and to be used by other drivers like NAND.
> E.g.: - ioctl function
>      - ecc functions
>
> Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
> ---
>  arch/arm/mach-omap2/gpmc.c             |  246 +++++++++++++++++++++++++++++++-
>  arch/arm/plat-omap/include/plat/gpmc.h |   35 ++++-
>  drivers/mtd/nand/omap2.c               |    4 +-
>  3 files changed, 274 insertions(+), 11 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
> index 5bc3ca0..7e6d821
> --- a/arch/arm/mach-omap2/gpmc.c
> +++ b/arch/arm/mach-omap2/gpmc.c
> @@ -46,8 +46,9 @@
>  #define GPMC_ECC_CONFIG                0x1f4
>  #define GPMC_ECC_CONTROL       0x1f8
>  #define GPMC_ECC_SIZE_CONFIG   0x1fc
> +#define GPMC_ECC1_RESULT        0x200
>
> -#define GPMC_CS0               0x60
> +#define GPMC_CS0_BASE          0x60
>  #define GPMC_CS_SIZE           0x30
>
>  #define GPMC_MEM_START         0x00000000
> @@ -92,7 +93,9 @@ struct omap3_gpmc_regs {
>  static struct resource gpmc_mem_root;
>  static struct resource gpmc_cs_mem[GPMC_CS_NUM];
>  static DEFINE_SPINLOCK(gpmc_mem_lock);
> -static unsigned                gpmc_cs_map;
> +static unsigned        int gpmc_cs_map;        /* flag for cs which are initialized */
> +static int gpmc_pref_used = -EINVAL;   /* cs using prefetch engine */
> +static int gpmc_ecc_used = -EINVAL;    /* cs using ecc engine */
>
>  static void __iomem *gpmc_base;
>
> @@ -108,11 +111,27 @@ static u32 gpmc_read_reg(int idx)
>        return __raw_readl(gpmc_base + idx);
>  }
>
> +static void gpmc_cs_write_byte(int cs, int idx, u8 val)
> +{
> +       void __iomem *reg_addr;
> +
> +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> +       __raw_writeb(val, reg_addr);
> +}
> +
> +static u8 gpmc_cs_read_byte(int cs, int idx)
> +{
> +       void __iomem *reg_addr;
> +
> +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> +       return __raw_readb(reg_addr);
> +}
> +
>  void gpmc_cs_write_reg(int cs, int idx, u32 val)
>  {
>        void __iomem *reg_addr;
>
> -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
>        __raw_writel(val, reg_addr);
>  }
>
> @@ -120,7 +139,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
>  {
>        void __iomem *reg_addr;
>
> -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
>        return __raw_readl(reg_addr);
>  }
>
> @@ -419,8 +438,100 @@ void gpmc_cs_free(int cs)
>  EXPORT_SYMBOL(gpmc_cs_free);
>
>  /**
> + * gpmc_hwcontrol - hardware specific access (read/ write) control
> + * @cs: chip select number
> + * @cmd: command type
> + * @write: 1 for write; 0 for read
> + * @wval: value to write
> + * @rval: read pointer
> + */
> +int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval)
> +{
> +       u32 regval = 0;
> +
> +       if (!write && !rval)
> +               return -EINVAL;
> +
> +       switch (cmd) {
> +       case GPMC_STATUS_BUFFER:
> +               regval = gpmc_read_reg(GPMC_STATUS);
> +               /* 1 : buffer is available to write */
> +               *rval = regval & GPMC_STATUS_BUFF_EMPTY;
> +               break;
> +
> +       case GPMC_GET_SET_IRQ_STATUS:
> +               if (write)
> +                       gpmc_write_reg(GPMC_IRQSTATUS, wval);
> +               else
> +                       *rval = gpmc_read_reg(GPMC_IRQSTATUS);
> +               break;
> +
> +       case GPMC_PREFETCH_FIFO_CNT:
> +               regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> +               *rval = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
> +               break;
> +
> +       case GPMC_PREFETCH_COUNT:
> +               regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> +               *rval = GPMC_PREFETCH_STATUS_COUNT(regval);
> +               break;
> +
> +       case GPMC_CONFIG_WP:
> +               regval = gpmc_read_reg(GPMC_CONFIG);
> +               if (wval)
> +                       regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
> +               else
> +                       regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
> +               gpmc_write_reg(GPMC_CONFIG, regval);
> +               break;
> +
> +       case GPMC_CONFIG_RDY_BSY:
> +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +               regval |= WR_RD_PIN_MONITORING;
> +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +               break;

IIRC, at least in OMAP2/3, ready/busy pin is not in use (not connected).

> +
> +       case GPMC_CONFIG_DEV_SIZE:
> +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +               regval |= GPMC_CONFIG1_DEVICESIZE(wval);
> +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +               break;
> +
> +       case GPMC_CONFIG_DEV_TYPE:
> +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +               regval |= GPMC_CONFIG1_DEVICETYPE(wval);
> +               if (wval == GPMC_DEVICETYPE_NOR)
> +                       regval |= GPMC_CONFIG1_MUXADDDATA;
> +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +               break;
> +
> +       case GPMC_NAND_COMMAND:
> +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
> +               break;
> +
> +       case GPMC_NAND_ADDRESS:
> +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
> +               break;
> +
> +       case GPMC_NAND_DATA:
> +               if (write)
> +                       gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
> +               else
> +                       *rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
> +               break;
> +
> +       default:
> +               printk(KERN_ERR "gpmc_hwcontrol: Not supported\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(gpmc_hwcontrol);
> +
> +/**
>  * gpmc_prefetch_enable - configures and starts prefetch transfer
> - * @cs: nand cs (chip select) number
> + * @cs: cs (chip select) number
>  * @dma_mode: dma mode enable (1) or disable (0)
>  * @u32_count: number of bytes to be transferred
>  * @is_write: prefetch read(0) or write post(1) mode
> @@ -430,6 +541,11 @@ int gpmc_prefetch_enable(int cs, int dma_mode,
>  {
>        uint32_t prefetch_config1;
>
> +       if (gpmc_pref_used == -EINVAL)
> +               gpmc_pref_used = cs;
> +       else
> +               return -EBUSY;

This is  not required. Prefetch engine has just one instance

> +
>        if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {

and any prefetch request will be done only if above check passes.
Which actually checks if 'prefetch' is busy or not.
You can see in NAND driver (omap2.c) code, it understands that.

>                /* Set the amount of bytes to be prefetched */
>                gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
> @@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
>  /**
>  * gpmc_prefetch_reset - disables and stops the prefetch engine
>  */
> -void gpmc_prefetch_reset(void)
> +int gpmc_prefetch_reset(int cs)
>  {
> +       if (gpmc_pref_used == cs)
> +               gpmc_pref_used = -EINVAL;
> +       else
> +               return -EINVAL;
> +

This is also not required. As, this function will be called only if
prefetch was used.

>        /* Stop the PFPW engine */
>        gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
>
>        /* Reset/disable the PFPW engine */
>        gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
> +
> +       return 0;
>  }
>  EXPORT_SYMBOL(gpmc_prefetch_reset);
>
> @@ -615,3 +738,114 @@ void omap3_gpmc_restore_context(void)
>        }
>  }
>  #endif /* CONFIG_ARCH_OMAP3 */
> +
> +/**
> + * gpmc_ecc_init - initialize hw ecc for device in GPMC controller
> + * @cs: chip select number
> + * @ecc_size: number of bytes for ecc generation
> + */
> +
> +int gpmc_ecc_init(int cs, int ecc_size)
> +{
> +       unsigned int val = 0x0;
> +
> +       /* check if ecc engine already by another cs */
> +       if (gpmc_ecc_used == -EINVAL)
> +               gpmc_ecc_used = cs;
> +       else
> +               return -EBUSY;
Here few things need be to consider:
1. 'init' is supposed to done once for every instance of driver during probe
2. But ECC engine, too, have only one instance at a time, So
3. As long as all NAND chip are supposed to use same ECC machenism, we
can go for only one time 'init' for all drivers, perhaps in
gpmc_nand.c.
4. But in case, different instances of driver (or NAND chip) requires
different ECC machenism (for ex. Hamming or BCH, or even with
different capabilities of error correction),
this will no longer vailid. Then rather we should have something like
'gpmc_ecc_config' call to configer ECC engine for everytime a driver
needs it (something like as it is done for prefetch engine).

> +
> +       /* read ecc control register */
> +       val = gpmc_read_reg(GPMC_ECC_CONTROL);
> +
> +       /* clear ecc and enable bits */
> +       val = ((0x00000001<<8) | 0x00000001);
> +       gpmc_write_reg(GPMC_ECC_CONTROL, val);
> +
> +       /* Read from ECC Size Config Register */
> +       val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
> +
> +       /* program ecc and result sizes */
> +       val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
> +       gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
> +
> +       return 0;
> +}
> +
> +/**
> + * gpmc_calculate_ecc - generate non-inverted ecc bytes
> + * @cs: chip select number
> + * @dat: data pointer over which ecc is computed
> + * @ecc_code: ecc code buffer
> + *
> + * Using non-inverted ECC is considered ugly since writing a blank
> + * page (padding) will clear the ECC bytes. This is not a problem as long
> + * no one is trying to write data on the seemingly unused page. Reading
> + * an erased page will produce an ECC mismatch between generated and read
> + * ECC bytes that has to be dealt with separately.
> + */
> +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
> +{
> +       unsigned int val = 0x0;
> +
> +       if (gpmc_ecc_used != cs)
> +               return -EINVAL;
> +
> +       /* read ecc result */
> +       val = gpmc_read_reg(GPMC_ECC1_RESULT);
> +       *ecc_code++ = val;          /* P128e, ..., P1e */
> +       *ecc_code++ = val >> 16;    /* P128o, ..., P1o */
> +       /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
> +       *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
> +
> +       return 0;
> +}
> +
> +/**
> + * gpmc_enable_hwecc - enable hardware ecc functionality
> + * @cs: chip select number
> + * @mode: read/write mode
> + * @dev_width: device bus width(1 for x16, 0 for x8)
> + */
> +int gpmc_enable_hwecc(int cs, int mode, int dev_width)
> +{
> +       unsigned int val;
> +
> +       if (gpmc_ecc_used != cs)
> +               return -EINVAL;
> +
> +       switch (mode) {
> +       case GPMC_ECC_READ:
> +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> +               break;
> +       case GPMC_ECC_READSYN:
> +                gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
> +               break;
> +       case GPMC_ECC_WRITE:
> +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> +               break;
> +       default:
> +               printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode);
> +               break;
> +       }
> +
> +       /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> +       val = (dev_width << 7) | (cs << 1) | (0x1);
> +       gpmc_write_reg(GPMC_ECC_CONFIG, val);
> +       return 0;
> +}
> +
> +/**
> + * gmpc_ecc_reset - release the HW ECC in GPMC controller
> + * @cs: Chip select number
> + */
> +int gpmc_ecc_reset(int cs)
> +{
> +       if (gpmc_ecc_used == cs)
> +               gpmc_ecc_used = -EINVAL;
> +       else
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
> index 145838a..67a3442
> --- a/arch/arm/plat-omap/include/plat/gpmc.h
> +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> @@ -27,8 +27,24 @@
>
>  #define GPMC_CONFIG            0x50
>  #define GPMC_STATUS            0x54
> -#define GPMC_CS0_BASE          0x60
> -#define GPMC_CS_SIZE           0x30
> +
> +/* Control Commands */
> +#define GPMC_CONFIG_WP         0x00000001
> +#define GPMC_CONFIG_RDY_BSY    0x00000002
> +#define GPMC_CONFIG_DEV_SIZE   0x00000003
> +#define GPMC_CONFIG_DEV_TYPE   0x00000004
> +#define GPMC_NAND_COMMAND      0x00000005
> +#define GPMC_NAND_ADDRESS      0x00000006
> +#define GPMC_NAND_DATA         0x00000007
> +#define GPMC_STATUS_BUFFER     0x00000008 /* 1: buffer is available to write */
> +#define GPMC_PREFETCH_FIFO_CNT 0x00000009 /* bytes available in FIFO for r/w */
> +#define GPMC_PREFETCH_COUNT    0x0000000A /* remaining bytes to be read/write*/
> +#define GPMC_GET_SET_IRQ_STATUS        0x0000000B
> +
> +/* ECC commands */
> +#define GPMC_ECC_READ          0 /* Reset Hardware ECC for read */
> +#define GPMC_ECC_WRITE         1 /* Reset Hardware ECC for write */
> +#define GPMC_ECC_READSYN       2 /* Reset before syndrom is read back */
>
>  #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
>  #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
> @@ -56,6 +72,14 @@
>  #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
>  #define GPMC_CONFIG7_CSVALID           (1 << 6)
>
> +#define GPMC_DEVICETYPE_NOR            0
> +#define GPMC_DEVICETYPE_NAND           2
> +#define GPMC_CONFIG_WRITEPROTECT       0x00000010
> +#define GPMC_STATUS_BUFF_EMPTY         0x00000001
> +#define WR_RD_PIN_MONITORING           0x00600000
> +#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)     ((val & 0x7f000000) >> 24)
> +#define GPMC_PREFETCH_STATUS_COUNT(val)        (val & 0x00003fff)
> +
>  /*
>  * Note that all values in this struct are in nanoseconds, while
>  * the register values are in gpmc_fck cycles.
> @@ -108,10 +132,15 @@ extern int gpmc_cs_set_reserved(int cs, int reserved);
>  extern int gpmc_cs_reserved(int cs);
>  extern int gpmc_prefetch_enable(int cs, int dma_mode,
>                                        unsigned int u32_count, int is_write);
> -extern void gpmc_prefetch_reset(void);
> +extern int gpmc_prefetch_reset(int cs);
>  extern int gpmc_prefetch_status(void);
>  extern void omap3_gpmc_save_context(void);
>  extern void omap3_gpmc_restore_context(void);
>  extern void gpmc_init(void);
> +extern int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval);
>
> +int gpmc_ecc_init(int cs, int ecc_size);
> +int gpmc_enable_hwecc(int cs, int mode, int dev_width);
> +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
> +int gpmc_ecc_reset(int cs);
>  #endif
> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> index 7545568..206406b
> --- a/drivers/mtd/nand/omap2.c
> +++ b/drivers/mtd/nand/omap2.c
> @@ -316,7 +316,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
>                } while (len);
>
>                /* disable and stop the PFPW engine */
> -               gpmc_prefetch_reset();
> +               gpmc_prefetch_reset(info->gpmc_cs);
Not required. see above comments.

>        }
>  }
>
> @@ -360,7 +360,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
>                }
>
>                /* disable and stop the PFPW engine */
> -               gpmc_prefetch_reset();
> +               gpmc_prefetch_reset(info->gpmc_cs);
Not required. see above comments.
>        }
>  }
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-19 14:46     ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Vimal Singh
@ 2010-05-19 15:14       ` Peter Barada
  2010-05-19 15:48       ` Peter Barada
  1 sibling, 0 replies; 57+ messages in thread
From: Peter Barada @ 2010-05-19 15:14 UTC (permalink / raw)
  To: Vimal Singh
  Cc: Artem.Bityutskiy, tony, Sukumar Ghorai, sakoman, linux-mtd,
	linux-omap

On Wed, 2010-05-19 at 20:16 +0530, Vimal Singh wrote:
> On Tue, May 18, 2010 at 4:46 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> > few functions added in gpmc module and to be used by other drivers like NAND.
> > E.g.: - ioctl function
> >      - ecc functions
> >
> > Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
> > ---
> >  arch/arm/mach-omap2/gpmc.c             |  246 +++++++++++++++++++++++++++++++-
> >  arch/arm/plat-omap/include/plat/gpmc.h |   35 ++++-
> >  drivers/mtd/nand/omap2.c               |    4 +-
> >  3 files changed, 274 insertions(+), 11 deletions(-)
> >
> > diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
> > index 5bc3ca0..7e6d821
> > --- a/arch/arm/mach-omap2/gpmc.c
> > +++ b/arch/arm/mach-omap2/gpmc.c
> > @@ -46,8 +46,9 @@
> >  #define GPMC_ECC_CONFIG                0x1f4
> >  #define GPMC_ECC_CONTROL       0x1f8
> >  #define GPMC_ECC_SIZE_CONFIG   0x1fc
> > +#define GPMC_ECC1_RESULT        0x200
> >
> > -#define GPMC_CS0               0x60
> > +#define GPMC_CS0_BASE          0x60
> >  #define GPMC_CS_SIZE           0x30
> >
> >  #define GPMC_MEM_START         0x00000000
> > @@ -92,7 +93,9 @@ struct omap3_gpmc_regs {
> >  static struct resource gpmc_mem_root;
> >  static struct resource gpmc_cs_mem[GPMC_CS_NUM];
> >  static DEFINE_SPINLOCK(gpmc_mem_lock);
> > -static unsigned                gpmc_cs_map;
> > +static unsigned        int gpmc_cs_map;        /* flag for cs which are initialized */
> > +static int gpmc_pref_used = -EINVAL;   /* cs using prefetch engine */
> > +static int gpmc_ecc_used = -EINVAL;    /* cs using ecc engine */
> >
> >  static void __iomem *gpmc_base;
> >
> > @@ -108,11 +111,27 @@ static u32 gpmc_read_reg(int idx)
> >        return __raw_readl(gpmc_base + idx);
> >  }
> >
> > +static void gpmc_cs_write_byte(int cs, int idx, u8 val)
> > +{
> > +       void __iomem *reg_addr;
> > +
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> > +       __raw_writeb(val, reg_addr);
> > +}
> > +
> > +static u8 gpmc_cs_read_byte(int cs, int idx)
> > +{
> > +       void __iomem *reg_addr;
> > +
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> > +       return __raw_readb(reg_addr);
> > +}
> > +
> >  void gpmc_cs_write_reg(int cs, int idx, u32 val)
> >  {
> >        void __iomem *reg_addr;
> >
> > -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> >        __raw_writel(val, reg_addr);
> >  }
> >
> > @@ -120,7 +139,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
> >  {
> >        void __iomem *reg_addr;
> >
> > -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> >        return __raw_readl(reg_addr);
> >  }
> >
> > @@ -419,8 +438,100 @@ void gpmc_cs_free(int cs)
> >  EXPORT_SYMBOL(gpmc_cs_free);
> >
> >  /**
> > + * gpmc_hwcontrol - hardware specific access (read/ write) control
> > + * @cs: chip select number
> > + * @cmd: command type
> > + * @write: 1 for write; 0 for read
> > + * @wval: value to write
> > + * @rval: read pointer
> > + */
> > +int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval)
> > +{
> > +       u32 regval = 0;
> > +
> > +       if (!write && !rval)
> > +               return -EINVAL;
> > +
> > +       switch (cmd) {
> > +       case GPMC_STATUS_BUFFER:
> > +               regval = gpmc_read_reg(GPMC_STATUS);
> > +               /* 1 : buffer is available to write */
> > +               *rval = regval & GPMC_STATUS_BUFF_EMPTY;
> > +               break;
> > +
> > +       case GPMC_GET_SET_IRQ_STATUS:
> > +               if (write)
> > +                       gpmc_write_reg(GPMC_IRQSTATUS, wval);
> > +               else
> > +                       *rval = gpmc_read_reg(GPMC_IRQSTATUS);
> > +               break;
> > +
> > +       case GPMC_PREFETCH_FIFO_CNT:
> > +               regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > +               *rval = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
> > +               break;
> > +
> > +       case GPMC_PREFETCH_COUNT:
> > +               regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > +               *rval = GPMC_PREFETCH_STATUS_COUNT(regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_WP:
> > +               regval = gpmc_read_reg(GPMC_CONFIG);
> > +               if (wval)
> > +                       regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
> > +               else
> > +                       regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
> > +               gpmc_write_reg(GPMC_CONFIG, regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_RDY_BSY:
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= WR_RD_PIN_MONITORING;
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> 
> IIRC, at least in OMAP2/3, ready/busy pin is not in use (not connected).

On the Logic LV SOM/Torpedo, indeed the R/B# pin from the NAND flash in
the Micron mt29c2g4maklajg-6it POP part is connected to the WAIT0 pin on
the OMAP3530 and I'm looking to use it to speed up NAND accesses.

> > +
> > +       case GPMC_CONFIG_DEV_SIZE:
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= GPMC_CONFIG1_DEVICESIZE(wval);
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_DEV_TYPE:
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= GPMC_CONFIG1_DEVICETYPE(wval);
> > +               if (wval == GPMC_DEVICETYPE_NOR)
> > +                       regval |= GPMC_CONFIG1_MUXADDDATA;
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> > +
> > +       case GPMC_NAND_COMMAND:
> > +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
> > +               break;
> > +
> > +       case GPMC_NAND_ADDRESS:
> > +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
> > +               break;
> > +
> > +       case GPMC_NAND_DATA:
> > +               if (write)
> > +                       gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
> > +               else
> > +                       *rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
> > +               break;
> > +
> > +       default:
> > +               printk(KERN_ERR "gpmc_hwcontrol: Not supported\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       return 0;
> > +}
> > +EXPORT_SYMBOL(gpmc_hwcontrol);
> > +
> > +/**
> >  * gpmc_prefetch_enable - configures and starts prefetch transfer
> > - * @cs: nand cs (chip select) number
> > + * @cs: cs (chip select) number
> >  * @dma_mode: dma mode enable (1) or disable (0)
> >  * @u32_count: number of bytes to be transferred
> >  * @is_write: prefetch read(0) or write post(1) mode
> > @@ -430,6 +541,11 @@ int gpmc_prefetch_enable(int cs, int dma_mode,
> >  {
> >        uint32_t prefetch_config1;
> >
> > +       if (gpmc_pref_used == -EINVAL)
> > +               gpmc_pref_used = cs;
> > +       else
> > +               return -EBUSY;
> 
> This is  not required. Prefetch engine has just one instance
> 
> > +
> >        if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
> 
> and any prefetch request will be done only if above check passes.
> Which actually checks if 'prefetch' is busy or not.
> You can see in NAND driver (omap2.c) code, it understands that.
> 
> >                /* Set the amount of bytes to be prefetched */
> >                gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
> > @@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
> >  /**
> >  * gpmc_prefetch_reset - disables and stops the prefetch engine
> >  */
> > -void gpmc_prefetch_reset(void)
> > +int gpmc_prefetch_reset(int cs)
> >  {
> > +       if (gpmc_pref_used == cs)
> > +               gpmc_pref_used = -EINVAL;
> > +       else
> > +               return -EINVAL;
> > +
> 
> This is also not required. As, this function will be called only if
> prefetch was used.
> 
> >        /* Stop the PFPW engine */
> >        gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
> >
> >        /* Reset/disable the PFPW engine */
> >        gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
> > +
> > +       return 0;
> >  }
> >  EXPORT_SYMBOL(gpmc_prefetch_reset);
> >
> > @@ -615,3 +738,114 @@ void omap3_gpmc_restore_context(void)
> >        }
> >  }
> >  #endif /* CONFIG_ARCH_OMAP3 */
> > +
> > +/**
> > + * gpmc_ecc_init - initialize hw ecc for device in GPMC controller
> > + * @cs: chip select number
> > + * @ecc_size: number of bytes for ecc generation
> > + */
> > +
> > +int gpmc_ecc_init(int cs, int ecc_size)
> > +{
> > +       unsigned int val = 0x0;
> > +
> > +       /* check if ecc engine already by another cs */
> > +       if (gpmc_ecc_used == -EINVAL)
> > +               gpmc_ecc_used = cs;
> > +       else
> > +               return -EBUSY;
> Here few things need be to consider:
> 1. 'init' is supposed to done once for every instance of driver during probe
> 2. But ECC engine, too, have only one instance at a time, So
> 3. As long as all NAND chip are supposed to use same ECC machenism, we
> can go for only one time 'init' for all drivers, perhaps in
> gpmc_nand.c.
> 4. But in case, different instances of driver (or NAND chip) requires
> different ECC machenism (for ex. Hamming or BCH, or even with
> different capabilities of error correction),
> this will no longer vailid. Then rather we should have something like
> 'gpmc_ecc_config' call to configer ECC engine for everytime a driver
> needs it (something like as it is done for prefetch engine).
> 
> > +
> > +       /* read ecc control register */
> > +       val = gpmc_read_reg(GPMC_ECC_CONTROL);
> > +
> > +       /* clear ecc and enable bits */
> > +       val = ((0x00000001<<8) | 0x00000001);
> > +       gpmc_write_reg(GPMC_ECC_CONTROL, val);
> > +
> > +       /* Read from ECC Size Config Register */
> > +       val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
> > +
> > +       /* program ecc and result sizes */
> > +       val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
> > +       gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * gpmc_calculate_ecc - generate non-inverted ecc bytes
> > + * @cs: chip select number
> > + * @dat: data pointer over which ecc is computed
> > + * @ecc_code: ecc code buffer
> > + *
> > + * Using non-inverted ECC is considered ugly since writing a blank
> > + * page (padding) will clear the ECC bytes. This is not a problem as long
> > + * no one is trying to write data on the seemingly unused page. Reading
> > + * an erased page will produce an ECC mismatch between generated and read
> > + * ECC bytes that has to be dealt with separately.
> > + */
> > +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
> > +{
> > +       unsigned int val = 0x0;
> > +
> > +       if (gpmc_ecc_used != cs)
> > +               return -EINVAL;
> > +
> > +       /* read ecc result */
> > +       val = gpmc_read_reg(GPMC_ECC1_RESULT);
> > +       *ecc_code++ = val;          /* P128e, ..., P1e */
> > +       *ecc_code++ = val >> 16;    /* P128o, ..., P1o */
> > +       /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
> > +       *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * gpmc_enable_hwecc - enable hardware ecc functionality
> > + * @cs: chip select number
> > + * @mode: read/write mode
> > + * @dev_width: device bus width(1 for x16, 0 for x8)
> > + */
> > +int gpmc_enable_hwecc(int cs, int mode, int dev_width)
> > +{
> > +       unsigned int val;
> > +
> > +       if (gpmc_ecc_used != cs)
> > +               return -EINVAL;
> > +
> > +       switch (mode) {
> > +       case GPMC_ECC_READ:
> > +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> > +               break;
> > +       case GPMC_ECC_READSYN:
> > +                gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
> > +               break;
> > +       case GPMC_ECC_WRITE:
> > +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> > +               break;
> > +       default:
> > +               printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode);
> > +               break;
> > +       }
> > +
> > +       /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> > +       val = (dev_width << 7) | (cs << 1) | (0x1);
> > +       gpmc_write_reg(GPMC_ECC_CONFIG, val);
> > +       return 0;
> > +}
> > +
> > +/**
> > + * gmpc_ecc_reset - release the HW ECC in GPMC controller
> > + * @cs: Chip select number
> > + */
> > +int gpmc_ecc_reset(int cs)
> > +{
> > +       if (gpmc_ecc_used == cs)
> > +               gpmc_ecc_used = -EINVAL;
> > +       else
> > +               return -EINVAL;
> > +
> > +       return 0;
> > +}
> > +
> > diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
> > index 145838a..67a3442
> > --- a/arch/arm/plat-omap/include/plat/gpmc.h
> > +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> > @@ -27,8 +27,24 @@
> >
> >  #define GPMC_CONFIG            0x50
> >  #define GPMC_STATUS            0x54
> > -#define GPMC_CS0_BASE          0x60
> > -#define GPMC_CS_SIZE           0x30
> > +
> > +/* Control Commands */
> > +#define GPMC_CONFIG_WP         0x00000001
> > +#define GPMC_CONFIG_RDY_BSY    0x00000002
> > +#define GPMC_CONFIG_DEV_SIZE   0x00000003
> > +#define GPMC_CONFIG_DEV_TYPE   0x00000004
> > +#define GPMC_NAND_COMMAND      0x00000005
> > +#define GPMC_NAND_ADDRESS      0x00000006
> > +#define GPMC_NAND_DATA         0x00000007
> > +#define GPMC_STATUS_BUFFER     0x00000008 /* 1: buffer is available to write */
> > +#define GPMC_PREFETCH_FIFO_CNT 0x00000009 /* bytes available in FIFO for r/w */
> > +#define GPMC_PREFETCH_COUNT    0x0000000A /* remaining bytes to be read/write*/
> > +#define GPMC_GET_SET_IRQ_STATUS        0x0000000B
> > +
> > +/* ECC commands */
> > +#define GPMC_ECC_READ          0 /* Reset Hardware ECC for read */
> > +#define GPMC_ECC_WRITE         1 /* Reset Hardware ECC for write */
> > +#define GPMC_ECC_READSYN       2 /* Reset before syndrom is read back */
> >
> >  #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
> >  #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
> > @@ -56,6 +72,14 @@
> >  #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
> >  #define GPMC_CONFIG7_CSVALID           (1 << 6)
> >
> > +#define GPMC_DEVICETYPE_NOR            0
> > +#define GPMC_DEVICETYPE_NAND           2
> > +#define GPMC_CONFIG_WRITEPROTECT       0x00000010
> > +#define GPMC_STATUS_BUFF_EMPTY         0x00000001
> > +#define WR_RD_PIN_MONITORING           0x00600000
> > +#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)     ((val & 0x7f000000) >> 24)
> > +#define GPMC_PREFETCH_STATUS_COUNT(val)        (val & 0x00003fff)
> > +
> >  /*
> >  * Note that all values in this struct are in nanoseconds, while
> >  * the register values are in gpmc_fck cycles.
> > @@ -108,10 +132,15 @@ extern int gpmc_cs_set_reserved(int cs, int reserved);
> >  extern int gpmc_cs_reserved(int cs);
> >  extern int gpmc_prefetch_enable(int cs, int dma_mode,
> >                                        unsigned int u32_count, int is_write);
> > -extern void gpmc_prefetch_reset(void);
> > +extern int gpmc_prefetch_reset(int cs);
> >  extern int gpmc_prefetch_status(void);
> >  extern void omap3_gpmc_save_context(void);
> >  extern void omap3_gpmc_restore_context(void);
> >  extern void gpmc_init(void);
> > +extern int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval);
> >
> > +int gpmc_ecc_init(int cs, int ecc_size);
> > +int gpmc_enable_hwecc(int cs, int mode, int dev_width);
> > +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
> > +int gpmc_ecc_reset(int cs);
> >  #endif
> > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> > index 7545568..206406b
> > --- a/drivers/mtd/nand/omap2.c
> > +++ b/drivers/mtd/nand/omap2.c
> > @@ -316,7 +316,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
> >                } while (len);
> >
> >                /* disable and stop the PFPW engine */
> > -               gpmc_prefetch_reset();
> > +               gpmc_prefetch_reset(info->gpmc_cs);
> Not required. see above comments.
> 
> >        }
> >  }
> >
> > @@ -360,7 +360,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
> >                }
> >
> >                /* disable and stop the PFPW engine */
> > -               gpmc_prefetch_reset();
> > +               gpmc_prefetch_reset(info->gpmc_cs);
> Not required. see above comments.
> >        }
> >  }
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> 
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 2/3] omap3 nand: cleanup virtual address usages
  2010-05-18 11:16     ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
  2010-05-18 11:16       ` [PATCH v3 3/3] omap3 nand: fix issue in board file to detect nand Sukumar Ghorai
@ 2010-05-19 15:30       ` Vimal Singh
  2010-05-19 17:24         ` Ghorai, Sukumar
  1 sibling, 1 reply; 57+ messages in thread
From: Vimal Singh @ 2010-05-19 15:30 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: Artem.Bityutskiy, tony, sakoman, linux-mtd, linux-omap

On Tue, May 18, 2010 at 4:46 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> This patch removes direct reference of gpmc address from generic nand platform code.
> Nand platform code now uses wrapper functions which are implemented in gpmc module.
>
> Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
[...]

>
> @@ -287,16 +246,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
>  {
>        struct omap_nand_info *info = container_of(mtd,
>                                                struct omap_nand_info, mtd);
> -       uint32_t pfpw_status = 0, r_count = 0;
> +       u32 r_count = 0;
>        int ret = 0;
> -       u32 *p = (u32 *)buf;
> +       u32 *p;
>
>        /* take care of subpage reads */
>        for (; len % 4 != 0; ) {
>                *buf++ = __raw_readb(info->nand.IO_ADDR_R);
>                len--;
>        }
> -       p = (u32 *) buf;

Above code had an issue, which was fixed by this commit:
http://git.infradead.org/mtd-2.6.git/commitdiff/c3341d0ceb4de1680572024f50233403c6a8b10d

I would suggest you to prepare your patch on MTD tree.

>
>        /* configure and start prefetch transfer */
>        ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
> @@ -307,17 +265,18 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
>                else
>                        omap_read_buf8(mtd, buf, len);
>        } else {
> +               p = (u32 *) buf;
>                do {
> -                       pfpw_status = gpmc_prefetch_status();
> -                       r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
> -                       ioread32_rep(info->nand_pref_fifo_add, p, r_count);
> +                       gpmc_hwcontrol(info->gpmc_cs,
> +                               GPMC_PREFETCH_FIFO_CNT, 0, 0, &r_count);
> +                       r_count = r_count >> 2;
> +                       ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
>                        p += r_count;
> -                       len -= r_count << 2;
> +                       len -= (r_count << 2);

Braces are not required here.

>                } while (len);
> -

After call to 'gpmc_prefetch_enable', next line are:
           if (ret) {
                       /* PFPW engine is busy, use cpu copy method */
                       if (info->nand.options & NAND_BUSWIDTH_16)
                       ...
                       ...
> -               /* disable and stop the PFPW engine */
> -               gpmc_prefetch_reset(info->gpmc_cs);
>        }

So, if above 'if' fails, driver will not get prefetch engine (it was
already busy). Then it doesn't makes sense to call for __reset__.

> +       /* disable and stop the PFPW engine */
> +       gpmc_prefetch_reset(info->gpmc_cs);

(Also see my comments on your other patch.)

>  }
>
>  /**
> @@ -331,13 +290,13 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
>  {
>        struct omap_nand_info *info = container_of(mtd,
>                                                struct omap_nand_info, mtd);
> -       uint32_t pfpw_status = 0, w_count = 0;
> +       uint32_t pref_count = 0, w_count = 0;
>        int i = 0, ret = 0;
> -       u16 *p = (u16 *) buf;
> +       u16 *p;
>
>        /* take care of subpage writes */
>        if (len % 2 != 0) {
> -               writeb(*buf, info->nand.IO_ADDR_R);
> +               writeb(*buf, info->nand.IO_ADDR_W);
>                p = (u16 *)(buf + 1);
>                len--;
>        }
> @@ -351,17 +310,22 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
>                else
>                        omap_write_buf8(mtd, buf, len);
>        } else {
> -               pfpw_status = gpmc_prefetch_status();
> -               while (pfpw_status & 0x3FFF) {
> -                       w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
> +               p = (u16 *) buf;
> +               while (len) {
> +                       gpmc_hwcontrol(info->gpmc_cs,
> +                                       GPMC_PREFETCH_FIFO_CNT, 0, 0, &w_count);
> +                       w_count = w_count >> 1;
>                        for (i = 0; (i < w_count) && len; i++, len -= 2)
> -                               iowrite16(*p++, info->nand_pref_fifo_add);
> -                       pfpw_status = gpmc_prefetch_status();
> +                               iowrite16(*p++, info->nand.IO_ADDR_W);
>                }
> -
> -               /* disable and stop the PFPW engine */
> -               gpmc_prefetch_reset(info->gpmc_cs);
> +               /* wait for data to flushed-out before reset the prefetch */
> +               do {
> +                       gpmc_hwcontrol(info->gpmc_cs,
> +                               GPMC_PREFETCH_COUNT, 0, 0, &pref_count);
> +               } while (pref_count);
>        }
> +       /* disable and stop the PFPW engine */
> +       gpmc_prefetch_reset(info->gpmc_cs);

Same as above.


>  }
>
>  #ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
> @@ -448,8 +412,10 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
>        /* setup and start DMA using dma_addr */
>        wait_for_completion(&info->comp);
>
> -       while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
> -               ;
> +       do {
> +               gpmc_hwcontrol(info->gpmc_cs,
> +                               GPMC_PREFETCH_COUNT, 0, 0, &prefetch_status);
> +       } while (prefetch_status);
>        /* disable and stop the PFPW engine */
>        gpmc_prefetch_reset();
>
> @@ -502,7 +468,7 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
>                omap_write_buf_pref(mtd, buf, len);
>        else
>                /* start transfer in DMA mode */
> -               omap_nand_dma_transfer(mtd, buf, len, 0x1);
> +               omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);

This is already fixed. See commit:
http://git.infradead.org/mtd-2.6.git/commitdiff/bdaefc41627b6f2815ef7aa476dfa4ebb3ad499f


Rest, patches looks good. It is a good clean-up all together.

-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-19 14:46     ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Vimal Singh
  2010-05-19 15:14       ` Peter Barada
@ 2010-05-19 15:48       ` Peter Barada
  2010-05-19 18:04         ` Ghorai, Sukumar
  1 sibling, 1 reply; 57+ messages in thread
From: Peter Barada @ 2010-05-19 15:48 UTC (permalink / raw)
  To: Vimal Singh
  Cc: Artem.Bityutskiy, tony, Sukumar Ghorai, sakoman, linux-mtd,
	linux-omap

On Wed, 2010-05-19 at 20:16 +0530, Vimal Singh wrote:
> On Tue, May 18, 2010 at 4:46 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> > few functions added in gpmc module and to be used by other drivers like NAND.
> > E.g.: - ioctl function
> >      - ecc functions
> >
> > Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
> > ---
> >  arch/arm/mach-omap2/gpmc.c             |  246 +++++++++++++++++++++++++++++++-
> >  arch/arm/plat-omap/include/plat/gpmc.h |   35 ++++-
> >  drivers/mtd/nand/omap2.c               |    4 +-
> >  3 files changed, 274 insertions(+), 11 deletions(-)
> >
> > diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
> > index 5bc3ca0..7e6d821
> > --- a/arch/arm/mach-omap2/gpmc.c
> > +++ b/arch/arm/mach-omap2/gpmc.c
> > @@ -46,8 +46,9 @@
> >  #define GPMC_ECC_CONFIG                0x1f4
> >  #define GPMC_ECC_CONTROL       0x1f8
> >  #define GPMC_ECC_SIZE_CONFIG   0x1fc
> > +#define GPMC_ECC1_RESULT        0x200
> >
> > -#define GPMC_CS0               0x60
> > +#define GPMC_CS0_BASE          0x60
> >  #define GPMC_CS_SIZE           0x30
> >
> >  #define GPMC_MEM_START         0x00000000
> > @@ -92,7 +93,9 @@ struct omap3_gpmc_regs {
> >  static struct resource gpmc_mem_root;
> >  static struct resource gpmc_cs_mem[GPMC_CS_NUM];
> >  static DEFINE_SPINLOCK(gpmc_mem_lock);
> > -static unsigned                gpmc_cs_map;
> > +static unsigned        int gpmc_cs_map;        /* flag for cs which are initialized */
> > +static int gpmc_pref_used = -EINVAL;   /* cs using prefetch engine */
> > +static int gpmc_ecc_used = -EINVAL;    /* cs using ecc engine */
> >
> >  static void __iomem *gpmc_base;
> >
> > @@ -108,11 +111,27 @@ static u32 gpmc_read_reg(int idx)
> >        return __raw_readl(gpmc_base + idx);
> >  }
> >
> > +static void gpmc_cs_write_byte(int cs, int idx, u8 val)
> > +{
> > +       void __iomem *reg_addr;
> > +
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> > +       __raw_writeb(val, reg_addr);
> > +}
> > +
> > +static u8 gpmc_cs_read_byte(int cs, int idx)
> > +{
> > +       void __iomem *reg_addr;
> > +
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> > +       return __raw_readb(reg_addr);
> > +}
> > +
> >  void gpmc_cs_write_reg(int cs, int idx, u32 val)
> >  {
> >        void __iomem *reg_addr;
> >
> > -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> >        __raw_writel(val, reg_addr);
> >  }
> >
> > @@ -120,7 +139,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
> >  {
> >        void __iomem *reg_addr;
> >
> > -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
> >        return __raw_readl(reg_addr);
> >  }
> >
> > @@ -419,8 +438,100 @@ void gpmc_cs_free(int cs)
> >  EXPORT_SYMBOL(gpmc_cs_free);
> >
> >  /**
> > + * gpmc_hwcontrol - hardware specific access (read/ write) control
> > + * @cs: chip select number
> > + * @cmd: command type
> > + * @write: 1 for write; 0 for read
> > + * @wval: value to write
> > + * @rval: read pointer
> > + */
> > +int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval)
> > +{
> > +       u32 regval = 0;
> > +
> > +       if (!write && !rval)
> > +               return -EINVAL;
> > +
> > +       switch (cmd) {
> > +       case GPMC_STATUS_BUFFER:
> > +               regval = gpmc_read_reg(GPMC_STATUS);
> > +               /* 1 : buffer is available to write */
> > +               *rval = regval & GPMC_STATUS_BUFF_EMPTY;
> > +               break;
> > +
> > +       case GPMC_GET_SET_IRQ_STATUS:
> > +               if (write)
> > +                       gpmc_write_reg(GPMC_IRQSTATUS, wval);
> > +               else
> > +                       *rval = gpmc_read_reg(GPMC_IRQSTATUS);
> > +               break;
> > +
> > +       case GPMC_PREFETCH_FIFO_CNT:
> > +               regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > +               *rval = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
> > +               break;
> > +
> > +       case GPMC_PREFETCH_COUNT:
> > +               regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > +               *rval = GPMC_PREFETCH_STATUS_COUNT(regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_WP:
> > +               regval = gpmc_read_reg(GPMC_CONFIG);
> > +               if (wval)
> > +                       regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
> > +               else
> > +                       regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
> > +               gpmc_write_reg(GPMC_CONFIG, regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_RDY_BSY:
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= WR_RD_PIN_MONITORING;
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> 
> IIRC, at least in OMAP2/3, ready/busy pin is not in use (not connected).

On the Logic OMAP3530 LV SOM and Torpedo modules, the R/B# pin of the
NAND in the Micron mt29c2g4maklajg-6it POP part is connected to the
WAIT0 pin on the OMAP3530 and I'm looking to use it to speed up NAND
accesses

> > +
> > +       case GPMC_CONFIG_DEV_SIZE:
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= GPMC_CONFIG1_DEVICESIZE(wval);
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> > +
> > +       case GPMC_CONFIG_DEV_TYPE:
> > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +               regval |= GPMC_CONFIG1_DEVICETYPE(wval);
> > +               if (wval == GPMC_DEVICETYPE_NOR)
> > +                       regval |= GPMC_CONFIG1_MUXADDDATA;
> > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +               break;
> > +
> > +       case GPMC_NAND_COMMAND:
> > +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
> > +               break;
> > +
> > +       case GPMC_NAND_ADDRESS:
> > +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
> > +               break;
> > +
> > +       case GPMC_NAND_DATA:
> > +               if (write)
> > +                       gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
> > +               else
> > +                       *rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
> > +               break;
> > +
> > +       default:
> > +               printk(KERN_ERR "gpmc_hwcontrol: Not supported\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       return 0;
> > +}
> > +EXPORT_SYMBOL(gpmc_hwcontrol);
> > +
> > +/**
> >  * gpmc_prefetch_enable - configures and starts prefetch transfer
> > - * @cs: nand cs (chip select) number
> > + * @cs: cs (chip select) number
> >  * @dma_mode: dma mode enable (1) or disable (0)
> >  * @u32_count: number of bytes to be transferred
> >  * @is_write: prefetch read(0) or write post(1) mode
> > @@ -430,6 +541,11 @@ int gpmc_prefetch_enable(int cs, int dma_mode,
> >  {
> >        uint32_t prefetch_config1;
> >
> > +       if (gpmc_pref_used == -EINVAL)
> > +               gpmc_pref_used = cs;
> > +       else
> > +               return -EBUSY;
> 
> This is  not required. Prefetch engine has just one instance
> 
> > +
> >        if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
> 
> and any prefetch request will be done only if above check passes.
> Which actually checks if 'prefetch' is busy or not.
> You can see in NAND driver (omap2.c) code, it understands that.
> 
> >                /* Set the amount of bytes to be prefetched */
> >                gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
> > @@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
> >  /**
> >  * gpmc_prefetch_reset - disables and stops the prefetch engine
> >  */
> > -void gpmc_prefetch_reset(void)
> > +int gpmc_prefetch_reset(int cs)
> >  {
> > +       if (gpmc_pref_used == cs)
> > +               gpmc_pref_used = -EINVAL;
> > +       else
> > +               return -EINVAL;
> > +
> 
> This is also not required. As, this function will be called only if
> prefetch was used.
> 
> >        /* Stop the PFPW engine */
> >        gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
> >
> >        /* Reset/disable the PFPW engine */
> >        gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
> > +
> > +       return 0;
> >  }
> >  EXPORT_SYMBOL(gpmc_prefetch_reset);
> >
> > @@ -615,3 +738,114 @@ void omap3_gpmc_restore_context(void)
> >        }
> >  }
> >  #endif /* CONFIG_ARCH_OMAP3 */
> > +
> > +/**
> > + * gpmc_ecc_init - initialize hw ecc for device in GPMC controller
> > + * @cs: chip select number
> > + * @ecc_size: number of bytes for ecc generation
> > + */
> > +
> > +int gpmc_ecc_init(int cs, int ecc_size)
> > +{
> > +       unsigned int val = 0x0;
> > +
> > +       /* check if ecc engine already by another cs */
> > +       if (gpmc_ecc_used == -EINVAL)
> > +               gpmc_ecc_used = cs;
> > +       else
> > +               return -EBUSY;
> Here few things need be to consider:
> 1. 'init' is supposed to done once for every instance of driver during probe
> 2. But ECC engine, too, have only one instance at a time, So
> 3. As long as all NAND chip are supposed to use same ECC machenism, we
> can go for only one time 'init' for all drivers, perhaps in
> gpmc_nand.c.
> 4. But in case, different instances of driver (or NAND chip) requires
> different ECC machenism (for ex. Hamming or BCH, or even with
> different capabilities of error correction),
> this will no longer vailid. Then rather we should have something like
> 'gpmc_ecc_config' call to configer ECC engine for everytime a driver
> needs it (something like as it is done for prefetch engine).
> 
> > +
> > +       /* read ecc control register */
> > +       val = gpmc_read_reg(GPMC_ECC_CONTROL);
> > +
> > +       /* clear ecc and enable bits */
> > +       val = ((0x00000001<<8) | 0x00000001);
> > +       gpmc_write_reg(GPMC_ECC_CONTROL, val);
> > +
> > +       /* Read from ECC Size Config Register */
> > +       val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
> > +
> > +       /* program ecc and result sizes */
> > +       val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
> > +       gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * gpmc_calculate_ecc - generate non-inverted ecc bytes
> > + * @cs: chip select number
> > + * @dat: data pointer over which ecc is computed
> > + * @ecc_code: ecc code buffer
> > + *
> > + * Using non-inverted ECC is considered ugly since writing a blank
> > + * page (padding) will clear the ECC bytes. This is not a problem as long
> > + * no one is trying to write data on the seemingly unused page. Reading
> > + * an erased page will produce an ECC mismatch between generated and read
> > + * ECC bytes that has to be dealt with separately.
> > + */
> > +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
> > +{
> > +       unsigned int val = 0x0;
> > +
> > +       if (gpmc_ecc_used != cs)
> > +               return -EINVAL;
> > +
> > +       /* read ecc result */
> > +       val = gpmc_read_reg(GPMC_ECC1_RESULT);
> > +       *ecc_code++ = val;          /* P128e, ..., P1e */
> > +       *ecc_code++ = val >> 16;    /* P128o, ..., P1o */
> > +       /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
> > +       *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * gpmc_enable_hwecc - enable hardware ecc functionality
> > + * @cs: chip select number
> > + * @mode: read/write mode
> > + * @dev_width: device bus width(1 for x16, 0 for x8)
> > + */
> > +int gpmc_enable_hwecc(int cs, int mode, int dev_width)
> > +{
> > +       unsigned int val;
> > +
> > +       if (gpmc_ecc_used != cs)
> > +               return -EINVAL;
> > +
> > +       switch (mode) {
> > +       case GPMC_ECC_READ:
> > +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> > +               break;
> > +       case GPMC_ECC_READSYN:
> > +                gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
> > +               break;
> > +       case GPMC_ECC_WRITE:
> > +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> > +               break;
> > +       default:
> > +               printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode);
> > +               break;
> > +       }
> > +
> > +       /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> > +       val = (dev_width << 7) | (cs << 1) | (0x1);
> > +       gpmc_write_reg(GPMC_ECC_CONFIG, val);
> > +       return 0;
> > +}
> > +
> > +/**
> > + * gmpc_ecc_reset - release the HW ECC in GPMC controller
> > + * @cs: Chip select number
> > + */
> > +int gpmc_ecc_reset(int cs)
> > +{
> > +       if (gpmc_ecc_used == cs)
> > +               gpmc_ecc_used = -EINVAL;
> > +       else
> > +               return -EINVAL;
> > +
> > +       return 0;
> > +}
> > +
> > diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
> > index 145838a..67a3442
> > --- a/arch/arm/plat-omap/include/plat/gpmc.h
> > +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> > @@ -27,8 +27,24 @@
> >
> >  #define GPMC_CONFIG            0x50
> >  #define GPMC_STATUS            0x54
> > -#define GPMC_CS0_BASE          0x60
> > -#define GPMC_CS_SIZE           0x30
> > +
> > +/* Control Commands */
> > +#define GPMC_CONFIG_WP         0x00000001
> > +#define GPMC_CONFIG_RDY_BSY    0x00000002
> > +#define GPMC_CONFIG_DEV_SIZE   0x00000003
> > +#define GPMC_CONFIG_DEV_TYPE   0x00000004
> > +#define GPMC_NAND_COMMAND      0x00000005
> > +#define GPMC_NAND_ADDRESS      0x00000006
> > +#define GPMC_NAND_DATA         0x00000007
> > +#define GPMC_STATUS_BUFFER     0x00000008 /* 1: buffer is available to write */
> > +#define GPMC_PREFETCH_FIFO_CNT 0x00000009 /* bytes available in FIFO for r/w */
> > +#define GPMC_PREFETCH_COUNT    0x0000000A /* remaining bytes to be read/write*/
> > +#define GPMC_GET_SET_IRQ_STATUS        0x0000000B
> > +
> > +/* ECC commands */
> > +#define GPMC_ECC_READ          0 /* Reset Hardware ECC for read */
> > +#define GPMC_ECC_WRITE         1 /* Reset Hardware ECC for write */
> > +#define GPMC_ECC_READSYN       2 /* Reset before syndrom is read back */
> >
> >  #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
> >  #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
> > @@ -56,6 +72,14 @@
> >  #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
> >  #define GPMC_CONFIG7_CSVALID           (1 << 6)
> >
> > +#define GPMC_DEVICETYPE_NOR            0
> > +#define GPMC_DEVICETYPE_NAND           2
> > +#define GPMC_CONFIG_WRITEPROTECT       0x00000010
> > +#define GPMC_STATUS_BUFF_EMPTY         0x00000001
> > +#define WR_RD_PIN_MONITORING           0x00600000
> > +#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)     ((val & 0x7f000000) >> 24)
> > +#define GPMC_PREFETCH_STATUS_COUNT(val)        (val & 0x00003fff)
> > +
> >  /*
> >  * Note that all values in this struct are in nanoseconds, while
> >  * the register values are in gpmc_fck cycles.
> > @@ -108,10 +132,15 @@ extern int gpmc_cs_set_reserved(int cs, int reserved);
> >  extern int gpmc_cs_reserved(int cs);
> >  extern int gpmc_prefetch_enable(int cs, int dma_mode,
> >                                        unsigned int u32_count, int is_write);
> > -extern void gpmc_prefetch_reset(void);
> > +extern int gpmc_prefetch_reset(int cs);
> >  extern int gpmc_prefetch_status(void);
> >  extern void omap3_gpmc_save_context(void);
> >  extern void omap3_gpmc_restore_context(void);
> >  extern void gpmc_init(void);
> > +extern int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval);
> >
> > +int gpmc_ecc_init(int cs, int ecc_size);
> > +int gpmc_enable_hwecc(int cs, int mode, int dev_width);
> > +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
> > +int gpmc_ecc_reset(int cs);
> >  #endif
> > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> > index 7545568..206406b
> > --- a/drivers/mtd/nand/omap2.c
> > +++ b/drivers/mtd/nand/omap2.c
> > @@ -316,7 +316,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
> >                } while (len);
> >
> >                /* disable and stop the PFPW engine */
> > -               gpmc_prefetch_reset();
> > +               gpmc_prefetch_reset(info->gpmc_cs);
> Not required. see above comments.
> 
> >        }
> >  }
> >
> > @@ -360,7 +360,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
> >                }
> >
> >                /* disable and stop the PFPW engine */
> > -               gpmc_prefetch_reset();
> > +               gpmc_prefetch_reset(info->gpmc_cs);
> Not required. see above comments.
> >        }
> >  }
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> 
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v3 2/3] omap3 nand: cleanup virtual address usages
  2010-05-19 15:30       ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Vimal Singh
@ 2010-05-19 17:24         ` Ghorai, Sukumar
  2010-05-19 18:07           ` Vimal Singh
  0 siblings, 1 reply; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-05-19 17:24 UTC (permalink / raw)
  To: Vimal Singh
  Cc: Artem.Bityutskiy@nokia.com, tony@atomide.com, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, linux-omap@vger.kernel.org

Vimal,

> -----Original Message-----
> From: Vimal Singh [mailto:vimal.newwork@gmail.com]
> Sent: 2010-05-19 21:00
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> tony@atomide.com; sakoman@gmail.com; mike@compulab.co.il;
> Artem.Bityutskiy@nokia.com
> Subject: Re: [PATCH v3 2/3] omap3 nand: cleanup virtual address usages
> 
> On Tue, May 18, 2010 at 4:46 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> > This patch removes direct reference of gpmc address from generic nand
> platform code.
> > Nand platform code now uses wrapper functions which are implemented in
> gpmc module.
> >
> > Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
> [...]
> 
> >
> > @@ -287,16 +246,15 @@ static void omap_read_buf_pref(struct mtd_info
> *mtd, u_char *buf, int len)
> >  {
> >        struct omap_nand_info *info = container_of(mtd,
> >                                                struct omap_nand_info,
> mtd);
> > -       uint32_t pfpw_status = 0, r_count = 0;
> > +       u32 r_count = 0;
> >        int ret = 0;
> > -       u32 *p = (u32 *)buf;
> > +       u32 *p;
> >
> >        /* take care of subpage reads */
> >        for (; len % 4 != 0; ) {
> >                *buf++ = __raw_readb(info->nand.IO_ADDR_R);
> >                len--;
> >        }
> > -       p = (u32 *) buf;
> 
> Above code had an issue, which was fixed by this commit:
> http://git.infradead.org/mtd-
> 2.6.git/commitdiff/c3341d0ceb4de1680572024f50233403c6a8b10d
> 
> I would suggest you to prepare your patch on MTD tree.
[Ghorai] Patches started posting on lo. And lets continue the same.
> 
> >
> >        /* configure and start prefetch transfer */
> >        ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
> > @@ -307,17 +265,18 @@ static void omap_read_buf_pref(struct mtd_info
> *mtd, u_char *buf, int len)
> >                else
> >                        omap_read_buf8(mtd, buf, len);
> >        } else {
> > +               p = (u32 *) buf;
> >                do {
> > -                       pfpw_status = gpmc_prefetch_status();
> > -                       r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
> > -                       ioread32_rep(info->nand_pref_fifo_add, p,
> r_count);
> > +                       gpmc_hwcontrol(info->gpmc_cs,
> > +                               GPMC_PREFETCH_FIFO_CNT, 0, 0, &r_count);
> > +                       r_count = r_count >> 2;
> > +                       ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
> >                        p += r_count;
> > -                       len -= r_count << 2;
> > +                       len -= (r_count << 2);
> 
> Braces are not required here.
[Ghorai] thanks
> 
> >                } while (len);
> > -
> 
> After call to 'gpmc_prefetch_enable', next line are:
>            if (ret) {
>                        /* PFPW engine is busy, use cpu copy method */
>                        if (info->nand.options & NAND_BUSWIDTH_16)
>                        ...
>                        ...
> > -               /* disable and stop the PFPW engine */
> > -               gpmc_prefetch_reset(info->gpmc_cs);
> >        }
> 
> So, if above 'if' fails, driver will not get prefetch engine (it was
> already busy). Then it doesn't makes sense to call for __reset__.
[Ghorai] I will take this clean up as 4th patch. As its not matching with patch description.
> 
> > +       /* disable and stop the PFPW engine */
> > +       gpmc_prefetch_reset(info->gpmc_cs);
> 
> (Also see my comments on your other patch.)
[Ghorai] Agree and I will take this kind of cleanup as 4th patch
> 
> >  }
> >
> >  /**
> > @@ -331,13 +290,13 @@ static void omap_write_buf_pref(struct mtd_info
> *mtd,
> >  {
> >        struct omap_nand_info *info = container_of(mtd,
> >                                                struct omap_nand_info,
> mtd);
> > -       uint32_t pfpw_status = 0, w_count = 0;
> > +       uint32_t pref_count = 0, w_count = 0;
> >        int i = 0, ret = 0;
> > -       u16 *p = (u16 *) buf;
> > +       u16 *p;
> >
> >        /* take care of subpage writes */
> >        if (len % 2 != 0) {
> > -               writeb(*buf, info->nand.IO_ADDR_R);
> > +               writeb(*buf, info->nand.IO_ADDR_W);
> >                p = (u16 *)(buf + 1);
> >                len--;
> >        }
> > @@ -351,17 +310,22 @@ static void omap_write_buf_pref(struct mtd_info
> *mtd,
> >                else
> >                        omap_write_buf8(mtd, buf, len);
> >        } else {
> > -               pfpw_status = gpmc_prefetch_status();
> > -               while (pfpw_status & 0x3FFF) {
> > -                       w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
> > +               p = (u16 *) buf;
> > +               while (len) {
> > +                       gpmc_hwcontrol(info->gpmc_cs,
> > +                                       GPMC_PREFETCH_FIFO_CNT, 0, 0,
> &w_count);
> > +                       w_count = w_count >> 1;
> >                        for (i = 0; (i < w_count) && len; i++, len -= 2)
> > -                               iowrite16(*p++, info-
> >nand_pref_fifo_add);
> > -                       pfpw_status = gpmc_prefetch_status();
> > +                               iowrite16(*p++, info->nand.IO_ADDR_W);
> >                }
> > -
> > -               /* disable and stop the PFPW engine */
> > -               gpmc_prefetch_reset(info->gpmc_cs);
> > +               /* wait for data to flushed-out before reset the
> prefetch */
> > +               do {
> > +                       gpmc_hwcontrol(info->gpmc_cs,
> > +                               GPMC_PREFETCH_COUNT, 0, 0, &pref_count);
> > +               } while (pref_count);
> >        }
> > +       /* disable and stop the PFPW engine */
> > +       gpmc_prefetch_reset(info->gpmc_cs);
> 
> Same as above.
[Ghorai] Agree and I will take this kind of cleanup as 4th patch, as its not matching with patch description.
> 
> 
> >  }
> >
> >  #ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
> > @@ -448,8 +412,10 @@ static inline int omap_nand_dma_transfer(struct
> mtd_info *mtd, void *addr,
> >        /* setup and start DMA using dma_addr */
> >        wait_for_completion(&info->comp);
> >
> > -       while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
> > -               ;
> > +       do {
> > +               gpmc_hwcontrol(info->gpmc_cs,
> > +                               GPMC_PREFETCH_COUNT, 0, 0,
> &prefetch_status);
> > +       } while (prefetch_status);
> >        /* disable and stop the PFPW engine */
> >        gpmc_prefetch_reset();
> >
> > @@ -502,7 +468,7 @@ static void omap_write_buf_dma_pref(struct mtd_info
> *mtd,
> >                omap_write_buf_pref(mtd, buf, len);
> >        else
> >                /* start transfer in DMA mode */
> > -               omap_nand_dma_transfer(mtd, buf, len, 0x1);
> > +               omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
> 
> This is already fixed. See commit:
> http://git.infradead.org/mtd-
> 2.6.git/commitdiff/bdaefc41627b6f2815ef7aa476dfa4ebb3ad499f
[Ghorai] thanks I will omit this from this patch
> 
> 
> Rest, patches looks good. It is a good clean-up all together.
[Ghorai] Is it possible for you to check once again if you have any additional comments! This is to identify the issue if any at early stage.
> 
> --
> Regards,
> Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-19 15:48       ` Peter Barada
@ 2010-05-19 18:04         ` Ghorai, Sukumar
  2010-05-19 18:30           ` Vimal Singh
  0 siblings, 1 reply; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-05-19 18:04 UTC (permalink / raw)
  To: Vimal Singh
  Cc: Artem.Bityutskiy@nokia.com, tony@atomide.com, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, peter.barada@gmail.com,
	linux-omap@vger.kernel.org

Vimal,

> -----Original Message-----
> From: Peter Barada [mailto:peter.barada@gmail.com]
> Sent: 2010-05-19 21:18
> To: Vimal Singh
> Cc: Ghorai, Sukumar; linux-omap@vger.kernel.org; linux-
> mtd@lists.infradead.org; tony@atomide.com; sakoman@gmail.com;
> mike@compulab.co.il; Artem.Bityutskiy@nokia.com
> Subject: Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
>
> On Wed, 2010-05-19 at 20:16 +0530, Vimal Singh wrote:
> > On Tue, May 18, 2010 at 4:46 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> > > few functions added in gpmc module and to be used by other drivers
> like NAND.
> > > E.g.: - ioctl function
> > >      - ecc functions
> > >
> > > Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
> > > ---
> > >  arch/arm/mach-omap2/gpmc.c             |  246
> +++++++++++++++++++++++++++++++-
> > >  arch/arm/plat-omap/include/plat/gpmc.h |   35 ++++-
> > >  drivers/mtd/nand/omap2.c               |    4 +-
> > >  3 files changed, 274 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
> > > index 5bc3ca0..7e6d821
> > > --- a/arch/arm/mach-omap2/gpmc.c
> > > +++ b/arch/arm/mach-omap2/gpmc.c
> > > @@ -46,8 +46,9 @@
> > >  #define GPMC_ECC_CONFIG                0x1f4
> > >  #define GPMC_ECC_CONTROL       0x1f8
> > >  #define GPMC_ECC_SIZE_CONFIG   0x1fc
> > > +#define GPMC_ECC1_RESULT        0x200
> > >
> > > -#define GPMC_CS0               0x60
> > > +#define GPMC_CS0_BASE          0x60
> > >  #define GPMC_CS_SIZE           0x30
> > >
> > >  #define GPMC_MEM_START         0x00000000
> > > @@ -92,7 +93,9 @@ struct omap3_gpmc_regs {
> > >  static struct resource gpmc_mem_root;
> > >  static struct resource gpmc_cs_mem[GPMC_CS_NUM];
> > >  static DEFINE_SPINLOCK(gpmc_mem_lock);
> > > -static unsigned                gpmc_cs_map;
> > > +static unsigned        int gpmc_cs_map;        /* flag for cs which
> are initialized */
> > > +static int gpmc_pref_used = -EINVAL;   /* cs using prefetch engine */
> > > +static int gpmc_ecc_used = -EINVAL;    /* cs using ecc engine */
> > >
> > >  static void __iomem *gpmc_base;
> > >
> > > @@ -108,11 +111,27 @@ static u32 gpmc_read_reg(int idx)
> > >        return __raw_readl(gpmc_base + idx);
> > >  }
> > >
> > > +static void gpmc_cs_write_byte(int cs, int idx, u8 val)
> > > +{
> > > +       void __iomem *reg_addr;
> > > +
> > > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> idx;
> > > +       __raw_writeb(val, reg_addr);
> > > +}
> > > +
> > > +static u8 gpmc_cs_read_byte(int cs, int idx)
> > > +{
> > > +       void __iomem *reg_addr;
> > > +
> > > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> idx;
> > > +       return __raw_readb(reg_addr);
> > > +}
> > > +
> > >  void gpmc_cs_write_reg(int cs, int idx, u32 val)
> > >  {
> > >        void __iomem *reg_addr;
> > >
> > > -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> > > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> idx;
> > >        __raw_writel(val, reg_addr);
> > >  }
> > >
> > > @@ -120,7 +139,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
> > >  {
> > >        void __iomem *reg_addr;
> > >
> > > -       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
> > > +       reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) +
> idx;
> > >        return __raw_readl(reg_addr);
> > >  }
> > >
> > > @@ -419,8 +438,100 @@ void gpmc_cs_free(int cs)
> > >  EXPORT_SYMBOL(gpmc_cs_free);
> > >
> > >  /**
> > > + * gpmc_hwcontrol - hardware specific access (read/ write) control
> > > + * @cs: chip select number
> > > + * @cmd: command type
> > > + * @write: 1 for write; 0 for read
> > > + * @wval: value to write
> > > + * @rval: read pointer
> > > + */
> > > +int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval)
> > > +{
> > > +       u32 regval = 0;
> > > +
> > > +       if (!write && !rval)
> > > +               return -EINVAL;
> > > +
> > > +       switch (cmd) {
> > > +       case GPMC_STATUS_BUFFER:
> > > +               regval = gpmc_read_reg(GPMC_STATUS);
> > > +               /* 1 : buffer is available to write */
> > > +               *rval = regval & GPMC_STATUS_BUFF_EMPTY;
> > > +               break;
> > > +
> > > +       case GPMC_GET_SET_IRQ_STATUS:
> > > +               if (write)
> > > +                       gpmc_write_reg(GPMC_IRQSTATUS, wval);
> > > +               else
> > > +                       *rval = gpmc_read_reg(GPMC_IRQSTATUS);
> > > +               break;
> > > +
> > > +       case GPMC_PREFETCH_FIFO_CNT:
> > > +               regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > > +               *rval = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
> > > +               break;
> > > +
> > > +       case GPMC_PREFETCH_COUNT:
> > > +               regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > > +               *rval = GPMC_PREFETCH_STATUS_COUNT(regval);
> > > +               break;
> > > +
> > > +       case GPMC_CONFIG_WP:
> > > +               regval = gpmc_read_reg(GPMC_CONFIG);
> > > +               if (wval)
> > > +                       regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is
> ON */
> > > +               else
> > > +                       regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is
> OFF */
> > > +               gpmc_write_reg(GPMC_CONFIG, regval);
> > > +               break;
> > > +
> > > +       case GPMC_CONFIG_RDY_BSY:
> > > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > > +               regval |= WR_RD_PIN_MONITORING;
> > > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > > +               break;
> >
> > IIRC, at least in OMAP2/3, ready/busy pin is not in use (not connected).
>
> On the Logic OMAP3530 LV SOM and Torpedo modules, the R/B# pin of the
> NAND in the Micron mt29c2g4maklajg-6it POP part is connected to the
> WAIT0 pin on the OMAP3530 and I'm looking to use it to speed up NAND
> accesses
[Ghorai] So better keep this feature,
>
> > > +
> > > +       case GPMC_CONFIG_DEV_SIZE:
> > > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > > +               regval |= GPMC_CONFIG1_DEVICESIZE(wval);
> > > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > > +               break;
> > > +
> > > +       case GPMC_CONFIG_DEV_TYPE:
> > > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > > +               regval |= GPMC_CONFIG1_DEVICETYPE(wval);
> > > +               if (wval == GPMC_DEVICETYPE_NOR)
> > > +                       regval |= GPMC_CONFIG1_MUXADDDATA;
> > > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > > +               break;
> > > +
> > > +       case GPMC_NAND_COMMAND:
> > > +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
> > > +               break;
> > > +
> > > +       case GPMC_NAND_ADDRESS:
> > > +               gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
> > > +               break;
> > > +
> > > +       case GPMC_NAND_DATA:
> > > +               if (write)
> > > +                       gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA,
> wval);
> > > +               else
> > > +                       *rval = gpmc_cs_read_byte(cs,
> GPMC_CS_NAND_DATA);
> > > +               break;
> > > +
> > > +       default:
> > > +               printk(KERN_ERR "gpmc_hwcontrol: Not supported\n");
> > > +               return -EINVAL;
> > > +       }
> > > +
> > > +       return 0;
> > > +}
> > > +EXPORT_SYMBOL(gpmc_hwcontrol);
> > > +
> > > +/**
> > >  * gpmc_prefetch_enable - configures and starts prefetch transfer
> > > - * @cs: nand cs (chip select) number
> > > + * @cs: cs (chip select) number
> > >  * @dma_mode: dma mode enable (1) or disable (0)
> > >  * @u32_count: number of bytes to be transferred
> > >  * @is_write: prefetch read(0) or write post(1) mode
> > > @@ -430,6 +541,11 @@ int gpmc_prefetch_enable(int cs, int dma_mode,
> > >  {
> > >        uint32_t prefetch_config1;
> > >
> > > +       if (gpmc_pref_used == -EINVAL)
> > > +               gpmc_pref_used = cs;
> > > +       else
> > > +               return -EBUSY;
> >
> > This is  not required. Prefetch engine has just one instance
> >
> > > +
> > >        if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
> >
> > and any prefetch request will be done only if above check passes.
> > Which actually checks if 'prefetch' is busy or not.
> > You can see in NAND driver (omap2.c) code, it understands that.
[Ghorai] Agree here and also you mentioned not to use the reset function. So will take all these as 4th patch for cleanup.
> >
> > >                /* Set the amount of bytes to be prefetched */
> > >                gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
> > > @@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
> > >  /**
> > >  * gpmc_prefetch_reset - disables and stops the prefetch engine
> > >  */
> > > -void gpmc_prefetch_reset(void)
> > > +int gpmc_prefetch_reset(int cs)
> > >  {
> > > +       if (gpmc_pref_used == cs)
> > > +               gpmc_pref_used = -EINVAL;
> > > +       else
> > > +               return -EINVAL;
> > > +
> >
> > This is also not required. As, this function will be called only if
> > prefetch was used.
[Ghorai] Agree. Can you see this input too?
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28520.html

> >
> > >        /* Stop the PFPW engine */
> > >        gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
> > >
> > >        /* Reset/disable the PFPW engine */
> > >        gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
> > > +
> > > +       return 0;
> > >  }
> > >  EXPORT_SYMBOL(gpmc_prefetch_reset);
> > >
> > > @@ -615,3 +738,114 @@ void omap3_gpmc_restore_context(void)
> > >        }
> > >  }
> > >  #endif /* CONFIG_ARCH_OMAP3 */
> > > +
> > > +/**
> > > + * gpmc_ecc_init - initialize hw ecc for device in GPMC controller
> > > + * @cs: chip select number
> > > + * @ecc_size: number of bytes for ecc generation
> > > + */
> > > +
> > > +int gpmc_ecc_init(int cs, int ecc_size)
> > > +{
> > > +       unsigned int val = 0x0;
> > > +
> > > +       /* check if ecc engine already by another cs */
> > > +       if (gpmc_ecc_used == -EINVAL)
> > > +               gpmc_ecc_used = cs;
> > > +       else
> > > +               return -EBUSY;
> > Here few things need be to consider:
> > 1. 'init' is supposed to done once for every instance of driver during
> probe
> > 2. But ECC engine, too, have only one instance at a time, So
> > 3. As long as all NAND chip are supposed to use same ECC machenism, we
> > can go for only one time 'init' for all drivers, perhaps in
> > gpmc_nand.c.
> > 4. But in case, different instances of driver (or NAND chip) requires
> > different ECC machenism (for ex. Hamming or BCH, or even with
> > different capabilities of error correction),
> > this will no longer vailid. Then rather we should have something like
> > 'gpmc_ecc_config' call to configer ECC engine for everytime a driver
> > needs it (something like as it is done for prefetch engine).
[Ghorai]
a. do you think it will reduce the throughput?
b. Moreover I think we will take this as 5th patch as cleanup/ improvemnt.
c. And how to know that ECC engine is in used other driver should not use it? Any bit to know that ecc engine is busy, as we check for prefetch?
d. any further input on http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28520.html

> >
> > > +
> > > +       /* read ecc control register */
> > > +       val = gpmc_read_reg(GPMC_ECC_CONTROL);
> > > +
> > > +       /* clear ecc and enable bits */
> > > +       val = ((0x00000001<<8) | 0x00000001);
> > > +       gpmc_write_reg(GPMC_ECC_CONTROL, val);
> > > +
> > > +       /* Read from ECC Size Config Register */
> > > +       val = gpmc_read_reg(GPMC_ECC_SIZE_CONFIG);
> > > +
> > > +       /* program ecc and result sizes */
> > > +       val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
> > > +       gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +/**
> > > + * gpmc_calculate_ecc - generate non-inverted ecc bytes
> > > + * @cs: chip select number
> > > + * @dat: data pointer over which ecc is computed
> > > + * @ecc_code: ecc code buffer
> > > + *
> > > + * Using non-inverted ECC is considered ugly since writing a blank
> > > + * page (padding) will clear the ECC bytes. This is not a problem as
> long
> > > + * no one is trying to write data on the seemingly unused page.
> Reading
> > > + * an erased page will produce an ECC mismatch between generated and
> read
> > > + * ECC bytes that has to be dealt with separately.
> > > + */
> > > +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
> > > +{
> > > +       unsigned int val = 0x0;
> > > +
> > > +       if (gpmc_ecc_used != cs)
> > > +               return -EINVAL;
> > > +
> > > +       /* read ecc result */
> > > +       val = gpmc_read_reg(GPMC_ECC1_RESULT);
> > > +       *ecc_code++ = val;          /* P128e, ..., P1e */
> > > +       *ecc_code++ = val >> 16;    /* P128o, ..., P1o */
> > > +       /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e
> */
> > > +       *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +/**
> > > + * gpmc_enable_hwecc - enable hardware ecc functionality
> > > + * @cs: chip select number
> > > + * @mode: read/write mode
> > > + * @dev_width: device bus width(1 for x16, 0 for x8)
> > > + */
> > > +int gpmc_enable_hwecc(int cs, int mode, int dev_width)
> > > +{
> > > +       unsigned int val;
> > > +
> > > +       if (gpmc_ecc_used != cs)
> > > +               return -EINVAL;
> > > +
> > > +       switch (mode) {
> > > +       case GPMC_ECC_READ:
> > > +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> > > +               break;
> > > +       case GPMC_ECC_READSYN:
> > > +                gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
> > > +               break;
> > > +       case GPMC_ECC_WRITE:
> > > +               gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
> > > +               break;
> > > +       default:
> > > +               printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n",
> mode);
> > > +               break;
> > > +       }
> > > +
> > > +       /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
> > > +       val = (dev_width << 7) | (cs << 1) | (0x1);
> > > +       gpmc_write_reg(GPMC_ECC_CONFIG, val);
> > > +       return 0;
> > > +}
> > > +
> > > +/**
> > > + * gmpc_ecc_reset - release the HW ECC in GPMC controller
> > > + * @cs: Chip select number
> > > + */
> > > +int gpmc_ecc_reset(int cs)
> > > +{
> > > +       if (gpmc_ecc_used == cs)
> > > +               gpmc_ecc_used = -EINVAL;
> > > +       else
> > > +               return -EINVAL;
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-
> omap/include/plat/gpmc.h
> > > index 145838a..67a3442
> > > --- a/arch/arm/plat-omap/include/plat/gpmc.h
> > > +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> > > @@ -27,8 +27,24 @@
> > >
> > >  #define GPMC_CONFIG            0x50
> > >  #define GPMC_STATUS            0x54
> > > -#define GPMC_CS0_BASE          0x60
> > > -#define GPMC_CS_SIZE           0x30
> > > +
> > > +/* Control Commands */
> > > +#define GPMC_CONFIG_WP         0x00000001
> > > +#define GPMC_CONFIG_RDY_BSY    0x00000002
> > > +#define GPMC_CONFIG_DEV_SIZE   0x00000003
> > > +#define GPMC_CONFIG_DEV_TYPE   0x00000004
> > > +#define GPMC_NAND_COMMAND      0x00000005
> > > +#define GPMC_NAND_ADDRESS      0x00000006
> > > +#define GPMC_NAND_DATA         0x00000007
> > > +#define GPMC_STATUS_BUFFER     0x00000008 /* 1: buffer is available
> to write */
> > > +#define GPMC_PREFETCH_FIFO_CNT 0x00000009 /* bytes available in FIFO
> for r/w */
> > > +#define GPMC_PREFETCH_COUNT    0x0000000A /* remaining bytes to be
> read/write*/
> > > +#define GPMC_GET_SET_IRQ_STATUS        0x0000000B
> > > +
> > > +/* ECC commands */
> > > +#define GPMC_ECC_READ          0 /* Reset Hardware ECC for read */
> > > +#define GPMC_ECC_WRITE         1 /* Reset Hardware ECC for write */
> > > +#define GPMC_ECC_READSYN       2 /* Reset before syndrom is read back
> */
> > >
> > >  #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
> > >  #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
> > > @@ -56,6 +72,14 @@
> > >  #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
> > >  #define GPMC_CONFIG7_CSVALID           (1 << 6)
> > >
> > > +#define GPMC_DEVICETYPE_NOR            0
> > > +#define GPMC_DEVICETYPE_NAND           2
> > > +#define GPMC_CONFIG_WRITEPROTECT       0x00000010
> > > +#define GPMC_STATUS_BUFF_EMPTY         0x00000001
> > > +#define WR_RD_PIN_MONITORING           0x00600000
> > > +#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)     ((val & 0x7f000000) >>
> 24)
> > > +#define GPMC_PREFETCH_STATUS_COUNT(val)        (val & 0x00003fff)
> > > +
> > >  /*
> > >  * Note that all values in this struct are in nanoseconds, while
> > >  * the register values are in gpmc_fck cycles.
> > > @@ -108,10 +132,15 @@ extern int gpmc_cs_set_reserved(int cs, int
> reserved);
> > >  extern int gpmc_cs_reserved(int cs);
> > >  extern int gpmc_prefetch_enable(int cs, int dma_mode,
> > >                                        unsigned int u32_count, int
> is_write);
> > > -extern void gpmc_prefetch_reset(void);
> > > +extern int gpmc_prefetch_reset(int cs);
> > >  extern int gpmc_prefetch_status(void);
> > >  extern void omap3_gpmc_save_context(void);
> > >  extern void omap3_gpmc_restore_context(void);
> > >  extern void gpmc_init(void);
> > > +extern int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int
> *rval);
> > >
> > > +int gpmc_ecc_init(int cs, int ecc_size);
> > > +int gpmc_enable_hwecc(int cs, int mode, int dev_width);
> > > +int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
> > > +int gpmc_ecc_reset(int cs);
> > >  #endif
> > > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> > > index 7545568..206406b
> > > --- a/drivers/mtd/nand/omap2.c
> > > +++ b/drivers/mtd/nand/omap2.c
> > > @@ -316,7 +316,7 @@ static void omap_read_buf_pref(struct mtd_info
> *mtd, u_char *buf, int len)
> > >                } while (len);
> > >
> > >                /* disable and stop the PFPW engine */
> > > -               gpmc_prefetch_reset();
> > > +               gpmc_prefetch_reset(info->gpmc_cs);
> > Not required. see above comments.
[Ghorai] agree and will take as 4th patch as cleanup and its not matching with patch description
> >
> > >        }
> > >  }
> > >
> > > @@ -360,7 +360,7 @@ static void omap_write_buf_pref(struct mtd_info
> *mtd,
> > >                }
> > >
> > >                /* disable and stop the PFPW engine */
> > > -               gpmc_prefetch_reset();
> > > +               gpmc_prefetch_reset(info->gpmc_cs);
> > Not required. see above comments.
[Ghorai] agree and will take as 4th patch as cleanup and its not matching with patch description
> > >        }
> > >  }
> > >
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-omap"
> in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > >
> >
> >
> >
>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 2/3] omap3 nand: cleanup virtual address usages
  2010-05-19 17:24         ` Ghorai, Sukumar
@ 2010-05-19 18:07           ` Vimal Singh
  2010-05-19 18:19             ` Tony Lindgren
  0 siblings, 1 reply; 57+ messages in thread
From: Vimal Singh @ 2010-05-19 18:07 UTC (permalink / raw)
  To: Ghorai, Sukumar
  Cc: Artem.Bityutskiy@nokia.com, tony@atomide.com, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, linux-omap@vger.kernel.org

On Wed, May 19, 2010 at 10:54 PM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
>> >        /* take care of subpage reads */
>> >        for (; len % 4 != 0; ) {
>> >                *buf++ = __raw_readb(info->nand.IO_ADDR_R);
>> >                len--;
>> >        }
>> > -       p = (u32 *) buf;
>>
>> Above code had an issue, which was fixed by this commit:
>> http://git.infradead.org/mtd-
>> 2.6.git/commitdiff/c3341d0ceb4de1680572024f50233403c6a8b10d
>>
>> I would suggest you to prepare your patch on MTD tree.
> [Ghorai] Patches started posting on lo. And lets continue the same.

Not sure about this. Its your/Tony's call.

>>
>> >
>> >        /* configure and start prefetch transfer */
>> >        ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
>> > @@ -307,17 +265,18 @@ static void omap_read_buf_pref(struct mtd_info
>> *mtd, u_char *buf, int len)
>> >                else
>> >                        omap_read_buf8(mtd, buf, len);
>> >        } else {
>> > +               p = (u32 *) buf;
>> >                do {
>> > -                       pfpw_status = gpmc_prefetch_status();
>> > -                       r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
>> > -                       ioread32_rep(info->nand_pref_fifo_add, p,
>> r_count);
>> > +                       gpmc_hwcontrol(info->gpmc_cs,
>> > +                               GPMC_PREFETCH_FIFO_CNT, 0, 0, &r_count);
>> > +                       r_count = r_count >> 2;
>> > +                       ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
>> >                        p += r_count;
>> > -                       len -= r_count << 2;
>> > +                       len -= (r_count << 2);
>>
>> Braces are not required here.
> [Ghorai] thanks
>>
>> >                } while (len);
>> > -
>>
>> After call to 'gpmc_prefetch_enable', next line are:
>>            if (ret) {
>>                        /* PFPW engine is busy, use cpu copy method */
>>                        if (info->nand.options & NAND_BUSWIDTH_16)
>>                        ...
>>                        ...
>> > -               /* disable and stop the PFPW engine */
>> > -               gpmc_prefetch_reset(info->gpmc_cs);
>> >        }
>>
>> So, if above 'if' fails, driver will not get prefetch engine (it was
>> already busy). Then it doesn't makes sense to call for __reset__.
> [Ghorai] I will take this clean up as 4th patch. As its not matching with patch description.
>>
>> > +       /* disable and stop the PFPW engine */
>> > +       gpmc_prefetch_reset(info->gpmc_cs);
>>
>> (Also see my comments on your other patch.)
> [Ghorai] Agree and I will take this kind of cleanup as 4th patch
>>
>> >  }
>> >
>> >  /**
>> > @@ -331,13 +290,13 @@ static void omap_write_buf_pref(struct mtd_info
>> *mtd,
>> >  {
>> >        struct omap_nand_info *info = container_of(mtd,
>> >                                                struct omap_nand_info,
>> mtd);
>> > -       uint32_t pfpw_status = 0, w_count = 0;
>> > +       uint32_t pref_count = 0, w_count = 0;
>> >        int i = 0, ret = 0;
>> > -       u16 *p = (u16 *) buf;
>> > +       u16 *p;
>> >
>> >        /* take care of subpage writes */
>> >        if (len % 2 != 0) {
>> > -               writeb(*buf, info->nand.IO_ADDR_R);
>> > +               writeb(*buf, info->nand.IO_ADDR_W);
>> >                p = (u16 *)(buf + 1);
>> >                len--;
>> >        }
>> > @@ -351,17 +310,22 @@ static void omap_write_buf_pref(struct mtd_info
>> *mtd,
>> >                else
>> >                        omap_write_buf8(mtd, buf, len);
>> >        } else {
>> > -               pfpw_status = gpmc_prefetch_status();
>> > -               while (pfpw_status & 0x3FFF) {
>> > -                       w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
>> > +               p = (u16 *) buf;
>> > +               while (len) {
>> > +                       gpmc_hwcontrol(info->gpmc_cs,
>> > +                                       GPMC_PREFETCH_FIFO_CNT, 0, 0,
>> &w_count);
>> > +                       w_count = w_count >> 1;
>> >                        for (i = 0; (i < w_count) && len; i++, len -= 2)
>> > -                               iowrite16(*p++, info-
>> >nand_pref_fifo_add);
>> > -                       pfpw_status = gpmc_prefetch_status();
>> > +                               iowrite16(*p++, info->nand.IO_ADDR_W);
>> >                }
>> > -
>> > -               /* disable and stop the PFPW engine */
>> > -               gpmc_prefetch_reset(info->gpmc_cs);
>> > +               /* wait for data to flushed-out before reset the
>> prefetch */
>> > +               do {
>> > +                       gpmc_hwcontrol(info->gpmc_cs,
>> > +                               GPMC_PREFETCH_COUNT, 0, 0, &pref_count);
>> > +               } while (pref_count);
>> >        }
>> > +       /* disable and stop the PFPW engine */
>> > +       gpmc_prefetch_reset(info->gpmc_cs);
>>
>> Same as above.
> [Ghorai] Agree and I will take this kind of cleanup as 4th patch, as its not matching with patch description.
>>
>>
>> >  }
>> >
>> >  #ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
>> > @@ -448,8 +412,10 @@ static inline int omap_nand_dma_transfer(struct
>> mtd_info *mtd, void *addr,
>> >        /* setup and start DMA using dma_addr */
>> >        wait_for_completion(&info->comp);
>> >
>> > -       while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
>> > -               ;
>> > +       do {
>> > +               gpmc_hwcontrol(info->gpmc_cs,
>> > +                               GPMC_PREFETCH_COUNT, 0, 0,
>> &prefetch_status);
>> > +       } while (prefetch_status);
>> >        /* disable and stop the PFPW engine */
>> >        gpmc_prefetch_reset();
>> >
>> > @@ -502,7 +468,7 @@ static void omap_write_buf_dma_pref(struct mtd_info
>> *mtd,
>> >                omap_write_buf_pref(mtd, buf, len);
>> >        else
>> >                /* start transfer in DMA mode */
>> > -               omap_nand_dma_transfer(mtd, buf, len, 0x1);
>> > +               omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
>>
>> This is already fixed. See commit:
>> http://git.infradead.org/mtd-
>> 2.6.git/commitdiff/bdaefc41627b6f2815ef7aa476dfa4ebb3ad499f
> [Ghorai] thanks I will omit this from this patch
>>
>>
>> Rest, patches looks good. It is a good clean-up all together.
> [Ghorai] Is it possible for you to check once again if you have any additional comments! This is to identify the issue if any at early stage.

Yeah, I can understand. I tried to review it fully, but can not say if
still something left and gets attention later on. Even sometimes they
will become visible when you fix current one.
As of now this is all what I had.

-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 2/3] omap3 nand: cleanup virtual address usages
  2010-05-19 18:07           ` Vimal Singh
@ 2010-05-19 18:19             ` Tony Lindgren
  0 siblings, 0 replies; 57+ messages in thread
From: Tony Lindgren @ 2010-05-19 18:19 UTC (permalink / raw)
  To: Vimal Singh
  Cc: Artem.Bityutskiy@nokia.com, Ghorai, Sukumar, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, linux-omap@vger.kernel.org

* Vimal Singh <vimal.newwork@gmail.com> [100519 11:02]:
> On Wed, May 19, 2010 at 10:54 PM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
> >> >        /* take care of subpage reads */
> >> >        for (; len % 4 != 0; ) {
> >> >                *buf++ = __raw_readb(info->nand.IO_ADDR_R);
> >> >                len--;
> >> >        }
> >> > -       p = (u32 *) buf;
> >>
> >> Above code had an issue, which was fixed by this commit:
> >> http://git.infradead.org/mtd-
> >> 2.6.git/commitdiff/c3341d0ceb4de1680572024f50233403c6a8b10d
> >>
> >> I would suggest you to prepare your patch on MTD tree.
> > [Ghorai] Patches started posting on lo. And lets continue the same.
> 
> Not sure about this. Its your/Tony's call.

I'd assume that fix is on it's way to the mainline kernel,
looks like a trivial rebase after the merge window is over.

Anyways, this will not make it this merge window, we're
out of time.

Regards,

Tony 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-19 18:04         ` Ghorai, Sukumar
@ 2010-05-19 18:30           ` Vimal Singh
  2010-05-20  5:38             ` Ghorai, Sukumar
  2010-05-25 14:37             ` Ghorai, Sukumar
  0 siblings, 2 replies; 57+ messages in thread
From: Vimal Singh @ 2010-05-19 18:30 UTC (permalink / raw)
  To: Ghorai, Sukumar
  Cc: Artem.Bityutskiy@nokia.com, tony@atomide.com, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, peter.barada@gmail.com,
	linux-omap@vger.kernel.org

On Wed, May 19, 2010 at 11:34 PM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
>> > > +
>> > > +       case GPMC_CONFIG_RDY_BSY:
>> > > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
>> > > +               regval |= WR_RD_PIN_MONITORING;
>> > > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
>> > > +               break;
>> >
>> > IIRC, at least in OMAP2/3, ready/busy pin is not in use (not connected).
>>
>> On the Logic OMAP3530 LV SOM and Torpedo modules, the R/B# pin of the
>> NAND in the Micron mt29c2g4maklajg-6it POP part is connected to the
>> WAIT0 pin on the OMAP3530 and I'm looking to use it to speed up NAND
>> accesses
> [Ghorai] So better keep this feature,

Yes, looks like there are some boards which can still take advantage of this.

>>
[...]
>> > > @@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
>> > >  /**
>> > >  * gpmc_prefetch_reset - disables and stops the prefetch engine
>> > >  */
>> > > -void gpmc_prefetch_reset(void)
>> > > +int gpmc_prefetch_reset(int cs)
>> > >  {
>> > > +       if (gpmc_pref_used == cs)
>> > > +               gpmc_pref_used = -EINVAL;
>> > > +       else
>> > > +               return -EINVAL;
>> > > +
>> >
>> > This is also not required. As, this function will be called only if
>> > prefetch was used.
> [Ghorai] Agree. Can you see this input too?
> http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28520.html

Exactly, this is what I am telling here. Enable prefetch engine call
is already being check for *busy* or not.

>
[...]
>> > > +int gpmc_ecc_init(int cs, int ecc_size)
>> > > +{
>> > > +       unsigned int val = 0x0;
>> > > +
>> > > +       /* check if ecc engine already by another cs */
>> > > +       if (gpmc_ecc_used == -EINVAL)
>> > > +               gpmc_ecc_used = cs;
>> > > +       else
>> > > +               return -EBUSY;
>> > Here few things need be to consider:
>> > 1. 'init' is supposed to done once for every instance of driver during
>> probe
>> > 2. But ECC engine, too, have only one instance at a time, So
>> > 3. As long as all NAND chip are supposed to use same ECC machenism, we
>> > can go for only one time 'init' for all drivers, perhaps in
>> > gpmc_nand.c.
>> > 4. But in case, different instances of driver (or NAND chip) requires
>> > different ECC machenism (for ex. Hamming or BCH, or even with
>> > different capabilities of error correction),
>> > this will no longer vailid. Then rather we should have something like
>> > 'gpmc_ecc_config' call to configer ECC engine for everytime a driver
>> > needs it (something like as it is done for prefetch engine).
> [Ghorai]
> a. do you think it will reduce the throughput?
No. But in current implementation it will be called for each instance
driver. (see my 3rd point)

> b. Moreover I think we will take this as 5th patch as cleanup/ improvemnt.
> c. And how to know that ECC engine is in used other driver should not use it? Any bit to know that ecc engine is busy, as we check for prefetch?
Do not really remember config registers. Perhaps there is no way.
But I guess you should check into register GPMC_ECC_CONFIG at bit 1.
This is the bit we are setting to enable ECC calculation, IIRC.

> d. any further input on http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28520.html
And this what I was suggesting in my point 4. In my example
'gpmc_ecc_config' is analogy to 'gpmc_ecc_request'.
I said *config*, since in such scenario you need to configer HW
ECCconfig register everytime as well, rather just checking
availability and enabling.

>
[...]
>> > > +int gpmc_ecc_reset(int cs)
>> > > +{
>> > > +       if (gpmc_ecc_used == cs)
>> > > +               gpmc_ecc_used = -EINVAL;
>> > > +       else
>> > > +               return -EINVAL;
>> > > +
>> > > +       return 0;
>> > > +}

I guess in this function you should also clear gpmc ecc config
register explicitly.


-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-19 18:30           ` Vimal Singh
@ 2010-05-20  5:38             ` Ghorai, Sukumar
  2010-05-20 14:34               ` Vimal Singh
  2010-05-25 14:37             ` Ghorai, Sukumar
  1 sibling, 1 reply; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-05-20  5:38 UTC (permalink / raw)
  To: Vimal Singh
  Cc: Artem.Bityutskiy@nokia.com, tony@atomide.com, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, peter.barada@gmail.com,
	linux-omap@vger.kernel.org

Vimal,

> -----Original Message-----
> From: Vimal Singh [mailto:vimal.newwork@gmail.com]
> Sent: 2010-05-20 00:01
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> tony@atomide.com; sakoman@gmail.com; mike@compulab.co.il;
> Artem.Bityutskiy@nokia.com; peter.barada@gmail.com
> Subject: Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
> 
> On Wed, May 19, 2010 at 11:34 PM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
> >> > > +
> >> > > +       case GPMC_CONFIG_RDY_BSY:
> >> > > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> >> > > +               regval |= WR_RD_PIN_MONITORING;
> >> > > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> >> > > +               break;
> >> >
> >> > IIRC, at least in OMAP2/3, ready/busy pin is not in use (not
> connected).
> >>
> >> On the Logic OMAP3530 LV SOM and Torpedo modules, the R/B# pin of the
> >> NAND in the Micron mt29c2g4maklajg-6it POP part is connected to the
> >> WAIT0 pin on the OMAP3530 and I'm looking to use it to speed up NAND
> >> accesses
> > [Ghorai] So better keep this feature,
> 
> Yes, looks like there are some boards which can still take advantage of
> this.
> 
> >>
> [...]
> >> > > @@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
> >> > >  /**
> >> > >  * gpmc_prefetch_reset - disables and stops the prefetch engine
> >> > >  */
> >> > > -void gpmc_prefetch_reset(void)
> >> > > +int gpmc_prefetch_reset(int cs)
> >> > >  {
> >> > > +       if (gpmc_pref_used == cs)
> >> > > +               gpmc_pref_used = -EINVAL;
> >> > > +       else
> >> > > +               return -EINVAL;
> >> > > +
> >> >
> >> > This is also not required. As, this function will be called only if
> >> > prefetch was used.
> > [Ghorai] Agree. Can you see this input too?
> > http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28520.html
> 
> Exactly, this is what I am telling here. Enable prefetch engine call
> is already being check for *busy* or not.
> 
> >
> [...]
> >> > > +int gpmc_ecc_init(int cs, int ecc_size)
> >> > > +{
> >> > > +       unsigned int val = 0x0;
> >> > > +
> >> > > +       /* check if ecc engine already by another cs */
> >> > > +       if (gpmc_ecc_used == -EINVAL)
> >> > > +               gpmc_ecc_used = cs;
> >> > > +       else
> >> > > +               return -EBUSY;
> >> > Here few things need be to consider:
> >> > 1. 'init' is supposed to done once for every instance of driver
> during
> >> probe
> >> > 2. But ECC engine, too, have only one instance at a time, So
> >> > 3. As long as all NAND chip are supposed to use same ECC machenism,
> we
> >> > can go for only one time 'init' for all drivers, perhaps in
> >> > gpmc_nand.c.
> >> > 4. But in case, different instances of driver (or NAND chip) requires
> >> > different ECC machenism (for ex. Hamming or BCH, or even with
> >> > different capabilities of error correction),
> >> > this will no longer vailid. Then rather we should have something like
> >> > 'gpmc_ecc_config' call to configer ECC engine for everytime a driver
> >> > needs it (something like as it is done for prefetch engine).
> > [Ghorai]
> > a. do you think it will reduce the throughput?
> No. But in current implementation it will be called for each instance
> driver. (see my 3rd point)
> 
> > b. Moreover I think we will take this as 5th patch as cleanup/
> improvemnt.
> > c. And how to know that ECC engine is in used other driver should not
> use it? Any bit to know that ecc engine is busy, as we check for prefetch?
> Do not really remember config registers. Perhaps there is no way.
> But I guess you should check into register GPMC_ECC_CONFIG at bit 1.
> This is the bit we are setting to enable ECC calculation, IIRC.
> 
> > d. any further input on http://www.mail-archive.com/linux-
> omap@vger.kernel.org/msg28520.html
> And this what I was suggesting in my point 4. In my example
> 'gpmc_ecc_config' is analogy to 'gpmc_ecc_request'.
> I said *config*, since in such scenario you need to configer HW
> ECCconfig register everytime as well, rather just checking
> availability and enabling.
[Ghorai] still I feel we should not mix this patch with cleanup. And yes if possible this will be the 5th one as cleanup.
4th one - prefetch cleanup
5th one - ecc cleanup.
Do you think still missing anything for this patch?

> 
> >
> [...]
> >> > > +int gpmc_ecc_reset(int cs)
> >> > > +{
> >> > > +       if (gpmc_ecc_used == cs)
> >> > > +               gpmc_ecc_used = -EINVAL;
> >> > > +       else
> >> > > +               return -EINVAL;
> >> > > +
> >> > > +       return 0;
> >> > > +}
> 
> I guess in this function you should also clear gpmc ecc config
> register explicitly.
> 
> 
> --
> Regards,
> Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-20  5:38             ` Ghorai, Sukumar
@ 2010-05-20 14:34               ` Vimal Singh
  0 siblings, 0 replies; 57+ messages in thread
From: Vimal Singh @ 2010-05-20 14:34 UTC (permalink / raw)
  To: Ghorai, Sukumar
  Cc: Artem.Bityutskiy@nokia.com, tony@atomide.com, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, peter.barada@gmail.com,
	linux-omap@vger.kernel.org

On Thu, May 20, 2010 at 11:08 AM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
> Vimal,
>
>> -----Original Message-----
>> From: Vimal Singh [mailto:vimal.newwork@gmail.com]
>> Sent: 2010-05-20 00:01
>> To: Ghorai, Sukumar
>> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
>> tony@atomide.com; sakoman@gmail.com; mike@compulab.co.il;
>> Artem.Bityutskiy@nokia.com; peter.barada@gmail.com
>> Subject: Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
>>
>> On Wed, May 19, 2010 at 11:34 PM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
>> >> > > +
>> >> > > +       case GPMC_CONFIG_RDY_BSY:
>> >> > > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
>> >> > > +               regval |= WR_RD_PIN_MONITORING;
>> >> > > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
>> >> > > +               break;
>> >> >
>> >> > IIRC, at least in OMAP2/3, ready/busy pin is not in use (not
>> connected).
>> >>
>> >> On the Logic OMAP3530 LV SOM and Torpedo modules, the R/B# pin of the
>> >> NAND in the Micron mt29c2g4maklajg-6it POP part is connected to the
>> >> WAIT0 pin on the OMAP3530 and I'm looking to use it to speed up NAND
>> >> accesses
>> > [Ghorai] So better keep this feature,
>>
>> Yes, looks like there are some boards which can still take advantage of
>> this.
>>
>> >>
>> [...]
>> >> > > @@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
>> >> > >  /**
>> >> > >  * gpmc_prefetch_reset - disables and stops the prefetch engine
>> >> > >  */
>> >> > > -void gpmc_prefetch_reset(void)
>> >> > > +int gpmc_prefetch_reset(int cs)
>> >> > >  {
>> >> > > +       if (gpmc_pref_used == cs)
>> >> > > +               gpmc_pref_used = -EINVAL;
>> >> > > +       else
>> >> > > +               return -EINVAL;
>> >> > > +
>> >> >
>> >> > This is also not required. As, this function will be called only if
>> >> > prefetch was used.
>> > [Ghorai] Agree. Can you see this input too?
>> > http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28520.html
>>
>> Exactly, this is what I am telling here. Enable prefetch engine call
>> is already being check for *busy* or not.
>>
>> >
>> [...]
>> >> > > +int gpmc_ecc_init(int cs, int ecc_size)
>> >> > > +{
>> >> > > +       unsigned int val = 0x0;
>> >> > > +
>> >> > > +       /* check if ecc engine already by another cs */
>> >> > > +       if (gpmc_ecc_used == -EINVAL)
>> >> > > +               gpmc_ecc_used = cs;
>> >> > > +       else
>> >> > > +               return -EBUSY;
>> >> > Here few things need be to consider:
>> >> > 1. 'init' is supposed to done once for every instance of driver
>> during
>> >> probe
>> >> > 2. But ECC engine, too, have only one instance at a time, So
>> >> > 3. As long as all NAND chip are supposed to use same ECC machenism,
>> we
>> >> > can go for only one time 'init' for all drivers, perhaps in
>> >> > gpmc_nand.c.
>> >> > 4. But in case, different instances of driver (or NAND chip) requires
>> >> > different ECC machenism (for ex. Hamming or BCH, or even with
>> >> > different capabilities of error correction),
>> >> > this will no longer vailid. Then rather we should have something like
>> >> > 'gpmc_ecc_config' call to configer ECC engine for everytime a driver
>> >> > needs it (something like as it is done for prefetch engine).
>> > [Ghorai]
>> > a. do you think it will reduce the throughput?
>> No. But in current implementation it will be called for each instance
>> driver. (see my 3rd point)
>>
>> > b. Moreover I think we will take this as 5th patch as cleanup/
>> improvemnt.
>> > c. And how to know that ECC engine is in used other driver should not
>> use it? Any bit to know that ecc engine is busy, as we check for prefetch?
>> Do not really remember config registers. Perhaps there is no way.
>> But I guess you should check into register GPMC_ECC_CONFIG at bit 1.
>> This is the bit we are setting to enable ECC calculation, IIRC.
>>
>> > d. any further input on http://www.mail-archive.com/linux-
>> omap@vger.kernel.org/msg28520.html
>> And this what I was suggesting in my point 4. In my example
>> 'gpmc_ecc_config' is analogy to 'gpmc_ecc_request'.
>> I said *config*, since in such scenario you need to configer HW
>> ECCconfig register everytime as well, rather just checking
>> availability and enabling.
> [Ghorai] still I feel we should not mix this patch with cleanup. And yes if possible this will be the 5th one as cleanup.
> 4th one - prefetch cleanup
> 5th one - ecc cleanup.
> Do you think still missing anything for this patch?

As long as you take care of current comments, I do not have any
further comment for now.


-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-19 18:30           ` Vimal Singh
  2010-05-20  5:38             ` Ghorai, Sukumar
@ 2010-05-25 14:37             ` Ghorai, Sukumar
  2010-05-25 15:34               ` Vimal Singh
  1 sibling, 1 reply; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-05-25 14:37 UTC (permalink / raw)
  To: Vimal Singh
  Cc: Artem.Bityutskiy@nokia.com, tony@atomide.com, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, peter.barada@gmail.com,
	linux-omap@vger.kernel.org

Vimal,

> -----Original Message-----
> From: Vimal Singh [mailto:vimal.newwork@gmail.com]
> Sent: Thursday, May 20, 2010 12:01 AM
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> tony@atomide.com; sakoman@gmail.com; mike@compulab.co.il;
> Artem.Bityutskiy@nokia.com; peter.barada@gmail.com
> Subject: Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
> 
> On Wed, May 19, 2010 at 11:34 PM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
> >> > > +
> >> > > +       case GPMC_CONFIG_RDY_BSY:
> >> > > +               regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> >> > > +               regval |= WR_RD_PIN_MONITORING;
> >> > > +               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> >> > > +               break;
> >> >
> >> > IIRC, at least in OMAP2/3, ready/busy pin is not in use (not
> connected).
> >>
> >> On the Logic OMAP3530 LV SOM and Torpedo modules, the R/B# pin of the
> >> NAND in the Micron mt29c2g4maklajg-6it POP part is connected to the
> >> WAIT0 pin on the OMAP3530 and I'm looking to use it to speed up NAND
> >> accesses
> > [Ghorai] So better keep this feature,
> 
> Yes, looks like there are some boards which can still take advantage of
> this.
> 
> >>
> [...]
> >> > > @@ -456,13 +572,20 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
> >> > >  /**
> >> > >  * gpmc_prefetch_reset - disables and stops the prefetch engine
> >> > >  */
> >> > > -void gpmc_prefetch_reset(void)
> >> > > +int gpmc_prefetch_reset(int cs)
> >> > >  {
> >> > > +       if (gpmc_pref_used == cs)
> >> > > +               gpmc_pref_used = -EINVAL;
> >> > > +       else
> >> > > +               return -EINVAL;
> >> > > +
> >> >
> >> > This is also not required. As, this function will be called only if
> >> > prefetch was used.
> > [Ghorai] Agree. Can you see this input too?
> > http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28520.html
> 
> Exactly, this is what I am telling here. Enable prefetch engine call
> is already being check for *busy* or not.
[Ghorai] Agree.
> 
> >
> [...]
> >> > > +int gpmc_ecc_init(int cs, int ecc_size)
> >> > > +{
> >> > > +       unsigned int val = 0x0;
> >> > > +
> >> > > +       /* check if ecc engine already by another cs */
> >> > > +       if (gpmc_ecc_used == -EINVAL)
> >> > > +               gpmc_ecc_used = cs;
> >> > > +       else
> >> > > +               return -EBUSY;
> >> > Here few things need be to consider:
> >> > 1. 'init' is supposed to done once for every instance of driver
> during
> >> probe
> >> > 2. But ECC engine, too, have only one instance at a time, So
> >> > 3. As long as all NAND chip are supposed to use same ECC machenism,
> we
> >> > can go for only one time 'init' for all drivers, perhaps in
> >> > gpmc_nand.c.
> >> > 4. But in case, different instances of driver (or NAND chip) requires
> >> > different ECC machenism (for ex. Hamming or BCH, or even with
> >> > different capabilities of error correction),
> >> > this will no longer vailid. Then rather we should have something like
> >> > 'gpmc_ecc_config' call to configer ECC engine for everytime a driver
> >> > needs it (something like as it is done for prefetch engine).
> > [Ghorai]
> > a. do you think it will reduce the throughput?
> No. But in current implementation it will be called for each instance
> driver. (see my 3rd point)
> 
> > b. Moreover I think we will take this as 5th patch as cleanup/
> improvemnt.
> > c. And how to know that ECC engine is in used other driver should not
> use it? Any bit to know that ecc engine is busy, as we check for prefetch?
> Do not really remember config registers. Perhaps there is no way.
> But I guess you should check into register GPMC_ECC_CONFIG at bit 1.
> This is the bit we are setting to enable ECC calculation, IIRC.
[Ghorai] there are two functions -
       info->nand.ecc.calculate        = omap_calculate_ecc;
       info->nand.ecc.hwctl            = omap_enable_hwecc;
And GPMC_ECC_CONFIG register..
	3:1 ECCCS Selects the CS where ECC is computed 
	0 ECCENABLE Enables the ECC feature
Now we enable omap_enable_hwecc (with GPMC_ECC_CONFIG[ECCENABLE]=1); and its get disabled (automatically) when ecc_size data transfer over. But say still it did not read the ecc value yet (omap_calculate_ecc).
So how to protect following omap_enable_hwecc() before omap_calculate_ecc()  without additional flag? Any input is welcome.

> 
> > d. any further input on http://www.mail-archive.com/linux-
> omap@vger.kernel.org/msg28520.html
> And this what I was suggesting in my point 4. In my example
> 'gpmc_ecc_config' is analogy to 'gpmc_ecc_request'.
> I said *config*, since in such scenario you need to configer HW
> ECCconfig register everytime as well, rather just checking
> availability and enabling.
[Ghorai] As above.
> 
> >
> [...]
> >> > > +int gpmc_ecc_reset(int cs)
> >> > > +{
> >> > > +       if (gpmc_ecc_used == cs)
> >> > > +               gpmc_ecc_used = -EINVAL;
> >> > > +       else
> >> > > +               return -EINVAL;
> >> > > +
> >> > > +       return 0;
> >> > > +}
> 
> I guess in this function you should also clear gpmc ecc config
> register explicitly.
> 
> 
> --
> Regards,
> Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v3 1/3] omap3 gpmc: functionality enhancement
  2010-05-25 14:37             ` Ghorai, Sukumar
@ 2010-05-25 15:34               ` Vimal Singh
  0 siblings, 0 replies; 57+ messages in thread
From: Vimal Singh @ 2010-05-25 15:34 UTC (permalink / raw)
  To: Ghorai, Sukumar
  Cc: Artem.Bityutskiy@nokia.com, tony@atomide.com, sakoman@gmail.com,
	linux-mtd@lists.infradead.org, peter.barada@gmail.com,
	linux-omap@vger.kernel.org

On Tue, May 25, 2010 at 8:07 PM, Ghorai, Sukumar <s-ghorai@ti.com> wrote:
[...]
>> > c. And how to know that ECC engine is in used other driver should not
>> use it? Any bit to know that ecc engine is busy, as we check for prefetch?
>> Do not really remember config registers. Perhaps there is no way.
>> But I guess you should check into register GPMC_ECC_CONFIG at bit 1.
>> This is the bit we are setting to enable ECC calculation, IIRC.
> [Ghorai] there are two functions -
>       info->nand.ecc.calculate        = omap_calculate_ecc;
>       info->nand.ecc.hwctl            = omap_enable_hwecc;
> And GPMC_ECC_CONFIG register..
>        3:1 ECCCS Selects the CS where ECC is computed
>        0 ECCENABLE Enables the ECC feature
> Now we enable omap_enable_hwecc (with GPMC_ECC_CONFIG[ECCENABLE]=1); and its get disabled (automatically) when ecc_size data transfer over.
> But say still it did not read the ecc value yet (omap_calculate_ecc).
> So how to protect following omap_enable_hwecc() before omap_calculate_ecc()  without additional flag? Any input is welcome.

Oh yes, that's is a problem. Perhaps in that case you have to protect
it in very much same way you already did.

-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code
       [not found] <Sukumar Ghorai <s-ghorai@ti.com>
                   ` (9 preceding siblings ...)
  2010-05-18 11:16 ` [PATCH v3 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
@ 2010-06-04  7:40 ` Sukumar Ghorai
  2010-06-04  7:40   ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
  2010-06-08 17:12   ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Vimal Singh
  10 siblings, 2 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-06-04  7:40 UTC (permalink / raw)
  To: linux-omap; +Cc: tony, Sukumar Ghorai, linux-mtd

   The following set of patches applies on top of for-next branch.
	http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git
   Patches verified on: omap3430-SDP, omap3630-sdp, zoom3 and beagle board

   And these are the patches required to address the following input -
     1. The NAND driver needs to stop tinkering with the GPMC registers
	The omap General Purpose Memory Controller (GPMC) registers are omap
        specific, and not driver specific. Tinkering with these registers can
        cause issues with the other devices on the GPMC.

     2. Passing hardcoded GPMC_CS0_BASE needs to go from the board files
	Passing hardcoded GPMC virtual addressess is sure way to mess up things.
        This should all become unnecessary once the NAND drivers stops messing
        with the GPMC registers directly.
     Discussion: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg27630.html

   Changes in this series -
		Unused function removed.
		
  Functions related to ecc and prefetch engine are optimized.
  v4: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg29458.html

  Few functionality was missing  like - There should be some locking as only
   one chipselect can use the ECC or prefetch engine at a time. If you have
   NAND in two chipselects, bad things would happen.
  v3: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28715.html

  Additionally, it was needed to implement more functions for the platform
  init code to use.
  v2: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28467.html
	
  v1: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28164.html


Sukumar Ghorai (3):
	omap3 gpmc: functionality enhancement
	omap3 nand: cleanup virtual address usages
	omap3 nand: fix issue in board file to detect nand
 arch/arm/mach-omap2/board-cm-t35.c         |   20 +---
 arch/arm/mach-omap2/board-devkit8000.c     |   25 +---
 arch/arm/mach-omap2/board-omap3beagle.c    |   24 +---
 arch/arm/mach-omap2/board-omap3touchbook.c |   25 +---
 arch/arm/mach-omap2/board-overo.c          |   24 +---
 arch/arm/mach-omap2/board-sdp-flash.c      |    5 -
 arch/arm/mach-omap2/gpmc-nand.c            |   39 ++----
 arch/arm/mach-omap2/gpmc.c                 |  228 +++++++++++++++++++++++++---
 arch/arm/plat-omap/include/plat/gpmc.h     |   36 ++++-
 arch/arm/plat-omap/include/plat/nand.h     |    6 +-
 drivers/mtd/nand/omap2.c                   |  229 ++++++++--------------------
 11 files changed, 320 insertions(+), 341 deletions(-)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH v5 1/3] omap3 gpmc: functionality enhancement
  2010-06-04  7:40 ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
@ 2010-06-04  7:40   ` Sukumar Ghorai
  2010-06-04  7:40     ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
  2010-07-07 10:18     ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Tony Lindgren
  2010-06-08 17:12   ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Vimal Singh
  1 sibling, 2 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-06-04  7:40 UTC (permalink / raw)
  To: linux-omap; +Cc: tony, Sukumar Ghorai, linux-mtd

few functions added in gpmc module and to be used by other drivers like NAND.
E.g.: - ioctl function
      - ecc functions

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |  219 ++++++++++++++++++++++++++++++--
 arch/arm/plat-omap/include/plat/gpmc.h |   33 +++++-
 drivers/mtd/nand/omap2.c               |    4 +-
 3 files changed, 239 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5bc3ca0..48b5af0
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -46,8 +46,9 @@
 #define GPMC_ECC_CONFIG		0x1f4
 #define GPMC_ECC_CONTROL	0x1f8
 #define GPMC_ECC_SIZE_CONFIG	0x1fc
+#define GPMC_ECC1_RESULT        0x200
 
-#define GPMC_CS0		0x60
+#define GPMC_CS0_BASE		0x60
 #define GPMC_CS_SIZE		0x30
 
 #define GPMC_MEM_START		0x00000000
@@ -92,7 +93,8 @@ struct omap3_gpmc_regs {
 static struct resource	gpmc_mem_root;
 static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
-static unsigned		gpmc_cs_map;
+static unsigned int gpmc_cs_map;	/* flag for cs which are initialized */
+static int gpmc_ecc_used = -EINVAL;	/* cs using ecc engine */
 
 static void __iomem *gpmc_base;
 
@@ -108,11 +110,27 @@ static u32 gpmc_read_reg(int idx)
 	return __raw_readl(gpmc_base + idx);
 }
 
+static void gpmc_cs_write_byte(int cs, int idx, u8 val)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
+	__raw_writeb(val, reg_addr);
+}
+
+static u8 gpmc_cs_read_byte(int cs, int idx)
+{
+	void __iomem *reg_addr;
+
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
+	return __raw_readb(reg_addr);
+}
+
 void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	__raw_writel(val, reg_addr);
 }
 
@@ -120,7 +138,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+	reg_addr = gpmc_base + GPMC_CS0_BASE + (cs * GPMC_CS_SIZE) + idx;
 	return __raw_readl(reg_addr);
 }
 
@@ -419,8 +437,100 @@ void gpmc_cs_free(int cs)
 EXPORT_SYMBOL(gpmc_cs_free);
 
 /**
+ * gpmc_hwcontrol - hardware specific access (read/ write) control
+ * @cs: chip select number
+ * @cmd: command type
+ * @write: 1 for write; 0 for read
+ * @wval: value to write
+ * @rval: read pointer
+ */
+int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval)
+{
+	u32 regval = 0;
+
+	if (!write && !rval)
+		return -EINVAL;
+
+	switch (cmd) {
+	case GPMC_STATUS_BUFFER:
+		regval = gpmc_read_reg(GPMC_STATUS);
+		/* 1 : buffer is available to write */
+		*rval = regval & GPMC_STATUS_BUFF_EMPTY;
+		break;
+
+	case GPMC_GET_SET_IRQ_STATUS:
+		if (write)
+			gpmc_write_reg(GPMC_IRQSTATUS, wval);
+		else
+			*rval = gpmc_read_reg(GPMC_IRQSTATUS);
+		break;
+
+	case GPMC_PREFETCH_FIFO_CNT:
+		regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
+		*rval = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
+		break;
+
+	case GPMC_PREFETCH_COUNT:
+		regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
+		*rval = GPMC_PREFETCH_STATUS_COUNT(regval);
+		break;
+
+	case GPMC_CONFIG_WP:
+		regval = gpmc_read_reg(GPMC_CONFIG);
+		if (wval)
+			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
+		else
+			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
+		gpmc_write_reg(GPMC_CONFIG, regval);
+		break;
+
+	case GPMC_CONFIG_RDY_BSY:
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= WR_RD_PIN_MONITORING;
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_CONFIG_DEV_SIZE:
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= GPMC_CONFIG1_DEVICESIZE(wval);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_CONFIG_DEV_TYPE:
+		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+		regval |= GPMC_CONFIG1_DEVICETYPE(wval);
+		if (wval == GPMC_DEVICETYPE_NOR)
+			regval |= GPMC_CONFIG1_MUXADDDATA;
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
+		break;
+
+	case GPMC_NAND_COMMAND:
+		gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
+		break;
+
+	case GPMC_NAND_ADDRESS:
+		gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
+		break;
+
+	case GPMC_NAND_DATA:
+		if (write)
+			gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
+		else
+			*rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
+		break;
+
+	default:
+		printk(KERN_ERR "gpmc_hwcontrol: Not supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(gpmc_hwcontrol);
+
+/**
  * gpmc_prefetch_enable - configures and starts prefetch transfer
- * @cs: nand cs (chip select) number
+ * @cs: cs (chip select) number
  * @dma_mode: dma mode enable (1) or disable (0)
  * @u32_count: number of bytes to be transferred
  * @is_write: prefetch read(0) or write post(1) mode
@@ -428,7 +538,6 @@ EXPORT_SYMBOL(gpmc_cs_free);
 int gpmc_prefetch_enable(int cs, int dma_mode,
 				unsigned int u32_count, int is_write)
 {
-	uint32_t prefetch_config1;
 
 	if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
 		/* Set the amount of bytes to be prefetched */
@@ -437,17 +546,17 @@ int gpmc_prefetch_enable(int cs, int dma_mode,
 		/* Set dma/mpu mode, the prefetch read / post write and
 		 * enable the engine. Set which cs is has requested for.
 		 */
-		prefetch_config1 = ((cs << CS_NUM_SHIFT) |
+		gpmc_write_reg(GPMC_PREFETCH_CONFIG1, ((cs << CS_NUM_SHIFT) |
 					PREFETCH_FIFOTHRESHOLD |
 					ENABLE_PREFETCH |
 					(dma_mode << DMA_MPU_MODE) |
-					(0x1 & is_write));
-		gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1);
+					(0x1 & is_write)));
+
+		/*  Start the prefetch engine */
+		gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1);
 	} else {
 		return -EBUSY;
 	}
-	/*  Start the prefetch engine */
-	gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1);
 
 	return 0;
 }
@@ -456,13 +565,22 @@ EXPORT_SYMBOL(gpmc_prefetch_enable);
 /**
  * gpmc_prefetch_reset - disables and stops the prefetch engine
  */
-void gpmc_prefetch_reset(void)
+int gpmc_prefetch_reset(int cs)
 {
+	u32 config1;
+
+	/* check if the same module/cs is trying to reset */
+	config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
+	if (((config1 >> CS_NUM_SHIFT) & 0x7) != cs)
+		return -EINVAL;
+
 	/* Stop the PFPW engine */
 	gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
 
 	/* Reset/disable the PFPW engine */
 	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
+
+	return 0;
 }
 EXPORT_SYMBOL(gpmc_prefetch_reset);
 
@@ -615,3 +733,80 @@ void omap3_gpmc_restore_context(void)
 	}
 }
 #endif /* CONFIG_ARCH_OMAP3 */
+
+/**
+ * gpmc_enable_hwecc - enable hardware ecc functionality
+ * @cs: chip select number
+ * @mode: read/write mode
+ * @dev_width: device bus width(1 for x16, 0 for x8)
+ * @ecc_size: bytes for which ECC will be generated
+ */
+int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size)
+{
+	unsigned int val;
+
+	/* check if ecc module is in used */
+	if (gpmc_ecc_used != -EINVAL)
+		return -EINVAL;
+
+	gpmc_ecc_used = cs;
+
+	/* clear ecc and enable bits */
+	val = ((0x00000001<<8) | 0x00000001);
+	gpmc_write_reg(GPMC_ECC_CONTROL, val);
+
+	/* program ecc and result sizes */
+	val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F));
+	gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, val);
+
+	switch (mode) {
+	case GPMC_ECC_READ:
+		gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
+		break;
+	case GPMC_ECC_READSYN:
+		 gpmc_write_reg(GPMC_ECC_CONTROL, 0x100);
+		break;
+	case GPMC_ECC_WRITE:
+		gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
+		break;
+	default:
+		printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode);
+		break;
+	}
+
+	/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+	val = (dev_width << 7) | (cs << 1) | (0x1);
+	gpmc_write_reg(GPMC_ECC_CONFIG, val);
+	return 0;
+}
+
+/**
+ * gpmc_calculate_ecc - generate non-inverted ecc bytes
+ * @cs: chip select number
+ * @dat: data pointer over which ecc is computed
+ * @ecc_code: ecc code buffer
+ *
+ * Using non-inverted ECC is considered ugly since writing a blank
+ * page (padding) will clear the ECC bytes. This is not a problem as long
+ * no one is trying to write data on the seemingly unused page. Reading
+ * an erased page will produce an ECC mismatch between generated and read
+ * ECC bytes that has to be dealt with separately.
+ */
+int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
+{
+	unsigned int val = 0x0;
+
+	if (gpmc_ecc_used != cs)
+		return -EINVAL;
+
+	/* read ecc result */
+	val = gpmc_read_reg(GPMC_ECC1_RESULT);
+	*ecc_code++ = val;          /* P128e, ..., P1e */
+	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
+	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
+
+	gpmc_ecc_used = -EINVAL;
+	return 0;
+}
+
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 145838a..8a1e9d9
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -27,8 +27,24 @@
 
 #define GPMC_CONFIG		0x50
 #define GPMC_STATUS		0x54
-#define GPMC_CS0_BASE		0x60
-#define GPMC_CS_SIZE		0x30
+
+/* Control Commands */
+#define GPMC_CONFIG_WP		0x00000001
+#define GPMC_CONFIG_RDY_BSY	0x00000002
+#define GPMC_CONFIG_DEV_SIZE	0x00000003
+#define GPMC_CONFIG_DEV_TYPE	0x00000004
+#define GPMC_NAND_COMMAND	0x00000005
+#define GPMC_NAND_ADDRESS	0x00000006
+#define GPMC_NAND_DATA		0x00000007
+#define GPMC_STATUS_BUFFER	0x00000008 /* 1: buffer is available to write */
+#define GPMC_PREFETCH_FIFO_CNT	0x00000009 /* bytes available in FIFO for r/w */
+#define GPMC_PREFETCH_COUNT	0x0000000A /* remaining bytes to be read/write*/
+#define GPMC_GET_SET_IRQ_STATUS	0x0000000B
+
+/* ECC commands */
+#define GPMC_ECC_READ		0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE		1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN	2 /* Reset before syndrom is read back */
 
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
@@ -56,6 +72,14 @@
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 #define GPMC_CONFIG7_CSVALID		(1 << 6)
 
+#define GPMC_DEVICETYPE_NOR		0
+#define GPMC_DEVICETYPE_NAND		2
+#define GPMC_CONFIG_WRITEPROTECT	0x00000010
+#define GPMC_STATUS_BUFF_EMPTY		0x00000001
+#define WR_RD_PIN_MONITORING		0x00600000
+#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)	((val >> 24) & 0x7F)
+#define GPMC_PREFETCH_STATUS_COUNT(val)	(val & 0x00003fff)
+
 /*
  * Note that all values in this struct are in nanoseconds, while
  * the register values are in gpmc_fck cycles.
@@ -108,10 +132,13 @@ extern int gpmc_cs_set_reserved(int cs, int reserved);
 extern int gpmc_cs_reserved(int cs);
 extern int gpmc_prefetch_enable(int cs, int dma_mode,
 					unsigned int u32_count, int is_write);
-extern void gpmc_prefetch_reset(void);
+extern int gpmc_prefetch_reset(int cs);
 extern int gpmc_prefetch_status(void);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_init(void);
+extern int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval);
 
+int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size);
+int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
 #endif
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index ee87325..ec8eb31
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -319,7 +319,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 		} while (len);
 
 		/* disable and stop the PFPW engine */
-		gpmc_prefetch_reset();
+		gpmc_prefetch_reset(info->gpmc_cs);
 	}
 }
 
@@ -363,7 +363,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 		}
 
 		/* disable and stop the PFPW engine */
-		gpmc_prefetch_reset();
+		gpmc_prefetch_reset(info->gpmc_cs);
 	}
 }
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v5 2/3] omap3 nand: cleanup virtual address usages
  2010-06-04  7:40   ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
@ 2010-06-04  7:40     ` Sukumar Ghorai
  2010-06-04  7:40       ` [PATCH v5 3/3] omap3 nand: fix issue in board file to detect nand Sukumar Ghorai
  2010-07-07 10:21       ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Tony Lindgren
  2010-07-07 10:18     ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Tony Lindgren
  1 sibling, 2 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-06-04  7:40 UTC (permalink / raw)
  To: linux-omap; +Cc: tony, Sukumar Ghorai, linux-mtd

This patch removes direct reference of gpmc address from generic nand platform code.
Nand platform code now uses wrapper functions which are implemented in gpmc module. 

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c        |   39 ++----
 arch/arm/mach-omap2/gpmc.c             |    9 --
 arch/arm/plat-omap/include/plat/gpmc.h |    5 -
 arch/arm/plat-omap/include/plat/nand.h |    6 +-
 drivers/mtd/nand/omap2.c               |  225 +++++++++-----------------------
 5 files changed, 77 insertions(+), 207 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index e57fb29..80f5d94
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -19,8 +19,6 @@
 #include <plat/board.h>
 #include <plat/gpmc.h>
 
-#define WR_RD_PIN_MONITORING	0x00600000
-
 static struct omap_nand_platform_data *gpmc_nand_data;
 
 static struct resource gpmc_nand_resource = {
@@ -71,10 +69,10 @@ static int omap2_nand_gpmc_retime(void)
 	t.wr_cycle  = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);
 
 	/* Configure GPMC */
-	gpmc_cs_write_reg(gpmc_nand_data->cs, GPMC_CS_CONFIG1,
-			GPMC_CONFIG1_DEVICESIZE(gpmc_nand_data->devsize) |
-			GPMC_CONFIG1_DEVICETYPE_NAND);
-
+	gpmc_hwcontrol(gpmc_nand_data->cs,
+			GPMC_CONFIG_DEV_SIZE, 1, gpmc_nand_data->devsize, NULL);
+	gpmc_hwcontrol(gpmc_nand_data->cs,
+			GPMC_CONFIG_DEV_TYPE, 1, GPMC_DEVICETYPE_NAND, NULL);
 	err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
 	if (err)
 		return err;
@@ -82,27 +80,13 @@ static int omap2_nand_gpmc_retime(void)
 	return 0;
 }
 
-static int gpmc_nand_setup(void)
-{
-	struct device *dev = &gpmc_nand_device.dev;
-
-	/* Set timings in GPMC */
-	if (omap2_nand_gpmc_retime() < 0) {
-		dev_err(dev, "Unable to set gpmc timings\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
 {
-	unsigned int val;
 	int err	= 0;
 	struct device *dev = &gpmc_nand_device.dev;
 
 	gpmc_nand_data = _nand_data;
-	gpmc_nand_data->nand_setup = gpmc_nand_setup;
+	gpmc_nand_data->nand_setup = omap2_nand_gpmc_retime;
 	gpmc_nand_device.dev.platform_data = gpmc_nand_data;
 
 	err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
@@ -112,19 +96,17 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)
 		return err;
 	}
 
-	err = gpmc_nand_setup();
+	 /* Set timings in GPMC */
+	err = omap2_nand_gpmc_retime();
 	if (err < 0) {
-		dev_err(dev, "NAND platform setup failed: %d\n", err);
+		dev_err(dev, "Unable to set gpmc timings: %d\n", err);
 		return err;
 	}
 
 	/* Enable RD PIN Monitoring Reg */
 	if (gpmc_nand_data->dev_ready) {
-		val  = gpmc_cs_read_reg(gpmc_nand_data->cs,
-						 GPMC_CS_CONFIG1);
-		val |= WR_RD_PIN_MONITORING;
-		gpmc_cs_write_reg(gpmc_nand_data->cs,
-						GPMC_CS_CONFIG1, val);
+		gpmc_hwcontrol(gpmc_nand_data->cs,
+					GPMC_CONFIG_RDY_BSY, 1, 1, NULL);
 	}
 
 	err = platform_device_register(&gpmc_nand_device);
@@ -140,3 +122,4 @@ out_free_cs:
 
 	return err;
 }
+
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 48b5af0..91e1526 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -584,15 +584,6 @@ int gpmc_prefetch_reset(int cs)
 }
 EXPORT_SYMBOL(gpmc_prefetch_reset);
 
-/**
- * gpmc_prefetch_status - reads prefetch status of engine
- */
-int  gpmc_prefetch_status(void)
-{
-	return gpmc_read_reg(GPMC_PREFETCH_STATUS);
-}
-EXPORT_SYMBOL(gpmc_prefetch_status);
-
 static void __init gpmc_mem_init(void)
 {
 	int cs;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 8a1e9d9..ccbc530
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -25,9 +25,6 @@
 #define GPMC_CS_NAND_ADDRESS	0x20
 #define GPMC_CS_NAND_DATA	0x24
 
-#define GPMC_CONFIG		0x50
-#define GPMC_STATUS		0x54
-
 /* Control Commands */
 #define GPMC_CONFIG_WP		0x00000001
 #define GPMC_CONFIG_RDY_BSY	0x00000002
@@ -63,7 +60,6 @@
 #define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
 #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
 #define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_DEVICETYPE_NAND    GPMC_CONFIG1_DEVICETYPE(2)
 #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
 #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
 #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
@@ -133,7 +129,6 @@ extern int gpmc_cs_reserved(int cs);
 extern int gpmc_prefetch_enable(int cs, int dma_mode,
 					unsigned int u32_count, int is_write);
 extern int gpmc_prefetch_reset(int cs);
-extern int gpmc_prefetch_status(void);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void gpmc_init(void);
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index f8efd54..6562cd0
--- a/arch/arm/plat-omap/include/plat/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
@@ -21,13 +21,11 @@ struct omap_nand_platform_data {
 	int			(*dev_ready)(struct omap_nand_platform_data *);
 	int			dma_channel;
 	unsigned long		phys_base;
-	void __iomem		*gpmc_cs_baseaddr;
-	void __iomem		*gpmc_baseaddr;
 	int			devsize;
 };
 
-/* size (4 KiB) for IO mapping */
-#define	NAND_IO_SIZE	SZ_4K
+/* minimum size for IO mapping */
+#define	NAND_IO_SIZE	4
 
 #if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
 extern int gpmc_nand_init(struct omap_nand_platform_data *d);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index ec8eb31..f9fa3cb
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -7,6 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#define CONFIG_MTD_NAND_OMAP_HWECC
 
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
@@ -23,20 +24,8 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 
-#define GPMC_IRQ_STATUS		0x18
-#define GPMC_ECC_CONFIG		0x1F4
-#define GPMC_ECC_CONTROL	0x1F8
-#define GPMC_ECC_SIZE_CONFIG	0x1FC
-#define GPMC_ECC1_RESULT	0x200
-
 #define	DRIVER_NAME	"omap2-nand"
 
-#define	NAND_WP_OFF	0
-#define NAND_WP_BIT	0x00000010
-
-#define	GPMC_BUF_FULL	0x00000001
-#define	GPMC_BUF_EMPTY	0x00000000
-
 #define NAND_Ecc_P1e		(1 << 0)
 #define NAND_Ecc_P2e		(1 << 1)
 #define NAND_Ecc_P4e		(1 << 2)
@@ -139,34 +128,11 @@ struct omap_nand_info {
 
 	int				gpmc_cs;
 	unsigned long			phys_base;
-	void __iomem			*gpmc_cs_baseaddr;
-	void __iomem			*gpmc_baseaddr;
-	void __iomem			*nand_pref_fifo_add;
 	struct completion		comp;
 	int				dma_ch;
 };
 
 /**
- * omap_nand_wp - This function enable or disable the Write Protect feature
- * @mtd: MTD device structure
- * @mode: WP ON/OFF
- */
-static void omap_nand_wp(struct mtd_info *mtd, int mode)
-{
-	struct omap_nand_info *info = container_of(mtd,
-						struct omap_nand_info, mtd);
-
-	unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);
-
-	if (mode)
-		config &= ~(NAND_WP_BIT);	/* WP is ON */
-	else
-		config |= (NAND_WP_BIT);	/* WP is OFF */
-
-	__raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
-}
-
-/**
  * omap_hwcontrol - hardware specific access to control-lines
  * @mtd: MTD device structure
  * @cmd: command to device
@@ -181,31 +147,20 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
 	struct omap_nand_info *info = container_of(mtd,
 					struct omap_nand_info, mtd);
-	switch (ctrl) {
-	case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_COMMAND;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-
-	case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_ADDRESS;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-
-	case NAND_CTRL_CHANGE | NAND_NCE:
-		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_DATA;
-		break;
-	}
 
-	if (cmd != NAND_CMD_NONE)
-		__raw_writeb(cmd, info->nand.IO_ADDR_W);
+	if (cmd != NAND_CMD_NONE) {
+		if (ctrl & NAND_CLE)
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_NAND_COMMAND, 1, cmd, NULL);
+
+		else if (ctrl & NAND_ALE)
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_NAND_ADDRESS, 1, cmd, NULL);
+
+		else /* NAND_NCE */
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_NAND_DATA, 1, cmd, NULL);
+	}
 }
 
 /**
@@ -232,11 +187,15 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
 	u_char *p = (u_char *)buf;
+	u32	status = 0;
 
 	while (len--) {
 		iowrite8(*p++, info->nand.IO_ADDR_W);
-		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
-						GPMC_STATUS) & GPMC_BUF_FULL));
+		/* wait until buffer is available for write */
+		do {
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_STATUS_BUFFER, 0, 0, &status);
+		} while (!status);
 	}
 }
 
@@ -264,16 +223,17 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
 	u16 *p = (u16 *) buf;
-
+	u32	status = 0;
 	/* FIXME try bursts of writesw() or DMA ... */
 	len >>= 1;
 
 	while (len--) {
 		iowrite16(*p++, info->nand.IO_ADDR_W);
-
-		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
-						GPMC_STATUS) & GPMC_BUF_FULL))
-			;
+		/* wait until buffer is available for write */
+		do {
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_STATUS_BUFFER, 0, 0, &status);
+		} while (!status);
 	}
 }
 
@@ -287,7 +247,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 {
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
-	uint32_t pfpw_status = 0, r_count = 0;
+	uint32_t r_count = 0;
 	int ret = 0;
 	u32 *p = (u32 *)buf;
 
@@ -310,14 +270,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 		else
 			omap_read_buf8(mtd, buf, len);
 	} else {
+		p = (u32 *) buf;
 		do {
-			pfpw_status = gpmc_prefetch_status();
-			r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
-			ioread32_rep(info->nand_pref_fifo_add, p, r_count);
+			gpmc_hwcontrol(info->gpmc_cs,
+				GPMC_PREFETCH_FIFO_CNT, 0, 0, &r_count);
+			r_count = r_count >> 2;
+			ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
 			p += r_count;
 			len -= r_count << 2;
 		} while (len);
-
 		/* disable and stop the PFPW engine */
 		gpmc_prefetch_reset(info->gpmc_cs);
 	}
@@ -334,13 +295,13 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 {
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
-	uint32_t pfpw_status = 0, w_count = 0;
+	uint32_t pref_count = 0, w_count = 0;
 	int i = 0, ret = 0;
-	u16 *p = (u16 *) buf;
+	u16 *p;
 
 	/* take care of subpage writes */
 	if (len % 2 != 0) {
-		writeb(*buf, info->nand.IO_ADDR_R);
+		writeb(*buf, info->nand.IO_ADDR_W);
 		p = (u16 *)(buf + 1);
 		len--;
 	}
@@ -354,14 +315,19 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 		else
 			omap_write_buf8(mtd, buf, len);
 	} else {
-		pfpw_status = gpmc_prefetch_status();
-		while (pfpw_status & 0x3FFF) {
-			w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
+		p = (u16 *) buf;
+		while (len) {
+			gpmc_hwcontrol(info->gpmc_cs,
+					GPMC_PREFETCH_FIFO_CNT, 0, 0, &w_count);
+			w_count = w_count >> 1;
 			for (i = 0; (i < w_count) && len; i++, len -= 2)
-				iowrite16(*p++, info->nand_pref_fifo_add);
-			pfpw_status = gpmc_prefetch_status();
+				iowrite16(*p++, info->nand.IO_ADDR_W);
 		}
-
+		/* wait for data to flushed-out before reset the prefetch */
+		do {
+			gpmc_hwcontrol(info->gpmc_cs,
+				GPMC_PREFETCH_COUNT, 0, 0, &pref_count);
+		} while (pref_count);
 		/* disable and stop the PFPW engine */
 		gpmc_prefetch_reset(info->gpmc_cs);
 	}
@@ -451,8 +417,10 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
 	/* setup and start DMA using dma_addr */
 	wait_for_completion(&info->comp);
 
-	while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
-		;
+	do {
+		gpmc_hwcontrol(info->gpmc_cs,
+				GPMC_PREFETCH_COUNT, 0, 0, &prefetch_status);
+	} while (prefetch_status);
 	/* disable and stop the PFPW engine */
 	gpmc_prefetch_reset();
 
@@ -530,29 +498,6 @@ static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len)
 }
 
 #ifdef CONFIG_MTD_NAND_OMAP_HWECC
-/**
- * omap_hwecc_init - Initialize the HW ECC for NAND flash in GPMC controller
- * @mtd: MTD device structure
- */
-static void omap_hwecc_init(struct mtd_info *mtd)
-{
-	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-							mtd);
-	struct nand_chip *chip = mtd->priv;
-	unsigned long val = 0x0;
-
-	/* Read from ECC Control Register */
-	val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-	/* Clear all ECC | Enable Reg1 */
-	val = ((0x00000001<<8) | 0x00000001);
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-
-	/* Read from ECC Size Config Register */
-	val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
-	/* ECCSIZE1=512 | Select eccResultsize[0-3] */
-	val = ((((chip->ecc.size >> 1) - 1) << 22) | (0x0000000F));
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
-}
 
 /**
  * gen_true_ecc - This function will generate true ECC value
@@ -755,19 +700,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 {
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	unsigned long val = 0x0;
-	unsigned long reg;
-
-	/* Start Reading from HW ECC1_Result = 0x200 */
-	reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT);
-	val = __raw_readl(reg);
-	*ecc_code++ = val;          /* P128e, ..., P1e */
-	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
-	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
-	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
-	reg += 4;
-
-	return 0;
+	return gpmc_calculate_ecc(info->gpmc_cs, dat, ecc_code);
 }
 
 /**
@@ -781,32 +714,10 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
 							mtd);
 	struct nand_chip *chip = mtd->priv;
 	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
-	unsigned long val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONFIG);
-
-	switch (mode) {
-	case NAND_ECC_READ:
-		__raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	case NAND_ECC_READSYN:
-		 __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	case NAND_ECC_WRITE:
-		__raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
-		/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-		val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-		break;
-	default:
-		DEBUG(MTD_DEBUG_LEVEL0, "Error: Unrecognized Mode[%d]!\n",
-					mode);
-		break;
-	}
 
-	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+	gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size);
 }
+
 #endif
 
 /**
@@ -834,14 +745,10 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 	else
 		timeo += (HZ * 20) / 1000;
 
-	this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr +
-						GPMC_CS_NAND_COMMAND;
-	this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA;
-
-	__raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W);
-
+	gpmc_hwcontrol(info->gpmc_cs,
+			GPMC_NAND_COMMAND, 1,  (NAND_CMD_STATUS & 0xFF), NULL);
 	while (time_before(jiffies, timeo)) {
-		status = __raw_readb(this->IO_ADDR_R);
+		gpmc_hwcontrol(info->gpmc_cs, GPMC_NAND_DATA, 0,  0, &status);
 		if (status & NAND_STATUS_READY)
 			break;
 		cond_resched();
@@ -855,22 +762,24 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
  */
 static int omap_dev_ready(struct mtd_info *mtd)
 {
+	unsigned int val = 0;
 	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
 							mtd);
-	unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS);
 
+	gpmc_hwcontrol(info->gpmc_cs, GPMC_GET_SET_IRQ_STATUS, 0, 0, &val);
 	if ((val & 0x100) == 0x100) {
 		/* Clear IRQ Interrupt */
 		val |= 0x100;
 		val &= ~(0x0);
-		__raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+		gpmc_hwcontrol(info->gpmc_cs,
+			GPMC_GET_SET_IRQ_STATUS, 1, val, NULL);
 	} else {
 		unsigned int cnt = 0;
 		while (cnt++ < 0x1FF) {
 			if  ((val & 0x100) == 0x100)
 				return 0;
-			val = __raw_readl(info->gpmc_baseaddr +
-							GPMC_IRQ_STATUS);
+			gpmc_hwcontrol(info->gpmc_cs,
+				GPMC_GET_SET_IRQ_STATUS, 0, 0, &val);
 		}
 	}
 
@@ -901,8 +810,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->pdev = pdev;
 
 	info->gpmc_cs		= pdata->cs;
-	info->gpmc_baseaddr	= pdata->gpmc_baseaddr;
-	info->gpmc_cs_baseaddr	= pdata->gpmc_cs_baseaddr;
 	info->phys_base		= pdata->phys_base;
 
 	info->mtd.priv		= &info->nand;
@@ -913,7 +820,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->nand.options	|= NAND_SKIP_BBTSCAN;
 
 	/* NAND write protect off */
-	omap_nand_wp(&info->mtd, NAND_WP_OFF);
+	gpmc_hwcontrol(info->gpmc_cs, GPMC_CONFIG_WP, 1, 0, NULL);
 
 	if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
 				pdev->dev.driver->name)) {
@@ -948,8 +855,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	}
 
 	if (use_prefetch) {
-		/* copy the virtual address of nand base for fifo access */
-		info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
 
 		info->nand.read_buf   = omap_read_buf_pref;
 		info->nand.write_buf  = omap_write_buf_pref;
@@ -989,8 +894,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 	info->nand.ecc.correct		= omap_correct_data;
 	info->nand.ecc.mode		= NAND_ECC_HW;
 
-	/* init HW ECC */
-	omap_hwecc_init(&info->mtd);
 #else
 	info->nand.ecc.mode = NAND_ECC_SOFT;
 #endif
@@ -1040,7 +943,7 @@ static int omap_nand_remove(struct platform_device *pdev)
 
 	/* Release NAND device, its internal structures and partitions */
 	nand_release(&info->mtd);
-	iounmap(info->nand_pref_fifo_add);
+	iounmap(info->nand.IO_ADDR_R);
 	kfree(&info->mtd);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH v5 3/3] omap3 nand: fix issue in board file to detect nand
  2010-06-04  7:40     ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
@ 2010-06-04  7:40       ` Sukumar Ghorai
  2010-07-07 10:21       ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Tony Lindgren
  1 sibling, 0 replies; 57+ messages in thread
From: Sukumar Ghorai @ 2010-06-04  7:40 UTC (permalink / raw)
  To: linux-omap; +Cc: tony, Sukumar Ghorai, linux-mtd

Board file modified for not to provide gpmc phys_base address to nand driver.
The gpmc_nand_init funciton is now used to detect the nand and required to
adopt _prob function as in nand/omap2.c

Signed-off-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/board-cm-t35.c         |   20 +-------------------
 arch/arm/mach-omap2/board-devkit8000.c     |   25 +------------------------
 arch/arm/mach-omap2/board-omap3beagle.c    |   24 +-----------------------
 arch/arm/mach-omap2/board-omap3touchbook.c |   25 +------------------------
 arch/arm/mach-omap2/board-overo.c          |   24 +-----------------------
 arch/arm/mach-omap2/board-sdp-flash.c      |    5 -----
 6 files changed, 5 insertions(+), 118 deletions(-)

diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index bc4c3f8..4870da2
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -61,8 +61,6 @@
 #define SB_T35_SMSC911X_GPIO	65
 
 #define NAND_BLOCK_SIZE		SZ_128K
-#define GPMC_CS0_BASE		0x60
-#define GPMC_CS0_BASE_ADDR	(OMAP34XX_GPMC_VIRT + GPMC_CS0_BASE)
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #include <linux/smsc911x.h>
@@ -223,28 +221,12 @@ static struct omap_nand_platform_data cm_t35_nand_data = {
 	.nr_parts		= ARRAY_SIZE(cm_t35_nand_partitions),
 	.dma_channel		= -1,	/* disable DMA in OMAP NAND driver */
 	.cs			= 0,
-	.gpmc_cs_baseaddr	= (void __iomem *)GPMC_CS0_BASE_ADDR,
-	.gpmc_baseaddr		= (void __iomem *)OMAP34XX_GPMC_VIRT,
 
 };
 
-static struct resource cm_t35_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device cm_t35_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.num_resources	= 1,
-	.resource	= &cm_t35_nand_resource,
-	.dev		= {
-		.platform_data	= &cm_t35_nand_data,
-	},
-};
-
 static void __init cm_t35_init_nand(void)
 {
-	if (platform_device_register(&cm_t35_nand_device) < 0)
+	if (gpmc_nand_init(&cm_t35_nand_data) < 0)
 		pr_err("CM-T35: Unable to register NAND device\n");
 }
 #else
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 922b746..364511a
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -58,9 +58,6 @@
 #include "mux.h"
 #include "hsmmc.h"
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 #define OMAP_DM9000_GPIO_IRQ	25
@@ -104,20 +101,6 @@ static struct omap_nand_platform_data devkit8000_nand_data = {
 	.dma_channel	= -1,		/* disable DMA in OMAP NAND driver */
 };
 
-static struct resource devkit8000_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device devkit8000_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &devkit8000_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &devkit8000_nand_resource,
-};
-
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
@@ -581,8 +564,6 @@ static void __init devkit8000_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -604,13 +585,9 @@ static void __init devkit8000_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		devkit8000_nand_data.cs = nandcs;
-		devkit8000_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		devkit8000_nand_data.gpmc_baseaddr = (void *)
-			(gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&devkit8000_nand_device) < 0)
+		if (gpmc_nand_init(&devkit8000_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 0ab0c26..befb5e3
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -48,9 +48,6 @@
 #include "mux.h"
 #include "hsmmc.h"
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 static struct mtd_partition omap3beagle_nand_partitions[] = {
@@ -93,20 +90,6 @@ static struct omap_nand_platform_data omap3beagle_nand_data = {
 	.dev_ready	= NULL,
 };
 
-static struct resource omap3beagle_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device omap3beagle_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &omap3beagle_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &omap3beagle_nand_resource,
-};
-
 /* DSS */
 
 static int beagle_enable_dvi(struct omap_dss_device *dssdev)
@@ -424,8 +407,6 @@ static void __init omap3beagle_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -447,12 +428,9 @@ static void __init omap3beagle_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		omap3beagle_nand_data.cs = nandcs;
-		omap3beagle_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		omap3beagle_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&omap3beagle_nand_device) < 0)
+		if (gpmc_nand_init(&omap3beagle_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index f05b867..bf8089f
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -54,9 +54,6 @@
 
 #include <asm/setup.h>
 
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
-
 #define NAND_BLOCK_SIZE		SZ_128K
 
 #define OMAP3_AC_GPIO		136
@@ -106,20 +103,6 @@ static struct omap_nand_platform_data omap3touchbook_nand_data = {
 	.dev_ready	= NULL,
 };
 
-static struct resource omap3touchbook_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device omap3touchbook_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &omap3touchbook_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &omap3touchbook_nand_resource,
-};
-
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 static struct omap2_hsmmc_info mmc[] = {
@@ -458,8 +441,6 @@ static void __init omap3touchbook_flash_init(void)
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -481,13 +462,9 @@ static void __init omap3touchbook_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		omap3touchbook_nand_data.cs = nandcs;
-		omap3touchbook_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		omap3touchbook_nand_data.gpmc_baseaddr =
-						(void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&omap3touchbook_nand_device) < 0)
+		if (gpmc_nand_init(&omap3touchbook_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index d05ced5..9c51936
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -58,8 +58,6 @@
 #define OVERO_GPIO_USBH_NRESET	183
 
 #define NAND_BLOCK_SIZE SZ_128K
-#define GPMC_CS0_BASE  0x60
-#define GPMC_CS_SIZE   0x30
 
 #define OVERO_SMSC911X_CS      5
 #define OVERO_SMSC911X_GPIO    176
@@ -269,28 +267,11 @@ static struct omap_nand_platform_data overo_nand_data = {
 	.dma_channel = -1,	/* disable DMA in OMAP NAND driver */
 };
 
-static struct resource overo_nand_resource = {
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device overo_nand_device = {
-	.name		= "omap2-nand",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &overo_nand_data,
-	},
-	.num_resources	= 1,
-	.resource	= &overo_nand_resource,
-};
-
-
 static void __init overo_flash_init(void)
 {
 	u8 cs = 0;
 	u8 nandcs = GPMC_CS_NUM + 1;
 
-	u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
-
 	/* find out the chip-select on which NAND exists */
 	while (cs < GPMC_CS_NUM) {
 		u32 ret = 0;
@@ -312,12 +293,9 @@ static void __init overo_flash_init(void)
 
 	if (nandcs < GPMC_CS_NUM) {
 		overo_nand_data.cs = nandcs;
-		overo_nand_data.gpmc_cs_baseaddr = (void *)
-			(gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
-		overo_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
 
 		printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
-		if (platform_device_register(&overo_nand_device) < 0)
+		if (gpmc_nand_init(&overo_nand_data) < 0)
 			printk(KERN_ERR "Unable to register NAND device\n");
 	}
 }
diff --git a/arch/arm/mach-omap2/board-sdp-flash.c b/arch/arm/mach-omap2/board-sdp-flash.c
old mode 100644
new mode 100755
index 2d02632..2638c83
--- a/arch/arm/mach-omap2/board-sdp-flash.c
+++ b/arch/arm/mach-omap2/board-sdp-flash.c
@@ -162,11 +162,6 @@ __init board_nand_init(struct flash_partitions sdp_nand_parts, u8 cs)
 	sdp_nand_data.parts		= sdp_nand_parts.parts;
 	sdp_nand_data.nr_parts		= sdp_nand_parts.nr_parts;
 
-	sdp_nand_data.gpmc_cs_baseaddr	= (void *)(OMAP34XX_GPMC_VIRT +
-							GPMC_CS0_BASE +
-							cs * GPMC_CS_SIZE);
-	sdp_nand_data.gpmc_baseaddr	 = (void *) (OMAP34XX_GPMC_VIRT);
-
 	gpmc_nand_init(&sdp_nand_data);
 }
 #else

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code
  2010-06-04  7:40 ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
  2010-06-04  7:40   ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
@ 2010-06-08 17:12   ` Vimal Singh
  2010-06-15 13:26     ` Ghorai, Sukumar
  2010-06-30 14:42     ` Ghorai, Sukumar
  1 sibling, 2 replies; 57+ messages in thread
From: Vimal Singh @ 2010-06-08 17:12 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: tony, linux-omap, linux-mtd

Reviewed-by: Vimal Singh <vimal.newwork@gmail.com>

On Fri, Jun 4, 2010 at 1:10 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
>   The following set of patches applies on top of for-next branch.
>        http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-2.6.git
>   Patches verified on: omap3430-SDP, omap3630-sdp, zoom3 and beagle board
>
>   And these are the patches required to address the following input -
>     1. The NAND driver needs to stop tinkering with the GPMC registers
>        The omap General Purpose Memory Controller (GPMC) registers are omap
>        specific, and not driver specific. Tinkering with these registers can
>        cause issues with the other devices on the GPMC.
>
>     2. Passing hardcoded GPMC_CS0_BASE needs to go from the board files
>        Passing hardcoded GPMC virtual addressess is sure way to mess up things.
>        This should all become unnecessary once the NAND drivers stops messing
>        with the GPMC registers directly.
>     Discussion: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg27630.html
>
>   Changes in this series -
>                Unused function removed.
>
>  Functions related to ecc and prefetch engine are optimized.
>  v4: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg29458.html
>
>  Few functionality was missing  like - There should be some locking as only
>   one chipselect can use the ECC or prefetch engine at a time. If you have
>   NAND in two chipselects, bad things would happen.
>  v3: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28715.html
>
>  Additionally, it was needed to implement more functions for the platform
>  init code to use.
>  v2: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28467.html
>
>  v1: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg28164.html
>
>
> Sukumar Ghorai (3):
>        omap3 gpmc: functionality enhancement
>        omap3 nand: cleanup virtual address usages
>        omap3 nand: fix issue in board file to detect nand
>  arch/arm/mach-omap2/board-cm-t35.c         |   20 +---
>  arch/arm/mach-omap2/board-devkit8000.c     |   25 +---
>  arch/arm/mach-omap2/board-omap3beagle.c    |   24 +---
>  arch/arm/mach-omap2/board-omap3touchbook.c |   25 +---
>  arch/arm/mach-omap2/board-overo.c          |   24 +---
>  arch/arm/mach-omap2/board-sdp-flash.c      |    5 -
>  arch/arm/mach-omap2/gpmc-nand.c            |   39 ++----
>  arch/arm/mach-omap2/gpmc.c                 |  228 +++++++++++++++++++++++++---
>  arch/arm/plat-omap/include/plat/gpmc.h     |   36 ++++-
>  arch/arm/plat-omap/include/plat/nand.h     |    6 +-
>  drivers/mtd/nand/omap2.c                   |  229 ++++++++--------------------
>  11 files changed, 320 insertions(+), 341 deletions(-)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Regards,
Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code
  2010-06-08 17:12   ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Vimal Singh
@ 2010-06-15 13:26     ` Ghorai, Sukumar
  2010-06-30 14:42     ` Ghorai, Sukumar
  1 sibling, 0 replies; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-06-15 13:26 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: tony@atomide.com, Vimal Singh, linux-omap@vger.kernel.org,
	linux-mtd@lists.infradead.org

Tony,

> -----Original Message-----
> From: Vimal Singh [mailto:vimal.newwork@gmail.com]
> Sent: Tuesday, June 08, 2010 10:43 PM
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> tony@atomide.com; mike@compulab.co.il
> Subject: Re: [PATCH v5 0/3] omap3 nand: cleanup exiting platform related
> code
> 
> Reviewed-by: Vimal Singh <vimal.newwork@gmail.com>
> 
> On Fri, Jun 4, 2010 at 1:10 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> >   The following set of patches applies on top of for-next branch.
> >        http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-
> 2.6.git
> >   Patches verified on: omap3430-SDP, omap3630-sdp, zoom3 and beagle
> board
> >
> >   And these are the patches required to address the following input -
> >     1. The NAND driver needs to stop tinkering with the GPMC registers
> >        The omap General Purpose Memory Controller (GPMC) registers are
> omap
> >        specific, and not driver specific. Tinkering with these registers
> can
> >        cause issues with the other devices on the GPMC.
> >
> >     2. Passing hardcoded GPMC_CS0_BASE needs to go from the board files
> >        Passing hardcoded GPMC virtual addressess is sure way to mess up
> things.
> >        This should all become unnecessary once the NAND drivers stops
> messing
> >        with the GPMC registers directly.
> >     Discussion: http://www.mail-archive.com/linux-
> omap@vger.kernel.org/msg27630.html
> >
> >   Changes in this series -
> >                Unused function removed.
> >
> >  Functions related to ecc and prefetch engine are optimized.
> >  v4: http://www.mail-archive.com/linux-
> omap@vger.kernel.org/msg29458.html
> >
> >  Few functionality was missing  like - There should be some locking as
> only
> >   one chipselect can use the ECC or prefetch engine at a time. If you
> have
> >   NAND in two chipselects, bad things would happen.
> >  v3: http://www.mail-archive.com/linux-
> omap@vger.kernel.org/msg28715.html
> >
> >  Additionally, it was needed to implement more functions for the
> platform
> >  init code to use.
> >  v2: http://www.mail-archive.com/linux-
> omap@vger.kernel.org/msg28467.html
> >
> >  v1: http://www.mail-archive.com/linux-
> omap@vger.kernel.org/msg28164.html
> >
> >
> > Sukumar Ghorai (3):
> >        omap3 gpmc: functionality enhancement
> >        omap3 nand: cleanup virtual address usages
> >        omap3 nand: fix issue in board file to detect nand
> >  arch/arm/mach-omap2/board-cm-t35.c         |   20 +---
> >  arch/arm/mach-omap2/board-devkit8000.c     |   25 +---
> >  arch/arm/mach-omap2/board-omap3beagle.c    |   24 +---
> >  arch/arm/mach-omap2/board-omap3touchbook.c |   25 +---
> >  arch/arm/mach-omap2/board-overo.c          |   24 +---
> >  arch/arm/mach-omap2/board-sdp-flash.c      |    5 -
> >  arch/arm/mach-omap2/gpmc-nand.c            |   39 ++----
> >  arch/arm/mach-omap2/gpmc.c                 |  228
> +++++++++++++++++++++++++---
> >  arch/arm/plat-omap/include/plat/gpmc.h     |   36 ++++-
> >  arch/arm/plat-omap/include/plat/nand.h     |    6 +-
> >  drivers/mtd/nand/omap2.c                   |  229 ++++++++-------------
> -------
> >  11 files changed, 320 insertions(+), 341 deletions(-)

[Ghorai] Any comments or input on these patch?

> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> 
> 
> --
> Regards,
> Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code
  2010-06-08 17:12   ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Vimal Singh
  2010-06-15 13:26     ` Ghorai, Sukumar
@ 2010-06-30 14:42     ` Ghorai, Sukumar
  1 sibling, 0 replies; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-06-30 14:42 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Vimal Singh, linux-omap@vger.kernel.org,
	linux-mtd@lists.infradead.org

Tony,
Please let me know if any have input on following two series. 

http://www.mail-archive.com/linux-omap@vger.kernel.org/msg30305.html
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg30735.html

Regards,
Ghorai

> -----Original Message-----
> From: Ghorai, Sukumar
> Sent: Tuesday, June 15, 2010 6:57 PM
> To: 'Tony Lindgren'
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> tony@atomide.com; mike@compulab.co.il; 'Vimal Singh'
> Subject: RE: [PATCH v5 0/3] omap3 nand: cleanup exiting platform related
> code
> 
> Tony,
> 
> > -----Original Message-----
> > From: Vimal Singh [mailto:vimal.newwork@gmail.com]
> > Sent: Tuesday, June 08, 2010 10:43 PM
> > To: Ghorai, Sukumar
> > Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> > tony@atomide.com; mike@compulab.co.il
> > Subject: Re: [PATCH v5 0/3] omap3 nand: cleanup exiting platform related
> > code
> >
> > Reviewed-by: Vimal Singh <vimal.newwork@gmail.com>
> >
> > On Fri, Jun 4, 2010 at 1:10 PM, Sukumar Ghorai <s-ghorai@ti.com> wrote:
> > >   The following set of patches applies on top of for-next branch.
> > >        http://git.kernel.org/?p=linux/kernel/git/tmlind/linux-omap-
> > 2.6.git
> > >   Patches verified on: omap3430-SDP, omap3630-sdp, zoom3 and beagle
> > board
> > >
> > >   And these are the patches required to address the following input -
> > >     1. The NAND driver needs to stop tinkering with the GPMC registers
> > >        The omap General Purpose Memory Controller (GPMC) registers are
> > omap
> > >        specific, and not driver specific. Tinkering with these
> registers
> > can
> > >        cause issues with the other devices on the GPMC.
> > >
> > >     2. Passing hardcoded GPMC_CS0_BASE needs to go from the board
> files
> > >        Passing hardcoded GPMC virtual addressess is sure way to mess
> up
> > things.
> > >        This should all become unnecessary once the NAND drivers stops
> > messing
> > >        with the GPMC registers directly.
> > >     Discussion: http://www.mail-archive.com/linux-
> > omap@vger.kernel.org/msg27630.html
> > >
> > >   Changes in this series -
> > >                Unused function removed.
> > >
> > >  Functions related to ecc and prefetch engine are optimized.
> > >  v4: http://www.mail-archive.com/linux-
> > omap@vger.kernel.org/msg29458.html
> > >
> > >  Few functionality was missing  like - There should be some locking as
> > only
> > >   one chipselect can use the ECC or prefetch engine at a time. If you
> > have
> > >   NAND in two chipselects, bad things would happen.
> > >  v3: http://www.mail-archive.com/linux-
> > omap@vger.kernel.org/msg28715.html
> > >
> > >  Additionally, it was needed to implement more functions for the
> > platform
> > >  init code to use.
> > >  v2: http://www.mail-archive.com/linux-
> > omap@vger.kernel.org/msg28467.html
> > >
> > >  v1: http://www.mail-archive.com/linux-
> > omap@vger.kernel.org/msg28164.html
> > >
> > >
> > > Sukumar Ghorai (3):
> > >        omap3 gpmc: functionality enhancement
> > >        omap3 nand: cleanup virtual address usages
> > >        omap3 nand: fix issue in board file to detect nand
> > >  arch/arm/mach-omap2/board-cm-t35.c         |   20 +---
> > >  arch/arm/mach-omap2/board-devkit8000.c     |   25 +---
> > >  arch/arm/mach-omap2/board-omap3beagle.c    |   24 +---
> > >  arch/arm/mach-omap2/board-omap3touchbook.c |   25 +---
> > >  arch/arm/mach-omap2/board-overo.c          |   24 +---
> > >  arch/arm/mach-omap2/board-sdp-flash.c      |    5 -
> > >  arch/arm/mach-omap2/gpmc-nand.c            |   39 ++----
> > >  arch/arm/mach-omap2/gpmc.c                 |  228
> > +++++++++++++++++++++++++---
> > >  arch/arm/plat-omap/include/plat/gpmc.h     |   36 ++++-
> > >  arch/arm/plat-omap/include/plat/nand.h     |    6 +-
> > >  drivers/mtd/nand/omap2.c                   |  229 ++++++++-----------
> --
> > -------
> > >  11 files changed, 320 insertions(+), 341 deletions(-)
> 
> [Ghorai] Any comments or input on these patch?
> 
> > >
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-omap"
> in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > >
> >
> >
> >
> > --
> > Regards,
> > Vimal Singh

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v5 1/3] omap3 gpmc: functionality enhancement
  2010-06-04  7:40   ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
  2010-06-04  7:40     ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
@ 2010-07-07 10:18     ` Tony Lindgren
  2010-07-07 12:32       ` Ghorai, Sukumar
  1 sibling, 1 reply; 57+ messages in thread
From: Tony Lindgren @ 2010-07-07 10:18 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: linux-omap, linux-mtd

* Sukumar Ghorai <s-ghorai@ti.com> [100604 10:34]:
> few functions added in gpmc module and to be used by other drivers like NAND.
> E.g.: - ioctl function
>       - ecc functions

Uhh, let's leave out ioctl from the description.. Otherwise people
think you're adding new ioctls in this patch.
 
> @@ -46,8 +46,9 @@
>  #define GPMC_ECC_CONFIG		0x1f4
>  #define GPMC_ECC_CONTROL	0x1f8
>  #define GPMC_ECC_SIZE_CONFIG	0x1fc
> +#define GPMC_ECC1_RESULT        0x200
>  
> -#define GPMC_CS0		0x60
> +#define GPMC_CS0_BASE		0x60
>  #define GPMC_CS_SIZE		0x30
>  
>  #define GPMC_MEM_START		0x00000000

Why changing GPMC_CS0 to GPMC_CS0_BASE? Should it rather be
GPMC_CS0_OFFSET?

> @@ -419,8 +437,100 @@ void gpmc_cs_free(int cs)
>  EXPORT_SYMBOL(gpmc_cs_free);
>  
>  /**
> + * gpmc_hwcontrol - hardware specific access (read/ write) control
> + * @cs: chip select number
> + * @cmd: command type
> + * @write: 1 for write; 0 for read
> + * @wval: value to write
> + * @rval: read pointer
> + */
> +int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval)
> +{
> +	u32 regval = 0;
> +
> +	if (!write && !rval)
> +		return -EINVAL;

You pass int write, then return immediately if it's not set?

> +	switch (cmd) {
> +	case GPMC_STATUS_BUFFER:
> +		regval = gpmc_read_reg(GPMC_STATUS);
> +		/* 1 : buffer is available to write */
> +		*rval = regval & GPMC_STATUS_BUFF_EMPTY;
> +		break;
> +
> +	case GPMC_GET_SET_IRQ_STATUS:
> +		if (write)
> +			gpmc_write_reg(GPMC_IRQSTATUS, wval);
> +		else
> +			*rval = gpmc_read_reg(GPMC_IRQSTATUS);
> +		break;
> +
> +	case GPMC_PREFETCH_FIFO_CNT:
> +		regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> +		*rval = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
> +		break;
> +
> +	case GPMC_PREFETCH_COUNT:
> +		regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> +		*rval = GPMC_PREFETCH_STATUS_COUNT(regval);
> +		break;
> +
> +	case GPMC_CONFIG_WP:
> +		regval = gpmc_read_reg(GPMC_CONFIG);
> +		if (wval)
> +			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
> +		else
> +			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
> +		gpmc_write_reg(GPMC_CONFIG, regval);
> +		break;
> +
> +	case GPMC_CONFIG_RDY_BSY:
> +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +		regval |= WR_RD_PIN_MONITORING;
> +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +		break;
> +
> +	case GPMC_CONFIG_DEV_SIZE:
> +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +		regval |= GPMC_CONFIG1_DEVICESIZE(wval);
> +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +		break;
> +
> +	case GPMC_CONFIG_DEV_TYPE:
> +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> +		regval |= GPMC_CONFIG1_DEVICETYPE(wval);
> +		if (wval == GPMC_DEVICETYPE_NOR)
> +			regval |= GPMC_CONFIG1_MUXADDDATA;
> +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> +		break;
> +
> +	case GPMC_NAND_COMMAND:
> +		gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
> +		break;
> +
> +	case GPMC_NAND_ADDRESS:
> +		gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
> +		break;
> +
> +	case GPMC_NAND_DATA:
> +		if (write)
> +			gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
> +		else
> +			*rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
> +		break;
> +
> +	default:
> +		printk(KERN_ERR "gpmc_hwcontrol: Not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(gpmc_hwcontrol);

You should just replace this function with simple functions like we already
have in gpmc.c rather than trying to pack everything into one function.
Just add various gpmc_xxx_get/set functions rather than pass int *rval.

Regards,

Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v5 2/3] omap3 nand: cleanup virtual address usages
  2010-06-04  7:40     ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
  2010-06-04  7:40       ` [PATCH v5 3/3] omap3 nand: fix issue in board file to detect nand Sukumar Ghorai
@ 2010-07-07 10:21       ` Tony Lindgren
  2010-07-07 12:22         ` Ghorai, Sukumar
  1 sibling, 1 reply; 57+ messages in thread
From: Tony Lindgren @ 2010-07-07 10:21 UTC (permalink / raw)
  To: Sukumar Ghorai; +Cc: linux-omap, linux-mtd

* Sukumar Ghorai <s-ghorai@ti.com> [100604 10:34]:
> --- a/arch/arm/plat-omap/include/plat/gpmc.h
> +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> @@ -63,7 +60,6 @@
>  #define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
>  #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
>  #define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
> -#define GPMC_CONFIG1_DEVICETYPE_NAND    GPMC_CONFIG1_DEVICETYPE(2)
>  #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
>  #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
>  #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)

Is this no longer needed?

> --- a/arch/arm/plat-omap/include/plat/nand.h
> +++ b/arch/arm/plat-omap/include/plat/nand.h
> @@ -21,13 +21,11 @@ struct omap_nand_platform_data {
>  	int			(*dev_ready)(struct omap_nand_platform_data *);
>  	int			dma_channel;
>  	unsigned long		phys_base;
> -	void __iomem		*gpmc_cs_baseaddr;
> -	void __iomem		*gpmc_baseaddr;
>  	int			devsize;
>  };

Glad to see these finally going away!

Regards,

Tony 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v5 2/3] omap3 nand: cleanup virtual address usages
  2010-07-07 10:21       ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Tony Lindgren
@ 2010-07-07 12:22         ` Ghorai, Sukumar
  0 siblings, 0 replies; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-07-07 12:22 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap@vger.kernel.org, linux-mtd@lists.infradead.org

Tony,

> -----Original Message-----
> From: Tony Lindgren [mailto:tony@atomide.com]
> Sent: Wednesday, July 07, 2010 3:52 PM
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> mike@compulab.co.il
> Subject: Re: [PATCH v5 2/3] omap3 nand: cleanup virtual address usages
> 
> * Sukumar Ghorai <s-ghorai@ti.com> [100604 10:34]:
> > --- a/arch/arm/plat-omap/include/plat/gpmc.h
> > +++ b/arch/arm/plat-omap/include/plat/gpmc.h
> > @@ -63,7 +60,6 @@
> >  #define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
> >  #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
> >  #define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
> > -#define GPMC_CONFIG1_DEVICETYPE_NAND    GPMC_CONFIG1_DEVICETYPE(2)
> >  #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
> >  #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
> >  #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
> 
> Is this no longer needed?
[Ghorai] we pass GPMC_CONFIG_DEV_TYPE and GPMC_DEVICETYPE_NAND to gpmc_hwcontrol(); And GPMC_DEVICETYPE_NAND define in previous patch of the same series.

> 
> > --- a/arch/arm/plat-omap/include/plat/nand.h
> > +++ b/arch/arm/plat-omap/include/plat/nand.h
> > @@ -21,13 +21,11 @@ struct omap_nand_platform_data {
> >  	int			(*dev_ready)(struct omap_nand_platform_data *);
> >  	int			dma_channel;
> >  	unsigned long		phys_base;
> > -	void __iomem		*gpmc_cs_baseaddr;
> > -	void __iomem		*gpmc_baseaddr;
> >  	int			devsize;
> >  };
> 
> Glad to see these finally going away!
> 
> Regards,
> 
> Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v5 1/3] omap3 gpmc: functionality enhancement
  2010-07-07 10:18     ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Tony Lindgren
@ 2010-07-07 12:32       ` Ghorai, Sukumar
  2010-07-07 13:01         ` Tony Lindgren
  0 siblings, 1 reply; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-07-07 12:32 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap@vger.kernel.org, linux-mtd@lists.infradead.org

Tony,

> -----Original Message-----
> From: Tony Lindgren [mailto:tony@atomide.com]
> Sent: Wednesday, July 07, 2010 3:49 PM
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> mike@compulab.co.il
> Subject: Re: [PATCH v5 1/3] omap3 gpmc: functionality enhancement
> 
> * Sukumar Ghorai <s-ghorai@ti.com> [100604 10:34]:
> > few functions added in gpmc module and to be used by other drivers like
> NAND.
> > E.g.: - ioctl function
> >       - ecc functions
> 
> Uhh, let's leave out ioctl from the description.. Otherwise people
> think you're adding new ioctls in this patch.
[Ghorai] I am agree.
> 
> > @@ -46,8 +46,9 @@
> >  #define GPMC_ECC_CONFIG		0x1f4
> >  #define GPMC_ECC_CONTROL	0x1f8
> >  #define GPMC_ECC_SIZE_CONFIG	0x1fc
> > +#define GPMC_ECC1_RESULT        0x200
> >
> > -#define GPMC_CS0		0x60
> > +#define GPMC_CS0_BASE		0x60
> >  #define GPMC_CS_SIZE		0x30
> >
> >  #define GPMC_MEM_START		0x00000000
> 
> Why changing GPMC_CS0 to GPMC_CS0_BASE? Should it rather be
> GPMC_CS0_OFFSET?
[Ghorai] I am agree with your input.
> 
> > @@ -419,8 +437,100 @@ void gpmc_cs_free(int cs)
> >  EXPORT_SYMBOL(gpmc_cs_free);
> >
> >  /**
> > + * gpmc_hwcontrol - hardware specific access (read/ write) control
> > + * @cs: chip select number
> > + * @cmd: command type
> > + * @write: 1 for write; 0 for read
> > + * @wval: value to write
> > + * @rval: read pointer
> > + */
> > +int gpmc_hwcontrol(int cs, int cmd, int write, int wval, int *rval)
> > +{
> > +	u32 regval = 0;
> > +
> > +	if (!write && !rval)
> > +		return -EINVAL;
> 
> You pass int write, then return immediately if it's not set?
[Ghorai] This is just to check if argument passed correctly either for read or write functionally to do. We can remove this checking.
  
> 
> > +	switch (cmd) {
> > +	case GPMC_STATUS_BUFFER:
> > +		regval = gpmc_read_reg(GPMC_STATUS);
> > +		/* 1 : buffer is available to write */
> > +		*rval = regval & GPMC_STATUS_BUFF_EMPTY;
> > +		break;
> > +
> > +	case GPMC_GET_SET_IRQ_STATUS:
> > +		if (write)
> > +			gpmc_write_reg(GPMC_IRQSTATUS, wval);
> > +		else
> > +			*rval = gpmc_read_reg(GPMC_IRQSTATUS);
> > +		break;
> > +
> > +	case GPMC_PREFETCH_FIFO_CNT:
> > +		regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > +		*rval = GPMC_PREFETCH_STATUS_FIFO_CNT(regval);
> > +		break;
> > +
> > +	case GPMC_PREFETCH_COUNT:
> > +		regval = gpmc_read_reg(GPMC_PREFETCH_STATUS);
> > +		*rval = GPMC_PREFETCH_STATUS_COUNT(regval);
> > +		break;
> > +
> > +	case GPMC_CONFIG_WP:
> > +		regval = gpmc_read_reg(GPMC_CONFIG);
> > +		if (wval)
> > +			regval &= ~GPMC_CONFIG_WRITEPROTECT; /* WP is ON */
> > +		else
> > +			regval |= GPMC_CONFIG_WRITEPROTECT;  /* WP is OFF */
> > +		gpmc_write_reg(GPMC_CONFIG, regval);
> > +		break;
> > +
> > +	case GPMC_CONFIG_RDY_BSY:
> > +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +		regval |= WR_RD_PIN_MONITORING;
> > +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +		break;
> > +
> > +	case GPMC_CONFIG_DEV_SIZE:
> > +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +		regval |= GPMC_CONFIG1_DEVICESIZE(wval);
> > +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +		break;
> > +
> > +	case GPMC_CONFIG_DEV_TYPE:
> > +		regval  = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
> > +		regval |= GPMC_CONFIG1_DEVICETYPE(wval);
> > +		if (wval == GPMC_DEVICETYPE_NOR)
> > +			regval |= GPMC_CONFIG1_MUXADDDATA;
> > +		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
> > +		break;
> > +
> > +	case GPMC_NAND_COMMAND:
> > +		gpmc_cs_write_byte(cs, GPMC_CS_NAND_COMMAND, wval);
> > +		break;
> > +
> > +	case GPMC_NAND_ADDRESS:
> > +		gpmc_cs_write_byte(cs, GPMC_CS_NAND_ADDRESS, wval);
> > +		break;
> > +
> > +	case GPMC_NAND_DATA:
> > +		if (write)
> > +			gpmc_cs_write_byte(cs, GPMC_CS_NAND_DATA, wval);
> > +		else
> > +			*rval = gpmc_cs_read_byte(cs, GPMC_CS_NAND_DATA);
> > +		break;
> > +
> > +	default:
> > +		printk(KERN_ERR "gpmc_hwcontrol: Not supported\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(gpmc_hwcontrol);
> 
> You should just replace this function with simple functions like we
> already
> have in gpmc.c rather than trying to pack everything into one function.
> Just add various gpmc_xxx_get/set functions rather than pass int *rval.

[Ghorai] So I was having the same query very 1st time. 
So we need to implement 15 separate functions to do the same as you suggested. And in my approach it's very easy to enhance the functionally in future, say to add new set/get. E.g. we need the similar cleanup for OneNAND code too. 
So, would you please confirm once again with one is the best and should follow? 

> 
> Regards,
> 
> Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH v5 1/3] omap3 gpmc: functionality enhancement
  2010-07-07 12:32       ` Ghorai, Sukumar
@ 2010-07-07 13:01         ` Tony Lindgren
  2010-07-08  3:54           ` Ghorai, Sukumar
  0 siblings, 1 reply; 57+ messages in thread
From: Tony Lindgren @ 2010-07-07 13:01 UTC (permalink / raw)
  To: Ghorai, Sukumar; +Cc: linux-omap@vger.kernel.org, linux-mtd@lists.infradead.org

* Ghorai, Sukumar <s-ghorai@ti.com> [100707 15:26]:
> > From: Tony Lindgren [mailto:tony@atomide.com]
> > 
> > You should just replace this function with simple functions like we
> > already
> > have in gpmc.c rather than trying to pack everything into one function.
> > Just add various gpmc_xxx_get/set functions rather than pass int *rval.
> 
> [Ghorai] So I was having the same query very 1st time. 
> So we need to implement 15 separate functions to do the same as you suggested. And in my approach it's very easy to enhance the functionally in future, say to add new set/get. E.g. we need the similar cleanup for OneNAND code too. 
> So, would you please confirm once again with one is the best and should follow? 

In general, we should have separate read and write functions.

Maybe you can group them a little bit? Some of them need the chip
select, and some of them are generic. Then some of them are NAND
specific.

Regards,

Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

* RE: [PATCH v5 1/3] omap3 gpmc: functionality enhancement
  2010-07-07 13:01         ` Tony Lindgren
@ 2010-07-08  3:54           ` Ghorai, Sukumar
  0 siblings, 0 replies; 57+ messages in thread
From: Ghorai, Sukumar @ 2010-07-08  3:54 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap@vger.kernel.org, linux-mtd@lists.infradead.org



> -----Original Message-----
> From: Tony Lindgren [mailto:tony@atomide.com]
> Sent: Wednesday, July 07, 2010 6:32 PM
> To: Ghorai, Sukumar
> Cc: linux-omap@vger.kernel.org; linux-mtd@lists.infradead.org;
> mike@compulab.co.il
> Subject: Re: [PATCH v5 1/3] omap3 gpmc: functionality enhancement
> 
> * Ghorai, Sukumar <s-ghorai@ti.com> [100707 15:26]:
> > > From: Tony Lindgren [mailto:tony@atomide.com]
> > >
> > > You should just replace this function with simple functions like we
> > > already
> > > have in gpmc.c rather than trying to pack everything into one function.
> > > Just add various gpmc_xxx_get/set functions rather than pass int *rval.
> >
> > [Ghorai] So I was having the same query very 1st time.
> > So we need to implement 15 separate functions to do the same as you
> suggested. And in my approach it's very easy to enhance the functionally
> in future, say to add new set/get. E.g. we need the similar cleanup for
> OneNAND code too.
> > So, would you please confirm once again with one is the best and should
> follow?
> 
> In general, we should have separate read and write functions.
> 
> Maybe you can group them a little bit? Some of them need the chip
> select, and some of them are generic. Then some of them are NAND
> specific.
[Ghorai] ok. And let me re-work this for next version.
> 
> Regards,
> 
> Tony

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2010-07-08  3:54 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <Sukumar Ghorai <s-ghorai@ti.com>
2010-04-16 11:32 ` [PATCH 0/6] nand prefetch-irq support and ecc layout chanage Sukumar Ghorai
2010-04-16 11:34 ` [PATCH 1/6] omap3: GPMC register definition at common location Sukumar Ghorai
2010-04-16 11:35 ` [PATCH 2/6] omap3: NAND Prefetch in IRQ mode support Sukumar Ghorai
2010-04-16 11:35 ` [PATCH 3/6] OMAP NAND: configurable fifo threshold to gain the throughput Sukumar Ghorai
2010-04-16 12:45   ` Vimal Singh
2010-04-16 11:35 ` [PATCH 4/6] omap-3630 NAND: enable NAND io in prefetch-irq mode Sukumar Ghorai
2010-04-16 11:35 ` [PATCH 5/6] omap: NAND: ecc layout select from board file Sukumar Ghorai
2010-04-16 11:35 ` [PATCH 6/6] omap: NAND: Making ecc layout as compatible with romcode ecc Sukumar Ghorai
2010-05-12  9:48 ` [PATCH 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
2010-05-12  9:48   ` [PATCH 1/3] omap3: GPMC register definition at common location Sukumar Ghorai
2010-05-12  9:48     ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
2010-05-12  9:48       ` [PATCH 3/3] omap3 nand: fix issue in board file to detect the nand Sukumar Ghorai
2010-05-13 15:41       ` [PATCH 2/3] omap3 nand: cleanup for not to use GPMC virtual address Tony Lindgren
2010-05-13 18:48         ` Ghorai, Sukumar
2010-05-13  6:15     ` [PATCH 1/3] omap3: GPMC register definition at common location Mike Rapoport
2010-05-13 15:41     ` Tony Lindgren
2010-05-13 15:44   ` [PATCH 0/3] omap3 nand: cleanup exiting platform related code Tony Lindgren
2010-05-14 15:23 ` [PATCH v2 0/2] " Sukumar Ghorai
2010-05-14 15:23   ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Sukumar Ghorai
2010-05-14 15:23     ` [PATCH v2 2/2] omap3 nand: fix issue in board file to detect the nand Sukumar Ghorai
2010-05-14 15:28     ` [PATCH v2 1/2] omap3 nand: cleanup for not to use GPMC virtual address Tony Lindgren
2010-05-14 18:02     ` Vimal Singh
2010-05-17  4:22       ` Ghorai, Sukumar
2010-05-17 14:26         ` Vimal Singh
2010-05-17 14:34           ` Ghorai, Sukumar
2010-05-14 23:58     ` Tony Lindgren
2010-05-17  5:48       ` Ghorai, Sukumar
2010-05-18 11:16 ` [PATCH v3 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
2010-05-18 11:16   ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
2010-05-18 11:16     ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
2010-05-18 11:16       ` [PATCH v3 3/3] omap3 nand: fix issue in board file to detect nand Sukumar Ghorai
2010-05-19 15:30       ` [PATCH v3 2/3] omap3 nand: cleanup virtual address usages Vimal Singh
2010-05-19 17:24         ` Ghorai, Sukumar
2010-05-19 18:07           ` Vimal Singh
2010-05-19 18:19             ` Tony Lindgren
2010-05-19 14:46     ` [PATCH v3 1/3] omap3 gpmc: functionality enhancement Vimal Singh
2010-05-19 15:14       ` Peter Barada
2010-05-19 15:48       ` Peter Barada
2010-05-19 18:04         ` Ghorai, Sukumar
2010-05-19 18:30           ` Vimal Singh
2010-05-20  5:38             ` Ghorai, Sukumar
2010-05-20 14:34               ` Vimal Singh
2010-05-25 14:37             ` Ghorai, Sukumar
2010-05-25 15:34               ` Vimal Singh
2010-06-04  7:40 ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Sukumar Ghorai
2010-06-04  7:40   ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Sukumar Ghorai
2010-06-04  7:40     ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Sukumar Ghorai
2010-06-04  7:40       ` [PATCH v5 3/3] omap3 nand: fix issue in board file to detect nand Sukumar Ghorai
2010-07-07 10:21       ` [PATCH v5 2/3] omap3 nand: cleanup virtual address usages Tony Lindgren
2010-07-07 12:22         ` Ghorai, Sukumar
2010-07-07 10:18     ` [PATCH v5 1/3] omap3 gpmc: functionality enhancement Tony Lindgren
2010-07-07 12:32       ` Ghorai, Sukumar
2010-07-07 13:01         ` Tony Lindgren
2010-07-08  3:54           ` Ghorai, Sukumar
2010-06-08 17:12   ` [PATCH v5 0/3] omap3 nand: cleanup exiting platform related code Vimal Singh
2010-06-15 13:26     ` Ghorai, Sukumar
2010-06-30 14:42     ` Ghorai, Sukumar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).