* [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).