All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 00/13] GPMC driver conversion
@ 2012-06-22 12:55 ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:55 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Hi,

This series is based on 3.5-rc1, and is dependent on [1,2,3], and has
been tested on omap3evm (smsc911x) rev G & C and beagle board(nand).
Also using private patches, nand & onenand was tested on omap3evm,
rev G & C respectively (as support for these were not in mainline)

All boards will work using the old existing interface. Further patch
series would convert all boards to use new interface.

Many of GPMC peripherals depend on bootloader for configuration.
This is going to be deprecated. feature-removal-schedule.txt will be
updated in one of the upcoming patch series.

Thanks to Tony & Jon for their various suggestions.

[PATCH 03/13] ARM: OMAP2+: gpmc: driver migration helper, is to be
reverted once all GPMC peripherals are migrated to use driver
interface.

GPMC (General Purpose Memory Controller) in brief:
GPMC is an unified memory controller dedicated to interfacing external
memory devices like
 Asynchronous SRAM like memories and application specific integrated circuit devices.
 Asynchronous, synchronous, and page mode burst NOR flash devices NAND flash
 Pseudo-SRAM devices

GPMC details can be referred in AM335X Technical Reference Manual
@ http://www.ti.com/lit/pdf/spruh73

Regards
Afzal

[1] http://www.mail-archive.com/linux-omap@vger.kernel.org/msg70096.html
[2] http://www.mail-archive.com/linux-omap@vger.kernel.org/msg70730.html
[3] http://www.mail-archive.com/linux-omap@vger.kernel.org/msg69881.html

v6: Capability flag added that stores features based on revision
    Macros used for finding revision
    Return value from memory setup function corrected
    Comments added to clarify handling of device type, size
    Bool type time setting patch removed as has been taken care in [2]
    Handle variable number of waitpin
    Warn if driver is unable to configure interrupt
    Enhance some of commit messages
    Handle shared writeprotect case
    Fix a bug in gpmc_create_device
    Get clk from hwmod
    Remove unwanted code
v5: Make this a purely driver conversion series, i.e. gpmc-mtd
    interactions has been made as a separate series, so is adding
    hwmod entry for OMAP2/3.
    And modifying gpmc peripheral platform initialization has been
    separated out of this series, so is migrating boards to use new
    driver interface. GPMC driver conversion which was done in a few
    patches in v4 has been tranformed to series of small patches.
    Also care has been taken care that old interface will not break
    with any of these patches, so both interfaces can coexist.
    This helps in converting boards one-by-one gradually. Acquiring
    CS has been thrown out. And conclusive comments on v4 has been
    addressed.
v4: Handle wait pin (except for interrupts), enhance configuration
    & timing interface of GPMC to take care of all boards. Dynamic
    allocation of interrupt instead of static. Convert remaining
    peripherals to work with GPMC driver. Handle acquiring NAND CS#,
    adapt to HWMOD, update HWMOD OMAP2/3 entries, other minor
    commenst on v3.
v3: Single device structure passed from platform for peripherals using
    multiple CS instead of using multiple device structure having a few
    redundant data, handle interrupts, GPMC NAND handling by GPMC NAND
    driver instead of GPMC driver
v2: Avoid code movement that kept similar code together (for easy review)


Afzal Mohammed (13):
  ARM: OMAP2+: gpmc: platform definitions
  ARM: OMAP2+: gpmc: Adapt to HWMOD
  ARM: OMAP2+: gpmc: driver migration helper
  ARM: OMAP2+: gpmc: minimal driver support
  ARM: OMAP2+: gpmc: resource creation helpers
  ARM: OMAP2+: gpmc: CS configuration helper
  ARM: OMAP2+: gpmc: register time setting helper
  ARM: OMAP2+: gpmc: holler if no configuration
  ARM: OMAP2+: gpmc: waitpin helper
  ARM: OMAP2+: gpmc: handle connected peripherals
  ARM: OMAP2+: gpmc: cs reconfigure helper
  ARM: OMAP2+: gpmc: update nand register info
  ARM: OMAP2+: gpmc: configure writeprotect

 arch/arm/mach-omap2/gpmc.c             |  797 ++++++++++++++++++++++++++++++--
 arch/arm/plat-omap/include/plat/gpmc.h |   58 +++
 2 files changed, 812 insertions(+), 43 deletions(-)

-- 
1.7.10.2


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

* [PATCH v6 00/13] GPMC driver conversion
@ 2012-06-22 12:55 ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This series is based on 3.5-rc1, and is dependent on [1,2,3], and has
been tested on omap3evm (smsc911x) rev G & C and beagle board(nand).
Also using private patches, nand & onenand was tested on omap3evm,
rev G & C respectively (as support for these were not in mainline)

All boards will work using the old existing interface. Further patch
series would convert all boards to use new interface.

Many of GPMC peripherals depend on bootloader for configuration.
This is going to be deprecated. feature-removal-schedule.txt will be
updated in one of the upcoming patch series.

Thanks to Tony & Jon for their various suggestions.

[PATCH 03/13] ARM: OMAP2+: gpmc: driver migration helper, is to be
reverted once all GPMC peripherals are migrated to use driver
interface.

GPMC (General Purpose Memory Controller) in brief:
GPMC is an unified memory controller dedicated to interfacing external
memory devices like
 Asynchronous SRAM like memories and application specific integrated circuit devices.
 Asynchronous, synchronous, and page mode burst NOR flash devices NAND flash
 Pseudo-SRAM devices

GPMC details can be referred in AM335X Technical Reference Manual
@ http://www.ti.com/lit/pdf/spruh73

Regards
Afzal

[1] http://www.mail-archive.com/linux-omap at vger.kernel.org/msg70096.html
[2] http://www.mail-archive.com/linux-omap at vger.kernel.org/msg70730.html
[3] http://www.mail-archive.com/linux-omap at vger.kernel.org/msg69881.html

v6: Capability flag added that stores features based on revision
    Macros used for finding revision
    Return value from memory setup function corrected
    Comments added to clarify handling of device type, size
    Bool type time setting patch removed as has been taken care in [2]
    Handle variable number of waitpin
    Warn if driver is unable to configure interrupt
    Enhance some of commit messages
    Handle shared writeprotect case
    Fix a bug in gpmc_create_device
    Get clk from hwmod
    Remove unwanted code
v5: Make this a purely driver conversion series, i.e. gpmc-mtd
    interactions has been made as a separate series, so is adding
    hwmod entry for OMAP2/3.
    And modifying gpmc peripheral platform initialization has been
    separated out of this series, so is migrating boards to use new
    driver interface. GPMC driver conversion which was done in a few
    patches in v4 has been tranformed to series of small patches.
    Also care has been taken care that old interface will not break
    with any of these patches, so both interfaces can coexist.
    This helps in converting boards one-by-one gradually. Acquiring
    CS has been thrown out. And conclusive comments on v4 has been
    addressed.
v4: Handle wait pin (except for interrupts), enhance configuration
    & timing interface of GPMC to take care of all boards. Dynamic
    allocation of interrupt instead of static. Convert remaining
    peripherals to work with GPMC driver. Handle acquiring NAND CS#,
    adapt to HWMOD, update HWMOD OMAP2/3 entries, other minor
    commenst on v3.
v3: Single device structure passed from platform for peripherals using
    multiple CS instead of using multiple device structure having a few
    redundant data, handle interrupts, GPMC NAND handling by GPMC NAND
    driver instead of GPMC driver
v2: Avoid code movement that kept similar code together (for easy review)


Afzal Mohammed (13):
  ARM: OMAP2+: gpmc: platform definitions
  ARM: OMAP2+: gpmc: Adapt to HWMOD
  ARM: OMAP2+: gpmc: driver migration helper
  ARM: OMAP2+: gpmc: minimal driver support
  ARM: OMAP2+: gpmc: resource creation helpers
  ARM: OMAP2+: gpmc: CS configuration helper
  ARM: OMAP2+: gpmc: register time setting helper
  ARM: OMAP2+: gpmc: holler if no configuration
  ARM: OMAP2+: gpmc: waitpin helper
  ARM: OMAP2+: gpmc: handle connected peripherals
  ARM: OMAP2+: gpmc: cs reconfigure helper
  ARM: OMAP2+: gpmc: update nand register info
  ARM: OMAP2+: gpmc: configure writeprotect

 arch/arm/mach-omap2/gpmc.c             |  797 ++++++++++++++++++++++++++++++--
 arch/arm/plat-omap/include/plat/gpmc.h |   58 +++
 2 files changed, 812 insertions(+), 43 deletions(-)

-- 
1.7.10.2

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

* [PATCH v6 01/13] ARM: OMAP2+: gpmc: platform definitions
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:56   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

gpmc driver platform definitions

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/plat-omap/include/plat/gpmc.h |   37 ++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index b7c9ea6..4e799b1 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -152,6 +152,43 @@ struct gpmc_timings {
 	struct gpmc_bool_timings bool_timings;
 };
 
+enum {
+	has_none,
+	has_period,
+	has_clock
+};
+
+struct gpmc_time_ctrl {
+	int type;
+	struct gpmc_timings timings;
+};
+
+struct gpmc_cs_data {
+	unsigned		cs;
+	unsigned long		mem_size;
+	unsigned long		mem_offset;
+	bool			have_config;
+	unsigned		config;
+	struct gpmc_time_ctrl	time_ctrl;
+	unsigned		irq_config;
+};
+
+struct gpmc_device_pdata {
+	char			*name;
+	int			id;
+	void			*pdata;
+	unsigned		pdata_size;
+	struct resource		*per_res;
+	unsigned		per_res_cnt;
+	struct gpmc_cs_data	*cs_data;
+	unsigned		num_cs;
+};
+
+struct gpmc_pdata {
+	unsigned			waitpin_nr;
+	struct gpmc_device_pdata	**device_pdata;
+};
+
 struct gpmc_nand_regs {
 	void __iomem	*gpmc_status;
 	void __iomem	*gpmc_nand_command;
-- 
1.7.10.2


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

* [PATCH v6 01/13] ARM: OMAP2+: gpmc: platform definitions
@ 2012-06-22 12:56   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

gpmc driver platform definitions

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/plat-omap/include/plat/gpmc.h |   37 ++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index b7c9ea6..4e799b1 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -152,6 +152,43 @@ struct gpmc_timings {
 	struct gpmc_bool_timings bool_timings;
 };
 
+enum {
+	has_none,
+	has_period,
+	has_clock
+};
+
+struct gpmc_time_ctrl {
+	int type;
+	struct gpmc_timings timings;
+};
+
+struct gpmc_cs_data {
+	unsigned		cs;
+	unsigned long		mem_size;
+	unsigned long		mem_offset;
+	bool			have_config;
+	unsigned		config;
+	struct gpmc_time_ctrl	time_ctrl;
+	unsigned		irq_config;
+};
+
+struct gpmc_device_pdata {
+	char			*name;
+	int			id;
+	void			*pdata;
+	unsigned		pdata_size;
+	struct resource		*per_res;
+	unsigned		per_res_cnt;
+	struct gpmc_cs_data	*cs_data;
+	unsigned		num_cs;
+};
+
+struct gpmc_pdata {
+	unsigned			waitpin_nr;
+	struct gpmc_device_pdata	**device_pdata;
+};
+
 struct gpmc_nand_regs {
 	void __iomem	*gpmc_status;
 	void __iomem	*gpmc_nand_command;
-- 
1.7.10.2

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

* [PATCH v6 02/13] ARM: OMAP2+: gpmc: Adapt to HWMOD
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:56   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Create API for platforms to adapt gpmc to HWMOD

gpmc clk is stored as timing calculation for
platform code require its rate so that GPMC
timing values (platform data for gpmc driver)
can be calculated.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   31 +++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    2 ++
 2 files changed, 33 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 8b0978f..f8131f8 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -27,6 +27,7 @@
 
 #include <asm/mach-types.h>
 #include <plat/gpmc.h>
+#include <plat/omap_device.h>
 
 #include <plat/sdrc.h>
 
@@ -937,6 +938,36 @@ static int __init gpmc_init(void)
 }
 postcore_initcall(gpmc_init);
 
+__init int omap_gpmc_init(struct gpmc_pdata *pdata)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *name = "omap-gpmc";
+	char *oh_name = "gpmc";
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	gpmc_l3_clk = oh->_clk;
+	if (!gpmc_l3_clk) {
+		pr_err("Could not get GPMC clock\n");
+		return -EINVAL;
+	}
+
+	pdev = omap_device_build(name, -1, oh, pdata,
+					sizeof(*pdata), NULL, 0, 0);
+	if (IS_ERR(pdev)) {
+		WARN(1, "Can't build omap_device for %s:%s.\n",
+						name, oh->name);
+		return PTR_ERR(pdev);
+	}
+
+	return 0;
+}
+
 static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 {
 	int i;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 4e799b1..157753ab 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -208,6 +208,8 @@ struct gpmc_nand_regs {
 extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
 extern int gpmc_get_client_irq(unsigned irq_config);
 
+extern int omap_gpmc_init(struct gpmc_pdata *pdata);
+
 extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns);
 extern unsigned int gpmc_ps_to_ticks(unsigned int time_ps);
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
-- 
1.7.10.2


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

* [PATCH v6 02/13] ARM: OMAP2+: gpmc: Adapt to HWMOD
@ 2012-06-22 12:56   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Create API for platforms to adapt gpmc to HWMOD

gpmc clk is stored as timing calculation for
platform code require its rate so that GPMC
timing values (platform data for gpmc driver)
can be calculated.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   31 +++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    2 ++
 2 files changed, 33 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 8b0978f..f8131f8 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -27,6 +27,7 @@
 
 #include <asm/mach-types.h>
 #include <plat/gpmc.h>
+#include <plat/omap_device.h>
 
 #include <plat/sdrc.h>
 
@@ -937,6 +938,36 @@ static int __init gpmc_init(void)
 }
 postcore_initcall(gpmc_init);
 
