mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH] OMAP nand
@ 2012-08-02 10:10 Sascha Hauer
  2012-08-02 10:10 ` [PATCH 1/5] mtd OMAP NAND: Fix dev_ready handling Sascha Hauer
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Sascha Hauer @ 2012-08-02 10:10 UTC (permalink / raw)
  To: barebox

The following series has some general OMAP nand cleanups and greatly
improves the nand performance. Also we add a possibility to autodetect
the NAND buswidth.

Sascha

----------------------------------------------------------------
Sascha Hauer (5):
      mtd OMAP NAND: Fix dev_ready handling
      ARM OMAP gpmc nand: specify platform data in boards
      mtd OMAP NAND: Use prefetch engine
      mtd nand: implement buswidth detection
      mtd OMAP NAND: implement buswidth autodetection support

 arch/arm/boards/beagle/board.c              |    9 +-
 arch/arm/boards/pcm049/board.c              |   10 +-
 arch/arm/boards/phycard-a-xl2/pca-a-xl2.c   |    9 +-
 arch/arm/mach-omap/devices-gpmc-nand.c      |   26 +---
 arch/arm/mach-omap/gpmc.c                   |   61 +++++++++
 arch/arm/mach-omap/include/mach/gpmc.h      |   16 ++-
 arch/arm/mach-omap/include/mach/gpmc_nand.h |   20 +--
 drivers/mtd/nand/nand_base.c                |   20 ++-
 drivers/mtd/nand/nand_omap_gpmc.c           |  177 +++++++++++++++++++++------
 include/linux/mtd/nand.h                    |    3 +
 10 files changed, 261 insertions(+), 90 deletions(-)


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 1/5] mtd OMAP NAND: Fix dev_ready handling
  2012-08-02 10:10 [PATCH] OMAP nand Sascha Hauer
@ 2012-08-02 10:10 ` Sascha Hauer
  2012-08-02 10:10 ` [PATCH 2/5] ARM OMAP gpmc nand: specify platform data in boards Sascha Hauer
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2012-08-02 10:10 UTC (permalink / raw)
  To: barebox

- dev_ready is supposed to return whether the device is ready or
  not, not to poll until the device is ready.
- dev_ready should return true for ready and false for not ready
- waitpin polarity is not needed (at least the kernel does not have it)
- wait_mon_mask must be 32bit.

The code was unused since no board specified a wait pin, so no breakage
included. This also removes the now unused timeout variable from
platformdata.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-omap/devices-gpmc-nand.c      |    2 --
 arch/arm/mach-omap/include/mach/gpmc_nand.h |   13 ----------
 drivers/mtd/nand/nand_omap_gpmc.c           |   35 ++++++---------------------
 3 files changed, 7 insertions(+), 43 deletions(-)

diff --git a/arch/arm/mach-omap/devices-gpmc-nand.c b/arch/arm/mach-omap/devices-gpmc-nand.c
index cf87b57..9d0ab6e 100644
--- a/arch/arm/mach-omap/devices-gpmc-nand.c
+++ b/arch/arm/mach-omap/devices-gpmc-nand.c
@@ -41,8 +41,6 @@
 
 /** NAND platform specific settings settings */
 static struct gpmc_nand_platform_data nand_plat = {
-	.cs = 0,
-	.max_timeout = MSECOND,
 	.wait_mon_pin = 0,
 };
 
diff --git a/arch/arm/mach-omap/include/mach/gpmc_nand.h b/arch/arm/mach-omap/include/mach/gpmc_nand.h
index b9c659d..8a6927b 100644
--- a/arch/arm/mach-omap/include/mach/gpmc_nand.h
+++ b/arch/arm/mach-omap/include/mach/gpmc_nand.h
@@ -50,10 +50,6 @@ struct gpmc_nand_platform_data {
 	/** If there are any special setups you'd want to do */
 	int (*nand_setup) (struct gpmc_nand_platform_data *);
 
-	/** set up if we want H/w ECC here and other
-	 * platform specific configs here
-	 */
-	unsigned short plat_options;
 	/** ecc mode to use */
 	enum gpmc_ecc_mode ecc_mode;
 	/** setup any special options */
@@ -62,8 +58,6 @@ struct gpmc_nand_platform_data {
 	char device_width;
 	/** Set this to WAITx+1, so GPMC WAIT0 will be 1 and so on. */
 	char wait_mon_pin;
-	/** Set this to the max timeout for the device */
-	uint64_t max_timeout;
 
 	/* if you like a custom oob use this. */
 	struct nand_ecclayout *oob;
@@ -71,13 +65,6 @@ struct gpmc_nand_platform_data {
 	void *priv;
 };
 
-/** Platform specific options definitions */
-/** plat_options: Wait montioring pin low */
-#define NAND_WAITPOL_LOW        (0 << 0)
-/** plat_options: Wait montioring pin high */
-#define NAND_WAITPOL_HIGH       (1 << 0)
-#define NAND_WAITPOL_MASK       (1 << 0)
-
 int gpmc_generic_nand_devices_init(int cs, int width,
 			enum gpmc_ecc_mode, struct gpmc_config *nand_cfg);
 
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 86d4574..08008e7 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -22,11 +22,7 @@
  * static struct gpmc_nand_platform_data nand_plat = {
  *	.cs = give the chip select of the device
  *	.device_width = what is the width of the device 8 or 16?
- *	.max_timeout = delay desired for operation
  *	.wait_mon_pin = do you use wait monitoring? if so wait pin
- *	.plat_options = platform options.
- *		NAND_HWECC_ENABLE/DISABLE - hw ecc enable/disable
- *		NAND_WAITPOL_LOW/HIGH - wait pin polarity
  *	.oob = if you would like to replace oob with a custom OOB.
  *	.nand_setup  = if you would like a special setup function to be called
  *	.priv = any params you'd like to save(e.g. like nand_setup to use)
@@ -112,10 +108,8 @@ struct gpmc_nand_info {
 	void *gpmc_address;
 	void *gpmc_data;
 	void __iomem *gpmc_base;
-	unsigned char wait_mon_mask;
-	uint64_t timeout;
+	u32 wait_mon_mask;
 	unsigned inuse:1;
-	unsigned wait_pol:1;
 	unsigned char ecc_parity_pairs;
 	enum gpmc_ecc_mode ecc_mode;
 };
@@ -191,25 +185,11 @@ static int omap_dev_ready(struct mtd_info *mtd)
 {
 	struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
 	struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
-	uint64_t start = get_time_ns();
-	unsigned long comp;
-
-	/* What do we mean by assert and de-assert? */
-	comp = (oinfo->wait_pol == NAND_WAITPOL_HIGH) ?
-	    oinfo->wait_mon_mask : 0x0;
-	while (1) {
-		/* Breakout condition */
-		if (is_timeout(start, oinfo->timeout)) {
-			debug("%s timedout\n", __func__);
-			return -ETIMEDOUT;
-		}
-		/* if the wait is released, we are good to go */
-		if (comp ==
-		    (readl(oinfo->gpmc_base + GPMC_STATUS) &&
-		     oinfo->wait_mon_mask))
-			break;
-	}
-	return 0;
+
+	if (readl(oinfo->gpmc_base + GPMC_STATUS) & oinfo->wait_mon_mask)
+		return 1;
+	else
+		return 0;
 }
 
 /**
@@ -853,7 +833,6 @@ static int gpmc_nand_probe(struct device_d *pdev)
 	oinfo->gpmc_command = (void *)(cs_base + GPMC_CS_NAND_COMMAND);
 	oinfo->gpmc_address = (void *)(cs_base + GPMC_CS_NAND_ADDRESS);
 	oinfo->gpmc_data = (void *)(cs_base + GPMC_CS_NAND_DATA);
-	oinfo->timeout = pdata->max_timeout;
 	dev_dbg(pdev, "GPMC base=0x%p cmd=0x%p address=0x%p data=0x%p cs_base=0x%p\n",
 		oinfo->gpmc_base, oinfo->gpmc_command, oinfo->gpmc_address,
 		oinfo->gpmc_data, cs_base);
@@ -879,11 +858,11 @@ static int gpmc_nand_probe(struct device_d *pdev)
 		err = -EINVAL;
 		goto out_release_mem;
 	}
+
 	if (pdata->wait_mon_pin) {
 		/* Set up the wait monitoring mask
 		 * This is GPMC_STATUS reg relevant */
 		oinfo->wait_mon_mask = (0x1 << (pdata->wait_mon_pin - 1)) << 8;
-		oinfo->wait_pol = (pdata->plat_options & NAND_WAITPOL_MASK);
 		nand->dev_ready = omap_dev_ready;
 		nand->chip_delay = 0;
 	} else {
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 2/5] ARM OMAP gpmc nand: specify platform data in boards
  2012-08-02 10:10 [PATCH] OMAP nand Sascha Hauer
  2012-08-02 10:10 ` [PATCH 1/5] mtd OMAP NAND: Fix dev_ready handling Sascha Hauer
