linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms
@ 2015-08-07  9:12 Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 01/22] ARM: OMAP2+: gpmc: Add platform data Roger Quadros
                   ` (22 more replies)
  0 siblings, 23 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Hi,

We do a couple of things in this series which result in
cleaner device tree implementation, faster perfomance and
multi-platform support. As an added bonus we get new GPI/Interrupt pins
for use in the system.

- Establish a custom interface between NAND and GPMC driver. This is
needed because all of the NAND registers sit in the GPMC register space.
Some bits like NAND IRQ are even shared with GPMC.

- Remove NAND IRQ handling from omap-gpmc driver, share the GPMC IRQ
with the omap2-nand driver and handle NAND IRQ events in the NAND driver.
This causes performance increase when using prefetch-irq mode.
30% increase in read, 17% increase in write in prefetch-irq mode.

- Clean up device tree support so that omap-gpmc IP and the omap2 NAND
driver can be used on non-OMAP platforms. e.g. Keystone.

- Implement GPIOCHIP + IRQCHIP for the GPMC WAITPINS. SoCs can contain
2 to 4 of these and most of them would be unused otherwise. It also
allows a cleaner implementation of NAND Ready pin status for the NAND driver.

- Implement GPIOlib based NAND ready pin checking for OMAP NAND driver.

NOTE: I've only adapted dra7.dtsi and dra7x-evms for this series.
I will adapt all other boards when the series is in a shape to be accepted.

cheers,
-roger

This is done in patches 1 to 14

Roger Quadros (22):
  ARM: OMAP2+: gpmc: Add platform data
  ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
  memory: omap-gpmc: Introduce GPMC to NAND interface
  mtd: nand: omap2: Use gpmc_omap_get_nand_ops() to get NAND registers
  memory: omap-gpmc: Add GPMC-NAND ops to get writebufferempty status
  mtd: nand: omap2: Switch to using GPMC-NAND ops for writebuffer empty
    check
  memory: omap-gpmc: Remove NAND IRQ code
  memory: omap-gpmc: Add IRQ ops for GPMC-NAND interface
  mtd: nand: omap2: manage NAND interrupts
  mtd: nand: omap: Copy platform data parameters to omap_nand_info data
  mtd: nand: omap: Clean up device tree support
  mtd: nand: omap: Update DT binding documentation
  memory: omap-gpmc: Prevent mapping into 1st 16MB
  ARM: dts: OMAP2+: Fix NAND device nodes.
  memory: omap-gpmc: Move device tree binding to correct location
  memory: omap-gpmc: Support general purpose input for WAITPINs
  memory: omap-gpmc: Reserve WAITPIN if needed for WAIT monitoring
  memory: omap-gpmc: Add irqchip support to the gpiochip
  ARM: dts: dra7: Enable gpio & interrupt controller for gpmc node
  mtd: nand: omap2: Implement NAND ready using gpiolib
  ARM: dts: dra7x-evm: Provide NAND ready pin
  memory: omap-gpmc: Prevent GPMC_STATUS from being accessed via
    gpmc_regs

 .../omap-gpmc.txt}                                 |   0
 .../devicetree/bindings/mtd/gpmc-nand.txt          |  16 +-
 arch/arm/boot/dts/dra7-evm.dts                     |   6 +-
 arch/arm/boot/dts/dra7.dtsi                        |   4 +
 arch/arm/boot/dts/dra72-evm.dts                    |   2 +
 arch/arm/boot/dts/omap3-beagle.dts                 |   3 +-
 arch/arm/mach-omap2/gpmc-nand.c                    |  11 +-
 drivers/memory/omap-gpmc.c                         | 610 ++++++++++++---------
 drivers/mtd/nand/omap2.c                           | 261 ++++++---
 include/linux/omap-gpmc.h                          | 172 ++----
 include/linux/platform_data/gpmc-omap.h            | 169 ++++++
 include/linux/platform_data/mtd-nand-omap2.h       |  12 +-
 12 files changed, 782 insertions(+), 484 deletions(-)
 rename Documentation/devicetree/bindings/{bus/ti-gpmc.txt => memory-controllers/omap-gpmc.txt} (100%)
 create mode 100644 include/linux/platform_data/gpmc-omap.h

-- 
2.1.4


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

* [PATCH v2 01/22] ARM: OMAP2+: gpmc: Add platform data
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 02/22] ARM: OMAP2+: gpmc: Add gpmc timings and settings to " Roger Quadros
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Add a platform data structure for GPMC. It contains all the necessary
platform information that needs to be passed from platform init code
to GPMC driver.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 include/linux/omap-gpmc.h               |  3 +--
 include/linux/platform_data/gpmc-omap.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/platform_data/gpmc-omap.h

diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index 7dee0014..5c79190 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -7,8 +7,7 @@
  *  option) any later version.
  */
 
-/* Maximum Number of Chip Selects */
-#define GPMC_CS_NUM		8
+#include <linux/platform_data/gpmc-omap.h>
 
 #define GPMC_CONFIG_WP		0x00000005
 
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
new file mode 100644
index 0000000..d32d9de
--- /dev/null
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -0,0 +1,30 @@
+/*
+ * OMAP GPMC Platform data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc. - http://www.ti.com
+ *	Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef _GPMC_OMAP_H_
+#define _GPMC_OMAP_H_
+
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM		8
+
+/* Data for each chip select */
+struct gpmc_omap_cs_data {
+	bool valid;			/* data is valid */
+	bool is_nand;			/* device within this CS is NAND */
+	struct platform_device *pdev;	/* device within this CS region */
+	unsigned pdata_size;
+};
+
+struct gpmc_omap_platform_data {
+	struct gpmc_omap_cs_data cs[GPMC_CS_NUM];
+};
+
+#endif /* _GPMC_OMAP_H */
-- 
2.1.4


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

* [PATCH v2 02/22] ARM: OMAP2+: gpmc: Add gpmc timings and settings to platform data
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 01/22] ARM: OMAP2+: gpmc: Add platform data Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 03/22] memory: omap-gpmc: Introduce GPMC to NAND interface Roger Quadros
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Add device_timings, gpmc_timings and gpmc_setting to
gpmc platform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 include/linux/omap-gpmc.h               | 134 ------------------------------
 include/linux/platform_data/gpmc-omap.h | 139 ++++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 134 deletions(-)

diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index 5c79190..2dcef1c 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -14,140 +14,6 @@
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
 
-#define GPMC_BURST_4			4	/* 4 word burst */
-#define GPMC_BURST_8			8	/* 8 word burst */
-#define GPMC_BURST_16			16	/* 16 word burst */
-#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
-#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
-#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
-#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
-
-/* bool type time settings */
-struct gpmc_bool_timings {
-	bool cycle2cyclediffcsen;
-	bool cycle2cyclesamecsen;
-	bool we_extra_delay;
-	bool oe_extra_delay;
-	bool adv_extra_delay;
-	bool cs_extra_delay;
-	bool time_para_granularity;
-};
-
-/*
- * Note that all values in this struct are in nanoseconds except sync_clk
- * (which is in picoseconds), while the register values are in gpmc_fck cycles.
- */
-struct gpmc_timings {
-	/* Minimum clock period for synchronous mode (in picoseconds) */
-	u32 sync_clk;
-
-	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
-	u32 cs_on;		/* Assertion time */
-	u32 cs_rd_off;		/* Read deassertion time */
-	u32 cs_wr_off;		/* Write deassertion time */
-
-	/* ADV signal timings corresponding to GPMC_CONFIG3 */
-	u32 adv_on;		/* Assertion time */
-	u32 adv_rd_off;		/* Read deassertion time */
-	u32 adv_wr_off;		/* Write deassertion time */
-
-	/* WE signals timings corresponding to GPMC_CONFIG4 */
-	u32 we_on;		/* WE assertion time */
-	u32 we_off;		/* WE deassertion time */
-
-	/* OE signals timings corresponding to GPMC_CONFIG4 */
-	u32 oe_on;		/* OE assertion time */
-	u32 oe_off;		/* OE deassertion time */
-
-	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
-	u32 page_burst_access;	/* Multiple access word delay */
-	u32 access;		/* Start-cycle to first data valid delay */
-	u32 rd_cycle;		/* Total read cycle time */
-	u32 wr_cycle;		/* Total write cycle time */
-
-	u32 bus_turnaround;
-	u32 cycle2cycle_delay;
-
-	u32 wait_monitoring;
-	u32 clk_activation;
-
-	/* The following are only on OMAP3430 */
-	u32 wr_access;		/* WRACCESSTIME */
-	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
-
-	struct gpmc_bool_timings bool_timings;
-};
-
-/* Device timings in picoseconds */
-struct gpmc_device_timings {
-	u32 t_ceasu;	/* address setup to CS valid */
-	u32 t_avdasu;	/* address setup to ADV valid */
-	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
-	 * of tusb using these timings even for sync whilst
-	 * ideally for adv_rd/(wr)_off it should have considered
-	 * t_avdh instead. This indirectly necessitates r/w
-	 * variations of t_avdp as it is possible to have one
-	 * sync & other async
-	 */
-	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
-	u32 t_avdp_w;
-	u32 t_aavdh;	/* address hold time */
-	u32 t_oeasu;	/* address setup to OE valid */
-	u32 t_aa;	/* access time from ADV assertion */
-	u32 t_iaa;	/* initial access time */
-	u32 t_oe;	/* access time from OE assertion */
-	u32 t_ce;	/* access time from CS asertion */
-	u32 t_rd_cycle;	/* read cycle time */
-	u32 t_cez_r;	/* read CS deassertion to high Z */
-	u32 t_cez_w;	/* write CS deassertion to high Z */
-	u32 t_oez;	/* OE deassertion to high Z */
-	u32 t_weasu;	/* address setup to WE valid */
-	u32 t_wpl;	/* write assertion time */
-	u32 t_wph;	/* write deassertion time */
-	u32 t_wr_cycle;	/* write cycle time */
-
-	u32 clk;
-	u32 t_bacc;	/* burst access valid clock to output delay */
-	u32 t_ces;	/* CS setup time to clk */
-	u32 t_avds;	/* ADV setup time to clk */
-	u32 t_avdh;	/* ADV hold time from clk */
-	u32 t_ach;	/* address hold time from clk */
-	u32 t_rdyo;	/* clk to ready valid */
-
-	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
-	u32 t_ce_avd;	/* CS on to ADV on delay */
-
-	/* XXX: check the possibility of combining
-	 * cyc_aavhd_oe & cyc_aavdh_we
-	 */
-	u8 cyc_aavdh_oe;/* read address hold time in cycles */
-	u8 cyc_aavdh_we;/* write address hold time in cycles */
-	u8 cyc_oe;	/* access time from OE assertion in cycles */
-	u8 cyc_wpl;	/* write deassertion time in cycles */
-	u32 cyc_iaa;	/* initial access time in cycles */
-
-	/* extra delays */
-	bool ce_xdelay;
-	bool avd_xdelay;
-	bool oe_xdelay;
-	bool we_xdelay;
-};
-
-struct gpmc_settings {
-	bool burst_wrap;	/* enables wrap bursting */
-	bool burst_read;	/* enables read page/burst mode */
-	bool burst_write;	/* enables write page/burst mode */
-	bool device_nand;	/* device is NAND */
-	bool sync_read;		/* enables synchronous reads */
-	bool sync_write;	/* enables synchronous writes */
-	bool wait_on_read;	/* monitor wait on reads */
-	bool wait_on_write;	/* monitor wait on writes */
-	u32 burst_len;		/* page/burst length */
-	u32 device_width;	/* device bus width (8 or 16 bit) */
-	u32 mux_add_data;	/* multiplex address & data */
-	u32 wait_pin;		/* wait-pin to be used */
-};
-
 extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
diff --git a/include/linux/platform_data/gpmc-omap.h b/include/linux/platform_data/gpmc-omap.h
index d32d9de..e861112 100644
--- a/include/linux/platform_data/gpmc-omap.h
+++ b/include/linux/platform_data/gpmc-omap.h
@@ -15,10 +15,149 @@
 /* Maximum Number of Chip Selects */
 #define GPMC_CS_NUM		8
 
+/* bool type time settings */
+struct gpmc_bool_timings {
+	bool cycle2cyclediffcsen;
+	bool cycle2cyclesamecsen;
+	bool we_extra_delay;
+	bool oe_extra_delay;
+	bool adv_extra_delay;
+	bool cs_extra_delay;
+	bool time_para_granularity;
+};
+
+/*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+ */
+struct gpmc_timings {
+	/* Minimum clock period for synchronous mode (in picoseconds) */
+	u32 sync_clk;
+
+	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
+	u32 cs_on;		/* Assertion time */
+	u32 cs_rd_off;		/* Read deassertion time */
+	u32 cs_wr_off;		/* Write deassertion time */
+
+	/* ADV signal timings corresponding to GPMC_CONFIG3 */
+	u32 adv_on;		/* Assertion time */
+	u32 adv_rd_off;		/* Read deassertion time */
+	u32 adv_wr_off;		/* Write deassertion time */
+
+	/* WE signals timings corresponding to GPMC_CONFIG4 */
+	u32 we_on;		/* WE assertion time */
+	u32 we_off;		/* WE deassertion time */
+
+	/* OE signals timings corresponding to GPMC_CONFIG4 */
+	u32 oe_on;		/* OE assertion time */
+	u32 oe_off;		/* OE deassertion time */
+
+	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
+	u32 page_burst_access;	/* Multiple access word delay */
+	u32 access;		/* Start-cycle to first data valid delay */
+	u32 rd_cycle;		/* Total read cycle time */
+	u32 wr_cycle;		/* Total write cycle time */
+
+	u32 bus_turnaround;
+	u32 cycle2cycle_delay;
+
+	u32 wait_monitoring;
+	u32 clk_activation;
+
+	/* The following are only on OMAP3430 */
+	u32 wr_access;		/* WRACCESSTIME */
+	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+
+	struct gpmc_bool_timings bool_timings;
+};
+
+
+/* Device timings in picoseconds */
+struct gpmc_device_timings {
+	u32 t_ceasu;	/* address setup to CS valid */
+	u32 t_avdasu;	/* address setup to ADV valid */
+	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
+	 * of tusb using these timings even for sync whilst
+	 * ideally for adv_rd/(wr)_off it should have considered
+	 * t_avdh instead. This indirectly necessitates r/w
+	 * variations of t_avdp as it is possible to have one
+	 * sync & other async
+	 */
+	u32 t_avdp_r;	/* ADV low time (what about t_cer ?) */
+	u32 t_avdp_w;
+	u32 t_aavdh;	/* address hold time */
+	u32 t_oeasu;	/* address setup to OE valid */
+	u32 t_aa;	/* access time from ADV assertion */
+	u32 t_iaa;	/* initial access time */
+	u32 t_oe;	/* access time from OE assertion */
+	u32 t_ce;	/* access time from CS asertion */
+	u32 t_rd_cycle;	/* read cycle time */
+	u32 t_cez_r;	/* read CS deassertion to high Z */
+	u32 t_cez_w;	/* write CS deassertion to high Z */
+	u32 t_oez;	/* OE deassertion to high Z */
+	u32 t_weasu;	/* address setup to WE valid */
+	u32 t_wpl;	/* write assertion time */
+	u32 t_wph;	/* write deassertion time */
+	u32 t_wr_cycle;	/* write cycle time */
+
+	u32 clk;
+	u32 t_bacc;	/* burst access valid clock to output delay */
+	u32 t_ces;	/* CS setup time to clk */
+	u32 t_avds;	/* ADV setup time to clk */
+	u32 t_avdh;	/* ADV hold time from clk */
+	u32 t_ach;	/* address hold time from clk */
+	u32 t_rdyo;	/* clk to ready valid */
+
+	u32 t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
+	u32 t_ce_avd;	/* CS on to ADV on delay */
+
+	/* XXX: check the possibility of combining
+	 * cyc_aavhd_oe & cyc_aavdh_we
+	 */
+	u8 cyc_aavdh_oe;/* read address hold time in cycles */
+	u8 cyc_aavdh_we;/* write address hold time in cycles */
+	u8 cyc_oe;	/* access time from OE assertion in cycles */
+	u8 cyc_wpl;	/* write deassertion time in cycles */
+	u32 cyc_iaa;	/* initial access time in cycles */
+
+	/* extra delays */
+	bool ce_xdelay;
+	bool avd_xdelay;
+	bool oe_xdelay;
+	bool we_xdelay;
+};
+
+#define GPMC_BURST_4			4	/* 4 word burst */
+#define GPMC_BURST_8			8	/* 8 word burst */
+#define GPMC_BURST_16			16	/* 16 word burst */
+#define GPMC_DEVWIDTH_8BIT		1	/* 8-bit device width */
+#define GPMC_DEVWIDTH_16BIT		2	/* 16-bit device width */
+#define GPMC_MUX_AAD			1	/* Addr-Addr-Data multiplex */
+#define GPMC_MUX_AD			2	/* Addr-Data multiplex */
+
+struct gpmc_settings {
+	bool burst_wrap;	/* enables wrap bursting */
+	bool burst_read;	/* enables read page/burst mode */
+	bool burst_write;	/* enables write page/burst mode */
+	bool device_nand;	/* device is NAND */
+	bool sync_read;		/* enables synchronous reads */
+	bool sync_write;	/* enables synchronous writes */
+	bool wait_on_read;	/* monitor wait on reads */
+	bool wait_on_write;	/* monitor wait on writes */
+	u32 burst_len;		/* page/burst length */
+	u32 device_width;	/* device bus width (8 or 16 bit) */
+	u32 mux_add_data;	/* multiplex address & data */
+	u32 wait_pin;		/* wait-pin to be used */
+};
+
+
 /* Data for each chip select */
 struct gpmc_omap_cs_data {
 	bool valid;			/* data is valid */
 	bool is_nand;			/* device within this CS is NAND */
+	struct gpmc_settings *settings;
+	struct gpmc_device_timings *device_timings;
+	struct gpmc_timings *gpmc_timings;
 	struct platform_device *pdev;	/* device within this CS region */
 	unsigned pdata_size;
 };
-- 
2.1.4


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

* [PATCH v2 03/22] memory: omap-gpmc: Introduce GPMC to NAND interface
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 01/22] ARM: OMAP2+: gpmc: Add platform data Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 02/22] ARM: OMAP2+: gpmc: Add gpmc timings and settings to " Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 04/22] mtd: nand: omap2: Use gpmc_omap_get_nand_ops() to get NAND registers Roger Quadros
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

The OMAP GPMC module has certain registers dedicated for NAND
access and some NAND bits mixed with other GPMC functionality.

For the NAND dedicated registers we have the struct gpmc_nand_regs.

The NAND driver needs to access NAND specific bits from the
following non-dedicated registers
1) FIFOEVENT and TERMCOUNT from GPMC_IRQENABLE and GPMC_IRQSTATUS
2) EMPTYWRITEBUFFERSTATUS from GPMC_STATUS

For accessing these bits we introduce the struct gpmc_nand_ops.

Rename the gpmc_update_nand_reg() API to gpmc_omap_get_nand_ops()
and make it return the gpmc_nand_ops along with updating the
gpmc_nand_regs. This API will be called by the OMAP NAND driver
to access the necessary bits in GPMC register space.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/memory/omap-gpmc.c | 21 +++++++++++++++++++++
 include/linux/omap-gpmc.h  | 42 ++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 3a27a84..79d78ab 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -1099,6 +1099,27 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	}
 }
 
+static struct gpmc_nand_ops nand_ops;
+
+/**
+ * gpmc_omap_get_nand_ops - Get the GPMC NAND interface
+ * @regs: the GPMC NAND register map exclusive for NAND use.
+ * @cs: GPMC chip select number on which the NAND sits. The
+ *      register map returned will be specific to this chip select.
+ *
+ * Returns NULL on error e.g. invalid cs.
+ */
+struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs)
+{
+	if (cs >= gpmc_cs_num)
+		return NULL;
+
+	gpmc_update_nand_reg(reg, cs);
+
+	return &nand_ops;
+}
+EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops);
+
 int gpmc_get_client_irq(unsigned irq_config)
 {
 	int i;
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index 2dcef1c..a811c91 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -14,14 +14,52 @@
 #define GPMC_IRQ_FIFOEVENTENABLE	0x01
 #define GPMC_IRQ_COUNT_EVENT		0x02
 
+enum gpmc_nand_irq {
+	GPMC_NAND_IRQ_FIFOEVENT = 0,
+	GPMC_NAND_IRQ_TERMCOUNT,
+};
+
+/**
+ * gpmc_nand_ops - Interface between NAND and GPMC
+ * @nand_irq_enable: enable the requested GPMC NAND interrupt event.
+ * @nand_irq_disable: disable the requested GPMC NAND interrupt event.
+ * @nand_irq_clear: clears the GPMC NAND interrupt event status.
+ * @nand_irq_status: get the NAND interrupt event status.
+ * @nand_write_buffer_empty: get the NAND write buffer empty status.
+ */
+struct gpmc_nand_ops {
+	int (*nand_irq_enable)(enum gpmc_nand_irq irq);
+	int (*nand_irq_disable)(enum gpmc_nand_irq irq);
+	void (*nand_irq_clear)(enum gpmc_nand_irq irq);
+	u32 (*nand_irq_status)(void);
+	bool (*nand_writebuffer_empty)(void);
+};
+
+struct gpmc_nand_regs;
+
+#if IS_ENABLED(CONFIG_OMAP_GPMC)
+struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
+					     int cs);
+#else
+static inline gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *regs,
+						    int cs);
+{
+	return NULL;
+}
+#endif /* CONFIG_OMAP_GPMC */
+
+/*--------------------------------*/
+
+/* deprecated APIs */
+extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
+/*--------------------------------*/
+
 extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 			     struct gpmc_settings *gpmc_s,
 			     struct gpmc_device_timings *dev_t);
 
-struct gpmc_nand_regs;
 struct device_node;
 
-extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
 extern int gpmc_get_client_irq(unsigned irq_config);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
-- 
2.1.4


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

* [PATCH v2 04/22] mtd: nand: omap2: Use gpmc_omap_get_nand_ops() to get NAND registers
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (2 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 03/22] memory: omap-gpmc: Introduce GPMC to NAND interface Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 05/22] memory: omap-gpmc: Add GPMC-NAND ops to get writebufferempty status Roger Quadros
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Deprecate nand register passing via platform data and use
gpmc_omap_get_nand_ops() instead.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              | 2 --
 drivers/mtd/nand/omap2.c                     | 9 ++++++++-
 include/linux/platform_data/mtd-nand-omap2.h | 4 +++-
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 72918c4..04e6998 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -121,8 +121,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	if (err < 0)
 		goto out_free_cs;
 
-	gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
-
 	if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
 		pr_err("omap2-nand: Unsupported NAND ECC scheme selected\n");
 		err = -EINVAL;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 60fa899..f214fe2 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -28,6 +28,7 @@
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
 
+#include <linux/omap-gpmc.h>
 #include <linux/platform_data/mtd-nand-omap2.h>
 
 #define	DRIVER_NAME	"omap2-nand"
@@ -169,7 +170,9 @@ struct omap_nand_info {
 	} iomode;
 	u_char				*buf;
 	int					buf_len;
+	/* Interface to GPMC */
 	struct gpmc_nand_regs		reg;
+	struct gpmc_nand_ops		*ops;
 	/* generated at runtime depending on ECC algorithm and layout selected */
 	struct nand_ecclayout		oobinfo;
 	/* fields specific for BCHx_HW ECC scheme */
@@ -1677,9 +1680,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, info);
 
+	info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
+	if (!info->ops) {
+		dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
+		return -ENODEV;
+	}
 	info->pdev		= pdev;
 	info->gpmc_cs		= pdata->cs;
-	info->reg		= pdata->reg;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
 	mtd			= &info->mtd;
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 090bbab..a067f58 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -75,10 +75,12 @@ struct omap_nand_platform_data {
 	enum nand_io		xfer_type;
 	int			devsize;
 	enum omap_ecc           ecc_opt;
-	struct gpmc_nand_regs	reg;
 
 	/* for passing the partitions */
 	struct device_node	*of_node;
 	struct device_node	*elm_of_node;
+
+	/* deprecated */
+	struct gpmc_nand_regs	reg;
 };
 #endif
-- 
2.1.4


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

* [PATCH v2 05/22] memory: omap-gpmc: Add GPMC-NAND ops to get writebufferempty status
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (3 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 04/22] mtd: nand: omap2: Use gpmc_omap_get_nand_ops() to get NAND registers Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 06/22] mtd: nand: omap2: Switch to using GPMC-NAND ops for writebuffer empty check Roger Quadros
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

This is needed by OMAP NAND driver to poll the empty status
of the writebuffer.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/memory/omap-gpmc.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 79d78ab..41df030 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -81,6 +81,8 @@
 
 #define GPMC_CONFIG_LIMITEDADDRESS		BIT(1)
 
+#define GPMC_STATUS_EMPTYWRITEBUFFERSTATUS	BIT(0)
+
 #define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
 #define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
@@ -1099,7 +1101,17 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 	}
 }
 
-static struct gpmc_nand_ops nand_ops;
+static bool gpmc_nand_writebuffer_empty(void)
+{
+	if (gpmc_read_reg(GPMC_STATUS) & GPMC_STATUS_EMPTYWRITEBUFFERSTATUS)
+		return true;
+
+	return false;
+}
+
+static struct gpmc_nand_ops nand_ops = {
+	.nand_writebuffer_empty = gpmc_nand_writebuffer_empty,
+};
 
 /**
  * gpmc_omap_get_nand_ops - Get the GPMC NAND interface
-- 
2.1.4


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

* [PATCH v2 06/22] mtd: nand: omap2: Switch to using GPMC-NAND ops for writebuffer empty check
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (4 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 05/22] memory: omap-gpmc: Add GPMC-NAND ops to get writebufferempty status Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-13  7:18   ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 07/22] memory: omap-gpmc: Remove NAND IRQ code Roger Quadros
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Instead of accessing the gpmc_status register directly start
using the gpmc_nand_ops->nand_writebuffer_empty() helper
to check write buffer empty status.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/nand/omap2.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index f214fe2..5c2f6df 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -289,15 +289,11 @@ 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);
 		/* wait until buffer is available for write */
-		do {
-			status = readl(info->reg.gpmc_status) &
-					STATUS_BUFF_EMPTY;
-		} while (!status);
+		while (info->ops->nand_writebuffer_empty());
 	}
 }
 
@@ -325,17 +321,13 @@ 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);
 		/* wait until buffer is available for write */
-		do {
-			status = readl(info->reg.gpmc_status) &
-					STATUS_BUFF_EMPTY;
-		} while (!status);
+		while (info->ops->nand_writebuffer_empty());
 	}
 }
 
-- 
2.1.4


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

* [PATCH v2 07/22] memory: omap-gpmc: Remove NAND IRQ code
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (5 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 06/22] mtd: nand: omap2: Switch to using GPMC-NAND ops for writebuffer empty check Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 08/22] memory: omap-gpmc: Add IRQ ops for GPMC-NAND interface Roger Quadros
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

NAND IRQs will now be managed directly in the OMAP NAND driver
so remove the IRQchip model.

Another patch will add back GPIO-IRQchip code to handle the
WAITPIN interrupts.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c |   4 +-
 drivers/memory/omap-gpmc.c      | 164 +---------------------------------------
 include/linux/omap-gpmc.h       |   5 +-
 3 files changed, 5 insertions(+), 168 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 04e6998..ffe646a 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -80,7 +80,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	struct resource gpmc_nand_res[] = {
 		{ .flags = IORESOURCE_MEM, },
 		{ .flags = IORESOURCE_IRQ, },
-		{ .flags = IORESOURCE_IRQ, },
 	};
 
 	BUG_ON(gpmc_nand_data->cs >= GPMC_CS_NUM);
@@ -93,8 +92,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 		return err;
 	}
 	gpmc_nand_res[0].end = gpmc_nand_res[0].start + NAND_IO_SIZE - 1;
-	gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
-	gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
+	gpmc_nand_res[1].start = gpmc_get_irq();
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
 	if (gpmc_nand_data->of_node)
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 41df030..e70a8df 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -123,12 +123,6 @@
 #define GPMC_CS_NAND_ADDRESS	0x20
 #define GPMC_CS_NAND_DATA	0x24
 
-/* Control Commands */
-#define GPMC_CONFIG_RDY_BSY	0x00000001
-#define GPMC_CONFIG_DEV_SIZE	0x00000002
-#define GPMC_CONFIG_DEV_TYPE	0x00000003
-#define GPMC_SET_IRQ_STATUS	0x00000004
-
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
 #define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
@@ -176,17 +170,11 @@
 #define GPMC_CONFIG_WRITEPROTECT	0x00000010
 #define WR_RD_PIN_MONITORING		0x00600000
 
-#define GPMC_ENABLE_IRQ		0x0000000d
-
 /* 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 */
 
-/* XXX: Only NAND irq has been considered,currently these are the only ones used
- */
-#define	GPMC_NR_IRQ		2
-
 enum gpmc_clk_domain {
 	GPMC_CD_FCLK,
 	GPMC_CD_CLK
@@ -201,11 +189,6 @@ struct gpmc_cs_data {
 	struct resource mem;
 };
 
-struct gpmc_client_irq	{
-	unsigned		irq;
-	u32			bitmask;
-};
-
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -233,10 +216,6 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
-static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
-static struct irq_chip gpmc_irq_chip;
-static int gpmc_irq_start;
-
 static struct resource	gpmc_mem_root;
 static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -244,15 +223,13 @@ static DEFINE_SPINLOCK(gpmc_mem_lock);
 static unsigned int gpmc_cs_num = GPMC_CS_NUM;
 static unsigned int gpmc_nr_waitpins;
 static struct device *gpmc_dev;
-static int gpmc_irq;
+static int gpmc_irq = -EINVAL;
 static resource_size_t phys_base, mem_size;
 static unsigned gpmc_capability;
 static void __iomem *gpmc_base;
 
 static struct clk *gpmc_l3_clk;
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev);
-
 static void gpmc_write_reg(int idx, u32 val)
 {
 	writel_relaxed(val, gpmc_base + idx);
@@ -1037,14 +1014,6 @@ int gpmc_configure(int cmd, int wval)
 	u32 regval;
 
 	switch (cmd) {
-	case GPMC_ENABLE_IRQ:
-		gpmc_write_reg(GPMC_IRQENABLE, wval);
-		break;
-
-	case GPMC_SET_IRQ_STATUS:
-		gpmc_write_reg(GPMC_IRQSTATUS, wval);
-		break;
-
 	case GPMC_CONFIG_WP:
 		regval = gpmc_read_reg(GPMC_CONFIG);
 		if (wval)
@@ -1132,113 +1101,9 @@ struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs)
 }
 EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops);
 
-int gpmc_get_client_irq(unsigned irq_config)
-{
-	int i;
-
-	if (hweight32(irq_config) > 1)
-		return 0;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (gpmc_client_irq[i].bitmask & irq_config)
-			return gpmc_client_irq[i].irq;
-
-	return 0;
-}
-
-static int gpmc_irq_endis(unsigned irq, bool endis)
-{
-	int i;
-	u32 regval;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (irq == gpmc_client_irq[i].irq) {
-			regval = gpmc_read_reg(GPMC_IRQENABLE);
-			if (endis)
-				regval |= gpmc_client_irq[i].bitmask;
-			else
-				regval &= ~gpmc_client_irq[i].bitmask;
-			gpmc_write_reg(GPMC_IRQENABLE, regval);
-			break;
-		}
-
-	return 0;
-}
-
-static void gpmc_irq_disable(struct irq_data *p)
+int gpmc_get_irq(void)
 {
-	gpmc_irq_endis(p->irq, false);
-}
-
-static void gpmc_irq_enable(struct irq_data *p)
-{
-	gpmc_irq_endis(p->irq, true);
-}
-
-static void gpmc_irq_noop(struct irq_data *data) { }
-
-static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
-
-static int gpmc_setup_irq(void)
-{
-	int i;
-	u32 regval;
-
-	if (!gpmc_irq)
-		return -EINVAL;
-
-	gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
-	if (gpmc_irq_start < 0) {
-		pr_err("irq_alloc_descs failed\n");
-		return gpmc_irq_start;
-	}
-
-	gpmc_irq_chip.name = "gpmc";
-	gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret;
-	gpmc_irq_chip.irq_enable = gpmc_irq_enable;
-	gpmc_irq_chip.irq_disable = gpmc_irq_disable;
-	gpmc_irq_chip.irq_shutdown = gpmc_irq_noop;
-	gpmc_irq_chip.irq_ack = gpmc_irq_noop;
-	gpmc_irq_chip.irq_mask = gpmc_irq_noop;
-	gpmc_irq_chip.irq_unmask = gpmc_irq_noop;
-
-	gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE;
-	gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		gpmc_client_irq[i].irq = gpmc_irq_start + i;
-		irq_set_chip_and_handler(gpmc_client_irq[i].irq,
-					&gpmc_irq_chip, handle_simple_irq);
-		set_irq_flags(gpmc_client_irq[i].irq,
-				IRQF_VALID | IRQF_NOAUTOEN);
-	}
-
-	/* Disable interrupts */
-	gpmc_write_reg(GPMC_IRQENABLE, 0);
-
-	/* clear interrupts */
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
-}
-
-static int gpmc_free_irq(void)
-{
-	int i;
-
-	if (gpmc_irq)
-		free_irq(gpmc_irq, NULL);
-
-	for (i = 0; i < GPMC_NR_IRQ; i++) {
-		irq_set_handler(gpmc_client_irq[i].irq, NULL);
-		irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
-		irq_modify_status(gpmc_client_irq[i].irq, 0, 0);
-	}
-
-	irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
-
-	return 0;
+	return gpmc_irq;
 }
 
 static void gpmc_mem_exit(void)
@@ -2183,9 +2048,6 @@ static int gpmc_probe(struct platform_device *pdev)
 
 	gpmc_mem_init();
 
-	if (gpmc_setup_irq() < 0)
-		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
-
 	if (!pdev->dev.of_node) {
 		gpmc_cs_num	 = GPMC_CS_NUM;
 		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
@@ -2203,7 +2065,6 @@ static int gpmc_probe(struct platform_device *pdev)
 
 static int gpmc_remove(struct platform_device *pdev)
 {
-	gpmc_free_irq();
 	gpmc_mem_exit();
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -2253,25 +2114,6 @@ static __exit void gpmc_exit(void)
 postcore_initcall(gpmc_init);
 module_exit(gpmc_exit);
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev)
-{
-	int i;
-	u32 regval;
-
-	regval = gpmc_read_reg(GPMC_IRQSTATUS);
-
-	if (!regval)
-		return IRQ_NONE;
-
-	for (i = 0; i < GPMC_NR_IRQ; i++)
-		if (regval & gpmc_client_irq[i].bitmask)
-			generic_handle_irq(gpmc_client_irq[i].irq);
-
-	gpmc_write_reg(GPMC_IRQSTATUS, regval);
-
-	return IRQ_HANDLED;
-}
-
 static struct omap3_gpmc_regs gpmc_context;
 
 void omap3_gpmc_save_context(void)
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index a811c91..44e322f 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -11,9 +11,6 @@
 
 #define GPMC_CONFIG_WP		0x00000005
 
-#define GPMC_IRQ_FIFOEVENTENABLE	0x01
-#define GPMC_IRQ_COUNT_EVENT		0x02
-
 enum gpmc_nand_irq {
 	GPMC_NAND_IRQ_FIFOEVENT = 0,
 	GPMC_NAND_IRQ_TERMCOUNT,
@@ -60,7 +57,7 @@ extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
 
 struct device_node;
 
-extern int gpmc_get_client_irq(unsigned irq_config);
+extern int gpmc_get_irq(void);
 
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
 
-- 
2.1.4


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

* [PATCH v2 08/22] memory: omap-gpmc: Add IRQ ops for GPMC-NAND interface
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (6 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 07/22] memory: omap-gpmc: Remove NAND IRQ code Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 09/22] mtd: nand: omap2: manage NAND interrupts Roger Quadros
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Provide functions to enable/disable NAND IRQs, get
NAND event status and clear NAND events.

The NAND events of interest are TERMCOUNT and FIFOEVENT.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/memory/omap-gpmc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/omap-gpmc.h  |  4 ++++
 2 files changed, 54 insertions(+)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index e70a8df..713d7af 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -1078,8 +1078,58 @@ static bool gpmc_nand_writebuffer_empty(void)
 	return false;
 }
 
+static int gpmc_nand_irq_enable(enum gpmc_nand_irq irq)
+{
+	u32 reg;
+
+	if (irq > GPMC_NAND_IRQ_TERMCOUNT)
+		return -EINVAL;
+
+	reg = gpmc_read_reg(GPMC_IRQENABLE);
+	reg |= BIT(irq);
+	gpmc_write_reg(GPMC_IRQENABLE, reg);
+
+	return 0;
+}
+
+static int gpmc_nand_irq_disable(enum gpmc_nand_irq irq)
+{
+	u32 reg;
+
+	if (irq > GPMC_NAND_IRQ_TERMCOUNT)
+		return -EINVAL;
+
+	reg = gpmc_read_reg(GPMC_IRQENABLE);
+	reg &= ~BIT(irq);
+	gpmc_write_reg(GPMC_IRQENABLE, reg);
+
+	return 0;
+}
+
+static void gpmc_nand_irq_clear(enum gpmc_nand_irq irq)
+{
+	if (irq > GPMC_NAND_IRQ_TERMCOUNT)
+		return;
+
+	/* setting bit to 1 clears the bit in IRQSTATUS */
+	gpmc_write_reg(GPMC_IRQSTATUS, BIT(irq));
+}
+
+static u32 gpmc_nand_irq_status(void)
+{
+	u32 reg = gpmc_read_reg(GPMC_IRQSTATUS);
+
+	/* Mask out non-NAND bits */
+	reg &= GPMC_IRQENABLE_FIFOEVENT | GPMC_IRQENABLE_TERMCOUNT;
+	return reg;
+}
+
 static struct gpmc_nand_ops nand_ops = {
 	.nand_writebuffer_empty = gpmc_nand_writebuffer_empty,
+	.nand_irq_enable = gpmc_nand_irq_enable,
+	.nand_irq_disable = gpmc_nand_irq_disable,
+	.nand_irq_clear = gpmc_nand_irq_clear,
+	.nand_irq_status = gpmc_nand_irq_status,
 };
 
 /**
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index 44e322f..063a84f 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -11,6 +11,10 @@
 
 #define GPMC_CONFIG_WP		0x00000005
 
+/* GPMC IRQENABLE/IRQSTATUS BIT defs */
+#define GPMC_IRQENABLE_FIFOEVENT	BIT(0)
+#define GPMC_IRQENABLE_TERMCOUNT	BIT(1)
+
 enum gpmc_nand_irq {
 	GPMC_NAND_IRQ_FIFOEVENT = 0,
 	GPMC_NAND_IRQ_TERMCOUNT,
-- 
2.1.4


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

* [PATCH v2 09/22] mtd: nand: omap2: manage NAND interrupts
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (7 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 08/22] memory: omap-gpmc: Add IRQ ops for GPMC-NAND interface Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 10/22] mtd: nand: omap: Copy platform data parameters to omap_nand_info data Roger Quadros
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Manage NAND interrupts here using the GPMC IRQ ops.

This causes performance in prefetch-irq mode to be increased

from
[   38.252811] mtd_speedtest: eraseblock write speed is 5576 KiB/s
[   39.265259] mtd_speedtest: eraseblock read speed is 8192 KiB/s

to
[   35.666446] mtd_speedtest: eraseblock write speed is 6537 KiB/s
[   36.444842] mtd_speedtest: eraseblock read speed is 10680 KiB/s

Test results on dra7-evm using mtd_speedtest.ko

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/nand/omap2.c | 63 +++++++++++++++++++++++-------------------------
 1 file changed, 30 insertions(+), 33 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 5c2f6df..cabc5ea 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -162,8 +162,7 @@ struct omap_nand_info {
 	enum omap_ecc			ecc_opt;
 	struct completion		comp;
 	struct dma_chan			*dma;
-	int				gpmc_irq_fifo;
-	int				gpmc_irq_count;
+	int				gpmc_irq;
 	enum {
 		OMAP_NAND_IO_READ = 0,	/* read */
 		OMAP_NAND_IO_WRITE,	/* write */
@@ -573,12 +572,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 {
 	struct omap_nand_info *info = (struct omap_nand_info *) dev;
 	u32 bytes;
+	u32 irqstatus;
+
+	irqstatus = info->ops->nand_irq_status();
+	if (!irqstatus)
+		return IRQ_NONE;
 
 	bytes = readl(info->reg.gpmc_prefetch_status);
 	bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
 	bytes = bytes  & 0xFFFC; /* io in multiple of 4 bytes */
 	if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
-		if (this_irq == info->gpmc_irq_count)
+		if (irqstatus & GPMC_IRQENABLE_TERMCOUNT)
 			goto done;
 
 		if (info->buf_len && (info->buf_len < bytes))
@@ -595,17 +599,25 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
 						(u32 *)info->buf, bytes >> 2);
 		info->buf = info->buf + bytes;
 
-		if (this_irq == info->gpmc_irq_count)
+		if (irqstatus & GPMC_IRQENABLE_TERMCOUNT)
 			goto done;
 	}
 
+	/* Clear FIFOEVENT STATUS */
+	info->ops->nand_irq_clear(GPMC_NAND_IRQ_FIFOEVENT);
+
 	return IRQ_HANDLED;
 
 done:
 	complete(&info->comp);
 
-	disable_irq_nosync(info->gpmc_irq_fifo);
-	disable_irq_nosync(info->gpmc_irq_count);
+	/* Clear FIFOEVENT and TERMCOUNT STATUS */
+	info->ops->nand_irq_clear(GPMC_NAND_IRQ_FIFOEVENT);
+	info->ops->nand_irq_clear(GPMC_NAND_IRQ_TERMCOUNT);
+
+	/* Disable Interrupt generation */
+	info->ops->nand_irq_disable(GPMC_NAND_IRQ_FIFOEVENT);
+	info->ops->nand_irq_disable(GPMC_NAND_IRQ_TERMCOUNT);
 
 	return IRQ_HANDLED;
 }
@@ -640,8 +652,9 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
 
 	info->buf_len = len;
 
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
+	/* Enable Interrupt generation */
+	info->ops->nand_irq_enable(GPMC_NAND_IRQ_TERMCOUNT);
+	info->ops->nand_irq_enable(GPMC_NAND_IRQ_FIFOEVENT);
 
 	/* waiting for read to complete */
 	wait_for_completion(&info->comp);
@@ -690,8 +703,9 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
 
 	info->buf_len = len;
 
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
+	/* Enable Interrupt generation */
+	info->ops->nand_irq_enable(GPMC_NAND_IRQ_TERMCOUNT);
+	info->ops->nand_irq_enable(GPMC_NAND_IRQ_FIFOEVENT);
 
 	/* waiting for write to complete */
 	wait_for_completion(&info->comp);
@@ -1770,35 +1784,18 @@ static int omap_nand_probe(struct platform_device *pdev)
 		break;
 
 	case NAND_OMAP_PREFETCH_IRQ:
-		info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
-		if (info->gpmc_irq_fifo <= 0) {
-			dev_err(&pdev->dev, "error getting fifo irq\n");
-			err = -ENODEV;
-			goto return_error;
-		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-fifo", info);
-		if (err) {
-			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_fifo, err);
-			info->gpmc_irq_fifo = 0;
-			goto return_error;
-		}
-
-		info->gpmc_irq_count = platform_get_irq(pdev, 1);
-		if (info->gpmc_irq_count <= 0) {
-			dev_err(&pdev->dev, "error getting count irq\n");
+		info->gpmc_irq = platform_get_irq(pdev, 0);
+		if (info->gpmc_irq <= 0) {
+			dev_err(&pdev->dev, "error getting GPMC irq\n");
 			err = -ENODEV;
 			goto return_error;
 		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
+		err = devm_request_irq(&pdev->dev, info->gpmc_irq,
 					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-count", info);
+					DRIVER_NAME, info);
 		if (err) {
 			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_count, err);
-			info->gpmc_irq_count = 0;
+						info->gpmc_irq, err);
 			goto return_error;
 		}
 
-- 
2.1.4


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

* [PATCH v2 10/22] mtd: nand: omap: Copy platform data parameters to omap_nand_info data
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (8 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 09/22] mtd: nand: omap2: manage NAND interrupts Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 11/22] mtd: nand: omap: Clean up device tree support Roger Quadros
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Copy all the platform data parameters to the driver's local data
structure 'omap_nand_info' and use it in the entire driver. This will
make it easer for device tree migration.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/nand/omap2.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index cabc5ea..589404c 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -152,14 +152,18 @@ static struct nand_hw_control omap_gpmc_controller = {
 };
 
 struct omap_nand_info {
-	struct omap_nand_platform_data	*pdata;
 	struct mtd_info			mtd;
 	struct nand_chip		nand;
 	struct platform_device		*pdev;
 
 	int				gpmc_cs;
-	unsigned long			phys_base;
+	bool				dev_ready;
+	enum nand_io			xfer_type;
+	int				devsize;
 	enum omap_ecc			ecc_opt;
+	struct device_node		*elm_of_node;
+
+	unsigned long			phys_base;
 	struct completion		comp;
 	struct dma_chan			*dma;
 	int				gpmc_irq;
@@ -1650,7 +1654,7 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info,
 			"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
 		return false;
 	}
-	if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) {
+	if (ecc_needs_elm && !is_elm_present(info, info->elm_of_node)) {
 		dev_err(&info->pdev->dev, "ELM not available\n");
 		return false;
 	}
@@ -1695,6 +1699,11 @@ static int omap_nand_probe(struct platform_device *pdev)
 	info->gpmc_cs		= pdata->cs;
 	info->of_node		= pdata->of_node;
 	info->ecc_opt		= pdata->ecc_opt;
+	info->dev_ready	= pdata->dev_ready;
+	info->xfer_type = pdata->xfer_type;
+	info->devsize = pdata->devsize;
+	info->elm_of_node = pdata->elm_of_node;
+
 	mtd			= &info->mtd;
 	mtd->priv		= &info->nand;
 	mtd->name		= dev_name(&pdev->dev);
@@ -1721,7 +1730,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	 * chip delay which is slightly more than tR (AC Timing) of the NAND
 	 * device and read status register until you get a failure or success
 	 */
-	if (pdata->dev_ready) {
+	if (info->dev_ready) {
 		nand_chip->dev_ready = omap_dev_ready;
 		nand_chip->chip_delay = 0;
 	} else {
@@ -1735,15 +1744,16 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->options |= NAND_SKIP_BBTSCAN;
 
 	/* scan NAND device connected to chip controller */
-	nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
+	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
 	if (nand_scan_ident(mtd, 1, NULL)) {
-		dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n");
+		dev_err(&info->pdev->dev,
+			"scan failed, may be bus-width mismatch\n");
 		err = -ENXIO;
 		goto return_error;
 	}
 
 	/* re-populate low-level callbacks based on xfer modes */
-	switch (pdata->xfer_type) {
+	switch (info->xfer_type) {
 	case NAND_OMAP_PREFETCH_POLLED:
 		nand_chip->read_buf   = omap_read_buf_pref;
 		nand_chip->write_buf  = omap_write_buf_pref;
@@ -1806,7 +1816,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 	default:
 		dev_err(&pdev->dev,
-			"xfer_type(%d) not supported!\n", pdata->xfer_type);
+			"xfer_type(%d) not supported!\n", info->xfer_type);
 		err = -EINVAL;
 		goto return_error;
 	}
-- 
2.1.4


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

* [PATCH v2 11/22] mtd: nand: omap: Clean up device tree support
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (9 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 10/22] mtd: nand: omap: Copy platform data parameters to omap_nand_info data Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 12/22] mtd: nand: omap: Update DT binding documentation Roger Quadros
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Move NAND specific device tree parsing to NAND driver.

The NAND controller node must have a compatible id, register space
resource and interrupt resource.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/mach-omap2/gpmc-nand.c              |   5 +-
 drivers/memory/omap-gpmc.c                   | 135 ++++++--------------------
 drivers/mtd/nand/omap2.c                     | 136 +++++++++++++++++++++++----
 include/linux/platform_data/mtd-nand-omap2.h |   3 +-
 4 files changed, 147 insertions(+), 132 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index ffe646a..e07ca27 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -95,10 +95,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
 	gpmc_nand_res[1].start = gpmc_get_irq();
 
 	memset(&s, 0, sizeof(struct gpmc_settings));
-	if (gpmc_nand_data->of_node)
-		gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
-	else
-		gpmc_set_legacy(gpmc_nand_data, &s);
+	gpmc_set_legacy(gpmc_nand_data, &s);
 
 	s.device_nand = true;
 
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 713d7af..1c87252 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -29,7 +29,6 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/omap-gpmc.h>
-#include <linux/mtd/nand.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/platform_data/mtd-nand-omap2.h>
@@ -1716,105 +1715,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
 		of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#if IS_ENABLED(CONFIG_MTD_NAND)
-
-static const char * const nand_xfer_types[] = {
-	[NAND_OMAP_PREFETCH_POLLED]		= "prefetch-polled",
-	[NAND_OMAP_POLLED]			= "polled",
-	[NAND_OMAP_PREFETCH_DMA]		= "prefetch-dma",
-	[NAND_OMAP_PREFETCH_IRQ]		= "prefetch-irq",
-};
-
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	u32 val;
-	const char *s;
-	struct gpmc_timings gpmc_t;
-	struct omap_nand_platform_data *gpmc_nand_data;
-
-	if (of_property_read_u32(child, "reg", &val) < 0) {
-		dev_err(&pdev->dev, "%s has no 'reg' property\n",
-			child->full_name);
-		return -ENODEV;
-	}
-
-	gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
-				      GFP_KERNEL);
-	if (!gpmc_nand_data)
-		return -ENOMEM;
-
-	gpmc_nand_data->cs = val;
-	gpmc_nand_data->of_node = child;
-
-	/* Detect availability of ELM module */
-	gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
-	if (gpmc_nand_data->elm_of_node == NULL)
-		gpmc_nand_data->elm_of_node =
-					of_parse_phandle(child, "elm_id", 0);
-
-	/* select ecc-scheme for NAND */
-	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
-		pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
-		return -ENODEV;
-	}
-
-	if (!strcmp(s, "sw"))
-		gpmc_nand_data->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
-	else if (!strcmp(s, "ham1") ||
-		 !strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
-		gpmc_nand_data->ecc_opt =
-				OMAP_ECC_HAM1_CODE_HW;
-	else if (!strcmp(s, "bch4"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
-	else if (!strcmp(s, "bch8"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW;
-		else
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
-	else if (!strcmp(s, "bch16"))
-		if (gpmc_nand_data->elm_of_node)
-			gpmc_nand_data->ecc_opt =
-				OMAP_ECC_BCH16_CODE_HW;
-		else
-			pr_err("%s: BCH16 requires ELM support\n", __func__);
-	else
-		pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__);
-
-	/* select data transfer mode for NAND controller */
-	if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
-		for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
-			if (!strcasecmp(s, nand_xfer_types[val])) {
-				gpmc_nand_data->xfer_type = val;
-				break;
-			}
-
-	gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child);
-
-	val = of_get_nand_bus_width(child);
-	if (val == 16)
-		gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
-
-	gpmc_read_timings_dt(child, &gpmc_t);
-	gpmc_nand_init(gpmc_nand_data, &gpmc_t);
-
-	return 0;
-}
-#else
-static int gpmc_probe_nand_child(struct platform_device *pdev,
-				 struct device_node *child)
-{
-	return 0;
-}
-#endif
-
 #if IS_ENABLED(CONFIG_MTD_ONENAND)
 static int gpmc_probe_onenand_child(struct platform_device *pdev,
 				 struct device_node *child)
@@ -1933,9 +1833,34 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 		goto err;
 	}
 
-	ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
-	if (ret < 0)
-		goto err;
+	if (of_node_cmp(child->name, "nand") == 0) {
+		/* NAND specific setup */
+		u32 val;
+
+		val = of_get_nand_bus_width(child);
+		switch (val) {
+		case 8:
+			gpmc_s.device_width = GPMC_DEVWIDTH_8BIT;
+			break;
+		case 16:
+			gpmc_s.device_width = GPMC_DEVWIDTH_16BIT;
+			break;
+		default:
+			dev_err(&pdev->dev, "%s: invalid 'nand-bus-width'\n",
+				child->name);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		/* disable write protect */
+		gpmc_configure(GPMC_CONFIG_WP, 0);
+		gpmc_s.device_nand = true;
+	} else {
+		ret = of_property_read_u32(child, "bank-width",
+					   &gpmc_s.device_width);
+		if (ret < 0)
+			goto err;
+	}
 
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
 	if (ret < 0)
@@ -2018,9 +1943,7 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		if (!child->name)
 			continue;
 
-		if (of_node_cmp(child->name, "nand") == 0)
-			ret = gpmc_probe_nand_child(pdev, child);
-		else if (of_node_cmp(child->name, "onenand") == 0)
+		if (of_node_cmp(child->name, "onenand") == 0)
 			ret = gpmc_probe_onenand_child(pdev, child);
 		else
 			ret = gpmc_probe_generic_child(pdev, child);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 589404c..b009d1d 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_mtd.h>
 
 #include <linux/mtd/nand_bch.h>
 #include <linux/platform_data/elm.h>
@@ -177,6 +178,8 @@ struct omap_nand_info {
 	struct gpmc_nand_regs		reg;
 	struct gpmc_nand_ops		*ops;
 	/* generated at runtime depending on ECC algorithm and layout selected */
+	bool				flash_bbt;
+	/* generated at runtime depending on ECC algorithm and layout */
 	struct nand_ecclayout		oobinfo;
 	/* fields specific for BCHx_HW ECC scheme */
 	struct device			*elm_dev;
@@ -1662,10 +1665,84 @@ static bool omap2_nand_ecc_check(struct omap_nand_info *info,
 	return true;
 }
 
+static const char * const nand_xfer_types[] = {
+	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
+	[NAND_OMAP_POLLED] = "polled",
+	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
+	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
+};
+
+static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
+{
+	struct device_node *child = dev->of_node;
+	int i;
+	const char *s;
+
+	/* In old bindings, CS num is embedded in reg property */
+	if (of_property_read_u32(child, "reg", &info->gpmc_cs) < 0) {
+		dev_err(dev, "reg not found in DT\n");
+		return -EINVAL;
+	}
+
+	/* detect availability of ELM module. Won't be present pre-OMAP4 */
+	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
+	if (info->elm_of_node == NULL)
+		dev_dbg(dev, "ti,elm-id not in DT\n");
+
+	/* select ecc-scheme for NAND */
+	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
+		dev_err(dev, "ti,nand-ecc-opt not found\n");
+		return -EINVAL;
+	}
+
+	if (!strcmp(s, "sw"))
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
+	else if (!strcmp(s, "ham1") ||
+		 !strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
+		info->ecc_opt =	OMAP_ECC_HAM1_CODE_HW;
+	else if (!strcmp(s, "bch4")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
+	} else if (!strcmp(s, "bch8")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
+	} else if (!strcmp(s, "bch16")) {
+		info->ecc_opt =	OMAP_ECC_BCH16_CODE_HW;
+	} else {
+		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
+		return -EINVAL;
+	}
+
+	/* select data transfer mode */
+	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
+		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
+			if (!strcasecmp(s, nand_xfer_types[i])) {
+				info->xfer_type = i;
+				goto next;
+			}
+		}
+
+		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
+		return -EINVAL;
+	}
+
+next:
+	of_get_nand_on_flash_bbt(child);
+
+	if (of_get_nand_bus_width(child) == 16)
+		info->devsize = NAND_BUSWIDTH_16;
+
+	return 0;
+}
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
 	struct omap_nand_info		*info;
-	struct omap_nand_platform_data	*pdata;
+	struct omap_nand_platform_data	*pdata = NULL;
 	struct mtd_info			*mtd;
 	struct nand_chip		*nand_chip;
 	struct nand_ecclayout		*ecclayout;
@@ -1676,33 +1753,42 @@ static int omap_nand_probe(struct platform_device *pdev)
 	unsigned			oob_index;
 	struct resource			*res;
 	struct mtd_part_parser_data	ppdata = {};
-
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENODEV;
-	}
+	struct device			*dev = &pdev->dev;
 
 	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
 				GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, info);
+	info->pdev = pdev;
 
+	if (dev->of_node) {
+		if (omap_get_dt_info(dev, info))
+			return -EINVAL;
+	} else {
+		pdata = dev_get_platdata(&pdev->dev);
+		if (pdata == NULL) {
+			dev_err(&pdev->dev, "platform data missing\n");
+			return -EINVAL;
+		}
+
+		info->gpmc_cs = pdata->cs;
+		info->reg = pdata->reg;
+		info->of_node = pdata->of_node;
+		info->ecc_opt = pdata->ecc_opt;
+		info->dev_ready	= pdata->dev_ready;
+		info->xfer_type = pdata->xfer_type;
+		info->devsize = pdata->devsize;
+		info->elm_of_node = pdata->elm_of_node;
+		info->flash_bbt = pdata->flash_bbt;
+	}
+
+	platform_set_drvdata(pdev, info);
 	info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
 	if (!info->ops) {
 		dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
 		return -ENODEV;
 	}
-	info->pdev		= pdev;
-	info->gpmc_cs		= pdata->cs;
-	info->of_node		= pdata->of_node;
-	info->ecc_opt		= pdata->ecc_opt;
-	info->dev_ready	= pdata->dev_ready;
-	info->xfer_type = pdata->xfer_type;
-	info->devsize = pdata->devsize;
-	info->elm_of_node = pdata->elm_of_node;
 
 	mtd			= &info->mtd;
 	mtd->priv		= &info->nand;
@@ -1738,7 +1824,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 		nand_chip->chip_delay = 50;
 	}
 
-	if (pdata->flash_bbt)
+	if (info->flash_bbt)
 		nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
 	else
 		nand_chip->options |= NAND_SKIP_BBTSCAN;
@@ -2043,9 +2129,13 @@ scan_tail:
 		goto return_error;
 	}
 
-	ppdata.of_node = pdata->of_node;
-	mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts,
-				  pdata->nr_parts);
+	if (dev->of_node) {
+		ppdata.of_node = dev->of_node;
+		mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+
+	} else {
+		mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
+	}
 
 	platform_set_drvdata(pdev, mtd);
 
@@ -2077,11 +2167,17 @@ static int omap_nand_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id omap_nand_ids[] = {
+	{ .compatible = "ti,omap2-nand", },
+	{},
+};
+
 static struct platform_driver omap_nand_driver = {
 	.probe		= omap_nand_probe,
 	.remove		= omap_nand_remove,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.of_match_table = of_match_ptr(omap_nand_ids),
 	},
 };
 
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index a067f58..ff27e5a 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -76,11 +76,10 @@ struct omap_nand_platform_data {
 	int			devsize;
 	enum omap_ecc           ecc_opt;
 
-	/* for passing the partitions */
-	struct device_node	*of_node;
 	struct device_node	*elm_of_node;
 
 	/* deprecated */
 	struct gpmc_nand_regs	reg;
+	struct device_node	*of_node;
 };
 #endif
-- 
2.1.4


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

* [PATCH v2 12/22] mtd: nand: omap: Update DT binding documentation
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (10 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 11/22] mtd: nand: omap: Clean up device tree support Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 13/22] memory: omap-gpmc: Prevent mapping into 1st 16MB Roger Quadros
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Add compatible id and interrupts. The NAND interrupts are
provided by the GPMC controller node.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
index fb733c4..253e6de 100644
--- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -13,7 +13,11 @@ Documentation/devicetree/bindings/mtd/nand.txt
 
 Required properties:
 
- - reg:		The CS line the peripheral is connected to
+ - compatible:	"ti,omap2-nand"
+ - reg:		range id (CS number), base offset and length of the
+		NAND I/O space
+ - interrupt-parent: must point to gpmc node
+ - interrupts: gpmc interrupt
 
 Optional properties:
 
@@ -55,20 +59,24 @@ Example for an AM33xx board:
 	gpmc: gpmc@50000000 {
 		compatible = "ti,am3352-gpmc";
 		ti,hwmods = "gpmc";
-		reg = <0x50000000 0x1000000>;
+		reg = <0x50000000 0x36c>;
 		interrupts = <100>;
 		gpmc,num-cs = <8>;
 		gpmc,num-waitpins = <2>;
 		#address-cells = <2>;
 		#size-cells = <1>;
-		ranges = <0 0 0x08000000 0x2000>;	/* CS0: NAND */
+		ranges = <0 0 0x08000000 0x1000000>;	/* CS0 space, 16MB */
 		elm_id = <&elm>;
 
 		nand@0,0 {
-			reg = <0 0 0>; /* CS0, offset 0 */
+			compatible = "ti,omap2-nand";
+			reg = <0 0 4>;		/* CS0, offset 0, NAND I/O window 4 */
+			interrupts = <100>;
 			nand-bus-width = <16>;
 			ti,nand-ecc-opt = "bch8";
 			ti,nand-xfer-type = "polled";
+			interrupt-parent = <&gpmc>;
+			interrupts = <0>, <1>;
 
 			gpmc,sync-clk-ps = <0>;
 			gpmc,cs-on-ns = <0>;
-- 
2.1.4


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

* [PATCH v2 13/22] memory: omap-gpmc: Prevent mapping into 1st 16MB
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (11 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 12/22] mtd: nand: omap: Update DT binding documentation Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 14/22] ARM: dts: OMAP2+: Fix NAND device nodes Roger Quadros
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

We have been preventing mapping GPMC children in the
first 1MB but really it has to be the first 16MB as
the minimum GPMC partition size is 16MB.

Also print an error message if CS mapping fails
due to DT requesting address outside the GPMC
map.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/memory/omap-gpmc.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 1c87252..30d9c21 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -93,6 +93,14 @@
 #define GPMC_CS_SIZE		0x30
 #define	GPMC_BCH_SIZE		0x10
 
+/*
+ * The first 1MB of GPMC address space is typically mapped to
+ * the internal ROM. Never allocate the first page, to
+ * facilitate bug detection; even if we didn't boot from ROM.
+ * As GPMC minimum partition size is 16MB we can only start from
+ * there.
+ */
+#define GPMC_MEM_START		0x1000000
 #define GPMC_MEM_END		0x3FFFFFFF
 
 #define GPMC_CHUNK_SHIFT	24		/* 16 MB */
@@ -1171,12 +1179,7 @@ static void gpmc_mem_init(void)
 {
 	int cs;
 
-	/*
-	 * The first 1MB of GPMC address space is typically mapped to
-	 * the internal ROM. Never allocate the first page, to
-	 * facilitate bug detection; even if we didn't boot from ROM.
-	 */
-	gpmc_mem_root.start = SZ_1M;
+	gpmc_mem_root.start = GPMC_MEM_START;
 	gpmc_mem_root.end = GPMC_MEM_END;
 
 	/* Reserve all regions that has been set up by bootloader */
@@ -1830,6 +1833,15 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 	if (ret < 0) {
 		dev_err(&pdev->dev, "cannot remap GPMC CS %d to %pa\n",
 			cs, &res.start);
+		if (res.start < GPMC_MEM_START) {
+			dev_info(&pdev->dev,
+				 "GPMC CS %d start cannot be lesser than 0x%x\n",
+				 cs, GPMC_MEM_START);
+		} else if (res.end > GPMC_MEM_END) {
+			dev_info(&pdev->dev,
+				 "GPMC CS %d end cannot be greater than 0x%x\n",
+				 cs, GPMC_MEM_END);
+		}
 		goto err;
 	}
 
-- 
2.1.4


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

* [PATCH v2 14/22] ARM: dts: OMAP2+: Fix NAND device nodes.
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (12 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 13/22] memory: omap-gpmc: Prevent mapping into 1st 16MB Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 15/22] memory: omap-gpmc: Move device tree binding to correct location Roger Quadros
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

Add compatible id, GPMC register resource and interrupt
resource to NAND controller nodes.

TODO: For now only dra7-evm and omap3-beagle are fixed.
Once series is reviewed I'll update this patch to
fix all omap boards.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/dra7-evm.dts     | 4 +++-
 arch/arm/boot/dts/omap3-beagle.dts | 3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index 096f68b..ce11b0f 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -569,9 +569,11 @@
 	status = "okay";
 	pinctrl-names = "default";
 	pinctrl-0 = <&nand_flash_x16>;
-	ranges = <0 0 0 0x01000000>;	/* minimum GPMC partition = 16MB */
+	ranges = <0 0 0x08000000 0x01000000>;	/* minimum GPMC partition = 16MB */
 	nand@0,0 {
+		compatible = "ti,omap2-nand";
 		reg = <0 0 4>;		/* device IO registers */
+		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <16>;
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index a547411..34cf55e 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -384,7 +384,8 @@
 
 	/* Chip select 0 */
 	nand@0,0 {
-		reg = <0 0 4>;		/* NAND I/O window, 4 bytes */
+		compatible = "ti,omap2-nand";
+		reg = <0 0 4>;		/* CS0, offset 0, IO size 4 */
 		interrupts = <20>;
 		ti,nand-ecc-opt = "ham1";
 		nand-bus-width = <16>;
-- 
2.1.4


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

* [PATCH v2 15/22] memory: omap-gpmc: Move device tree binding to correct location
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (13 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 14/22] ARM: dts: OMAP2+: Fix NAND device nodes Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 16/22] memory: omap-gpmc: Support general purpose input for WAITPINs Roger Quadros
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

omap-gpmc.c is a memory controller so move the binding to the
right place.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../bindings/{bus/ti-gpmc.txt => memory-controllers/omap-gpmc.txt}        | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename Documentation/devicetree/bindings/{bus/ti-gpmc.txt => memory-controllers/omap-gpmc.txt} (100%)

diff --git a/Documentation/devicetree/bindings/bus/ti-gpmc.txt b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
similarity index 100%
rename from Documentation/devicetree/bindings/bus/ti-gpmc.txt
rename to Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
-- 
2.1.4


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

* [PATCH v2 16/22] memory: omap-gpmc: Support general purpose input for WAITPINs
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (14 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 15/22] memory: omap-gpmc: Move device tree binding to correct location Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-13 11:58   ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 17/22] memory: omap-gpmc: Reserve WAITPIN if needed for WAIT monitoring Roger Quadros
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

OMAPs can have 2 to 4 WAITPINs that can be used as general purpose
input if not used for memory wait state insertion.

The first user will be the OMAP NAND chip to get the NAND
read/busy status using gpiolib.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/memory/omap-gpmc.c | 122 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 117 insertions(+), 5 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 30d9c21..264009d 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
@@ -223,6 +224,11 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
+struct gpmc_device {
+	struct device *dev;
+	struct gpio_chip gpio_chip;
+};
+
 static struct resource	gpmc_mem_root;
 static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -1919,10 +1925,69 @@ err:
 	return ret;
 }
 
+static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	return 1;	/* we're input only */
+}
+
+static int gpmc_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	return 0;	/* we're input only */
+}
+
+static int gpmc_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+				      int value)
+{
+	return -EINVAL;	/* we're input only */
+}
+
+static void gpmc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+}
+
+static int gpmc_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	u32 reg;
+
+	offset += 8;
+
+	reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset);
+
+	return !!reg;
+}
+
+static int gpmc_gpio_init(struct gpmc_device *gpmc)
+{
+	int ret;
+
+	gpmc->gpio_chip.dev = gpmc->dev;
+	gpmc->gpio_chip.owner = THIS_MODULE;
+	gpmc->gpio_chip.label = DEVICE_NAME;
+	gpmc->gpio_chip.ngpio = gpmc_nr_waitpins;
+	gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction;
+	gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input;
+	gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output;
+	gpmc->gpio_chip.set = gpmc_gpio_set;
+	gpmc->gpio_chip.get = gpmc_gpio_get;
+	gpmc->gpio_chip.base = -1;
+
+	ret = gpiochip_add(&gpmc->gpio_chip);
+	if (ret < 0) {
+		dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void gpmc_gpio_exit(struct gpmc_device *gpmc)
+{
+	gpiochip_remove(&gpmc->gpio_chip);
+}
+
 static int gpmc_probe_dt(struct platform_device *pdev)
 {
 	int ret;
-	struct device_node *child;
 	const struct of_device_id *of_id =
 		of_match_device(gpmc_dt_ids, &pdev->dev);
 
@@ -1950,6 +2015,17 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 		return ret;
 	}
 
+	dev_info(&pdev->dev, "num-cs %d, num-wait %d\n",
+		 gpmc_cs_num, gpmc_nr_waitpins);
+
+	return 0;
+}
+
+static int gpmc_probe_dt_children(struct platform_device *pdev)
+{
+	int ret;
+	struct device_node *child;
+
 	for_each_available_child_of_node(pdev->dev.of_node, child) {
 
 		if (!child->name)
@@ -1959,6 +2035,9 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 			ret = gpmc_probe_onenand_child(pdev, child);
 		else
 			ret = gpmc_probe_generic_child(pdev, child);
+
+		if (ret)
+			return ret;
 	}
 
 	return 0;
@@ -1968,6 +2047,11 @@ static int gpmc_probe_dt(struct platform_device *pdev)
 {
 	return 0;
 }
+
+static int gpmc_probe_dt_children(struct platform_device *pdev)
+{
+	return 0;
+}
 #endif
 
 static int gpmc_probe(struct platform_device *pdev)
@@ -1975,6 +2059,7 @@ static int gpmc_probe(struct platform_device *pdev)
 	int rc;
 	u32 l;
 	struct resource *res;
+	struct gpmc_device *gpmc;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL)
@@ -2005,6 +2090,17 @@ static int gpmc_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
+	rc = gpmc_probe_dt(pdev);
+	if (rc)
+		return rc;
+
+	gpmc = devm_kzalloc(&pdev->dev, sizeof(*gpmc), GFP_KERNEL);
+	if (!gpmc)
+		return -ENOMEM;
+
+	gpmc->dev = &pdev->dev;
+	platform_set_drvdata(pdev, gpmc);
+
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
@@ -2032,24 +2128,40 @@ static int gpmc_probe(struct platform_device *pdev)
 		 GPMC_REVISION_MINOR(l));
 
 	gpmc_mem_init();
+	rc = gpmc_gpio_init(gpmc);
+	if (rc)
+		goto gpio_init_failed;
+
 
 	if (!pdev->dev.of_node) {
 		gpmc_cs_num	 = GPMC_CS_NUM;
 		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
 	}
 
-	rc = gpmc_probe_dt(pdev);
+	rc = gpmc_probe_dt_children(pdev);
 	if (rc < 0) {
-		pm_runtime_put_sync(&pdev->dev);
-		dev_err(gpmc_dev, "failed to probe DT parameters\n");
-		return rc;
+		dev_err(gpmc_dev, "failed to probe DT children\n");
+		goto dt_children_failed;
 	}
 
 	return 0;
+
+dt_children_failed:
+	gpmc_gpio_exit(gpmc);
+gpio_init_failed:
+	gpmc_mem_exit();
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	gpmc_dev = NULL;
+
+	return rc;
 }
 
 static int gpmc_remove(struct platform_device *pdev)
 {
+	struct gpmc_device *gpmc = platform_get_drvdata(pdev);
+
+	gpmc_gpio_exit(gpmc);
 	gpmc_mem_exit();
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
-- 
2.1.4


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

* [PATCH v2 17/22] memory: omap-gpmc: Reserve WAITPIN if needed for WAIT monitoring
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (15 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 16/22] memory: omap-gpmc: Support general purpose input for WAITPINs Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 18/22] memory: omap-gpmc: Add irqchip support to the gpiochip Roger Quadros
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

If the device attached to GPMC wants to use the WAIT pin
for WAIT monitoring then we reserve it internally for
exclusive use.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/memory/omap-gpmc.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 264009d..0df70ab 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -1779,6 +1779,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 	const char *name;
 	int ret, cs;
 	u32 val;
+	struct gpio_desc *waitpin_desc = NULL;
+	struct gpmc_device *gpmc = platform_get_drvdata(pdev);
 
 	if (of_property_read_u32(child, "reg", &cs) < 0) {
 		dev_err(&pdev->dev, "%s has no 'reg' property\n",
@@ -1880,15 +1882,28 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
 			goto err;
 	}
 
+	/* Reserve wait pin if it is required and valid */
+	if (gpmc_s.wait_on_read || gpmc_s.wait_on_write) {
+		unsigned wait_pin = gpmc_s.wait_pin;
+
+		waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
+							 wait_pin, "WAITPIN");
+		if (IS_ERR(waitpin_desc)) {
+			dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
+			ret = PTR_ERR(waitpin_desc);
+			goto err;
+		}
+	}
+
 	ret = gpmc_cs_program_settings(cs, &gpmc_s);
 	if (ret < 0)
-		goto err;
+		goto err_cs;
 
 	ret = gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n",
 			child->name);
-		goto err;
+		goto err_cs;
 	}
 
 	/* Clear limited address i.e. enable A26-A11 */
@@ -1919,6 +1934,10 @@ err_child_fail:
 	dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
 	ret = -ENODEV;
 
+err_cs:
+	if (waitpin_desc)
+		gpiochip_free_own_desc(waitpin_desc);
+
 err:
 	gpmc_cs_free(cs);
 
-- 
2.1.4


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

* [PATCH v2 18/22] memory: omap-gpmc: Add irqchip support to the gpiochip
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (16 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 17/22] memory: omap-gpmc: Reserve WAITPIN if needed for WAIT monitoring Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 19/22] ARM: dts: dra7: Enable gpio & interrupt controller for gpmc node Roger Quadros
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

The WAIT pins support falling edge interrupts so add irqchip
support to the gpiochip model.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/memory/omap-gpmc.c | 111 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 0df70ab..417acce 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -13,6 +13,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -227,6 +228,7 @@ struct omap3_gpmc_regs {
 struct gpmc_device {
 	struct device *dev;
 	struct gpio_chip gpio_chip;
+	struct irq_chip	irq_chip;
 };
 
 static struct resource	gpmc_mem_root;
@@ -1944,6 +1946,79 @@ err:
 	return ret;
 }
 
+static int gpmc_irq_endis(unsigned long hwirq, bool endis)
+{
+	u32 regval;
+
+	/* WAITPIN starts at BIT 8 */
+	hwirq += 8;
+
+	regval = gpmc_read_reg(GPMC_IRQENABLE);
+	if (endis)
+		regval |= BIT(hwirq);
+	else
+		regval &= ~BIT(hwirq);
+	gpmc_write_reg(GPMC_IRQENABLE, regval);
+
+	return 0;
+}
+
+static void gpmc_irq_mask(struct irq_data *d)
+{
+	gpmc_irq_endis(d->hwirq, false);
+}
+
+static void gpmc_irq_unmask(struct irq_data *d)
+{
+	gpmc_irq_endis(d->hwirq, true);
+}
+
+static void gpmc_irq_ack(struct irq_data *d)
+{
+	unsigned hwirq = d->hwirq + 8;
+
+	/* Setting bit to 1 clears (or Acks) the interrupt */
+	gpmc_write_reg(GPMC_IRQSTATUS, BIT(hwirq));
+}
+
+static int gpmc_irq_set_type(struct irq_data *d, unsigned trigger)
+{
+	/* We only support falling edge interrupts */
+	if (trigger & ~IRQ_TYPE_EDGE_FALLING)
+		return -EINVAL;
+
+	return 0;
+}
+
+static irqreturn_t gpmc_handle_irq(int irq, void *data)
+{
+	int hwirq, virq;
+	u32 regval;
+	struct gpmc_device *gpmc = data;
+
+	regval = gpmc_read_reg(GPMC_IRQSTATUS);
+	regval >>= 8;	/* we're only interested in WAIT pins */
+
+	if (!regval)
+		return IRQ_NONE;
+
+	for (hwirq = 0; hwirq < gpmc->gpio_chip.ngpio; hwirq++) {
+		if (regval & BIT(hwirq)) {
+			virq = irq_find_mapping(gpmc->gpio_chip.irqdomain,
+						hwirq);
+			if (!virq) {
+				dev_warn(gpmc_dev,
+					 "spurious irq detected hwirq %d, virq %d\n",
+					 hwirq, virq);
+			}
+
+			generic_handle_irq(virq);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
 	return 1;	/* we're input only */
@@ -1978,6 +2053,7 @@ static int gpmc_gpio_get(struct gpio_chip *chip, unsigned offset)
 static int gpmc_gpio_init(struct gpmc_device *gpmc)
 {
 	int ret;
+	u32 regval;
 
 	gpmc->gpio_chip.dev = gpmc->dev;
 	gpmc->gpio_chip.owner = THIS_MODULE;
@@ -1996,7 +2072,42 @@ static int gpmc_gpio_init(struct gpmc_device *gpmc)
 		return ret;
 	}
 
+	/* Disable interrupts */
+	gpmc_write_reg(GPMC_IRQENABLE, 0);
+
+	/* clear interrupts */
+	regval = gpmc_read_reg(GPMC_IRQSTATUS);
+	gpmc_write_reg(GPMC_IRQSTATUS, regval);
+
+	gpmc->irq_chip.name = DEVICE_NAME;
+	gpmc->irq_chip.irq_ack = gpmc_irq_ack;
+	gpmc->irq_chip.irq_mask = gpmc_irq_mask;
+	gpmc->irq_chip.irq_unmask = gpmc_irq_unmask;
+	gpmc->irq_chip.irq_set_type = gpmc_irq_set_type;
+
+	ret = gpiochip_irqchip_add(&gpmc->gpio_chip, &gpmc->irq_chip, 0,
+				   handle_edge_irq, IRQ_TYPE_NONE);
+
+	if (ret) {
+		dev_err(gpmc->dev, "could not add irqchip to gpiochip: %d\n",
+			ret);
+		goto fail;
+	}
+
+	/* We're sharing this IRQ with OMAP NAND driver */
+	ret = request_irq(gpmc_irq, gpmc_handle_irq, IRQF_SHARED, "gpmc", gpmc);
+	if (ret) {
+		dev_err(gpmc->dev, "could not request gpmc irq (%d): %d\n",
+			gpmc_irq, ret);
+		goto fail;
+	}
+
 	return 0;
+
+fail:
+	gpiochip_remove(&gpmc->gpio_chip);
+
+	return ret;
 }
 
 static void gpmc_gpio_exit(struct gpmc_device *gpmc)
-- 
2.1.4


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

* [PATCH v2 19/22] ARM: dts: dra7: Enable gpio & interrupt controller for gpmc node
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (17 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 18/22] memory: omap-gpmc: Add irqchip support to the gpiochip Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 20/22] mtd: nand: omap2: Implement NAND ready using gpiolib Roger Quadros
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

The GPMC driver now implements gpiochip and irqchip so
enable gpio-controller and interrupt-controller properties.

With this the interrupt parent of NAND node changes so fix it
accordingly.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/dra7-evm.dts  | 1 +
 arch/arm/boot/dts/dra7.dtsi     | 4 ++++
 arch/arm/boot/dts/dra72-evm.dts | 1 +
 3 files changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index ce11b0f..3fb1ced 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -573,6 +573,7 @@
 	nand@0,0 {
 		compatible = "ti,omap2-nand";
 		reg = <0 0 4>;		/* device IO registers */
+		interrupt-parent = <&crossbar_mpu>;
 		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 8f1e25b..a4ab66d 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -1369,6 +1369,10 @@
 			gpmc,num-waitpins = <2>;
 			#address-cells = <2>;
 			#size-cells = <1>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
 			status = "disabled";
 		};
 
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index 8037384..fc0677a 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -386,6 +386,7 @@
 		 * SW5.9 (GPMC_WPN) = OFF (HIGH)
 		 */
 		reg = <0 0 4>;		/* device IO registers */
+		interrupt-parent = <&crossbar_mpu>;
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <16>;
-- 
2.1.4


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

* [PATCH v2 20/22] mtd: nand: omap2: Implement NAND ready using gpiolib
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (18 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 19/22] ARM: dts: dra7: Enable gpio & interrupt controller for gpmc node Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 21/22] ARM: dts: dra7x-evm: Provide NAND ready pin Roger Quadros
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

The GPMC WAIT pin status are now available over gpiolib.
Update the omap_dev_ready() function to use gpio instead of
directly accessing GPMC register space.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/mtd/nand/omap2.c                     | 29 +++++++++++++++++-----------
 include/linux/platform_data/mtd-nand-omap2.h |  2 +-
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index b009d1d..8ace767 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -12,6 +12,7 @@
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
@@ -184,6 +185,8 @@ struct omap_nand_info {
 	/* fields specific for BCHx_HW ECC scheme */
 	struct device			*elm_dev;
 	struct device_node		*of_node;
+	/* NAND ready gpio */
+	struct gpio_desc		*ready_gpiod;
 };
 
 /**
@@ -1041,22 +1044,17 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 }
 
 /**
- * omap_dev_ready - calls the platform specific dev_ready function
+ * omap_dev_ready - checks the NAND Ready GPIO line
  * @mtd: MTD device structure
+ *
+ * Returns true if ready and false if busy.
  */
 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);
 
-	val = readl(info->reg.gpmc_status);
-
-	if ((val & 0x100) == 0x100) {
-		return 1;
-	} else {
-		return 0;
-	}
+	return gpiod_get_value(info->ready_gpiod);
 }
 
 /**
@@ -1776,7 +1774,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 		info->reg = pdata->reg;
 		info->of_node = pdata->of_node;
 		info->ecc_opt = pdata->ecc_opt;
-		info->dev_ready	= pdata->dev_ready;
+		if (pdata->dev_ready)
+			dev_info(&pdev->dev, "pdata->dev_ready is deprecated\n");
+
 		info->xfer_type = pdata->xfer_type;
 		info->devsize = pdata->devsize;
 		info->elm_of_node = pdata->elm_of_node;
@@ -1809,6 +1809,13 @@ static int omap_nand_probe(struct platform_device *pdev)
 	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
 	nand_chip->cmd_ctrl  = omap_hwcontrol;
 
+	info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "ready",
+						    GPIOD_IN);
+	if (IS_ERR(info->ready_gpiod)) {
+		dev_err(dev, "failed to get ready gpio\n");
+		return PTR_ERR(info->ready_gpiod);
+	}
+
 	/*
 	 * If RDY/BSY line is connected to OMAP then use the omap ready
 	 * function and the generic nand_wait function which reads the status
@@ -1816,7 +1823,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	 * chip delay which is slightly more than tR (AC Timing) of the NAND
 	 * device and read status register until you get a failure or success
 	 */
-	if (info->dev_ready) {
+	if (info->ready_gpiod) {
 		nand_chip->dev_ready = omap_dev_ready;
 		nand_chip->chip_delay = 0;
 	} else {
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index ff27e5a..19e509d 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -70,7 +70,6 @@ struct omap_nand_platform_data {
 	int			cs;
 	struct mtd_partition	*parts;
 	int			nr_parts;
-	bool			dev_ready;
 	bool			flash_bbt;
 	enum nand_io		xfer_type;
 	int			devsize;
@@ -81,5 +80,6 @@ struct omap_nand_platform_data {
 	/* deprecated */
 	struct gpmc_nand_regs	reg;
 	struct device_node	*of_node;
+	bool			dev_ready;
 };
 #endif
-- 
2.1.4


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

* [PATCH v2 21/22] ARM: dts: dra7x-evm: Provide NAND ready pin
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (19 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 20/22] mtd: nand: omap2: Implement NAND ready using gpiolib Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-07  9:12 ` [PATCH v2 22/22] memory: omap-gpmc: Prevent GPMC_STATUS from being accessed via gpmc_regs Roger Quadros
  2015-08-11 12:48 ` [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Tony Lindgren
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

On these boards NAND ready pin status is avilable over
GPMC_WAIT0 pin.

Read speed increases from 13768 KiB/ to 17246 KiB/s.
Write speed was unchanged at 7123 KiB/s.
Measured using mtd_speedtest.ko.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 arch/arm/boot/dts/dra7-evm.dts  | 1 +
 arch/arm/boot/dts/dra72-evm.dts | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index 3fb1ced..b717fd0 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -575,6 +575,7 @@
 		reg = <0 0 4>;		/* device IO registers */
 		interrupt-parent = <&crossbar_mpu>;
 		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+		ready-gpio = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 pin */
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <16>;
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index fc0677a..c1a3397 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -387,6 +387,7 @@
 		 */
 		reg = <0 0 4>;		/* device IO registers */
 		interrupt-parent = <&crossbar_mpu>;
+		ready-gpio = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 pin */
 		ti,nand-ecc-opt = "bch8";
 		ti,elm-id = <&elm>;
 		nand-bus-width = <16>;
-- 
2.1.4


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

* [PATCH v2 22/22] memory: omap-gpmc: Prevent GPMC_STATUS from being accessed via gpmc_regs
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (20 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 21/22] ARM: dts: dra7x-evm: Provide NAND ready pin Roger Quadros
@ 2015-08-07  9:12 ` Roger Quadros
  2015-08-11 12:48 ` [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Tony Lindgren
  22 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-07  9:12 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel, Roger Quadros

GPMC_STATUS register is private to the GPMC module and must not be
accessed directly by NAND driver through the gpmc_regs.

They must use gpmc_omap_get_nand_ops() instead.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/memory/omap-gpmc.c                   | 2 +-
 include/linux/platform_data/mtd-nand-omap2.h | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 417acce..bdd1533 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -1051,7 +1051,7 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
 {
 	int i;
 
-	reg->gpmc_status = gpmc_base + GPMC_STATUS;
+	reg->gpmc_status = NULL;	/* deprecated */
 	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET +
 				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs;
 	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET +
diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h
index 19e509d..17d57a1 100644
--- a/include/linux/platform_data/mtd-nand-omap2.h
+++ b/include/linux/platform_data/mtd-nand-omap2.h
@@ -45,7 +45,6 @@ enum omap_ecc {
 };
 
 struct gpmc_nand_regs {
-	void __iomem	*gpmc_status;
 	void __iomem	*gpmc_nand_command;
 	void __iomem	*gpmc_nand_address;
 	void __iomem	*gpmc_nand_data;
@@ -64,6 +63,8 @@ struct gpmc_nand_regs {
 	void __iomem	*gpmc_bch_result4[GPMC_BCH_NUM_REMAINDER];
 	void __iomem	*gpmc_bch_result5[GPMC_BCH_NUM_REMAINDER];
 	void __iomem	*gpmc_bch_result6[GPMC_BCH_NUM_REMAINDER];
+	/* Deprecated. Do not use */
+	void __iomem	*gpmc_status;
 };
 
 struct omap_nand_platform_data {
-- 
2.1.4


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

* Re: [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms
  2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
                   ` (21 preceding siblings ...)
  2015-08-07  9:12 ` [PATCH v2 22/22] memory: omap-gpmc: Prevent GPMC_STATUS from being accessed via gpmc_regs Roger Quadros
@ 2015-08-11 12:48 ` Tony Lindgren
  2015-08-13  7:13   ` Roger Quadros
  22 siblings, 1 reply; 29+ messages in thread
From: Tony Lindgren @ 2015-08-11 12:48 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [150807 02:15]:
> Hi,
> 
> We do a couple of things in this series which result in
> cleaner device tree implementation, faster perfomance and
> multi-platform support. As an added bonus we get new GPI/Interrupt pins
> for use in the system.
> 
> - Establish a custom interface between NAND and GPMC driver. This is
> needed because all of the NAND registers sit in the GPMC register space.
> Some bits like NAND IRQ are even shared with GPMC.
> 
> - Remove NAND IRQ handling from omap-gpmc driver, share the GPMC IRQ
> with the omap2-nand driver and handle NAND IRQ events in the NAND driver.
> This causes performance increase when using prefetch-irq mode.
> 30% increase in read, 17% increase in write in prefetch-irq mode.
> 
> - Clean up device tree support so that omap-gpmc IP and the omap2 NAND
> driver can be used on non-OMAP platforms. e.g. Keystone.
> 
> - Implement GPIOCHIP + IRQCHIP for the GPMC WAITPINS. SoCs can contain
> 2 to 4 of these and most of them would be unused otherwise. It also
> allows a cleaner implementation of NAND Ready pin status for the NAND driver.
> 
> - Implement GPIOlib based NAND ready pin checking for OMAP NAND driver.

Nice job :) Using GPIOCHIP + IRQCHIP allows us to make the GPMC
using drivers pretty much generic eventually.
 
> NOTE: I've only adapted dra7.dtsi and dra7x-evms for this series.
> I will adapt all other boards when the series is in a shape to be accepted.

OK. Yeah let's make sure no regressions are caused by this.. We also
still have the omap3 legacy booting around, have you checked that it
keeps on working?

Regards,

Tony

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

* Re: [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms
  2015-08-11 12:48 ` [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Tony Lindgren
@ 2015-08-13  7:13   ` Roger Quadros
  2015-08-13  8:36     ` Tony Lindgren
  0 siblings, 1 reply; 29+ messages in thread
From: Roger Quadros @ 2015-08-13  7:13 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel


On 11/08/15 15:48, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [150807 02:15]:
>> Hi,
>>
>> We do a couple of things in this series which result in
>> cleaner device tree implementation, faster perfomance and
>> multi-platform support. As an added bonus we get new GPI/Interrupt pins
>> for use in the system.
>>
>> - Establish a custom interface between NAND and GPMC driver. This is
>> needed because all of the NAND registers sit in the GPMC register space.
>> Some bits like NAND IRQ are even shared with GPMC.
>>
>> - Remove NAND IRQ handling from omap-gpmc driver, share the GPMC IRQ
>> with the omap2-nand driver and handle NAND IRQ events in the NAND driver.
>> This causes performance increase when using prefetch-irq mode.
>> 30% increase in read, 17% increase in write in prefetch-irq mode.
>>
>> - Clean up device tree support so that omap-gpmc IP and the omap2 NAND
>> driver can be used on non-OMAP platforms. e.g. Keystone.
>>
>> - Implement GPIOCHIP + IRQCHIP for the GPMC WAITPINS. SoCs can contain
>> 2 to 4 of these and most of them would be unused otherwise. It also
>> allows a cleaner implementation of NAND Ready pin status for the NAND driver.
>>
>> - Implement GPIOlib based NAND ready pin checking for OMAP NAND driver.
> 
> Nice job :) Using GPIOCHIP + IRQCHIP allows us to make the GPMC
> using drivers pretty much generic eventually.