+__init int omap_gpmc_init(struct gpmc_pdata *pdata)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *name = "omap-gpmc";
+	char *oh_name = "gpmc";
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	gpmc_l3_clk = oh->_clk;
+	if (!gpmc_l3_clk) {
+		pr_err("Could not get GPMC clock\n");
+		return -EINVAL;
+	}
+
+	pdev = omap_device_build(name, -1, oh, pdata,
+					sizeof(*pdata), NULL, 0, 0);
+	if (IS_ERR(pdev)) {
+		WARN(1, "Can't build omap_device for %s:%s.\n",
+						name, oh->name);
+		return PTR_ERR(pdev);
+	}
+
+	return 0;
+}
+
 static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 {
 	int i;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 4e799b1..157753ab 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -208,6 +208,8 @@ struct gpmc_nand_regs {
 extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
 extern int gpmc_get_client_irq(unsigned irq_config);
 
+extern int omap_gpmc_init(struct gpmc_pdata *pdata);
+
 extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns);
 extern unsigned int gpmc_ps_to_ticks(unsigned int time_ps);
 extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
-- 
1.7.10.2

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

* [PATCH v6 03/13] ARM: OMAP2+: gpmc: driver migration helper
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:56   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

A driver is being created out of GPMC code. This is being
attempted to acheive by not breaking existing interface,
necessitating requirement of GPMC peripherals being able
to work with using new interface as well as with the old
existing interface. To not break existing, initcall is
required as in old interface GPMC is configured at arch
initcall and GPMC should be ready to handle old interface
by that time

Note: This commit has to be reverted once all boards have
been converted to work with gpmc driver interface

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |   18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index f8131f8..f64f55a 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -941,7 +941,7 @@ postcore_initcall(gpmc_init);
 __init int omap_gpmc_init(struct gpmc_pdata *pdata)
 {
 	struct omap_hwmod *oh;
-	struct platform_device *pdev;
+	static struct platform_device *pdev;
 	char *name = "omap-gpmc";
 	char *oh_name = "gpmc";
 
@@ -951,6 +951,11 @@ __init int omap_gpmc_init(struct gpmc_pdata *pdata)
 		return -ENODEV;
 	}
 
+	if (pdev != NULL) {
+		omap_device_delete(pdev->archdata.od);
+		platform_device_unregister(pdev);
+	}
+
 	gpmc_l3_clk = oh->_clk;
 	if (!gpmc_l3_clk) {
 		pr_err("Could not get GPMC clock\n");
@@ -968,6 +973,17 @@ __init int omap_gpmc_init(struct gpmc_pdata *pdata)
 	return 0;
 }
 
+static int __init gpmc_pre_init(void)
+{
+	static struct gpmc_device_pdata *gpmc_device_data[1];
+	struct gpmc_pdata gpmc_data = {
+		.device_pdata	= gpmc_device_data,
+	};
+
+	return omap_gpmc_init(&gpmc_data);
+}
+postcore_initcall(gpmc_pre_init);
+
 static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 {
 	int i;
-- 
1.7.10.2


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

* [PATCH v6 03/13] ARM: OMAP2+: gpmc: driver migration helper
@ 2012-06-22 12:56   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

A driver is being created out of GPMC code. This is being
attempted to acheive by not breaking existing interface,
necessitating requirement of GPMC peripherals being able
to work with using new interface as well as with the old
existing interface. To not break existing, initcall is
required as in old interface GPMC is configured at arch
initcall and GPMC should be ready to handle old interface
by that time

Note: This commit has to be reverted once all boards have
been converted to work with gpmc driver interface

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |   18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index f8131f8..f64f55a 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -941,7 +941,7 @@ postcore_initcall(gpmc_init);
 __init int omap_gpmc_init(struct gpmc_pdata *pdata)
 {
 	struct omap_hwmod *oh;
-	struct platform_device *pdev;
+	static struct platform_device *pdev;
 	char *name = "omap-gpmc";
 	char *oh_name = "gpmc";
 
@@ -951,6 +951,11 @@ __init int omap_gpmc_init(struct gpmc_pdata *pdata)
 		return -ENODEV;
 	}
 
+	if (pdev != NULL) {
+		omap_device_delete(pdev->archdata.od);
+		platform_device_unregister(pdev);
+	}
+
 	gpmc_l3_clk = oh->_clk;
 	if (!gpmc_l3_clk) {
 		pr_err("Could not get GPMC clock\n");
@@ -968,6 +973,17 @@ __init int omap_gpmc_init(struct gpmc_pdata *pdata)
 	return 0;
 }
 
+static int __init gpmc_pre_init(void)
+{
+	static struct gpmc_device_pdata *gpmc_device_data[1];
+	struct gpmc_pdata gpmc_data = {
+		.device_pdata	= gpmc_device_data,
+	};
+
+	return omap_gpmc_init(&gpmc_data);
+}
+postcore_initcall(gpmc_pre_init);
+
 static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 {
 	int i;
-- 
1.7.10.2

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

* [PATCH v6 04/13] ARM: OMAP2+: gpmc: minimal driver support
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:56   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Create a minimal driver out of gpmc code.
Responsibilities handled by earlier gpmc
initialization is now achieved in probe.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |  179 ++++++++++++++++++++++++++++++++------------
 1 file changed, 132 insertions(+), 47 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index f64f55a..08fc5df 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
 #include <plat/gpmc.h>
@@ -31,6 +32,8 @@
 
 #include <plat/sdrc.h>
 
+#define	DRIVER_NAME		"omap-gpmc"
+
 /* GPMC register offsets */
 #define GPMC_REVISION		0x00
 #define GPMC_SYSCONFIG		0x10
@@ -86,6 +89,12 @@
 #define ENABLE_PREFETCH		(0x1 << 7)
 #define DMA_MPU_MODE		2
 
+#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
+#define	GPMC_REVISION_MINOR(l)		(l & 0xf)
+
+#define	GPMC_HAS_WR_ACCESS		0x1
+#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
+
 /* XXX: Only NAND irq has been considered,currently these are the only ones used
  */
 #define	GPMC_NR_IRQ		2
@@ -122,6 +131,21 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
+struct gpmc_peripheral {
+	char			*name;
+	int			id;
+	void			*pdata;
+	unsigned		pdata_size;
+	struct resource		*per_res;
+	unsigned		per_res_cnt;
+	struct resource		*gpmc_res;
+	unsigned		gpmc_res_cnt;
+	bool			have_waitpin;
+	bool			waitpin_high;
+	unsigned		waitpin;
+	struct platform_device	*pdev;
+};
+
 static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
 static struct irq_chip gpmc_irq_chip;
 static unsigned gpmc_irq_start;
@@ -131,6 +155,10 @@ static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
 static unsigned int gpmc_cs_map;	/* flag for cs which are initialized */
 static int gpmc_ecc_used = -EINVAL;	/* cs using ecc engine */
+static struct device *gpmc_dev;
+static u32 gpmc_capability;
+static int gpmc_irq;
+static resource_size_t phys_base, mem_size;
 
 static void __iomem *gpmc_base;
 
@@ -472,6 +500,19 @@ static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
 	return r;
 }
 
+static int gpmc_cs_delete_mem(int cs)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+	int r;
+
+	spin_lock(&gpmc_mem_lock);
+	r = release_resource(&gpmc_cs_mem[cs]);
+	res->start = res->end = 0;
+	spin_unlock(&gpmc_mem_lock);
+
+	return r;
+}
+
 int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 {
 	struct resource *res = &gpmc_cs_mem[cs];
@@ -808,7 +849,7 @@ 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(int gpmc_irq)
+static int gpmc_setup_irq(void)
 {
 	int i;
 	u32 regval;
@@ -852,7 +893,37 @@ static int gpmc_setup_irq(int gpmc_irq)
 	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
 }
 
-static void __init gpmc_mem_init(void)
+static __exit 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;
+}
+
+static void __devexit gpmc_mem_exit(void)
+{
+	int cs;
+
+	for (cs = 0; cs < GPMC_CS_NUM; cs++) {
+		if (!gpmc_cs_mem_enabled(cs))
+			continue;
+		gpmc_cs_delete_mem(cs);
+	}
+
+}
+
+static void __devinit gpmc_mem_init(void)
 {
 	int cs;
 	unsigned long boot_rom_space = 0;
@@ -879,64 +950,78 @@ static void __init gpmc_mem_init(void)
 	}
 }
 
-static int __init gpmc_init(void)
+static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
-	int ret = -EINVAL;
-	int gpmc_irq;
-	char *ck = NULL;
-
-	if (cpu_is_omap24xx()) {
-		ck = "core_l3_ck";
-		if (cpu_is_omap2420())
-			l = OMAP2420_GPMC_BASE;
-		else
-			l = OMAP34XX_GPMC_BASE;
-		gpmc_irq = INT_34XX_GPMC_IRQ;
-	} else if (cpu_is_omap34xx()) {
-		ck = "gpmc_fck";
-		l = OMAP34XX_GPMC_BASE;
-		gpmc_irq = INT_34XX_GPMC_IRQ;
-	} else if (cpu_is_omap44xx()) {
-		ck = "gpmc_ck";
-		l = OMAP44XX_GPMC_BASE;
-		gpmc_irq = OMAP44XX_IRQ_GPMC;
-	}
+	struct resource *res;
+	struct gpmc_pdata *gp = dev_get_platdata(&pdev->dev);
 
-	if (WARN_ON(!ck))
-		return ret;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENOENT;
 
-	gpmc_l3_clk = clk_get(NULL, ck);
-	if (IS_ERR(gpmc_l3_clk)) {
-		printk(KERN_ERR "Could not get GPMC clock %s\n", ck);
-		BUG();
-	}
+	phys_base = res->start;
+	mem_size = resource_size(res);
 
-	gpmc_base = ioremap(l, SZ_4K);
-	if (!gpmc_base) {
-		clk_put(gpmc_l3_clk);
-		printk(KERN_ERR "Could not get GPMC register memory\n");
-		BUG();
-	}
+	gpmc_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!gpmc_base)
+		return -EADDRNOTAVAIL;
+
+	gpmc_dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL)
+		dev_warn(gpmc_dev, "Failed to get resource: irq\n");
+	else
+		gpmc_irq = res->start;
 
 	clk_enable(gpmc_l3_clk);
 
 	l = gpmc_read_reg(GPMC_REVISION);
-	printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
-	/* Set smart idle mode and automatic L3 clock gating */
-	l = gpmc_read_reg(GPMC_SYSCONFIG);
-	l &= 0x03 << 3;
-	l |= (0x02 << 3) | (1 << 0);
-	gpmc_write_reg(GPMC_SYSCONFIG, l);
+	if (GPMC_REVISION_MAJOR(l) > 0x4)
+		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
+	dev_info(gpmc_dev, "GPMC revision %d.%d\n",
+				GPMC_REVISION_MAJOR(l), GPMC_REVISION_MINOR(l));
+
 	gpmc_mem_init();
 
-	ret = gpmc_setup_irq(gpmc_irq);
-	if (ret)
-		pr_err("gpmc: irq-%d could not claim: err %d\n",
-						gpmc_irq, ret);
-	return ret;
+	if (IS_ERR_VALUE(gpmc_setup_irq()))
+		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
+
+	return 0;
 }
+
+static __exit int gpmc_remove(struct platform_device *pdev)
+{
+	gpmc_free_irq();
+	gpmc_mem_exit();
+	gpmc_dev = NULL;
+	return 0;
+}
+
+static struct platform_driver gpmc_driver = {
+	.probe		= gpmc_probe,
+	.remove		= __devexit_p(gpmc_remove),
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static __init int gpmc_init(void)
+{
+	return platform_driver_register(&gpmc_driver);
+
+}
+
+static __exit void gpmc_exit(void)
+{
+	platform_driver_unregister(&gpmc_driver);
+
+}
+
 postcore_initcall(gpmc_init);
+module_exit(gpmc_exit);
 
 __init int omap_gpmc_init(struct gpmc_pdata *pdata)
 {
-- 
1.7.10.2


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

* [PATCH v6 04/13] ARM: OMAP2+: gpmc: minimal driver support
@ 2012-06-22 12:56   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Create a minimal driver out of gpmc code.
Responsibilities handled by earlier gpmc
initialization is now achieved in probe.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |  179 ++++++++++++++++++++++++++++++++------------
 1 file changed, 132 insertions(+), 47 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index f64f55a..08fc5df 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
 #include <plat/gpmc.h>
@@ -31,6 +32,8 @@
 
 #include <plat/sdrc.h>
 
+#define	DRIVER_NAME		"omap-gpmc"
+
 /* GPMC register offsets */
 #define GPMC_REVISION		0x00
 #define GPMC_SYSCONFIG		0x10
@@ -86,6 +89,12 @@
 #define ENABLE_PREFETCH		(0x1 << 7)
 #define DMA_MPU_MODE		2
 
+#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
+#define	GPMC_REVISION_MINOR(l)		(l & 0xf)
+
+#define	GPMC_HAS_WR_ACCESS		0x1
+#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
+
 /* XXX: Only NAND irq has been considered,currently these are the only ones used
  */
 #define	GPMC_NR_IRQ		2
@@ -122,6 +131,21 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
+struct gpmc_peripheral {
+	char			*name;
+	int			id;
+	void			*pdata;
+	unsigned		pdata_size;
+	struct resource		*per_res;
+	unsigned		per_res_cnt;
+	struct resource		*gpmc_res;
+	unsigned		gpmc_res_cnt;
+	bool			have_waitpin;
+	bool			waitpin_high;
+	unsigned		waitpin;
+	struct platform_device	*pdev;
+};
+
 static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
 static struct irq_chip gpmc_irq_chip;
 static unsigned gpmc_irq_start;
@@ -131,6 +155,10 @@ static struct resource	gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
 static unsigned int gpmc_cs_map;	/* flag for cs which are initialized */
 static int gpmc_ecc_used = -EINVAL;	/* cs using ecc engine */
+static struct device *gpmc_dev;
+static u32 gpmc_capability;
+static int gpmc_irq;
+static resource_size_t phys_base, mem_size;
 
 static void __iomem *gpmc_base;
 
@@ -472,6 +500,19 @@ static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
 	return r;
 }
 
+static int gpmc_cs_delete_mem(int cs)
+{
+	struct resource	*res = &gpmc_cs_mem[cs];
+	int r;
+
+	spin_lock(&gpmc_mem_lock);
+	r = release_resource(&gpmc_cs_mem[cs]);
+	res->start = res->end = 0;
+	spin_unlock(&gpmc_mem_lock);
+
+	return r;
+}
+
 int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 {
 	struct resource *res = &gpmc_cs_mem[cs];
@@ -808,7 +849,7 @@ 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(int gpmc_irq)
+static int gpmc_setup_irq(void)
 {
 	int i;
 	u32 regval;
@@ -852,7 +893,37 @@ static int gpmc_setup_irq(int gpmc_irq)
 	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
 }
 
-static void __init gpmc_mem_init(void)
+static __exit 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;
+}
+
+static void __devexit gpmc_mem_exit(void)
+{
+	int cs;
+
+	for (cs = 0; cs < GPMC_CS_NUM; cs++) {
+		if (!gpmc_cs_mem_enabled(cs))
+			continue;
+		gpmc_cs_delete_mem(cs);
+	}
+
+}
+
+static void __devinit gpmc_mem_init(void)
 {
 	int cs;
 	unsigned long boot_rom_space = 0;
@@ -879,64 +950,78 @@ static void __init gpmc_mem_init(void)
 	}
 }
 