@ 2012-08-02 10:10 ` Sascha Hauer
  2012-08-02 10:10 ` [PATCH 3/5] mtd OMAP NAND: Use prefetch engine Sascha Hauer
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2012-08-02 10:10 UTC (permalink / raw)
  To: barebox

Instead of passing several options into the nand register function
it is much more straight forward to just pass the platformdata.
While at it, rename the function to omap_add_gpmc_nand_device to
better describe what it does.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/boards/beagle/board.c              |    9 +++++++--
 arch/arm/boards/pcm049/board.c              |   10 ++++++++--
 arch/arm/boards/phycard-a-xl2/pca-a-xl2.c   |    9 +++++++--
 arch/arm/mach-omap/devices-gpmc-nand.c      |   24 ++++++------------------
 arch/arm/mach-omap/include/mach/gpmc_nand.h |    7 +++----
 5 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/arch/arm/boards/beagle/board.c b/arch/arm/boards/beagle/board.c
index 9ddf317..5122817 100644
--- a/arch/arm/boards/beagle/board.c
+++ b/arch/arm/boards/beagle/board.c
@@ -283,6 +283,12 @@ static struct i2c_board_info i2c_devices[] = {
 	},
 };
 
+static struct gpmc_nand_platform_data nand_plat = {
+	.device_width = 16,
+	.ecc_mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
+	.nand_cfg = &omap3_nand_cfg,
+};
+
 static int beagle_mem_init(void)
 {
 	arm_add_mem_device("ram0", 0x80000000, 128 * 1024 * 1024);
@@ -306,8 +312,7 @@ static int beagle_devices_init(void)
 	/* WP is made high and WAIT1 active Low */
 	gpmc_generic_init(0x10);
 #endif
-	gpmc_generic_nand_devices_init(0, 16,
-			OMAP_ECC_HAMMING_CODE_HW_ROMCODE, &omap3_nand_cfg);
+	omap_add_gpmc_nand_device(&nand_plat);
 
 	add_generic_device("omap-hsmmc", DEVICE_ID_DYNAMIC, NULL, OMAP_MMC1_BASE, SZ_4K,
 			   IORESOURCE_MEM, NULL);
diff --git a/arch/arm/boards/pcm049/board.c b/arch/arm/boards/pcm049/board.c
index 5b7854a..09f0d6d 100644
--- a/arch/arm/boards/pcm049/board.c
+++ b/arch/arm/boards/pcm049/board.c
@@ -94,6 +94,13 @@ static struct i2c_board_info i2c_devices[] = {
 	},
 };
 