Thanks :)
>  
>> NOTE: I've only adapted dra7.dtsi and dra7x-evms for this series.
>> I will adapt all other boards when the series is in a shape to be accepted.
> 
> OK. Yeah let's make sure no regressions are caused by this.. We also
> still have the omap3 legacy booting around, have you checked that it
> keeps on working?

I don't have any omap3 board with legacy support with me. I have omap3-beagle
but looks like legacy boot is dropped for it already.

I'll try to revert the patch that drops beagle support and test it on that one.

cheers,
-roger

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

* Re: [PATCH v2 06/22] mtd: nand: omap2: Switch to using GPMC-NAND ops for writebuffer empty check
  2015-08-07  9:12 ` [PATCH v2 06/22] mtd: nand: omap2: Switch to using GPMC-NAND ops for writebuffer empty check Roger Quadros
@ 2015-08-13  7:18   ` Roger Quadros
  0 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-13  7:18 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel



On 07/08/15 12:12, Roger Quadros wrote:
> Instead of accessing the gpmc_status register directly start
> using the gpmc_nand_ops->nand_writebuffer_empty() helper
> to check write buffer empty status.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/mtd/nand/omap2.c | 12 ++----------
>  1 file changed, 2 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
> index f214fe2..5c2f6df 100644
> --- a/drivers/mtd/nand/omap2.c
> +++ b/drivers/mtd/nand/omap2.c
> @@ -289,15 +289,11 @@ 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);
>  		/* wait until buffer is available for write */
> -		do {
> -			status = readl(info->reg.gpmc_status) &
> -					STATUS_BUFF_EMPTY;
> -		} while (!status);
> +		while (info->ops->nand_writebuffer_empty());