-static int __init gpmc_init(void)
+static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
-	int ret = -EINVAL;
-	int gpmc_irq;
-	char *ck = NULL;
-
-	if (cpu_is_omap24xx()) {
-		ck = "core_l3_ck";
-		if (cpu_is_omap2420())
-			l = OMAP2420_GPMC_BASE;
-		else
-			l = OMAP34XX_GPMC_BASE;
-		gpmc_irq = INT_34XX_GPMC_IRQ;
-	} else if (cpu_is_omap34xx()) {
-		ck = "gpmc_fck";
-		l = OMAP34XX_GPMC_BASE;
-		gpmc_irq = INT_34XX_GPMC_IRQ;
-	} else if (cpu_is_omap44xx()) {
-		ck = "gpmc_ck";
-		l = OMAP44XX_GPMC_BASE;
-		gpmc_irq = OMAP44XX_IRQ_GPMC;
-	}
+	struct resource *res;
+	struct gpmc_pdata *gp = dev_get_platdata(&pdev->dev);
 
-	if (WARN_ON(!ck))
-		return ret;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENOENT;
 
-	gpmc_l3_clk = clk_get(NULL, ck);
-	if (IS_ERR(gpmc_l3_clk)) {
-		printk(KERN_ERR "Could not get GPMC clock %s\n", ck);
-		BUG();
-	}
+	phys_base = res->start;
+	mem_size = resource_size(res);
 
-	gpmc_base = ioremap(l, SZ_4K);
-	if (!gpmc_base) {
-		clk_put(gpmc_l3_clk);
-		printk(KERN_ERR "Could not get GPMC register memory\n");
-		BUG();
-	}
+	gpmc_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!gpmc_base)
+		return -EADDRNOTAVAIL;
+
+	gpmc_dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL)
+		dev_warn(gpmc_dev, "Failed to get resource: irq\n");
+	else
+		gpmc_irq = res->start;
 
 	clk_enable(gpmc_l3_clk);
 
 	l = gpmc_read_reg(GPMC_REVISION);
-	printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
-	/* Set smart idle mode and automatic L3 clock gating */
-	l = gpmc_read_reg(GPMC_SYSCONFIG);
-	l &= 0x03 << 3;
-	l |= (0x02 << 3) | (1 << 0);
-	gpmc_write_reg(GPMC_SYSCONFIG, l);
+	if (GPMC_REVISION_MAJOR(l) > 0x4)
+		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
+	dev_info(gpmc_dev, "GPMC revision %d.%d\n",
+				GPMC_REVISION_MAJOR(l), GPMC_REVISION_MINOR(l));
+
 	gpmc_mem_init();
 
-	ret = gpmc_setup_irq(gpmc_irq);
-	if (ret)
-		pr_err("gpmc: irq-%d could not claim: err %d\n",
-						gpmc_irq, ret);
-	return ret;
+	if (IS_ERR_VALUE(gpmc_setup_irq()))
+		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
+
+	return 0;
 }
+
+static __exit int gpmc_remove(struct platform_device *pdev)
+{
+	gpmc_free_irq();
+	gpmc_mem_exit();
+	gpmc_dev = NULL;
+	return 0;
+}
+
+static struct platform_driver gpmc_driver = {
+	.probe		= gpmc_probe,
+	.remove		= __devexit_p(gpmc_remove),
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static __init int gpmc_init(void)
+{
+	return platform_driver_register(&gpmc_driver);
+
+}
+
+static __exit void gpmc_exit(void)
+{
+	platform_driver_unregister(&gpmc_driver);
+
+}
+
 postcore_initcall(gpmc_init);
+module_exit(gpmc_exit);
 
 __init int omap_gpmc_init(struct gpmc_pdata *pdata)
 {
-- 
1.7.10.2

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

* [PATCH v6 05/13] ARM: OMAP2+: gpmc: resource creation helpers
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:56   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Helpers for populating given resource structure
with memory & interrupt information.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |   45 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 08fc5df..e427ff4 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -950,6 +950,51 @@ static void __devinit gpmc_mem_init(void)
 	}
 }
 
+static __devinit int gpmc_setup_cs_mem(struct gpmc_cs_data *cs,
+						struct resource *res)
+{
+	unsigned long start;
+	int ret;
+
+	ret = gpmc_cs_request(cs->cs, cs->mem_size, &start);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(gpmc_dev, "error: gpmc request on CS: %d\n", cs->cs);
+		return ret;
+	}
+
+	res->start = start + cs->mem_offset;
+	res->end = res->start + cs->mem_size - 1;
+	res->flags = IORESOURCE_MEM;
+
+	dev_info(gpmc_dev, "memory 0x%x-0x%x on CS %d\n", res->start,
+							res->end, cs->cs);
+
+	return 0;
+}
+
+static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
+						struct resource *res)
+{
+	int i, n;
+
+	if (!gpmc_irq || !gpmc_irq_start) {
+		if (cs->irq_config)
+			dev_err(gpmc_dev, "gpmc not able to configure irq\n");
+		return 0;
+	}
+
+	for (i = 0, n = 0; i < GPMC_NR_IRQ; i++)
+		if (gpmc_client_irq[i].bitmask & cs->irq_config) {
+			res[n].start = res[n].end = gpmc_client_irq[i].irq;
+			res[n].flags = IORESOURCE_IRQ;
+			dev_info(gpmc_dev, "irq %u on CS %d\n",
+						res[n].start, cs->cs);
+			n++;
+		}
+
+	return n;
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
-- 
1.7.10.2


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

* [PATCH v6 05/13] ARM: OMAP2+: gpmc: resource creation helpers
@ 2012-06-22 12:56   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Helpers for populating given resource structure
with memory & interrupt information.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |   45 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 08fc5df..e427ff4 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -950,6 +950,51 @@ static void __devinit gpmc_mem_init(void)
 	}
 }
 
+static __devinit int gpmc_setup_cs_mem(struct gpmc_cs_data *cs,
+						struct resource *res)
+{
+	unsigned long start;
+	int ret;
+
+	ret = gpmc_cs_request(cs->cs, cs->mem_size, &start);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(gpmc_dev, "error: gpmc request on CS: %d\n", cs->cs);
+		return ret;
+	}
+
+	res->start = start + cs->mem_offset;
+	res->end = res->start + cs->mem_size - 1;
+	res->flags = IORESOURCE_MEM;
+
+	dev_info(gpmc_dev, "memory 0x%x-0x%x on CS %d\n", res->start,
+							res->end, cs->cs);
+
+	return 0;
+}
+
+static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
+						struct resource *res)
+{
+	int i, n;
+
+	if (!gpmc_irq || !gpmc_irq_start) {
+		if (cs->irq_config)
+			dev_err(gpmc_dev, "gpmc not able to configure irq\n");
+		return 0;
+	}
+
+	for (i = 0, n = 0; i < GPMC_NR_IRQ; i++)
+		if (gpmc_client_irq[i].bitmask & cs->irq_config) {
+			res[n].start = res[n].end = gpmc_client_irq[i].irq;
+			res[n].flags = IORESOURCE_IRQ;
+			dev_info(gpmc_dev, "irq %u on CS %d\n",
+						res[n].start, cs->cs);
+			n++;
+		}
+
+	return n;
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
-- 
1.7.10.2

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

* [PATCH v6 06/13] ARM: OMAP2+: gpmc: CS configuration helper
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:57   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Helper for configuring given CS based on flags.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   39 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    5 ++++
 2 files changed, 44 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index e427ff4..8f596ce 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -972,6 +972,45 @@ static __devinit int gpmc_setup_cs_mem(struct gpmc_cs_data *cs,
 	return 0;
 }
 
+static void gpmc_setup_cs_config(unsigned cs, unsigned conf)
+{
+	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+	l &= ~(GPMC_CONFIG1_MUXADDDATA |
+		GPMC_CONFIG1_WRITETYPE_SYNC |
+		GPMC_CONFIG1_WRITEMULTIPLE_SUPP |
+		GPMC_CONFIG1_READTYPE_SYNC |
+		GPMC_CONFIG1_READMULTIPLE_SUPP |
+		GPMC_CONFIG1_WRAPBURST_SUPP |
+		GPMC_CONFIG1_DEVICETYPE(~0) |
+		GPMC_CONFIG1_DEVICESIZE(~0) |
+		GPMC_CONFIG1_PAGE_LEN(~0));
+
+	/* device type & size bits are cleared above, implying NOR & 8 bit,
+	 * only other options possible are NAND & 16 bit respectively,
+	 * configure if user asked for it, else default is already setup
+	 * users has been provided with NOR & 8 bit macros, nothing to be
+	 * done here as already it has been setup above
+	 */
+	l |= conf & GPMC_CONFIG1_DEVICETYPE_NAND;
+	l |= conf & GPMC_CONFIG1_DEVICESIZE_16;
+
+	if (conf & GPMC_CONFIG1_PAGE_LEN_8)
+		l |= GPMC_CONFIG1_PAGE_LEN_8;
+	else if (conf & GPMC_CONFIG1_PAGE_LEN_16)
+		l |= GPMC_CONFIG1_PAGE_LEN_16;
+
+	conf &= (GPMC_CONFIG1_MUXADDDATA |
+			GPMC_CONFIG1_WRITETYPE_SYNC |
+			GPMC_CONFIG1_WRITEMULTIPLE_SUPP |
+			GPMC_CONFIG1_READTYPE_SYNC |
+			GPMC_CONFIG1_READMULTIPLE_SUPP |
+			GPMC_CONFIG1_WRAPBURST_SUPP);
+	l |= conf;
+
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 157753ab..7187445 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -57,14 +57,19 @@
 #define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
 #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
 #define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define	GPMC_CONFIG1_PAGE_LEN_4		GPMC_CONFIG1_PAGE_LEN(0)
+#define	GPMC_CONFIG1_PAGE_LEN_8		GPMC_CONFIG1_PAGE_LEN(1)
+#define	GPMC_CONFIG1_PAGE_LEN_16	GPMC_CONFIG1_PAGE_LEN(2)
 #define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
 #define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
 #define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
+#define	GPMC_CONFIG1_DEVICESIZE_8	GPMC_CONFIG1_DEVICESIZE(0)
 #define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
 #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
 #define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
+#define	GPMC_CONFIG1_DEVICETYPE_NAND	GPMC_CONFIG1_DEVICETYPE(2)
 #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
 #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
 #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
-- 
1.7.10.2


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

* [PATCH v6 06/13] ARM: OMAP2+: gpmc: CS configuration helper
@ 2012-06-22 12:57   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

Helper for configuring given CS based on flags.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   39 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    5 ++++
 2 files changed, 44 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index e427ff4..8f596ce 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -972,6 +972,45 @@ static __devinit int gpmc_setup_cs_mem(struct gpmc_cs_data *cs,
 	return 0;
 }
 
+static void gpmc_setup_cs_config(unsigned cs, unsigned conf)
+{
+	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+	l &= ~(GPMC_CONFIG1_MUXADDDATA |
+		GPMC_CONFIG1_WRITETYPE_SYNC |
+		GPMC_CONFIG1_WRITEMULTIPLE_SUPP |
+		GPMC_CONFIG1_READTYPE_SYNC |
+		GPMC_CONFIG1_READMULTIPLE_SUPP |
+		GPMC_CONFIG1_WRAPBURST_SUPP |
+		GPMC_CONFIG1_DEVICETYPE(~0) |
+		GPMC_CONFIG1_DEVICESIZE(~0) |
+		GPMC_CONFIG1_PAGE_LEN(~0));
+
+	/* device type & size bits are cleared above, implying NOR & 8 bit,
+	 * only other options possible are NAND & 16 bit respectively,
+	 * configure if user asked for it, else default is already setup
+	 * users has been provided with NOR & 8 bit macros, nothing to be
+	 * done here as already it has been setup above
+	 */
+	l |= conf & GPMC_CONFIG1_DEVICETYPE_NAND;
+	l |= conf & GPMC_CONFIG1_DEVICESIZE_16;
+
+	if (conf & GPMC_CONFIG1_PAGE_LEN_8)
+		l |= GPMC_CONFIG1_PAGE_LEN_8;
+	else if (conf & GPMC_CONFIG1_PAGE_LEN_16)
+		l |= GPMC_CONFIG1_PAGE_LEN_16;
+
+	conf &= (GPMC_CONFIG1_MUXADDDATA |
+			GPMC_CONFIG1_WRITETYPE_SYNC |
+			GPMC_CONFIG1_WRITEMULTIPLE_SUPP |
+			GPMC_CONFIG1_READTYPE_SYNC |
+			GPMC_CONFIG1_READMULTIPLE_SUPP |
+			GPMC_CONFIG1_WRAPBURST_SUPP);
+	l |= conf;
+
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 157753ab..7187445 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -57,14 +57,19 @@
 #define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
 #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
 #define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define	GPMC_CONFIG1_PAGE_LEN_4		GPMC_CONFIG1_PAGE_LEN(0)
+#define	GPMC_CONFIG1_PAGE_LEN_8		GPMC_CONFIG1_PAGE_LEN(1)
+#define	GPMC_CONFIG1_PAGE_LEN_16	GPMC_CONFIG1_PAGE_LEN(2)
 #define GPMC_CONFIG1_WAIT_READ_MON      (1 << 22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
 #define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
 #define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
+#define	GPMC_CONFIG1_DEVICESIZE_8	GPMC_CONFIG1_DEVICESIZE(0)
 #define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
 #define GPMC_CONFIG1_DEVICETYPE(val)    ((val & 3) << 10)
 #define GPMC_CONFIG1_DEVICETYPE_NOR     GPMC_CONFIG1_DEVICETYPE(0)
+#define	GPMC_CONFIG1_DEVICETYPE_NAND	GPMC_CONFIG1_DEVICETYPE(2)
 #define GPMC_CONFIG1_MUXADDDATA         (1 << 9)
 #define GPMC_CONFIG1_TIME_PARA_GRAN     (1 << 4)
 #define GPMC_CONFIG1_FCLK_DIV(val)      (val & 3)
-- 
1.7.10.2

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

* [PATCH v6 07/13] ARM: OMAP2+: gpmc: register time setting helper
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:57   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Helper for setting GPMC timing by taking input as register values.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |   45 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 8f596ce..1998285 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1011,6 +1011,51 @@ static void gpmc_setup_cs_config(unsigned cs, unsigned conf)
 	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 }
 
+static inline void gpmc_set_one_timing(int cs, int reg, int start,
+							int end, u32 val)
+{
+	u32 l;
+	unsigned mask;
+
+	mask = (1 << (end - start + 1)) - 1;
+	l = gpmc_cs_read_reg(cs, reg);
+	l &= ~(mask << start);
+	l |= val << start;
+	gpmc_cs_write_reg(cs, reg, l);
+}
+
+static void gpmc_cs_set_register_timings(int cs, const struct gpmc_timings *t)
+{
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG1, 0, 1, t->sync_clk);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG1, 18, 19, t->wait_monitoring);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG1, 25, 26, t->clk_activation);
+
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG2, 0, 3, t->cs_on);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG2, 8, 12, t->cs_rd_off);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG2, 16, 20, t->cs_wr_off);
+
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG3, 0, 3, t->adv_on);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG3, 8, 12, t->adv_rd_off);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG3, 16, 20, t->adv_wr_off);
+
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG4, 0, 3, t->oe_on);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG4, 8, 12, t->oe_off);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG4, 16, 19, t->we_on);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG4, 24, 28, t->we_off);
+
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG5, 24, 27, t->page_burst_access);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG6, 0, 3, t->bus_turnaround);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG6, 8, 11,	t->cycle2cycle_delay);
+
+	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
+		gpmc_set_one_timing(cs, GPMC_CS_CONFIG6, 24, 28, t->wr_access);
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_set_one_timing(cs, GPMC_CS_CONFIG6, 16, 19,
+						t->wr_data_mux_bus);
+
+	gpmc_cs_bool_timings(cs, &t->bool_timings);
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
-- 
1.7.10.2


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