+static struct gpmc_nand_platform_data nand_plat = {
+	.wait_mon_pin = 1,
+	.device_width = 8,
+	.ecc_mode = OMAP_ECC_BCH8_CODE_HW,
+	.nand_cfg = &omap4_nand_cfg,
+};
+
 static int pcm049_devices_init(void)
 {
 	i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
@@ -107,8 +114,7 @@ static int pcm049_devices_init(void)
 
 	pcm049_network_init();
 
-	gpmc_generic_nand_devices_init(0, 8,
-			OMAP_ECC_BCH8_CODE_HW, &omap4_nand_cfg);
+	omap_add_gpmc_nand_device(&nand_plat);
 
 #ifdef CONFIG_PARTITION
 	devfs_add_partition("nand0", 0x00000, SZ_128K, DEVFS_PARTITION_FIXED, "xload_raw");
diff --git a/arch/arm/boards/phycard-a-xl2/pca-a-xl2.c b/arch/arm/boards/phycard-a-xl2/pca-a-xl2.c
index 128cb8f..220f7f4 100644
--- a/arch/arm/boards/phycard-a-xl2/pca-a-xl2.c
+++ b/arch/arm/boards/phycard-a-xl2/pca-a-xl2.c
@@ -104,6 +104,12 @@ static struct omap_hsmmc_platform_data mmc_device = {
 #define OMAP4_MMC1_PBIASLITE_PWRDNZ		(1<<22)
 #define OMAP4_MMC1_PWRDNZ			(1<<26)
 
+static struct gpmc_nand_platform_data nand_plat = {
+	.device_width = 16,
+	.ecc_mode = OMAP_ECC_BCH8_CODE_HW,
+	.nand_cfg = &omap4_nand_cfg,
+};
+
 static int pcaaxl2_devices_init(void)
 {
 	u32 value;
@@ -124,8 +130,7 @@ static int pcaaxl2_devices_init(void)
 
 	pcaaxl2_network_init();
 
-	gpmc_generic_nand_devices_init(0, 16,
-			OMAP_ECC_BCH8_CODE_HW, &omap4_nand_cfg);
+	omap_add_gpmc_nand_device(&nand_plat);
 
 #ifdef CONFIG_PARTITION
 	devfs_add_partition("nand0", 0x00000, SZ_128K,
diff --git a/arch/arm/mach-omap/devices-gpmc-nand.c b/arch/arm/mach-omap/devices-gpmc-nand.c
index 9d0ab6e..64ca666 100644
--- a/arch/arm/mach-omap/devices-gpmc-nand.c
+++ b/arch/arm/mach-omap/devices-gpmc-nand.c
@@ -39,35 +39,23 @@
 #define GPMC_CONF1_VALx8	0x00000800
 #define GPMC_CONF1_VALx16	0x00001800
 
-/** NAND platform specific settings settings */
-static struct gpmc_nand_platform_data nand_plat = {
-	.wait_mon_pin = 0,
-};
-
 /**
  * @brief gpmc_generic_nand_devices_init - init generic nand device
  *
  * @return success/fail based on device function
  */
-int gpmc_generic_nand_devices_init(int cs, int width,
-		enum gpmc_ecc_mode eccmode, struct gpmc_config *nand_cfg)
+int omap_add_gpmc_nand_device(struct gpmc_nand_platform_data *pdata)
 {
-	nand_plat.cs = cs;
-
-	if (width == 16)
-		nand_cfg->cfg[0] = GPMC_CONF1_VALx16;
+	if (pdata->device_width == 16)
+		pdata->nand_cfg->cfg[0] = GPMC_CONF1_VALx16;
 	else
-		nand_cfg->cfg[0] = GPMC_CONF1_VALx8;
-
-	nand_plat.device_width = width;
-	nand_plat.ecc_mode = eccmode;
-	nand_plat.priv = nand_cfg;
+		pdata->nand_cfg->cfg[0] = GPMC_CONF1_VALx8;
 
 	/* Configure GPMC CS before register */
-	gpmc_cs_config(nand_plat.cs, nand_cfg);
+	gpmc_cs_config(pdata->cs, pdata->nand_cfg);
 
 	add_generic_device("gpmc_nand", DEVICE_ID_DYNAMIC, NULL, OMAP_GPMC_BASE,
-			1024 * 4, IORESOURCE_MEM, &nand_plat);
+			1024 * 4, IORESOURCE_MEM, pdata);
 
 	return 0;
 }
diff --git a/arch/arm/mach-omap/include/mach/gpmc_nand.h b/arch/arm/mach-omap/include/mach/gpmc_nand.h
index 8a6927b..582fb36 100644
--- a/arch/arm/mach-omap/include/mach/gpmc_nand.h
+++ b/arch/arm/mach-omap/include/mach/gpmc_nand.h
@@ -61,12 +61,11 @@ struct gpmc_nand_platform_data {
 
 	/* if you like a custom oob use this. */
 	struct nand_ecclayout *oob;
-	/** platform specific private data */
-	void *priv;
+	/** gpmc config for nand */
+	struct gpmc_config *nand_cfg;
 };
 
-int gpmc_generic_nand_devices_init(int cs, int width,
-			enum gpmc_ecc_mode, struct gpmc_config *nand_cfg);
+int omap_add_gpmc_nand_device(struct gpmc_nand_platform_data *pdata);
 
 extern struct gpmc_config omap3_nand_cfg;
 extern struct gpmc_config omap4_nand_cfg;
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 3/5] mtd OMAP NAND: Use prefetch engine
  2012-08-02 10:10 [PATCH] OMAP nand Sascha Hauer
  2012-08-02 10:10 ` [PATCH 1/5] mtd OMAP NAND: Fix dev_ready handling Sascha Hauer
  2012-08-02 10:10 ` [PATCH 2/5] ARM OMAP gpmc nand: specify platform data in boards Sascha Hauer
@ 2012-08-02 10:10 ` Sascha Hauer
  2012-08-02 10:10 ` [PATCH 4/5] mtd nand: implement buswidth detection Sascha Hauer
  2012-08-02 10:10 ` [PATCH 5/5] mtd OMAP NAND: implement buswidth autodetection support Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2012-08-02 10:10 UTC (permalink / raw)
  To: barebox

Use the prefetch engine to improve NAND performance. The howto
is derived from the Kernel. Unlike the kernel we do not make
the access mode configurable.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-omap/gpmc.c              |   61 +++++++++++++++++++
 arch/arm/mach-omap/include/mach/gpmc.h |   16 ++++-
 drivers/mtd/nand/nand_omap_gpmc.c      |  100 ++++++++++++++++++++++++++++++++
 3 files changed, 174 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap/gpmc.c b/arch/arm/mach-omap/gpmc.c
index 92a8ae0..5b4daaf 100644
--- a/arch/arm/mach-omap/gpmc.c
+++ b/arch/arm/mach-omap/gpmc.c
@@ -31,6 +31,7 @@
 #include <clock.h>
 #include <init.h>
 #include <io.h>
+#include <errno.h>
 #include <mach/silicon.h>
 #include <mach/gpmc.h>
 #include <mach/sys_info.h>
@@ -125,3 +126,63 @@ void gpmc_cs_config(char cs, struct gpmc_config *config)
 	mdelay(1);		/* Settling time */
 }
 EXPORT_SYMBOL(gpmc_cs_config);
+
+#define CS_NUM_SHIFT		24
+#define ENABLE_PREFETCH		(0x1 << 7)
+#define DMA_MPU_MODE		2
+
+/**
+ * gpmc_prefetch_enable - configures and starts prefetch transfer
+ * @cs: cs (chip select) number
+ * @fifo_th: fifo threshold to be used for read/ write
+ * @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
+ */
+int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
+				unsigned int u32_count, int is_write)
+{
+	if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) {
+		pr_err("gpmc: fifo threshold is not supported\n");
+		return -EINVAL;
+	}
+
+	/* Set the amount of bytes to be prefetched */
+	writel(u32_count, GPMC_REG(PREFETCH_CONFIG2));
+
+	/* Set dma/mpu mode, the prefetch read / post write and
+	 * enable the engine. Set which cs is has requested for.
+	 */
+	writel(((cs << CS_NUM_SHIFT) | PREFETCH_FIFOTHRESHOLD(fifo_th) |
+				ENABLE_PREFETCH | (dma_mode << DMA_MPU_MODE) |
+				(0x1 & is_write)),
+			GPMC_REG(PREFETCH_CONFIG1));
+
+	/*  Start the prefetch engine */
+	writel(0x1, GPMC_REG(PREFETCH_CONTROL));
+
+	return 0;
+}
+EXPORT_SYMBOL(gpmc_prefetch_enable);
+
+/**
+ * gpmc_prefetch_reset - disables and stops the prefetch engine
+ */
+int gpmc_prefetch_reset(int cs)
+{
+	u32 config1;
+
+	/* check if the same module/cs is trying to reset */
+	config1 = readl(GPMC_REG(PREFETCH_CONFIG1));
+	if (((config1 >> CS_NUM_SHIFT) & 0x7) != cs)
+		return -EINVAL;
+
+	/* Stop the PFPW engine */
+	writel(0x0, GPMC_REG(PREFETCH_CONTROL));
+
+	/* Reset/disable the PFPW engine */
+	writel(0x0, GPMC_REG(PREFETCH_CONFIG1));
+
+	return 0;
+}
+EXPORT_SYMBOL(gpmc_prefetch_reset);
diff --git a/arch/arm/mach-omap/include/mach/gpmc.h b/arch/arm/mach-omap/include/mach/gpmc.h
index 3ddc5f5..ed4e82d 100644
--- a/arch/arm/mach-omap/include/mach/gpmc.h
+++ b/arch/arm/mach-omap/include/mach/gpmc.h
@@ -51,9 +51,10 @@
 #define GPMC_TIMEOUT_CONTROL	(0x40)
 #define GPMC_CFG		(0x50)
 #define GPMC_STATUS		(0x54)
-#define GPMC_PREFETCH_CONFIG_1	(0x1E0)
-#define GPMC_PREFETCH_CONFIG_2	(0x1E4)
-#define GPMC_PREFETCH_CTRL	(0x1EC)
+#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)
@@ -138,6 +139,15 @@
 #define GPMC_SIZE_32M		0x0E
 #define GPMC_SIZE_16M		0x0F
 
+#define PREFETCH_FIFOTHRESHOLD_MAX	0x40
+#define PREFETCH_FIFOTHRESHOLD(val)	((val) << 8)
+#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)	((val >> 24) & 0x7F)
+#define GPMC_PREFETCH_STATUS_COUNT(val)	(val & 0x00003fff)
+
+int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
+				unsigned int u32_count, int is_write);
+int gpmc_prefetch_reset(int cs);
+
 #define NAND_WP_BIT		0x00000010
 
 #ifndef __ASSEMBLY__
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 08008e7..39b4dd9 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -112,6 +112,7 @@ struct gpmc_nand_info {
 	unsigned inuse:1;
 	unsigned char ecc_parity_pairs;
 	enum gpmc_ecc_mode ecc_mode;
+	void *cs_base;
 };
 
 /* Typical BOOTROM oob layouts-requires hwecc **/
@@ -583,6 +584,101 @@ static int omap_gpmc_read_buf_manual(struct mtd_info *mtd, struct nand_chip *chi
 	return bytes;
 }
 
+/**
+ * omap_read_buf_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_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct gpmc_nand_info *info = container_of(mtd,
+						struct gpmc_nand_info, minfo);
+	u32 r_count = 0;
+	u32 *p = (u32 *)buf;
+
+	/* take care of subpage reads */
+	if (len % 4) {
+		if (info->nand.options & NAND_BUSWIDTH_16)
+			readsw(info->cs_base, buf, (len % 4) / 2);
+		else
+			readsb(info->cs_base, buf, len % 4);
+		p = (u32 *) (buf + len % 4);
+		len -= len % 4;
+	}
+
+	/* configure and start prefetch transfer */
+	gpmc_prefetch_enable(info->gpmc_cs,
+			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0);
+
+	do {
+		r_count = readl(info->gpmc_base + GPMC_PREFETCH_STATUS);
+		r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count);
+		r_count = r_count >> 2;
+		readsl(info->cs_base, p, r_count);
+		p += r_count;
+		len -= r_count << 2;
+	} while (len);
+
+	/* disable and stop the PFPW engine */
+	gpmc_prefetch_reset(info->gpmc_cs);
+}
+
+/**
+ * omap_write_buf_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_pref(struct mtd_info *mtd,
+					const u_char *buf, int len)
+{
+	struct gpmc_nand_info *info = container_of(mtd,
+						struct gpmc_nand_info, minfo);
+	u32 w_count = 0;
+	u_char *buf1 = (u_char *)buf;
+	u32 *p32 = (u32 *)buf;
+	uint64_t start;
+
+	/* take care of subpage writes */
+	while (len % 4 != 0) {
+		writeb(*buf, info->nand.IO_ADDR_W);
+		buf1++;
+		p32 = (u32 *)buf1;
+		len--;
+	}
+
+	/*  configure and start prefetch transfer */
+	gpmc_prefetch_enable(info->gpmc_cs,
+			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1);
+
+	while (len >= 0) {
+		w_count = readl(info->gpmc_base + GPMC_PREFETCH_STATUS);
+		w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count);
+		w_count = w_count >> 2;
+		writesl(info->cs_base, p32, w_count);
+		p32 += w_count;
+		len -= w_count << 2;
+	}
+
+	/* wait for data to flushed-out before reset the prefetch */
+	start = get_time_ns();
+	while (1) {
+		u32 regval, status;
+		regval = readl(info->gpmc_base + GPMC_PREFETCH_STATUS);
+		status = GPMC_PREFETCH_STATUS_COUNT(regval);
+		if (!status)
+			break;
+		if (is_timeout(start, 100 * MSECOND)) {
+			dev_err(mtd->dev, "prefetch flush timed out\n");
+			break;
+		}
+	}
+
+	/* disable and stop the PFPW engine */
+	gpmc_prefetch_reset(info->gpmc_cs);
+}
+
 /*
  * read a page with the ecc layout used by the OMAP4 romcode. The
  * romcode expects an unusual ecc layout (f = free, e = ecc):
@@ -833,6 +929,7 @@ static int gpmc_nand_probe(struct device_d *pdev)
 	oinfo->gpmc_command = (void *)(cs_base + GPMC_CS_NAND_COMMAND);
 	oinfo->gpmc_address = (void *)(cs_base + GPMC_CS_NAND_ADDRESS);
 	oinfo->gpmc_data = (void *)(cs_base + GPMC_CS_NAND_DATA);
+	oinfo->cs_base = (void *)pdata->nand_cfg->base;
 	dev_dbg(pdev, "GPMC base=0x%p cmd=0x%p address=0x%p data=0x%p cs_base=0x%p\n",
 		oinfo->gpmc_base, oinfo->gpmc_command, oinfo->gpmc_address,
 		oinfo->gpmc_data, cs_base);
@@ -933,6 +1030,9 @@ static int gpmc_nand_probe(struct device_d *pdev)
 		goto out_release_mem;
 	}
 
+	nand->read_buf   = omap_read_buf_pref;
+	nand->write_buf  = omap_write_buf_pref;
+
 	nand->options |= NAND_SKIP_BBTSCAN;
 
 	dev_add_param(pdev, "eccmode", omap_gpmc_eccmode_set, NULL, 0);
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 4/5] mtd nand: implement buswidth detection
  2012-08-02 10:10 [PATCH] OMAP nand Sascha Hauer
                   ` (2 preceding siblings ...)
  2012-08-02 10:10 ` [PATCH 3/5] mtd OMAP NAND: Use prefetch engine Sascha Hauer
@ 2012-08-02 10:10 ` Sascha Hauer
  2012-08-02 10:10 ` [PATCH 5/5] mtd OMAP NAND: implement buswidth autodetection support Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2012-08-02 10:10 UTC (permalink / raw)
  To: barebox

This introduces a new NAND_BUSWIDTH_AUTO flag which can be used
to automatically detect the nand buswidth. The id is always read
in 8bit mode. An additional callback is needed to switch the nand
controller into 16bit mode.
This currently depends on a safe read_byte (always) and read_buf
(for onfi-only flashes) callback. It has been tested on OMAP, but
is not something that generally works. For this reason the existence
of the set_buswidth callback is used to determine whether we are
able to do autodetection or not.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mtd/nand/nand_base.c |   20 ++++++++++++++++----
 include/linux/mtd/nand.h     |    3 +++
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a5bf757..37e57b3 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1000,7 +1000,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 
 	if (!chip->select_chip)
 		chip->select_chip = nand_select_chip;
-	if (!chip->read_byte)
+	if (!chip->read_byte || chip->read_byte == nand_read_byte)
 		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
 	if (!chip->read_word)
 		chip->read_word = nand_read_word;
@@ -1009,12 +1009,12 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 #ifdef CONFIG_MTD_WRITE
 	if (!chip->block_markbad)
 		chip->block_markbad = nand_default_block_markbad;
-	if (!chip->write_buf)
+	if (!chip->write_buf || chip->write_buf == nand_write_buf)
 		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
 #endif
-	if (!chip->read_buf)
+	if (!chip->read_buf || chip->read_buf == nand_read_buf)
 		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
-	if (!chip->verify_buf)
+	if (!chip->verify_buf || chip->verify_buf == nand_verify_buf)
 		chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
 #ifdef CONFIG_NAND_BBT
 	if (!chip->scan_bbt)
@@ -1258,6 +1258,13 @@ ident_done:
 			break;
 	}
 
+	if (chip->options & NAND_BUSWIDTH_AUTO) {
+		chip->options |= busw;
+		nand_set_defaults(chip, busw);
+		if (chip->set_buswidth)
+			chip->set_buswidth(mtd, chip, busw);
+	}
+
 	/*
 	 * Check, if buswidth is correct. Hardware drivers should set
 	 * chip correct !
@@ -1326,6 +1333,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
 	struct nand_chip *chip = mtd->priv;
 	struct nand_flash_dev *type;
 
+	if (chip->options & NAND_BUSWIDTH_AUTO && !chip->set_buswidth) {
+		printk(KERN_ERR "buswidth detection but no buswidth callback\n");
+		return -EINVAL;
+	}
+
 	/* Get buswidth to select the correct functions */
 	busw = chip->options & NAND_BUSWIDTH_16;
 	/* Set the default functions */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 4a492b5..d2f8648 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -169,6 +169,8 @@ typedef enum {
 #define NAND_NO_READRDY		0x00000100
 /* Chip does not allow subpage writes */
 #define NAND_NO_SUBPAGE_WRITE	0x00000200
+/* Buswitdh shal be autodetected */
+#define NAND_BUSWIDTH_AUTO	0x00080000
 
 
 /* Options valid for Samsung large page devices */
@@ -451,6 +453,7 @@ struct nand_chip {
 	int		(*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
 	int		(*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
 				      const uint8_t *buf, int page, int cached, int raw);
+	int		(*set_buswidth)(struct mtd_info *mtd, struct nand_chip *this, int buswidth);
 
 	int		chip_delay;
 	unsigned int	options;
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 5/5] mtd OMAP NAND: implement buswidth autodetection support
  2012-08-02 10:10 [PATCH] OMAP nand Sascha Hauer
                   ` (3 preceding siblings ...)
  2012-08-02 10:10 ` [PATCH 4/5] mtd nand: implement buswidth detection Sascha Hauer
@ 2012-08-02 10:10 ` Sascha Hauer
  4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2012-08-02 10:10 UTC (permalink / raw)
  To: barebox

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mtd/nand/nand_omap_gpmc.c |   44 ++++++++++++++++++++++++++-----------
 1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 39b4dd9..fa6074f 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -879,6 +879,20 @@ static int omap_gpmc_eccmode_set(struct device_d *dev, struct param_d *param, co
 	return omap_gpmc_eccmode(oinfo, i);
 }
 
+static int gpmc_set_buswidth(struct mtd_info *mtd, struct nand_chip *chip, int buswidth)
+{
+	struct gpmc_nand_info *oinfo = chip->priv;
+
+	if (buswidth == NAND_BUSWIDTH_16)
+		oinfo->pdata->nand_cfg->cfg[0] |= 0x00001000;
+	else
+		oinfo->pdata->nand_cfg->cfg[0] &= ~0x00001000;
+
+	gpmc_cs_config(oinfo->pdata->cs, oinfo->pdata->nand_cfg);
+
+	return 0;
+}
+
 /**
  * @brief nand device probe.
  *
@@ -934,10 +948,18 @@ static int gpmc_nand_probe(struct device_d *pdev)
 		oinfo->gpmc_base, oinfo->gpmc_command, oinfo->gpmc_address,
 		oinfo->gpmc_data, cs_base);
 
-	/* If we are 16 bit dev, our gpmc config tells us that */
-	if ((readl(cs_base) & 0x3000) == 0x1000) {
-		dev_dbg(pdev, "16 bit dev\n");
+	switch (pdata->device_width) {
+	case 0:
+		printk("probe buswidth\n");
+		nand->options |= NAND_BUSWIDTH_AUTO;
+		break;
+	case 8:
+		break;
+	case 16:
 		nand->options |= NAND_BUSWIDTH_16;
+		break;
+	default:
+		return -EINVAL;
 	}
 
 	/* Same data register for in and out */
@@ -977,6 +999,8 @@ static int gpmc_nand_probe(struct device_d *pdev)
 	nand->options |= NAND_OWN_BUFFERS;
 	nand->buffers = xzalloc(sizeof(*nand->buffers));
 
+	nand->set_buswidth = gpmc_set_buswidth;
+
 	/* State my controller */
 	nand->controller = &oinfo->controller;
 
@@ -1004,18 +1028,12 @@ static int gpmc_nand_probe(struct device_d *pdev)
 		goto out_release_mem;
 	}
 
-	switch (pdata->device_width) {
-	case 8:
-		lsp = &ecc_sp_x8;
-		llp = &ecc_lp_x8;
-		break;
-	case 16:
+	if (nand->options & NAND_BUSWIDTH_16) {
 		lsp = &ecc_sp_x16;
 		llp = &ecc_lp_x16;
-		break;
-	default:
-		err = -EINVAL;
-		goto out_release_mem;
+	} else {
+		lsp = &ecc_sp_x8;
+		llp = &ecc_lp_x8;
 	}
 
 	switch (minfo->writesize) {
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2012-08-02 10:11 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-02 10:10 [PATCH] OMAP nand Sascha Hauer
2012-08-02 10:10 ` [PATCH 1/5] mtd OMAP NAND: Fix dev_ready handling Sascha Hauer
2012-08-02 10:10 ` [PATCH 2/5] ARM OMAP gpmc nand: specify platform data in boards Sascha Hauer
2012-08-02 10:10 ` [PATCH 3/5] mtd OMAP NAND: Use prefetch engine Sascha Hauer
2012-08-02 10:10 ` [PATCH 4/5] mtd nand: implement buswidth detection Sascha Hauer
2012-08-02 10:10 ` [PATCH 5/5] mtd OMAP NAND: implement buswidth autodetection support Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox