Skip to contentSkip to conversation

GPMC driver conversion

PATCH New Afzal Mohammed 2 participants 8 messages Sep 11, 2012 – Sep 17, 2012

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

v9 cover GPMC driver conversion

Hi,

Basic gpmc driver conversion series. Driver that is now created out of gpmc code is a simple one, it handles tasks that were earlier executed by gpmc_init. Now instead of relying on cpu_is_* checks, it obtains resources and clk handle in the standard Linux way. The existing gpmc interface works as was without this series.

HWMOD patch also has been brought into this series back with v7 series

As this creates only a basic driver, further gpmc driver work can be based over this, while having a driver first in place.

This series is based on l-o/testing-cleanup as on 11-Sep-12, i.e. over commit,

e274bffb ARM: OMAP1: Move SoC specific headers from plat to mach for omap1

It is available @git://gitorious.org/x0148406-public/linux-kernel.git gpmc-drv-v9

This series has been tested on omap3evm (rev G).

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

v9:
3xxx gpmc clock domain as core_l3_clkdm
Lower case hex numbers

v8:
Use feature flag to decide whether wr_access and wr_data_mux_bus timings has to be configured (PATCH 3/3)
v7:
Create a simple driver that gets resources & clk the standard Linux way Pull in HMWOD patch back into this series
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 (3):
ARM: OMAP2/3: hwmod data: add gpmc
ARM: OMAP2+: gpmc: Adapt to HWMOD
ARM: OMAP2+: gpmc: minimal driver support

 arch/arm/mach-omap2/gpmc.c                         |  193 +++++++++++++++-----
 arch/arm/mach-omap2/omap_hwmod_2420_data.c         |   18 ++
 arch/arm/mach-omap2/omap_hwmod_2430_data.c         |   18 ++
 arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c |   44 +++++-
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |   54 ++++++
 arch/arm/mach-omap2/omap_hwmod_common_data.h       |    1 +
 arch/arm/mach-omap2/prcm-common.h                  |    2 +
 7 files changed, 280 insertions(+), 50 deletions(-)
#1 lore raw

PATCH v9 1/3 ARM: OMAP2/3: hwmod data: add gpmc

Add gpmc hwmod and associated interconnect data

---
 arch/arm/mach-omap2/omap_hwmod_2420_data.c         |   18 +++++++
 arch/arm/mach-omap2/omap_hwmod_2430_data.c         |   18 +++++++
 arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c |   44 ++++++++++++++++-
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |   54 ++++++++++++++++++++
 arch/arm/mach-omap2/omap_hwmod_common_data.h       |    1 +
 arch/arm/mach-omap2/prcm-common.h                  |    2 +
 6 files changed, 136 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +18 -0
index 4e81637..5fcd225 100644
@@ -535,6 +535,15 @@ static struct omap_hwmod_addr_space omap2420_counter_32k_addrs[] = {
 	{ }
 };
 
+static struct omap_hwmod_addr_space omap2420_gpmc_addrs[] = {
+	{
+		.pa_start	= 0x6800a000,
+		.pa_end		= 0x6800afff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
 static struct omap_hwmod_ocp_if omap2420_l4_wkup__counter_32k = {
 	.master		= &omap2xxx_l4_wkup_hwmod,
 	.slave		= &omap2xxx_counter_32k_hwmod,
@@ -543,6 +552,14 @@ static struct omap_hwmod_ocp_if omap2420_l4_wkup__counter_32k = {
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_ocp_if omap2420_l3__gpmc = {
+	.master		= &omap2xxx_l3_main_hwmod,
+	.slave		= &omap2xxx_gpmc_hwmod,
+	.clk		= "core_l3_ck",
+	.addr		= omap2420_gpmc_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = {
 	&omap2xxx_l3_main__l4_core,
 	&omap2xxx_mpu__l3_main,
@@ -586,6 +603,7 @@ static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = {
 	&omap2420_l4_core__msdi1,
 	&omap2420_l4_core__hdq1w,
 	&omap2420_l4_wkup__counter_32k,
+	&omap2420_l3__gpmc,
 	NULL,
 };
 
arch/arm/mach-omap2/omap_hwmod_2430_data.c +18 -0
index ceb23c3..a560563 100644
@@ -887,6 +887,15 @@ static struct omap_hwmod_addr_space omap2430_counter_32k_addrs[] = {
 	{ }
 };
 
+static struct omap_hwmod_addr_space omap2430_gpmc_addrs[] = {
+	{
+		.pa_start	= 0x6e000000,
+		.pa_end		= 0x6e000fff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
 static struct omap_hwmod_ocp_if omap2430_l4_wkup__counter_32k = {
 	.master		= &omap2xxx_l4_wkup_hwmod,
 	.slave		= &omap2xxx_counter_32k_hwmod,
@@ -895,6 +904,14 @@ static struct omap_hwmod_ocp_if omap2430_l4_wkup__counter_32k = {
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_ocp_if omap2430_l3__gpmc = {
+	.master		= &omap2xxx_l3_main_hwmod,
+	.slave		= &omap2xxx_gpmc_hwmod,
+	.clk		= "core_l3_ck",
+	.addr		= omap2430_gpmc_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = {
 	&omap2xxx_l3_main__l4_core,
 	&omap2xxx_mpu__l3_main,
@@ -945,6 +962,7 @@ static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = {
 	&omap2430_l4_core__mcbsp5,
 	&omap2430_l4_core__hdq1w,
 	&omap2430_l4_wkup__counter_32k,
+	&omap2430_l3__gpmc,
 	NULL,
 };
 
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +43 -1

59 lines not on this page · raw message

arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +54 -0

78 lines not on this page · raw message

arch/arm/mach-omap2/omap_hwmod_common_data.h +1 -0
index dddb677..6a033b8 100644
@@ -77,6 +77,7 @@ extern struct omap_hwmod omap2xxx_gpio4_hwmod;
 extern struct omap_hwmod omap2xxx_mcspi1_hwmod;
 extern struct omap_hwmod omap2xxx_mcspi2_hwmod;
 extern struct omap_hwmod omap2xxx_counter_32k_hwmod;
+extern struct omap_hwmod omap2xxx_gpmc_hwmod;
 
 /* Common interface data across OMAP2xxx */
 extern struct omap_hwmod_ocp_if omap2xxx_l3_main__l4_core;
arch/arm/mach-omap2/prcm-common.h +2 -0
index e5f0503..72df974 100644
@@ -109,6 +109,8 @@
 #define OMAP2430_EN_MDM_INTC_MASK			(1 << 11)
 #define OMAP2430_EN_USBHS_SHIFT				6
 #define OMAP2430_EN_USBHS_MASK				(1 << 6)
+#define OMAP24XX_EN_GPMC_SHIFT				1
+#define OMAP24XX_EN_GPMC_MASK				(1 << 1)
 
 /* CM_IDLEST1_CORE, PM_WKST1_CORE shared bits */
 #define OMAP2420_ST_MMC_SHIFT				26
Signature · 1 line
1.7.0.4
maintainer
#2 lore raw

PATCH v9 1/3 ARM: OMAP2/3: hwmod data: add gpmc

Hi

Quoted 3 lines · Afzal Mohammed

Add gpmc hwmod and associated interconnect data

So this adds HWMOD_INIT_NO_RESET across all the GPMC hwmods:

Review

Quoted 3 lines
(quoted diff) +3 -0
+	.flags		= HWMOD_INIT_NO_IDLE |
+				HWMOD_INIT_NO_RESET |
+				HWMOD_NO_IDLEST,

As I understand it, this is not due to any GPMC-related reset bugs, but just because the kernel is relying on the bootloader GPMC timing data being preserved. Is that correct?

Assuming it is, ideally we wouldn't merge such a patch, but I guess this is somewhat complicated now with the DT transition. So those should be marked with comments so we know this is not a hardware bug... something like the following.

- Paul

From: Afzal Mohammed <[email protected]>
Date: Tue, 11 Sep 2012 15:26:53 +0530
Subject: [PATCH] ARM: OMAP2/3: hwmod data: add gpmc

Add gpmc hwmod and associated interconnect data

[paul at pwsan.com: added comments to the use of HWMOD_INIT_NO_RESET]
---
 arch/arm/mach-omap2/omap_hwmod_2420_data.c         |   18 ++++++
 arch/arm/mach-omap2/omap_hwmod_2430_data.c         |   18 ++++++
 arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c |   51 +++++++++++++++-
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |   61 ++++++++++++++++++++
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c         |    8 +++
 arch/arm/mach-omap2/omap_hwmod_common_data.h       |    1 +
 arch/arm/mach-omap2/prcm-common.h                  |    2 +
 7 files changed, 158 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +18 -0
index 4e81637..5fcd225 100644
@@ -535,6 +535,15 @@ static struct omap_hwmod_addr_space omap2420_counter_32k_addrs[] = {
 	{ }
 };
 
+static struct omap_hwmod_addr_space omap2420_gpmc_addrs[] = {
+	{
+		.pa_start	= 0x6800a000,
+		.pa_end		= 0x6800afff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
 static struct omap_hwmod_ocp_if omap2420_l4_wkup__counter_32k = {
 	.master		= &omap2xxx_l4_wkup_hwmod,
 	.slave		= &omap2xxx_counter_32k_hwmod,
@@ -543,6 +552,14 @@ static struct omap_hwmod_ocp_if omap2420_l4_wkup__counter_32k = {
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_ocp_if omap2420_l3__gpmc = {
+	.master		= &omap2xxx_l3_main_hwmod,
+	.slave		= &omap2xxx_gpmc_hwmod,
+	.clk		= "core_l3_ck",
+	.addr		= omap2420_gpmc_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = {
 	&omap2xxx_l3_main__l4_core,
 	&omap2xxx_mpu__l3_main,
@@ -586,6 +603,7 @@ static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = {
 	&omap2420_l4_core__msdi1,
 	&omap2420_l4_core__hdq1w,
 	&omap2420_l4_wkup__counter_32k,
+	&omap2420_l3__gpmc,
 	NULL,
 };
 
arch/arm/mach-omap2/omap_hwmod_2430_data.c +18 -0
index ceb23c3..a560563 100644
@@ -887,6 +887,15 @@ static struct omap_hwmod_addr_space omap2430_counter_32k_addrs[] = {
 	{ }
 };
 
+static struct omap_hwmod_addr_space omap2430_gpmc_addrs[] = {
+	{
+		.pa_start	= 0x6e000000,
+		.pa_end		= 0x6e000fff,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
 static struct omap_hwmod_ocp_if omap2430_l4_wkup__counter_32k = {
 	.master		= &omap2xxx_l4_wkup_hwmod,
 	.slave		= &omap2xxx_counter_32k_hwmod,
@@ -895,6 +904,14 @@ static struct omap_hwmod_ocp_if omap2430_l4_wkup__counter_32k = {
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_ocp_if omap2430_l3__gpmc = {
+	.master		= &omap2xxx_l3_main_hwmod,
+	.slave		= &omap2xxx_gpmc_hwmod,
+	.clk		= "core_l3_ck",
+	.addr		= omap2430_gpmc_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = {
 	&omap2xxx_l3_main__l4_core,
 	&omap2xxx_mpu__l3_main,
@@ -945,6 +962,7 @@ static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = {
 	&omap2430_l4_core__mcbsp5,
 	&omap2430_l4_core__hdq1w,
 	&omap2430_l4_wkup__counter_32k,
+	&omap2430_l3__gpmc,
 	NULL,
 };
 
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +50 -1

66 lines not on this page · raw message

arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +61 -0

85 lines not on this page · raw message

arch/arm/mach-omap2/omap_hwmod_44xx_data.c +8 -0
index b95244b..6f3dfb0 100644
@@ -1323,6 +1323,14 @@ static struct omap_hwmod omap44xx_gpmc_hwmod = {
 	.name		= "gpmc",
 	.class		= &omap44xx_gpmc_hwmod_class,
 	.clkdm_name	= "l3_2_clkdm",
+	/*
+	 * XXX HWMOD_INIT_NO_RESET should not be needed for this IP
+	 * block.  It is not being added due to any known bugs with
+	 * resetting the GPMC IP block, but rather because any timings
+	 * set by the bootloader are not being correctly programmed by
+	 * the kernel from the board file or DT data.
+	 * HWMOD_INIT_NO_RESET should be removed ASAP.
+	 */
 	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
 	.mpu_irqs	= omap44xx_gpmc_irqs,
 	.sdma_reqs	= omap44xx_gpmc_sdma_reqs,
arch/arm/mach-omap2/omap_hwmod_common_data.h +1 -0
index dddb677..6a033b87 100644
@@ -77,6 +77,7 @@ extern struct omap_hwmod omap2xxx_gpio4_hwmod;
 extern struct omap_hwmod omap2xxx_mcspi1_hwmod;
 extern struct omap_hwmod omap2xxx_mcspi2_hwmod;
 extern struct omap_hwmod omap2xxx_counter_32k_hwmod;
+extern struct omap_hwmod omap2xxx_gpmc_hwmod;
 
 /* Common interface data across OMAP2xxx */
 extern struct omap_hwmod_ocp_if omap2xxx_l3_main__l4_core;
arch/arm/mach-omap2/prcm-common.h +2 -0
index e5f0503..72df974 100644
@@ -109,6 +109,8 @@
 #define OMAP2430_EN_MDM_INTC_MASK			(1 << 11)
 #define OMAP2430_EN_USBHS_SHIFT				6
 #define OMAP2430_EN_USBHS_MASK				(1 << 6)
+#define OMAP24XX_EN_GPMC_SHIFT				1
+#define OMAP24XX_EN_GPMC_MASK				(1 << 1)
 
 /* CM_IDLEST1_CORE, PM_WKST1_CORE shared bits */
 #define OMAP2420_ST_MMC_SHIFT				26
Signature · 1 line
1.7.10.4
#3 lore raw

PATCH v9 1/3 ARM: OMAP2/3: hwmod data: add gpmc

Hi Paul,

Quoted 5 lines · Paul Walmsley

Review

Quoted 1 line
(quoted diff) +1 -0
+				HWMOD_INIT_NO_RESET |

As I understand it, this is not due to any GPMC-related reset bugs, but just because the kernel is relying on the bootloader GPMC timing data being preserved. Is that correct?

Yes, it is due to Kernel relying on bootloader gpmc settings

Quoted 4 lines

Assuming it is, ideally we wouldn't merge such a patch, but I guess this is somewhat complicated now with the DT transition. So those should be marked with comments so we know this is not a hardware bug... something like the following.

Thanks

Regards
Afzal

#4 lore raw

PATCH v9 2/3 ARM: OMAP2+: gpmc: Adapt to HWMOD

In reply to Afzal Mohammed

Create API for platforms to adapt GPMC to HWMOD

---
 arch/arm/mach-omap2/gpmc.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/gpmc.c +22 -0
index 055ae8b..5462666 100644
@@ -31,10 +31,13 @@
 #include <plat/cpu.h>
 #include <plat/gpmc.h>
 #include <plat/sdrc.h>
+#include <plat/omap_device.h>
 
 #include "soc.h"
 #include "common.h"
 
+#define	DEVICE_NAME		"omap-gpmc"
+
 /* GPMC register offsets */
 #define GPMC_REVISION		0x00
 #define GPMC_SYSCONFIG		0x10
@@ -898,6 +901,25 @@ static int __init gpmc_init(void)
 }
 postcore_initcall(gpmc_init);
 
+static int __init omap_gpmc_init(void)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *oh_name = "gpmc";
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0, NULL, 0, 0);
+	WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
+
+	return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
+}
+postcore_initcall(omap_gpmc_init);
+
 static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 {
 	int i;
Signature · 1 line
1.7.0.4
#5 lore raw

PATCH v9 3/3 ARM: OMAP2+: gpmc: minimal driver support

In reply to Afzal Mohammed

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

---
 arch/arm/mach-omap2/gpmc.c |  171 +++++++++++++++++++++++++++++++-------------
 1 files changed, 122 insertions(+), 49 deletions(-)
arch/arm/mach-omap2/gpmc.c +122 -49
index 5462666..a628fdc 100644
@@ -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>
@@ -86,6 +87,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
@@ -131,7 +138,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 int gpmc_irq;
+static resource_size_t phys_base, mem_size;
+static unsigned gpmc_capability;
 static void __iomem *gpmc_base;
 
 static struct clk *gpmc_l3_clk;
@@ -321,10 +331,10 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 
 	GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
 
-	if (cpu_is_omap34xx()) {
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
 		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
+	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
 		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
-	}
 
 	/* caller is expected to have initialized CONFIG1 to cover
 	 * at least sync vs async
@@ -434,6 +444,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];
@@ -770,7 +793,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;
@@ -814,7 +837,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;
@@ -841,65 +894,85 @@ 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 = 20 + OMAP_INTC_START;
-	} else if (cpu_is_omap34xx()) {
-		ck = "gpmc_fck";
-		l = OMAP34XX_GPMC_BASE;
-		gpmc_irq = 20 + OMAP_INTC_START;
-	} else if (cpu_is_omap44xx() || soc_is_omap54xx()) {
-		/* Base address and irq number are same for OMAP4/5 */
-		ck = "gpmc_ck";
-		l = OMAP44XX_GPMC_BASE;
-		gpmc_irq = 20 + OMAP44XX_IRQ_GIC_START;
-	}
+	struct resource *res;
 
-	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);
+	gpmc_base = devm_request_and_ioremap(&pdev->dev, res);
 	if (!gpmc_base) {
-		clk_put(gpmc_l3_clk);
-		printk(KERN_ERR "Could not get GPMC register memory\n");
-		BUG();
+		dev_err(&pdev->dev, "error: request memory / ioremap\n");
+		return -EADDRNOTAVAIL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL)
+		dev_warn(&pdev->dev, "Failed to get resource: irq\n");
+	else
+		gpmc_irq = res->start;
+
+	gpmc_l3_clk = clk_get(&pdev->dev, "fck");
+	if (IS_ERR(gpmc_l3_clk)) {
+		dev_err(&pdev->dev, "error: clk_get\n");
+		gpmc_irq = 0;
+		return PTR_ERR(gpmc_l3_clk);
 	}
 
 	clk_enable(gpmc_l3_clk);
 
+	gpmc_dev = &pdev->dev;
+
 	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	= DEVICE_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);
 
 static int __init omap_gpmc_init(void)
 {
Signature · 1 line
1.7.0.4
maintainer
#6 lore raw

PATCH v9 3/3 ARM: OMAP2+: gpmc: minimal driver support

Hi

Quoted 6 lines · Afzal Mohammed

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

Two checkpatch warnings are added by this patch:

CHECK: multiple assignments should be avoided
#77: FILE: arch/arm/mach-omap2/gpmc.c:454:
+ res->start = res->end = 0;

CHECK: Alignment should match open parenthesis
#216: FILE: arch/arm/mach-omap2/gpmc.c:936:
+ dev_info(gpmc_dev, "GPMC revision %d.%d\n",
+ GPMC_REVISION_MAJOR(l), GPMC_REVISION_MINOR(l));

I've fixed them here in the obvious way. But please make sure that all your patches are clean with 'checkpatch.pl --strict'; saves us time and frustration...

- Paul

#7 lore raw

PATCH v9 3/3 ARM: OMAP2+: gpmc: minimal driver support

Hi Paul,

Quoted 1 line · Paul Walmsley

Two checkpatch warnings are added by this patch:

I did checkpatch earlier, but without --strict

Quoted 3 lines

I've fixed them here in the obvious way. But please make sure that all your patches are clean with 'checkpatch.pl --strict'; saves us time and frustration...

I am sorry for that, in future --strict will be part of my process

Perhaps it would be better to patch Documentation with a mention of --strict for checkpatch

And seeing an unpleasant behavior with --strict, running checkpatch over cached changes (for pre-commit hook) is not making effect of --strict felt

Regards
Afzal