* [PATCH v6 07/13] ARM: OMAP2+: gpmc: register time setting helper
@ 2012-06-22 12:57   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

Helper for setting GPMC timing by taking input as register values.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |   45 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 8f596ce..1998285 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1011,6 +1011,51 @@ static void gpmc_setup_cs_config(unsigned cs, unsigned conf)
 	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 }
 
+static inline void gpmc_set_one_timing(int cs, int reg, int start,
+							int end, u32 val)
+{
+	u32 l;
+	unsigned mask;
+
+	mask = (1 << (end - start + 1)) - 1;
+	l = gpmc_cs_read_reg(cs, reg);
+	l &= ~(mask << start);
+	l |= val << start;
+	gpmc_cs_write_reg(cs, reg, l);
+}
+
+static void gpmc_cs_set_register_timings(int cs, const struct gpmc_timings *t)
+{
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG1, 0, 1, t->sync_clk);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG1, 18, 19, t->wait_monitoring);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG1, 25, 26, t->clk_activation);
+
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG2, 0, 3, t->cs_on);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG2, 8, 12, t->cs_rd_off);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG2, 16, 20, t->cs_wr_off);
+
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG3, 0, 3, t->adv_on);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG3, 8, 12, t->adv_rd_off);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG3, 16, 20, t->adv_wr_off);
+
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG4, 0, 3, t->oe_on);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG4, 8, 12, t->oe_off);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG4, 16, 19, t->we_on);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG4, 24, 28, t->we_off);
+
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG5, 24, 27, t->page_burst_access);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG6, 0, 3, t->bus_turnaround);
+	gpmc_set_one_timing(cs, GPMC_CS_CONFIG6, 8, 11,	t->cycle2cycle_delay);
+
+	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
+		gpmc_set_one_timing(cs, GPMC_CS_CONFIG6, 24, 28, t->wr_access);
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_set_one_timing(cs, GPMC_CS_CONFIG6, 16, 19,
+						t->wr_data_mux_bus);
+
+	gpmc_cs_bool_timings(cs, &t->bool_timings);
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
-- 
1.7.10.2

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

* [PATCH v6 08/13] ARM: OMAP2+: gpmc: holler if no configuration
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:57   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Some of the GPMC peripherals depend on bootloader to do the
configuration. This facility is deprecated, notify user
about the present GPMC settings & inform that that relying
on bootloader for GPMC setting is deprecated.

Note: This has to be reverted once Kernel is updated with
sufficient details so that all the gpmc periherals can be
configured in Kernel for all boards instead of relying on
bootloader.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |  104 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 104 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 1998285..9e3960e 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1056,6 +1056,110 @@ static void gpmc_cs_set_register_timings(int cs, const struct gpmc_timings *t)
 	gpmc_cs_bool_timings(cs, &t->bool_timings);
 }
 