This should be
		while (!info->ops->nand_writebuffer_empty());

>  	}
>  }
>  
> @@ -325,17 +321,13 @@ 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);
>  		/* wait until buffer is available for write */
> -		do {
> -			status = readl(info->reg.gpmc_status) &
> -					STATUS_BUFF_EMPTY;
> -		} while (!status);
> +		while (info->ops->nand_writebuffer_empty());

here as well.

>  	}
>  }
>  
> 

cheers,
-roger

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

* Re: [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms
  2015-08-13  7:13   ` Roger Quadros
@ 2015-08-13  8:36     ` Tony Lindgren
  2015-08-13 12:00       ` Roger Quadros
  0 siblings, 1 reply; 29+ messages in thread
From: Tony Lindgren @ 2015-08-13  8:36 UTC (permalink / raw)
  To: Roger Quadros
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel

* Roger Quadros <rogerq@ti.com> [150813 00:17]:
> On 11/08/15 15:48, Tony Lindgren wrote:
> > 
> > OK. Yeah let's make sure no regressions are caused by this.. We also
> > still have the omap3 legacy booting around, have you checked that it
> > keeps on working?
> 
> I don't have any omap3 board with legacy support with me. I have omap3-beagle
> but looks like legacy boot is dropped for it already.
> 
> I'll try to revert the patch that drops beagle support and test it on that one.

OK yeah that should work just fine.

Tony

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

* Re: [PATCH v2 16/22] memory: omap-gpmc: Support general purpose input for WAITPINs
  2015-08-07  9:12 ` [PATCH v2 16/22] memory: omap-gpmc: Support general purpose input for WAITPINs Roger Quadros
@ 2015-08-13 11:58   ` Roger Quadros
  0 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-13 11:58 UTC (permalink / raw)
  To: tony
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel



On 07/08/15 12:12, Roger Quadros wrote:
> OMAPs can have 2 to 4 WAITPINs that can be used as general purpose
> input if not used for memory wait state insertion.
> 
> The first user will be the OMAP NAND chip to get the NAND
> read/busy status using gpiolib.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/memory/omap-gpmc.c | 122 +++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 117 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
> index 30d9c21..264009d 100644
> --- a/drivers/memory/omap-gpmc.c
> +++ b/drivers/memory/omap-gpmc.c
> @@ -21,6 +21,7 @@
>  #include <linux/spinlock.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> +#include <linux/gpio/driver.h>
>  #include <linux/interrupt.h>
>  #include <linux/platform_device.h>
>  #include <linux/of.h>
> @@ -223,6 +224,11 @@ struct omap3_gpmc_regs {
>  	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
>  };
>  
> +struct gpmc_device {
> +	struct device *dev;
> +	struct gpio_chip gpio_chip;
> +};
> +
>  static struct resource	gpmc_mem_root;
>  static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
>  static DEFINE_SPINLOCK(gpmc_mem_lock);
> @@ -1919,10 +1925,69 @@ err:
>  	return ret;
>  }
>  
> +static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
> +{
> +	return 1;	/* we're input only */
> +}
> +
> +static int gpmc_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +	return 0;	/* we're input only */
> +}
> +
> +static int gpmc_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
> +				      int value)
> +{
> +	return -EINVAL;	/* we're input only */
> +}
> +
> +static void gpmc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
> +{
> +}
> +
> +static int gpmc_gpio_get(struct gpio_chip *chip, unsigned offset)
> +{
> +	u32 reg;
> +
> +	offset += 8;
> +
> +	reg = gpmc_read_reg(GPMC_STATUS) & BIT(offset);
> +
> +	return !!reg;
> +}
> +
> +static int gpmc_gpio_init(struct gpmc_device *gpmc)
> +{
> +	int ret;
> +
> +	gpmc->gpio_chip.dev = gpmc->dev;
> +	gpmc->gpio_chip.owner = THIS_MODULE;
> +	gpmc->gpio_chip.label = DEVICE_NAME;
> +	gpmc->gpio_chip.ngpio = gpmc_nr_waitpins;
> +	gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction;
> +	gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input;
> +	gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output;
> +	gpmc->gpio_chip.set = gpmc_gpio_set;
> +	gpmc->gpio_chip.get = gpmc_gpio_get;
> +	gpmc->gpio_chip.base = -1;
> +
> +	ret = gpiochip_add(&gpmc->gpio_chip);
> +	if (ret < 0) {
> +		dev_err(gpmc->dev, "could not register gpio chip: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void gpmc_gpio_exit(struct gpmc_device *gpmc)
> +{
> +	gpiochip_remove(&gpmc->gpio_chip);
> +}
> +
>  static int gpmc_probe_dt(struct platform_device *pdev)
>  {
>  	int ret;
> -	struct device_node *child;
>  	const struct of_device_id *of_id =
>  		of_match_device(gpmc_dt_ids, &pdev->dev);
>  
> @@ -1950,6 +2015,17 @@ static int gpmc_probe_dt(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	dev_info(&pdev->dev, "num-cs %d, num-wait %d\n",
> +		 gpmc_cs_num, gpmc_nr_waitpins);
> +
> +	return 0;
> +}
> +
> +static int gpmc_probe_dt_children(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct device_node *child;
> +
>  	for_each_available_child_of_node(pdev->dev.of_node, child) {
>  
>  		if (!child->name)
> @@ -1959,6 +2035,9 @@ static int gpmc_probe_dt(struct platform_device *pdev)
>  			ret = gpmc_probe_onenand_child(pdev, child);
>  		else
>  			ret = gpmc_probe_generic_child(pdev, child);
> +
> +		if (ret)
> +			return ret;
>  	}
>  
>  	return 0;
> @@ -1968,6 +2047,11 @@ static int gpmc_probe_dt(struct platform_device *pdev)
>  {
>  	return 0;
>  }
> +
> +static int gpmc_probe_dt_children(struct platform_device *pdev)
> +{
> +	return 0;
> +}
>  #endif
>  
>  static int gpmc_probe(struct platform_device *pdev)
> @@ -1975,6 +2059,7 @@ static int gpmc_probe(struct platform_device *pdev)
>  	int rc;
>  	u32 l;
>  	struct resource *res;
> +	struct gpmc_device *gpmc;
>  
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	if (res == NULL)
> @@ -2005,6 +2090,17 @@ static int gpmc_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> +	rc = gpmc_probe_dt(pdev);
> +	if (rc)
> +		return rc;
> +
> +	gpmc = devm_kzalloc(&pdev->dev, sizeof(*gpmc), GFP_KERNEL);
> +	if (!gpmc)
> +		return -ENOMEM;
> +
> +	gpmc->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, gpmc);
> +
>  	pm_runtime_enable(&pdev->dev);
>  	pm_runtime_get_sync(&pdev->dev);
>  
> @@ -2032,24 +2128,40 @@ static int gpmc_probe(struct platform_device *pdev)
>  		 GPMC_REVISION_MINOR(l));
>  
>  	gpmc_mem_init();
> +	rc = gpmc_gpio_init(gpmc);
> +	if (rc)
> +		goto gpio_init_failed;
> +
>  
>  	if (!pdev->dev.of_node) {
>  		gpmc_cs_num	 = GPMC_CS_NUM;
>  		gpmc_nr_waitpins = GPMC_NR_WAITPINS;
>  	}

The above if {} needs to move near gpmc_probe_dt()
else we break gpmc for legacy boot.

cheers,
-roger

>  
> -	rc = gpmc_probe_dt(pdev);
> +	rc = gpmc_probe_dt_children(pdev);
>  	if (rc < 0) {
> -		pm_runtime_put_sync(&pdev->dev);
> -		dev_err(gpmc_dev, "failed to probe DT parameters\n");
> -		return rc;
> +		dev_err(gpmc_dev, "failed to probe DT children\n");
> +		goto dt_children_failed;
>  	}
>  
>  	return 0;
> +
> +dt_children_failed:
> +	gpmc_gpio_exit(gpmc);
> +gpio_init_failed:
> +	gpmc_mem_exit();
> +	pm_runtime_put_sync(&pdev->dev);
> +	pm_runtime_disable(&pdev->dev);
> +	gpmc_dev = NULL;
> +
> +	return rc;
>  }
>  
>  static int gpmc_remove(struct platform_device *pdev)
>  {
> +	struct gpmc_device *gpmc = platform_get_drvdata(pdev);
> +
> +	gpmc_gpio_exit(gpmc);
>  	gpmc_mem_exit();
>  	pm_runtime_put_sync(&pdev->dev);
>  	pm_runtime_disable(&pdev->dev);
> 

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

* Re: [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms
  2015-08-13  8:36     ` Tony Lindgren
@ 2015-08-13 12:00       ` Roger Quadros
  0 siblings, 0 replies; 29+ messages in thread
From: Roger Quadros @ 2015-08-13 12:00 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: dwmw2, computersforpeace, ezequiel, javier, fcooper, nsekhar,
	linux-mtd, linux-omap, devicetree, linux-kernel

On 13/08/15 11:36, Tony Lindgren wrote:
> * Roger Quadros <rogerq@ti.com> [150813 00:17]:
>> On 11/08/15 15:48, Tony Lindgren wrote:
>>>
>>> OK. Yeah let's make sure no regressions are caused by this.. We also
>>> still have the omap3 legacy booting around, have you checked that it
>>> keeps on working?
>>
>> I don't have any omap3 board with legacy support with me. I have omap3-beagle
>> but looks like legacy boot is dropped for it already.
>>
>> I'll try to revert the patch that drops beagle support and test it on that one.
> 
> OK yeah that should work just fine.
> 

Just verified that with the change in patch 6 it works on omap3-beagle legacy boot.
I have fixed some checkpatch issues in this series as well. Will post a v3
after you have gone one pass over this series.

cheers,
-roger

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

end of thread, other threads:[~2015-08-13 12:00 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-07  9:12 [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Roger Quadros
2015-08-07  9:12 ` [PATCH v2 01/22] ARM: OMAP2+: gpmc: Add platform data Roger Quadros
2015-08-07  9:12 ` [PATCH v2 02/22] ARM: OMAP2+: gpmc: Add gpmc timings and settings to " Roger Quadros
2015-08-07  9:12 ` [PATCH v2 03/22] memory: omap-gpmc: Introduce GPMC to NAND interface Roger Quadros
2015-08-07  9:12 ` [PATCH v2 04/22] mtd: nand: omap2: Use gpmc_omap_get_nand_ops() to get NAND registers Roger Quadros
2015-08-07  9:12 ` [PATCH v2 05/22] memory: omap-gpmc: Add GPMC-NAND ops to get writebufferempty status Roger Quadros
2015-08-07  9:12 ` [PATCH v2 06/22] mtd: nand: omap2: Switch to using GPMC-NAND ops for writebuffer empty check Roger Quadros
2015-08-13  7:18   ` Roger Quadros
2015-08-07  9:12 ` [PATCH v2 07/22] memory: omap-gpmc: Remove NAND IRQ code Roger Quadros
2015-08-07  9:12 ` [PATCH v2 08/22] memory: omap-gpmc: Add IRQ ops for GPMC-NAND interface Roger Quadros
2015-08-07  9:12 ` [PATCH v2 09/22] mtd: nand: omap2: manage NAND interrupts Roger Quadros
2015-08-07  9:12 ` [PATCH v2 10/22] mtd: nand: omap: Copy platform data parameters to omap_nand_info data Roger Quadros
2015-08-07  9:12 ` [PATCH v2 11/22] mtd: nand: omap: Clean up device tree support Roger Quadros
2015-08-07  9:12 ` [PATCH v2 12/22] mtd: nand: omap: Update DT binding documentation Roger Quadros
2015-08-07  9:12 ` [PATCH v2 13/22] memory: omap-gpmc: Prevent mapping into 1st 16MB Roger Quadros
2015-08-07  9:12 ` [PATCH v2 14/22] ARM: dts: OMAP2+: Fix NAND device nodes Roger Quadros
2015-08-07  9:12 ` [PATCH v2 15/22] memory: omap-gpmc: Move device tree binding to correct location Roger Quadros
2015-08-07  9:12 ` [PATCH v2 16/22] memory: omap-gpmc: Support general purpose input for WAITPINs Roger Quadros
2015-08-13 11:58   ` Roger Quadros
2015-08-07  9:12 ` [PATCH v2 17/22] memory: omap-gpmc: Reserve WAITPIN if needed for WAIT monitoring Roger Quadros
2015-08-07  9:12 ` [PATCH v2 18/22] memory: omap-gpmc: Add irqchip support to the gpiochip Roger Quadros
2015-08-07  9:12 ` [PATCH v2 19/22] ARM: dts: dra7: Enable gpio & interrupt controller for gpmc node Roger Quadros
2015-08-07  9:12 ` [PATCH v2 20/22] mtd: nand: omap2: Implement NAND ready using gpiolib Roger Quadros
2015-08-07  9:12 ` [PATCH v2 21/22] ARM: dts: dra7x-evm: Provide NAND ready pin Roger Quadros
2015-08-07  9:12 ` [PATCH v2 22/22] memory: omap-gpmc: Prevent GPMC_STATUS from being accessed via gpmc_regs Roger Quadros
2015-08-11 12:48 ` [PATCH v2 00/22] memory: omap-gpmc: mtd: nand: Support GPMC NAND on non-OMAP platforms Tony Lindgren
2015-08-13  7:13   ` Roger Quadros
2015-08-13  8:36     ` Tony Lindgren
2015-08-13 12:00       ` Roger Quadros

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