+static void gpmc_print_cs_config(int cs)
+{
+	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+	dev_warn(gpmc_dev, "GPMC CS%d depends on bootloader for config\n", cs);
+	dev_warn(gpmc_dev, "Please update it in Kernel ASAP to prevent losing support for this peripheral\n");
+	dev_warn(gpmc_dev, "Bootloader dependency for GPMC configuration is deprecated\n");
+
+	dev_warn(gpmc_dev, "muxadddata: %s\n",
+			l & GPMC_CONFIG1_MUXADDDATA ? "yes" : "no");
+	dev_warn(gpmc_dev, "writetypesync: %s\n",
+			l & GPMC_CONFIG1_WRITETYPE_SYNC ? "yes" : "no");
+	dev_warn(gpmc_dev, "writemultiple: %s\n",
+			l & GPMC_CONFIG1_WRITEMULTIPLE_SUPP ? "yes" : "no");
+	dev_warn(gpmc_dev, "readtypesync: %s\n",
+			l & GPMC_CONFIG1_READTYPE_SYNC ? "yes" : "no");
+	dev_warn(gpmc_dev, "readmultiple: %s\n",
+			l & GPMC_CONFIG1_READMULTIPLE_SUPP ? "yes" : "no");
+	dev_warn(gpmc_dev, "wrapburst: %s\n",
+			l & GPMC_CONFIG1_WRAPBURST_SUPP ? "yes" : "no");
+	dev_warn(gpmc_dev, "devicetype: %s\n",
+			l & GPMC_CONFIG1_DEVICETYPE_NAND ? "nand" : "nor");
+	dev_warn(gpmc_dev, "devicesize: %d\n",
+			l & GPMC_CONFIG1_DEVICESIZE_16 ? 16 : 8);
+	dev_warn(gpmc_dev, "pagelength: %d\n",
+			l & GPMC_CONFIG1_PAGE_LEN(~0) ?
+			(l & GPMC_CONFIG1_PAGE_LEN_16 ? 16 : 8) : 4);
+}
+static inline unsigned gpmc_get_one_timing(int cs, int reg, int start, int end)
+{
+	u32 l = gpmc_cs_read_reg(cs, reg);
+	unsigned mask;
+
+	mask = (1 << (end - start + 1)) - 1;
+	l &= (mask << start);
+	return l >>= start;
+}
+
+static void gpmc_print_cs_timings(int cs)
+{
+	dev_warn(gpmc_dev, "GPMC CS%d depends on bootloader for timing\n", cs);
+	dev_warn(gpmc_dev, "Please update it in Kernel ASAP to prevent losing support for this peripheral\n");
+	dev_warn(gpmc_dev, "Bootloader dependency for GPMC configuration is deprecated\n");
+
+	dev_warn(gpmc_dev, "fclk period: %lups\n", gpmc_get_fclk_period());
+	dev_warn(gpmc_dev, "sync_clk: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG1, 0, 1));
+	dev_warn(gpmc_dev, "wait_monitoring: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG1, 18, 19));
+	dev_warn(gpmc_dev, "clk_activation: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG1, 25, 26));
+	dev_warn(gpmc_dev, "cs_on: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG2, 0, 3));
+	dev_warn(gpmc_dev, "cs_rd_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG2, 8, 12));
+	dev_warn(gpmc_dev, "cs_wr_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG2, 16, 20));
+	dev_warn(gpmc_dev, "adv_on: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG3, 0, 3));
+	dev_warn(gpmc_dev, "adv_rd_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG3, 8, 12));
+	dev_warn(gpmc_dev, "adv_wr_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG3, 16, 20));
+	dev_warn(gpmc_dev, "oe_on: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 0, 3));
+	dev_warn(gpmc_dev, "oe_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 8, 12));
+	dev_warn(gpmc_dev, "we_on: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 16, 19));
+	dev_warn(gpmc_dev, "we_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 24, 28));
+	dev_warn(gpmc_dev, "rd_cycle: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG5, 0, 4));
+	dev_warn(gpmc_dev, "wr_cycle: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG5, 8, 12));
+	dev_warn(gpmc_dev, "acess: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG5, 16, 20));
+	dev_warn(gpmc_dev, "page_burst_access: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG5, 24, 27));
+	dev_warn(gpmc_dev, "bus_turnaround: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 0, 3));
+	dev_warn(gpmc_dev, "cycle2cycle_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 8, 11));
+	dev_warn(gpmc_dev, "wr_data_mux_bus: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 16, 19));
+	dev_warn(gpmc_dev, "wr_access: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 24, 28));
+
+	dev_warn(gpmc_dev, "time_para_granularity: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG1, 4, 4));
+	dev_warn(gpmc_dev, "cs_extra_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG2, 7, 7));
+	dev_warn(gpmc_dev, "adv_extra_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG3, 7, 7));
+	dev_warn(gpmc_dev, "oe_extra_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 7, 7));
+	dev_warn(gpmc_dev, "we_extra_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 23, 23));
+	dev_warn(gpmc_dev, "cycle2cyclediffcsen: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 6, 6));
+	dev_warn(gpmc_dev, "cycle2cyclesamecsen: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 7, 7));
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
-- 
1.7.10.2


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

* [PATCH v6 08/13] ARM: OMAP2+: gpmc: holler if no configuration
@ 2012-06-22 12:57   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

Some of the GPMC peripherals depend on bootloader to do the
configuration. This facility is deprecated, notify user
about the present GPMC settings & inform that that relying
on bootloader for GPMC setting is deprecated.

Note: This has to be reverted once Kernel is updated with
sufficient details so that all the gpmc periherals can be
configured in Kernel for all boards instead of relying on
bootloader.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |  104 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 104 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 1998285..9e3960e 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1056,6 +1056,110 @@ static void gpmc_cs_set_register_timings(int cs, const struct gpmc_timings *t)
 	gpmc_cs_bool_timings(cs, &t->bool_timings);
 }
 
+static void gpmc_print_cs_config(int cs)
+{
+	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+	dev_warn(gpmc_dev, "GPMC CS%d depends on bootloader for config\n", cs);
+	dev_warn(gpmc_dev, "Please update it in Kernel ASAP to prevent losing support for this peripheral\n");
+	dev_warn(gpmc_dev, "Bootloader dependency for GPMC configuration is deprecated\n");
+
+	dev_warn(gpmc_dev, "muxadddata: %s\n",
+			l & GPMC_CONFIG1_MUXADDDATA ? "yes" : "no");
+	dev_warn(gpmc_dev, "writetypesync: %s\n",
+			l & GPMC_CONFIG1_WRITETYPE_SYNC ? "yes" : "no");
+	dev_warn(gpmc_dev, "writemultiple: %s\n",
+			l & GPMC_CONFIG1_WRITEMULTIPLE_SUPP ? "yes" : "no");
+	dev_warn(gpmc_dev, "readtypesync: %s\n",
+			l & GPMC_CONFIG1_READTYPE_SYNC ? "yes" : "no");
+	dev_warn(gpmc_dev, "readmultiple: %s\n",
+			l & GPMC_CONFIG1_READMULTIPLE_SUPP ? "yes" : "no");
+	dev_warn(gpmc_dev, "wrapburst: %s\n",
+			l & GPMC_CONFIG1_WRAPBURST_SUPP ? "yes" : "no");
+	dev_warn(gpmc_dev, "devicetype: %s\n",
+			l & GPMC_CONFIG1_DEVICETYPE_NAND ? "nand" : "nor");
+	dev_warn(gpmc_dev, "devicesize: %d\n",
+			l & GPMC_CONFIG1_DEVICESIZE_16 ? 16 : 8);
+	dev_warn(gpmc_dev, "pagelength: %d\n",
+			l & GPMC_CONFIG1_PAGE_LEN(~0) ?
+			(l & GPMC_CONFIG1_PAGE_LEN_16 ? 16 : 8) : 4);
+}
+static inline unsigned gpmc_get_one_timing(int cs, int reg, int start, int end)
+{
+	u32 l = gpmc_cs_read_reg(cs, reg);
+	unsigned mask;
+
+	mask = (1 << (end - start + 1)) - 1;
+	l &= (mask << start);
+	return l >>= start;
+}
+
+static void gpmc_print_cs_timings(int cs)
+{
+	dev_warn(gpmc_dev, "GPMC CS%d depends on bootloader for timing\n", cs);
+	dev_warn(gpmc_dev, "Please update it in Kernel ASAP to prevent losing support for this peripheral\n");
+	dev_warn(gpmc_dev, "Bootloader dependency for GPMC configuration is deprecated\n");
+
+	dev_warn(gpmc_dev, "fclk period: %lups\n", gpmc_get_fclk_period());
+	dev_warn(gpmc_dev, "sync_clk: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG1, 0, 1));
+	dev_warn(gpmc_dev, "wait_monitoring: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG1, 18, 19));
+	dev_warn(gpmc_dev, "clk_activation: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG1, 25, 26));
+	dev_warn(gpmc_dev, "cs_on: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG2, 0, 3));
+	dev_warn(gpmc_dev, "cs_rd_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG2, 8, 12));
+	dev_warn(gpmc_dev, "cs_wr_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG2, 16, 20));
+	dev_warn(gpmc_dev, "adv_on: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG3, 0, 3));
+	dev_warn(gpmc_dev, "adv_rd_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG3, 8, 12));
+	dev_warn(gpmc_dev, "adv_wr_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG3, 16, 20));
+	dev_warn(gpmc_dev, "oe_on: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 0, 3));
+	dev_warn(gpmc_dev, "oe_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 8, 12));
+	dev_warn(gpmc_dev, "we_on: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 16, 19));
+	dev_warn(gpmc_dev, "we_off: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 24, 28));
+	dev_warn(gpmc_dev, "rd_cycle: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG5, 0, 4));
+	dev_warn(gpmc_dev, "wr_cycle: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG5, 8, 12));
+	dev_warn(gpmc_dev, "acess: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG5, 16, 20));
+	dev_warn(gpmc_dev, "page_burst_access: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG5, 24, 27));
+	dev_warn(gpmc_dev, "bus_turnaround: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 0, 3));
+	dev_warn(gpmc_dev, "cycle2cycle_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 8, 11));
+	dev_warn(gpmc_dev, "wr_data_mux_bus: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 16, 19));
+	dev_warn(gpmc_dev, "wr_access: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 24, 28));
+
+	dev_warn(gpmc_dev, "time_para_granularity: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG1, 4, 4));
+	dev_warn(gpmc_dev, "cs_extra_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG2, 7, 7));
+	dev_warn(gpmc_dev, "adv_extra_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG3, 7, 7));
+	dev_warn(gpmc_dev, "oe_extra_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 7, 7));
+	dev_warn(gpmc_dev, "we_extra_delay: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG4, 23, 23));
+	dev_warn(gpmc_dev, "cycle2cyclediffcsen: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 6, 6));
+	dev_warn(gpmc_dev, "cycle2cyclesamecsen: %u\n",
+			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 7, 7));
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
-- 
1.7.10.2

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

* [PATCH v6 09/13] ARM: OMAP2+: gpmc: waitpin helper
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:57   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Helper for configuring waitpin. There are two parts to it;
configuring at CS level and the other at device level.
A device embedding multiple CS has been provided the
capability to use same waitpin (different waitpins has not
been supported as presently there are no GPMC peripherals
doing so)

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |  123 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    9 +++
 2 files changed, 132 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9e3960e..15688da 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -75,6 +75,8 @@
 #define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
 #define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
 
+#define	GPMC_CONFIG_WAITPIN_POLARITY_SHIFT	0x8
+
 #define GPMC_CS0_OFFSET		0x60
 #define GPMC_CS_SIZE		0x30
 
@@ -99,6 +101,14 @@
  */
 #define	GPMC_NR_IRQ		2
 
+enum {
+	GPMC_WAITPIN_IDX0,
+	GPMC_WAITPIN_IDX1,
+	GPMC_WAITPIN_IDX2,
+	GPMC_WAITPIN_IDX3,
+	GPMC_MAX_NR_WAITPIN
+};
+
 struct gpmc_client_irq	{
 	unsigned		irq;
 	u32			bitmask;
@@ -146,6 +156,9 @@ struct gpmc_peripheral {
 	struct platform_device	*pdev;
 };
 
+static unsigned gpmc_waitpin_map;
+static unsigned gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
+
 static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
 static struct irq_chip gpmc_irq_chip;
 static unsigned gpmc_irq_start;
@@ -1160,6 +1173,62 @@ static void gpmc_print_cs_timings(int cs)
 			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 7, 7));
 }
 
+static int gpmc_setup_cs_waitpin(struct gpmc_peripheral *g_per, unsigned cs,
+							unsigned conf)
+{
+	unsigned idx;
+	bool polarity = 0;
+	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+	switch (conf & GPMC_WAITPIN_MASK) {
+	case GPMC_WAITPIN_0:
+		idx =  GPMC_WAITPIN_IDX0;
+		break;
+	case GPMC_WAITPIN_1:
+		idx =  GPMC_WAITPIN_IDX1;
+		break;
+	case GPMC_WAITPIN_2:
+		idx =  GPMC_WAITPIN_IDX2;
+		break;
+	case GPMC_WAITPIN_3:
+		idx =  GPMC_WAITPIN_IDX3;
+		break;
+	/* no waitpin */
+	case 0:
+		return 0;
+		break;
+	default:
+		dev_err(gpmc_dev, "multiple waitpins selected on CS:%u\n", cs);
+		return -EINVAL;
+		break;
+	}
+
+	polarity = !!(conf & GPMC_WAITPIN_ACTIVE_HIGH);
+
+	if (g_per->have_waitpin) {
+		if (g_per->waitpin != idx ||
+				g_per->waitpin_high != polarity) {
+			dev_err(gpmc_dev, "error: conflict: waitpin %u with polarity %d on device %s.%d\n",
+				g_per->waitpin, g_per->waitpin_high,
+				g_per->name, g_per->id);
+			return -EBUSY;
+		}
+	} else {
+		g_per->have_waitpin = true;
+		g_per->waitpin = idx;
+		g_per->waitpin_high = polarity;
+	}
+
+	l |= conf & GPMC_CONFIG1_WAIT_WRITE_MON;
+	l |= conf & GPMC_CONFIG1_WAIT_READ_MON;
+	l &= ~GPMC_CONFIG1_WAIT_PIN_SEL_MASK;
+	l |= GPMC_CONFIG1_WAIT_PIN_SEL(idx);
+
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+
+	return 0;
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
@@ -1183,6 +1252,55 @@ static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 	return n;
 }
 
+static inline int gpmc_waitpin_is_reserved(unsigned waitpin)
+{
+	return gpmc_waitpin_map & (0x1 << waitpin);
+}
+
+static inline void gpmc_reserve_waitpin(unsigned waitpin)
+{
+	gpmc_waitpin_map &= ~(0x1 << waitpin);
+	gpmc_waitpin_map |= (0x1 << waitpin);
+}
+
+static int gpmc_waitpin_request(unsigned waitpin)
+{
+	if (!(waitpin < gpmc_waitpin_nr))
+		return -ENODEV;
+
+	if (gpmc_waitpin_is_reserved(waitpin))
+		return -EBUSY;
+	else
+		gpmc_reserve_waitpin(waitpin);
+
+	return 0;
+}
+
+static int gpmc_setup_waitpin(struct gpmc_peripheral *g_per)
+{
+	int ret;
+	u32 l, shift;
+
+	if (!g_per->have_waitpin)
+		return 0;
+
+	ret = gpmc_waitpin_request(g_per->waitpin);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(gpmc_dev, "waitpin %u reserved\n", g_per->waitpin);
+		return ret;
+	}
+
+	l = gpmc_read_reg(GPMC_CONFIG);
+	shift = g_per->waitpin + GPMC_CONFIG_WAITPIN_POLARITY_SHIFT;
+	if (g_per->waitpin_high)
+		l |= 1 << shift;
+	else
+		l &= ~(1 << shift);
+	gpmc_write_reg(GPMC_CONFIG, l);
+
+	return 0;
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
@@ -1221,11 +1339,16 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
 	if (IS_ERR_VALUE(gpmc_setup_irq()))
 		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
 
+	/* waitpin default 4, update if platform passed available waitpin no. */
+	if (gp->waitpin_nr)
+		gpmc_waitpin_nr = gp->waitpin_nr;
+
 	return 0;
 }
 
 static __exit int gpmc_remove(struct platform_device *pdev)
 {
+	gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
 	gpmc_free_irq();
 	gpmc_mem_exit();
 	gpmc_dev = NULL;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 7187445..1185490 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -64,6 +64,7 @@
 #define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
 #define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
+#define	GPMC_CONFIG1_WAIT_PIN_SEL_MASK	GPMC_CONFIG1_WAIT_PIN_SEL(3)
 #define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
 #define	GPMC_CONFIG1_DEVICESIZE_8	GPMC_CONFIG1_DEVICESIZE(0)
 #define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
@@ -78,6 +79,14 @@
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 #define GPMC_CONFIG7_CSVALID		(1 << 6)
 
+#define	GPMC_WAITPIN_ACTIVE_HIGH	(1 << 4)
+#define	GPMC_WAITPIN_ACTIVE_LOW		(0 << 4)
+#define	GPMC_WAITPIN_0			(1 << 0)
+#define	GPMC_WAITPIN_1			(1 << 1)
+#define	GPMC_WAITPIN_2			(1 << 2)
+#define	GPMC_WAITPIN_3			(1 << 3)
+#define	GPMC_WAITPIN_MASK		(GPMC_WAITPIN_0 | GPMC_WAITPIN_1 | \
+					GPMC_WAITPIN_2 | GPMC_WAITPIN_3)
 #define GPMC_DEVICETYPE_NOR		0
 #define GPMC_DEVICETYPE_NAND		2
 #define GPMC_CONFIG_WRITEPROTECT	0x00000010
-- 
1.7.10.2


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

* [PATCH v6 09/13] ARM: OMAP2+: gpmc: waitpin helper
@ 2012-06-22 12:57   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

Helper for configuring waitpin. There are two parts to it;
configuring at CS level and the other at device level.
A device embedding multiple CS has been provided the
capability to use same waitpin (different waitpins has not
been supported as presently there are no GPMC peripherals
doing so)

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |  123 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    9 +++
 2 files changed, 132 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9e3960e..15688da 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -75,6 +75,8 @@
 #define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
 #define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
 
+#define	GPMC_CONFIG_WAITPIN_POLARITY_SHIFT	0x8
+
 #define GPMC_CS0_OFFSET		0x60
 #define GPMC_CS_SIZE		0x30
 
@@ -99,6 +101,14 @@
  */
 #define	GPMC_NR_IRQ		2
 
+enum {
+	GPMC_WAITPIN_IDX0,
+	GPMC_WAITPIN_IDX1,
+	GPMC_WAITPIN_IDX2,
+	GPMC_WAITPIN_IDX3,
+	GPMC_MAX_NR_WAITPIN
+};
+
 struct gpmc_client_irq	{
 	unsigned		irq;
 	u32			bitmask;
@@ -146,6 +156,9 @@ struct gpmc_peripheral {
 	struct platform_device	*pdev;
 };
 
+static unsigned gpmc_waitpin_map;
+static unsigned gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
+
 static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
 static struct irq_chip gpmc_irq_chip;
 static unsigned gpmc_irq_start;
@@ -1160,6 +1173,62 @@ static void gpmc_print_cs_timings(int cs)
 			gpmc_get_one_timing(cs, GPMC_CS_CONFIG6, 7, 7));
 }
 
+static int gpmc_setup_cs_waitpin(struct gpmc_peripheral *g_per, unsigned cs,
+							unsigned conf)
+{
+	unsigned idx;
+	bool polarity = 0;
+	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+	switch (conf & GPMC_WAITPIN_MASK) {
+	case GPMC_WAITPIN_0:
+		idx =  GPMC_WAITPIN_IDX0;
+		break;
+	case GPMC_WAITPIN_1:
+		idx =  GPMC_WAITPIN_IDX1;
+		break;
+	case GPMC_WAITPIN_2:
+		idx =  GPMC_WAITPIN_IDX2;
+		break;
+	case GPMC_WAITPIN_3:
+		idx =  GPMC_WAITPIN_IDX3;
+		break;
+	/* no waitpin */
+	case 0:
+		return 0;
+		break;
+	default:
+		dev_err(gpmc_dev, "multiple waitpins selected on CS:%u\n", cs);
+		return -EINVAL;
+		break;
+	}
+
+	polarity = !!(conf & GPMC_WAITPIN_ACTIVE_HIGH);
+
+	if (g_per->have_waitpin) {
+		if (g_per->waitpin != idx ||
+				g_per->waitpin_high != polarity) {
+			dev_err(gpmc_dev, "error: conflict: waitpin %u with polarity %d on device %s.%d\n",
+				g_per->waitpin, g_per->waitpin_high,
+				g_per->name, g_per->id);
+			return -EBUSY;
+		}
+	} else {
+		g_per->have_waitpin = true;
+		g_per->waitpin = idx;
+		g_per->waitpin_high = polarity;
+	}
+
+	l |= conf & GPMC_CONFIG1_WAIT_WRITE_MON;
+	l |= conf & GPMC_CONFIG1_WAIT_READ_MON;
+	l &= ~GPMC_CONFIG1_WAIT_PIN_SEL_MASK;
+	l |= GPMC_CONFIG1_WAIT_PIN_SEL(idx);
+
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+
+	return 0;
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
@@ -1183,6 +1252,55 @@ static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 	return n;
 }
 
+static inline int gpmc_waitpin_is_reserved(unsigned waitpin)
+{
+	return gpmc_waitpin_map & (0x1 << waitpin);
+}
+
+static inline void gpmc_reserve_waitpin(unsigned waitpin)
+{
+	gpmc_waitpin_map &= ~(0x1 << waitpin);
+	gpmc_waitpin_map |= (0x1 << waitpin);
+}
+
+static int gpmc_waitpin_request(unsigned waitpin)
+{
+	if (!(waitpin < gpmc_waitpin_nr))
+		return -ENODEV;
+
+	if (gpmc_waitpin_is_reserved(waitpin))
+		return -EBUSY;
+	else
+		gpmc_reserve_waitpin(waitpin);
+
+	return 0;
+}
+
+static int gpmc_setup_waitpin(struct gpmc_peripheral *g_per)
+{
+	int ret;
+	u32 l, shift;
+
+	if (!g_per->have_waitpin)
+		return 0;
+
+	ret = gpmc_waitpin_request(g_per->waitpin);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(gpmc_dev, "waitpin %u reserved\n", g_per->waitpin);
+		return ret;
+	}
+
+	l = gpmc_read_reg(GPMC_CONFIG);
+	shift = g_per->waitpin + GPMC_CONFIG_WAITPIN_POLARITY_SHIFT;
+	if (g_per->waitpin_high)
+		l |= 1 << shift;
+	else
+		l &= ~(1 << shift);
+	gpmc_write_reg(GPMC_CONFIG, l);
+
+	return 0;
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
@@ -1221,11 +1339,16 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
 	if (IS_ERR_VALUE(gpmc_setup_irq()))
 		dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
 
+	/* waitpin default 4, update if platform passed available waitpin no. */
+	if (gp->waitpin_nr)
+		gpmc_waitpin_nr = gp->waitpin_nr;
+
 	return 0;
 }
 
 static __exit int gpmc_remove(struct platform_device *pdev)
 {
+	gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
 	gpmc_free_irq();
 	gpmc_mem_exit();
 	gpmc_dev = NULL;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 7187445..1185490 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -64,6 +64,7 @@
 #define GPMC_CONFIG1_WAIT_WRITE_MON     (1 << 21)
 #define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
+#define	GPMC_CONFIG1_WAIT_PIN_SEL_MASK	GPMC_CONFIG1_WAIT_PIN_SEL(3)
 #define GPMC_CONFIG1_DEVICESIZE(val)    ((val & 3) << 12)
 #define	GPMC_CONFIG1_DEVICESIZE_8	GPMC_CONFIG1_DEVICESIZE(0)
 #define GPMC_CONFIG1_DEVICESIZE_16      GPMC_CONFIG1_DEVICESIZE(1)
@@ -78,6 +79,14 @@
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 #define GPMC_CONFIG7_CSVALID		(1 << 6)
 
+#define	GPMC_WAITPIN_ACTIVE_HIGH	(1 << 4)
+#define	GPMC_WAITPIN_ACTIVE_LOW		(0 << 4)
+#define	GPMC_WAITPIN_0			(1 << 0)
+#define	GPMC_WAITPIN_1			(1 << 1)
+#define	GPMC_WAITPIN_2			(1 << 2)
+#define	GPMC_WAITPIN_3			(1 << 3)
+#define	GPMC_WAITPIN_MASK		(GPMC_WAITPIN_0 | GPMC_WAITPIN_1 | \
+					GPMC_WAITPIN_2 | GPMC_WAITPIN_3)
 #define GPMC_DEVICETYPE_NOR		0
 #define GPMC_DEVICETYPE_NAND		2
 #define GPMC_CONFIG_WRITEPROTECT	0x00000010
-- 
1.7.10.2

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

* [PATCH v6 10/13] ARM: OMAP2+: gpmc: handle connected peripherals
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:57   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Platform will provide driver with configuration details for
each CS like configuration, timing, interrupts. Setup GPMC
based on it. Platform data also provides platform data &
resources used for connected peripheral (eg. gpio irq).
GPMC driver tunnels those information to respective driver.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |  142 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 15688da..ac66267 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -156,6 +156,8 @@ struct gpmc_peripheral {
 	struct platform_device	*pdev;
 };
 
+static struct gpmc_peripheral gpmc_peripheral[GPMC_CS_NUM];
+static unsigned gpmc_num_peripheral;
 static unsigned gpmc_waitpin_map;
 static unsigned gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
 
@@ -1229,6 +1231,37 @@ static int gpmc_setup_cs_waitpin(struct gpmc_peripheral *g_per, unsigned cs,
 	return 0;
 }
 
+static int gpmc_setup_cs_config_timing(struct gpmc_peripheral *g_per,
+						struct gpmc_cs_data *cs)
+{
+	int ret;
+
+	/* some boards rely on bootloader for configuration */
+	if (cs->have_config) {
+		gpmc_setup_cs_config(cs->cs, cs->config);
+		ret = gpmc_setup_cs_waitpin(g_per, cs->cs, cs->config);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(gpmc_dev, "error: waitpin on CS %d\n", cs->cs);
+			return ret;
+		}
+	} else
+		gpmc_print_cs_config(cs->cs);
+
+	/* some boards rely on bootloader for timing */
+	if (cs->time_ctrl.type == has_period) {
+		ret = gpmc_cs_set_timings(cs->cs, &cs->time_ctrl.timings);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(gpmc_dev, "error: timing on CS: %d\n", cs->cs);
+			return ret;
+		}
+	} else if (cs->time_ctrl.type == has_clock)
+		gpmc_cs_set_register_timings(cs->cs, &cs->time_ctrl.timings);
+	else
+		gpmc_print_cs_timings(cs->cs);
+
+	return 0;
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
@@ -1301,11 +1334,99 @@ static int gpmc_setup_waitpin(struct gpmc_peripheral *g_per)
 	return 0;
 }
 
+static __devinit int gpmc_setup_cs(struct gpmc_peripheral *g_per,
+				struct gpmc_cs_data *cs, struct resource *res)
+{
+	int num, ret;
+
+	ret = gpmc_setup_cs_mem(cs, res);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	ret = gpmc_setup_cs_config_timing(g_per, cs);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	num = gpmc_setup_cs_irq(cs, res + 1); /* +1 to account for memory */
+
+	return num + 1; /* +1 to account for memory*/
+}
+
+static __devinit int gpmc_setup_device(struct gpmc_peripheral *g_per,
+					struct gpmc_device_pdata *gdp)
+{
+	int i, n, ret;
+	struct gpmc_cs_data *cs;
+
+	for (i = 0, n = gdp->num_cs, cs = gdp->cs_data;
+				i < gdp->num_cs; i++, cs++)
+		n += hweight32(cs->irq_config);
+
+	g_per->gpmc_res = devm_kzalloc(gpmc_dev, sizeof(*g_per->gpmc_res) * n,
+								GFP_KERNEL);
+	if (g_per->gpmc_res == NULL) {
+		dev_err(gpmc_dev, "error: memory allocation\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0, cs = gdp->cs_data, g_per->gpmc_res_cnt = 0;
+			i < gdp->num_cs; cs++, i++) {
+		ret = gpmc_setup_cs(g_per, cs,
+					g_per->gpmc_res + g_per->gpmc_res_cnt);
+		if (IS_ERR_VALUE(ret) ||
+				IS_ERR_VALUE(gpmc_setup_waitpin(g_per))) {
+			dev_err(gpmc_dev, "error: setup for %s\n", gdp->name);
+			devm_kfree(gpmc_dev, g_per->gpmc_res);
+			g_per->gpmc_res = NULL;
+			g_per->gpmc_res_cnt = 0;
+			return -EINVAL;
+		} else
+			g_per->gpmc_res_cnt += ret;
+	}
+
+	g_per->name = gdp->name;
+	g_per->id = gdp->id;
+	g_per->pdata = gdp->pdata;
+	g_per->pdata_size = gdp->pdata_size;
+	g_per->per_res = gdp->per_res;
+	g_per->per_res_cnt = gdp->per_res_cnt;
+
+	return 0;
+}
+
+static __devinit
+struct platform_device *gpmc_create_device(struct gpmc_peripheral *p)
+{
+	int num = p->per_res_cnt + p->gpmc_res_cnt;
+	struct resource *res;
+
+	res = devm_kzalloc(gpmc_dev, sizeof(struct resource) * num,
+								GFP_KERNEL);
+	if (!res) {
+		dev_err(gpmc_dev, "error: allocating memory\n");
+		return NULL;
+	}
+
+	memcpy((char *)res, (const char *) p->gpmc_res,
+				sizeof(struct resource) * p->gpmc_res_cnt);
+	memcpy((char *)(res + p->gpmc_res_cnt), (const char *)p->per_res,
+				sizeof(struct resource) * p->per_res_cnt);
+
+	p->pdev = platform_device_register_resndata(gpmc_dev, p->name, p->id,
+					res, num, p->pdata, p->pdata_size);
+
+	devm_kfree(gpmc_dev, res);
+
+	return p->pdev;
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
 	struct resource *res;
 	struct gpmc_pdata *gp = dev_get_platdata(&pdev->dev);
+	struct gpmc_device_pdata **gdq = NULL;
+	struct gpmc_peripheral *g_per = NULL;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL)
@@ -1343,11 +1464,32 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
 	if (gp->waitpin_nr)
 		gpmc_waitpin_nr = gp->waitpin_nr;
 
+	/* Traverse NULL terminated array of peripheral pointers and setup */
+	for (gdq = gp->device_pdata, g_per = gpmc_peripheral; *gdq; gdq++)
+		if (IS_ERR_VALUE(gpmc_setup_device(g_per, *gdq)))
+			dev_err(gpmc_dev, "gpmc setup on %s failed\n",
+								(*gdq)->name);
+		else
+			g_per++;
+	gpmc_num_peripheral = g_per - gpmc_peripheral;
+
+	for (l = 0, g_per = gpmc_peripheral;
+			l < gpmc_num_peripheral; l++, g_per++)
+		if (IS_ERR(gpmc_create_device(g_per)))
+			dev_err(gpmc_dev, "device creation on %s failed\n",
+								g_per->name);
+
 	return 0;
 }
 
 static __exit int gpmc_remove(struct platform_device *pdev)
 {
+	struct gpmc_peripheral *g_per = gpmc_peripheral;
+
+	for (; gpmc_num_peripheral; g_per++, gpmc_num_peripheral--)
+		platform_device_unregister(g_per->pdev);
+
+	gpmc_waitpin_map = 0;
 	gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
 	gpmc_free_irq();
 	gpmc_mem_exit();
-- 
1.7.10.2


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

* [PATCH v6 10/13] ARM: OMAP2+: gpmc: handle connected peripherals
@ 2012-06-22 12:57   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

Platform will provide driver with configuration details for
each CS like configuration, timing, interrupts. Setup GPMC
based on it. Platform data also provides platform data &
resources used for connected peripheral (eg. gpio irq).
GPMC driver tunnels those information to respective driver.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |  142 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 15688da..ac66267 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -156,6 +156,8 @@ struct gpmc_peripheral {
 	struct platform_device	*pdev;
 };
 
+static struct gpmc_peripheral gpmc_peripheral[GPMC_CS_NUM];
+static unsigned gpmc_num_peripheral;
 static unsigned gpmc_waitpin_map;
 static unsigned gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
 
@@ -1229,6 +1231,37 @@ static int gpmc_setup_cs_waitpin(struct gpmc_peripheral *g_per, unsigned cs,
 	return 0;
 }
 
+static int gpmc_setup_cs_config_timing(struct gpmc_peripheral *g_per,
+						struct gpmc_cs_data *cs)
+{
+	int ret;
+
+	/* some boards rely on bootloader for configuration */
+	if (cs->have_config) {
+		gpmc_setup_cs_config(cs->cs, cs->config);
+		ret = gpmc_setup_cs_waitpin(g_per, cs->cs, cs->config);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(gpmc_dev, "error: waitpin on CS %d\n", cs->cs);
+			return ret;
+		}
+	} else
+		gpmc_print_cs_config(cs->cs);
+
+	/* some boards rely on bootloader for timing */
+	if (cs->time_ctrl.type == has_period) {
+		ret = gpmc_cs_set_timings(cs->cs, &cs->time_ctrl.timings);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(gpmc_dev, "error: timing on CS: %d\n", cs->cs);
+			return ret;
+		}
+	} else if (cs->time_ctrl.type == has_clock)
+		gpmc_cs_set_register_timings(cs->cs, &cs->time_ctrl.timings);
+	else
+		gpmc_print_cs_timings(cs->cs);
+
+	return 0;
+}
+
 static __devinit int gpmc_setup_cs_irq(struct gpmc_cs_data *cs,
 						struct resource *res)
 {
@@ -1301,11 +1334,99 @@ static int gpmc_setup_waitpin(struct gpmc_peripheral *g_per)
 	return 0;
 }
 
+static __devinit int gpmc_setup_cs(struct gpmc_peripheral *g_per,
+				struct gpmc_cs_data *cs, struct resource *res)
+{
+	int num, ret;
+
+	ret = gpmc_setup_cs_mem(cs, res);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	ret = gpmc_setup_cs_config_timing(g_per, cs);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	num = gpmc_setup_cs_irq(cs, res + 1); /* +1 to account for memory */
+
+	return num + 1; /* +1 to account for memory*/
+}
+
+static __devinit int gpmc_setup_device(struct gpmc_peripheral *g_per,
+					struct gpmc_device_pdata *gdp)
+{
+	int i, n, ret;
+	struct gpmc_cs_data *cs;
+
+	for (i = 0, n = gdp->num_cs, cs = gdp->cs_data;
+				i < gdp->num_cs; i++, cs++)
+		n += hweight32(cs->irq_config);
+
+	g_per->gpmc_res = devm_kzalloc(gpmc_dev, sizeof(*g_per->gpmc_res) * n,
+								GFP_KERNEL);
+	if (g_per->gpmc_res == NULL) {
+		dev_err(gpmc_dev, "error: memory allocation\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0, cs = gdp->cs_data, g_per->gpmc_res_cnt = 0;
+			i < gdp->num_cs; cs++, i++) {
+		ret = gpmc_setup_cs(g_per, cs,
+					g_per->gpmc_res + g_per->gpmc_res_cnt);
+		if (IS_ERR_VALUE(ret) ||
+				IS_ERR_VALUE(gpmc_setup_waitpin(g_per))) {
+			dev_err(gpmc_dev, "error: setup for %s\n", gdp->name);
+			devm_kfree(gpmc_dev, g_per->gpmc_res);
+			g_per->gpmc_res = NULL;
+			g_per->gpmc_res_cnt = 0;
+			return -EINVAL;
+		} else
+			g_per->gpmc_res_cnt += ret;
+	}
+
+	g_per->name = gdp->name;
+	g_per->id = gdp->id;
+	g_per->pdata = gdp->pdata;
+	g_per->pdata_size = gdp->pdata_size;
+	g_per->per_res = gdp->per_res;
+	g_per->per_res_cnt = gdp->per_res_cnt;
+
+	return 0;
+}
+
+static __devinit
+struct platform_device *gpmc_create_device(struct gpmc_peripheral *p)
+{
+	int num = p->per_res_cnt + p->gpmc_res_cnt;
+	struct resource *res;
+
+	res = devm_kzalloc(gpmc_dev, sizeof(struct resource) * num,
+								GFP_KERNEL);
+	if (!res) {
+		dev_err(gpmc_dev, "error: allocating memory\n");
+		return NULL;
+	}
+
+	memcpy((char *)res, (const char *) p->gpmc_res,
+				sizeof(struct resource) * p->gpmc_res_cnt);
+	memcpy((char *)(res + p->gpmc_res_cnt), (const char *)p->per_res,
+				sizeof(struct resource) * p->per_res_cnt);
+
+	p->pdev = platform_device_register_resndata(gpmc_dev, p->name, p->id,
+					res, num, p->pdata, p->pdata_size);
+
+	devm_kfree(gpmc_dev, res);
+
+	return p->pdev;
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
 	struct resource *res;
 	struct gpmc_pdata *gp = dev_get_platdata(&pdev->dev);
+	struct gpmc_device_pdata **gdq = NULL;
+	struct gpmc_peripheral *g_per = NULL;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL)
@@ -1343,11 +1464,32 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
 	if (gp->waitpin_nr)
 		gpmc_waitpin_nr = gp->waitpin_nr;
 
+	/* Traverse NULL terminated array of peripheral pointers and setup */
+	for (gdq = gp->device_pdata, g_per = gpmc_peripheral; *gdq; gdq++)
+		if (IS_ERR_VALUE(gpmc_setup_device(g_per, *gdq)))
+			dev_err(gpmc_dev, "gpmc setup on %s failed\n",
+								(*gdq)->name);
+		else
+			g_per++;
+	gpmc_num_peripheral = g_per - gpmc_peripheral;
+
+	for (l = 0, g_per = gpmc_peripheral;
+			l < gpmc_num_peripheral; l++, g_per++)
+		if (IS_ERR(gpmc_create_device(g_per)))
+			dev_err(gpmc_dev, "device creation on %s failed\n",
+								g_per->name);
+
 	return 0;
 }
 
 static __exit int gpmc_remove(struct platform_device *pdev)
 {
+	struct gpmc_peripheral *g_per = gpmc_peripheral;
+
+	for (; gpmc_num_peripheral; g_per++, gpmc_num_peripheral--)
+		platform_device_unregister(g_per->pdev);
+
+	gpmc_waitpin_map = 0;
 	gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
 	gpmc_free_irq();
 	gpmc_mem_exit();
-- 
1.7.10.2

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

* [PATCH v6 11/13] ARM: OMAP2+: gpmc: cs reconfigure helper
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:57   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

Helper for reconfiguring CS. This helps if a
peripheral needs to reconfigure GPMC settings
different from the one which was configured
during probe.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   32 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    2 ++
 2 files changed, 34 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index ac66267..3729136 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1420,6 +1420,38 @@ struct platform_device *gpmc_create_device(struct gpmc_peripheral *p)
 	return p->pdev;
 }
 
+static int gpmc_match_device(char *name, int id)
+{
+	int i;
+	struct gpmc_peripheral *g_per = gpmc_peripheral;
+
+	for (i = 0; i < gpmc_num_peripheral; i++, g_per++)
+		if (!strcmp(g_per->name, name) && g_per->id == id)
+			return i;
+
+	return -ENOENT;
+}
+
+int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *c)
+{
+	int i;
+
+	i = gpmc_match_device(name, id);
+	if (IS_ERR_VALUE(i)) {
+		dev_err(gpmc_dev, "no device %s.%d to configure\n", name, id);
+		return i;
+	}
+
+	if (IS_ERR_VALUE(gpmc_setup_cs_config_timing(gpmc_peripheral + i, c))) {
+		dev_err(gpmc_dev, "error: configure device %s.%d\n", name, id);
+		return i;
+	}
+
+	return gpmc_setup_waitpin(gpmc_peripheral + i);
+
+}
+EXPORT_SYMBOL_GPL(gpmc_cs_reconfigure);
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 1185490..7909867 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -248,6 +248,8 @@ extern int gpmc_cs_configure(int cs, int cmd, int wval);
 extern int gpmc_nand_read(int cs, int cmd);
 extern int gpmc_nand_write(int cs, int cmd, int wval);
 
+extern int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *c);
+
 int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size);
 int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
 
-- 
1.7.10.2


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

* [PATCH v6 11/13] ARM: OMAP2+: gpmc: cs reconfigure helper
@ 2012-06-22 12:57   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

Helper for reconfiguring CS. This helps if a
peripheral needs to reconfigure GPMC settings
different from the one which was configured
during probe.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   32 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    2 ++
 2 files changed, 34 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index ac66267..3729136 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1420,6 +1420,38 @@ struct platform_device *gpmc_create_device(struct gpmc_peripheral *p)
 	return p->pdev;
 }
 
+static int gpmc_match_device(char *name, int id)
+{
+	int i;
+	struct gpmc_peripheral *g_per = gpmc_peripheral;
+
+	for (i = 0; i < gpmc_num_peripheral; i++, g_per++)
+		if (!strcmp(g_per->name, name) && g_per->id == id)
+			return i;
+
+	return -ENOENT;
+}
+
+int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *c)
+{
+	int i;
+
+	i = gpmc_match_device(name, id);
+	if (IS_ERR_VALUE(i)) {
+		dev_err(gpmc_dev, "no device %s.%d to configure\n", name, id);
+		return i;
+	}
+
+	if (IS_ERR_VALUE(gpmc_setup_cs_config_timing(gpmc_peripheral + i, c))) {
+		dev_err(gpmc_dev, "error: configure device %s.%d\n", name, id);
+		return i;
+	}
+
+	return gpmc_setup_waitpin(gpmc_peripheral + i);
+
+}
+EXPORT_SYMBOL_GPL(gpmc_cs_reconfigure);
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 1185490..7909867 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -248,6 +248,8 @@ extern int gpmc_cs_configure(int cs, int cmd, int wval);
 extern int gpmc_nand_read(int cs, int cmd);
 extern int gpmc_nand_write(int cs, int cmd, int wval);
 
+extern int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *c);
+
 int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size);
 int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
 
-- 
1.7.10.2

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

* [PATCH v6 12/13] ARM: OMAP2+: gpmc: update nand register info
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:57   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

GPMC has dedicated NAND handling blocks and have a few
registers exclusively meant for NAND operations. These
registers can be handled by OMAP NAND driver as it is
meant for handling NAND on GPMC. Update OMAP NAND
platform data with GPMC-NAND register details so that
OMAP NAND driver can handle by itself instead of
relying on GPMC exported symbols.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |    9 ++++++++-
 arch/arm/plat-omap/include/plat/gpmc.h |    1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 3729136..c8e967f 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -28,6 +28,7 @@
 
 #include <asm/mach-types.h>
 #include <plat/gpmc.h>
+#include <plat/nand.h>
 #include <plat/omap_device.h>
 
 #include <plat/sdrc.h>
@@ -1497,12 +1498,18 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
 		gpmc_waitpin_nr = gp->waitpin_nr;
 
 	/* Traverse NULL terminated array of peripheral pointers and setup */
-	for (gdq = gp->device_pdata, g_per = gpmc_peripheral; *gdq; gdq++)
+	for (gdq = gp->device_pdata, g_per = gpmc_peripheral; *gdq; gdq++) {
+		if ((*gdq)->is_nand) {
+			struct omap_nand_platform_data *p = (*gdq)->pdata;
+
+			gpmc_update_nand_reg(&p->reg, p->cs);
+		}
 		if (IS_ERR_VALUE(gpmc_setup_device(g_per, *gdq)))
 			dev_err(gpmc_dev, "gpmc setup on %s failed\n",
 								(*gdq)->name);
 		else
 			g_per++;
+	}
 	gpmc_num_peripheral = g_per - gpmc_peripheral;
 
 	for (l = 0, g_per = gpmc_peripheral;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 7909867..0085a01 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -196,6 +196,7 @@ struct gpmc_device_pdata {
 	unsigned		per_res_cnt;
 	struct gpmc_cs_data	*cs_data;
 	unsigned		num_cs;
+	bool			is_nand;
 };
 
 struct gpmc_pdata {
-- 
1.7.10.2


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

* [PATCH v6 12/13] ARM: OMAP2+: gpmc: update nand register info
@ 2012-06-22 12:57   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

GPMC has dedicated NAND handling blocks and have a few
registers exclusively meant for NAND operations. These
registers can be handled by OMAP NAND driver as it is
meant for handling NAND on GPMC. Update OMAP NAND
platform data with GPMC-NAND register details so that
OMAP NAND driver can handle by itself instead of
relying on GPMC exported symbols.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |    9 ++++++++-
 arch/arm/plat-omap/include/plat/gpmc.h |    1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 3729136..c8e967f 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -28,6 +28,7 @@
 
 #include <asm/mach-types.h>
 #include <plat/gpmc.h>
+#include <plat/nand.h>
 #include <plat/omap_device.h>
 
 #include <plat/sdrc.h>
@@ -1497,12 +1498,18 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
 		gpmc_waitpin_nr = gp->waitpin_nr;
 
 	/* Traverse NULL terminated array of peripheral pointers and setup */
-	for (gdq = gp->device_pdata, g_per = gpmc_peripheral; *gdq; gdq++)
+	for (gdq = gp->device_pdata, g_per = gpmc_peripheral; *gdq; gdq++) {
+		if ((*gdq)->is_nand) {
+			struct omap_nand_platform_data *p = (*gdq)->pdata;
+
+			gpmc_update_nand_reg(&p->reg, p->cs);
+		}
 		if (IS_ERR_VALUE(gpmc_setup_device(g_per, *gdq)))
 			dev_err(gpmc_dev, "gpmc setup on %s failed\n",
 								(*gdq)->name);
 		else
 			g_per++;
+	}
 	gpmc_num_peripheral = g_per - gpmc_peripheral;
 
 	for (l = 0, g_per = gpmc_peripheral;
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 7909867..0085a01 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -196,6 +196,7 @@ struct gpmc_device_pdata {
 	unsigned		per_res_cnt;
 	struct gpmc_cs_data	*cs_data;
 	unsigned		num_cs;
+	bool			is_nand;
 };
 
 struct gpmc_pdata {
-- 
1.7.10.2

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

* [PATCH v6 13/13] ARM: OMAP2+: gpmc: configure writeprotect
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-22 12:57   ` Afzal Mohammed
  -1 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: tony, paul, jon-hunter, linux-omap, linux-arm-kernel; +Cc: Afzal Mohammed

GPMC has a writeprotect pin that can be connected to
peripherals. Default is to disable writeprotect. In
case of conflicting requirement of writeprotect, it
will be left in enabled state to be on safer side,
along with a warning to attract user attention.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   42 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    2 ++
 2 files changed, 44 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c8e967f..1b0b526 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -110,6 +110,12 @@ enum {
 	GPMC_MAX_NR_WAITPIN
 };
 
+enum {
+	NONE,
+	OFF,
+	ON
+};
+
 struct gpmc_client_irq	{
 	unsigned		irq;
 	u32			bitmask;
@@ -161,6 +167,7 @@ static struct gpmc_peripheral gpmc_peripheral[GPMC_CS_NUM];
 static unsigned gpmc_num_peripheral;
 static unsigned gpmc_waitpin_map;
 static unsigned gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
+static unsigned gpmc_writeprotect;
 
 static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
 static struct irq_chip gpmc_irq_chip;
@@ -192,6 +199,18 @@ static u32 gpmc_read_reg(int idx)
 	return __raw_readl(gpmc_base + idx);
 }
 
+static inline void gpmc_modify_reg(int idx, u32 mask, bool value)
+{
+	u32 l;
+
+	l = gpmc_read_reg(idx);
+	if (value)
+		l |= mask;
+	else
+		l &= ~mask;
+	gpmc_write_reg(idx, l);
+}
+
 static void gpmc_cs_write_byte(int cs, int idx, u8 val)
 {
 	void __iomem *reg_addr;
@@ -991,6 +1010,7 @@ static __devinit int gpmc_setup_cs_mem(struct gpmc_cs_data *cs,
 static void gpmc_setup_cs_config(unsigned cs, unsigned conf)
 {
 	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+	unsigned wp;
 
 	l &= ~(GPMC_CONFIG1_MUXADDDATA |
 		GPMC_CONFIG1_WRITETYPE_SYNC |
@@ -1025,6 +1045,19 @@ static void gpmc_setup_cs_config(unsigned cs, unsigned conf)
 	l |= conf;
 
 	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+
+	if (conf & GPMC_CONFIG_ENABLE_WRITEPROTECT)
+		wp = ON;
+	else
+		wp = OFF;
+
+	if (gpmc_writeprotect) {
+		if (gpmc_writeprotect != wp) {
+			dev_warn(gpmc_dev, "conflicting writeprotect requests, writeprotect is left enabled\n");
+			gpmc_writeprotect = ON;
+		}
+	} else
+		gpmc_writeprotect = wp;
 }
 
 static inline void gpmc_set_one_timing(int cs, int reg, int start,
@@ -1453,6 +1486,12 @@ int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *c)
 }
 EXPORT_SYMBOL_GPL(gpmc_cs_reconfigure);
 
+static inline void gpmc_setup_writeprotect(void)
+{
+	gpmc_modify_reg(GPMC_CONFIG, GPMC_CONFIG_WRITEPROTECT,
+					gpmc_writeprotect == ON ? false : true);
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
@@ -1512,6 +1551,8 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
 	}
 	gpmc_num_peripheral = g_per - gpmc_peripheral;
 
+	gpmc_setup_writeprotect();
+
 	for (l = 0, g_per = gpmc_peripheral;
 			l < gpmc_num_peripheral; l++, g_per++)
 		if (IS_ERR(gpmc_create_device(g_per)))
@@ -1528,6 +1569,7 @@ static __exit int gpmc_remove(struct platform_device *pdev)
 	for (; gpmc_num_peripheral; g_per++, gpmc_num_peripheral--)
 		platform_device_unregister(g_per->pdev);
 
+	gpmc_writeprotect = NONE;
 	gpmc_waitpin_map = 0;
 	gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
 	gpmc_free_irq();
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 0085a01..3de05dc 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -79,6 +79,8 @@
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 #define GPMC_CONFIG7_CSVALID		(1 << 6)
 
+#define	GPMC_CONFIG_ENABLE_WRITEPROTECT	(1 << 5)
+
 #define	GPMC_WAITPIN_ACTIVE_HIGH	(1 << 4)
 #define	GPMC_WAITPIN_ACTIVE_LOW		(0 << 4)
 #define	GPMC_WAITPIN_0			(1 << 0)
-- 
1.7.10.2


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

* [PATCH v6 13/13] ARM: OMAP2+: gpmc: configure writeprotect
@ 2012-06-22 12:57   ` Afzal Mohammed
  0 siblings, 0 replies; 30+ messages in thread
From: Afzal Mohammed @ 2012-06-22 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

GPMC has a writeprotect pin that can be connected to
peripherals. Default is to disable writeprotect. In
case of conflicting requirement of writeprotect, it
will be left in enabled state to be on safer side,
along with a warning to attract user attention.

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |   42 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |    2 ++
 2 files changed, 44 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c8e967f..1b0b526 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -110,6 +110,12 @@ enum {
 	GPMC_MAX_NR_WAITPIN
 };
 
+enum {
+	NONE,
+	OFF,
+	ON
+};
+
 struct gpmc_client_irq	{
 	unsigned		irq;
 	u32			bitmask;
@@ -161,6 +167,7 @@ static struct gpmc_peripheral gpmc_peripheral[GPMC_CS_NUM];
 static unsigned gpmc_num_peripheral;
 static unsigned gpmc_waitpin_map;
 static unsigned gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
+static unsigned gpmc_writeprotect;
 
 static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
 static struct irq_chip gpmc_irq_chip;
@@ -192,6 +199,18 @@ static u32 gpmc_read_reg(int idx)
 	return __raw_readl(gpmc_base + idx);
 }
 
+static inline void gpmc_modify_reg(int idx, u32 mask, bool value)
+{
+	u32 l;
+
+	l = gpmc_read_reg(idx);
+	if (value)
+		l |= mask;
+	else
+		l &= ~mask;
+	gpmc_write_reg(idx, l);
+}
+
 static void gpmc_cs_write_byte(int cs, int idx, u8 val)
 {
 	void __iomem *reg_addr;
@@ -991,6 +1010,7 @@ static __devinit int gpmc_setup_cs_mem(struct gpmc_cs_data *cs,
 static void gpmc_setup_cs_config(unsigned cs, unsigned conf)
 {
 	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+	unsigned wp;
 
 	l &= ~(GPMC_CONFIG1_MUXADDDATA |
 		GPMC_CONFIG1_WRITETYPE_SYNC |
@@ -1025,6 +1045,19 @@ static void gpmc_setup_cs_config(unsigned cs, unsigned conf)
 	l |= conf;
 
 	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+
+	if (conf & GPMC_CONFIG_ENABLE_WRITEPROTECT)
+		wp = ON;
+	else
+		wp = OFF;
+
+	if (gpmc_writeprotect) {
+		if (gpmc_writeprotect != wp) {
+			dev_warn(gpmc_dev, "conflicting writeprotect requests, writeprotect is left enabled\n");
+			gpmc_writeprotect = ON;
+		}
+	} else
+		gpmc_writeprotect = wp;
 }
 
 static inline void gpmc_set_one_timing(int cs, int reg, int start,
@@ -1453,6 +1486,12 @@ int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *c)
 }
 EXPORT_SYMBOL_GPL(gpmc_cs_reconfigure);
 
+static inline void gpmc_setup_writeprotect(void)
+{
+	gpmc_modify_reg(GPMC_CONFIG, GPMC_CONFIG_WRITEPROTECT,
+					gpmc_writeprotect == ON ? false : true);
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
 	u32 l;
@@ -1512,6 +1551,8 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
 	}
 	gpmc_num_peripheral = g_per - gpmc_peripheral;
 
+	gpmc_setup_writeprotect();
+
 	for (l = 0, g_per = gpmc_peripheral;
 			l < gpmc_num_peripheral; l++, g_per++)
 		if (IS_ERR(gpmc_create_device(g_per)))
@@ -1528,6 +1569,7 @@ static __exit int gpmc_remove(struct platform_device *pdev)
 	for (; gpmc_num_peripheral; g_per++, gpmc_num_peripheral--)
 		platform_device_unregister(g_per->pdev);
 
+	gpmc_writeprotect = NONE;
 	gpmc_waitpin_map = 0;
 	gpmc_waitpin_nr = GPMC_MAX_NR_WAITPIN;
 	gpmc_free_irq();
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 0085a01..3de05dc 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -79,6 +79,8 @@
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 #define GPMC_CONFIG7_CSVALID		(1 << 6)
 
+#define	GPMC_CONFIG_ENABLE_WRITEPROTECT	(1 << 5)
+
 #define	GPMC_WAITPIN_ACTIVE_HIGH	(1 << 4)
 #define	GPMC_WAITPIN_ACTIVE_LOW		(0 << 4)
 #define	GPMC_WAITPIN_0			(1 << 0)
-- 
1.7.10.2

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

* RE: [PATCH v6 00/13] GPMC driver conversion
  2012-06-22 12:55 ` Afzal Mohammed
@ 2012-06-26  8:58   ` Mohammed, Afzal
  -1 siblings, 0 replies; 30+ messages in thread
From: Mohammed, Afzal @ 2012-06-26  8:58 UTC (permalink / raw)
  To: tony, paul, Hunter, Jon, linux-omap, linux-arm-kernel

Hi Tony,

On Fri, Jun 22, 2012 at 18:25:38, Mohammed, Afzal wrote:

> This series is based on 3.5-rc1, and is dependent on [1,2,3], and has
> been tested on omap3evm (smsc911x) rev G & C and beagle board(nand).
> Also using private patches, nand & onenand was tested on omap3evm,
> rev G & C respectively (as support for these were not in mainline)
> 
> All boards will work using the old existing interface. Further patch
> series would convert all boards to use new interface.
> 
> Many of GPMC peripherals depend on bootloader for configuration.
> This is going to be deprecated. feature-removal-schedule.txt will be
> updated in one of the upcoming patch series.
> 
> Thanks to Tony & Jon for their various suggestions.
> 
> [PATCH 03/13] ARM: OMAP2+: gpmc: driver migration helper, is to be
> reverted once all GPMC peripherals are migrated to use driver
> interface.

Please let me know your comments on this series.

Regards
Afzal

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

* [PATCH v6 00/13] GPMC driver conversion
@ 2012-06-26  8:58   ` Mohammed, Afzal
  0 siblings, 0 replies; 30+ messages in thread
From: Mohammed, Afzal @ 2012-06-26  8:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tony,

On Fri, Jun 22, 2012 at 18:25:38, Mohammed, Afzal wrote:

> This series is based on 3.5-rc1, and is dependent on [1,2,3], and has
> been tested on omap3evm (smsc911x) rev G & C and beagle board(nand).
> Also using private patches, nand & onenand was tested on omap3evm,
> rev G & C respectively (as support for these were not in mainline)
> 
> All boards will work using the old existing interface. Further patch
> series would convert all boards to use new interface.
> 
> Many of GPMC peripherals depend on bootloader for configuration.
> This is going to be deprecated. feature-removal-schedule.txt will be
> updated in one of the upcoming patch series.
> 
> Thanks to Tony & Jon for their various suggestions.
> 
> [PATCH 03/13] ARM: OMAP2+: gpmc: driver migration helper, is to be
> reverted once all GPMC peripherals are migrated to use driver
> interface.

Please let me know your comments on this series.

Regards
Afzal

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

end of thread, other threads:[~2012-06-26  8:58 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-22 12:55 [PATCH v6 00/13] GPMC driver conversion Afzal Mohammed
2012-06-22 12:55 ` Afzal Mohammed
2012-06-22 12:56 ` [PATCH v6 01/13] ARM: OMAP2+: gpmc: platform definitions Afzal Mohammed
2012-06-22 12:56   ` Afzal Mohammed
2012-06-22 12:56 ` [PATCH v6 02/13] ARM: OMAP2+: gpmc: Adapt to HWMOD Afzal Mohammed
2012-06-22 12:56   ` Afzal Mohammed
2012-06-22 12:56 ` [PATCH v6 03/13] ARM: OMAP2+: gpmc: driver migration helper Afzal Mohammed
2012-06-22 12:56   ` Afzal Mohammed
2012-06-22 12:56 ` [PATCH v6 04/13] ARM: OMAP2+: gpmc: minimal driver support Afzal Mohammed
2012-06-22 12:56   ` Afzal Mohammed
2012-06-22 12:56 ` [PATCH v6 05/13] ARM: OMAP2+: gpmc: resource creation helpers Afzal Mohammed
2012-06-22 12:56   ` Afzal Mohammed
2012-06-22 12:57 ` [PATCH v6 06/13] ARM: OMAP2+: gpmc: CS configuration helper Afzal Mohammed
2012-06-22 12:57   ` Afzal Mohammed
2012-06-22 12:57 ` [PATCH v6 07/13] ARM: OMAP2+: gpmc: register time setting helper Afzal Mohammed
2012-06-22 12:57   ` Afzal Mohammed
2012-06-22 12:57 ` [PATCH v6 08/13] ARM: OMAP2+: gpmc: holler if no configuration Afzal Mohammed
2012-06-22 12:57   ` Afzal Mohammed
2012-06-22 12:57 ` [PATCH v6 09/13] ARM: OMAP2+: gpmc: waitpin helper Afzal Mohammed
2012-06-22 12:57   ` Afzal Mohammed
2012-06-22 12:57 ` [PATCH v6 10/13] ARM: OMAP2+: gpmc: handle connected peripherals Afzal Mohammed
2012-06-22 12:57   ` Afzal Mohammed
2012-06-22 12:57 ` [PATCH v6 11/13] ARM: OMAP2+: gpmc: cs reconfigure helper Afzal Mohammed
2012-06-22 12:57   ` Afzal Mohammed
2012-06-22 12:57 ` [PATCH v6 12/13] ARM: OMAP2+: gpmc: update nand register info Afzal Mohammed
2012-06-22 12:57   ` Afzal Mohammed
2012-06-22 12:57 ` [PATCH v6 13/13] ARM: OMAP2+: gpmc: configure writeprotect Afzal Mohammed
2012-06-22 12:57   ` Afzal Mohammed
2012-06-26  8:58 ` [PATCH v6 00/13] GPMC driver conversion Mohammed, Afzal
2012-06-26  8:58   ` Mohammed, Afzal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.