All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4-alt 0/6] GPMC driver migrate one
@ 2012-05-02  8:45 Afzal Mohammed
  2012-05-02  8:45 ` [PATCH v4-alt 1/6] ARM: OMAP2+: gpmc: driver conversion Afzal Mohammed
                   ` (6 more replies)
  0 siblings, 7 replies; 26+ messages in thread
From: Afzal Mohammed @ 2012-05-02  8:45 UTC (permalink / raw)
  To: tony; +Cc: linux-omap, Afzal Mohammed

Hi Tony,

As you would have already seen, v4 of GPMC driver conversion has been
posted (this is v4-alt). I undertand the risk involved in converting
all board files to use new interface in a single patch series. But to
have a decent set of patches, I feel this is required. But this may
bring us to a point where GPMC may not work on some boards.

To resolve this and as per your earlier question on whether old along
with new interface can be made to work parallely, here is suggestion
from my end to deal with it.

This series converts to driver, as an example provides new interface
for smsc911x, while keeping the old interface. As an example omap3evm
has been tested. With this patch series omap3evm will work with new
interface, and if 6/6 is not included, it will work with old
interface. But this necessitates some ugly patches which are present
in this series.

So the suggestion is, enhance v4-alt to handle new interface parallely
for others (GPMC peripherals & boards), hence creating vX-alt (I will
do it if you feel is required, but have not proceeded too much in this
dierction as of now as not sure whether you want to take this path),
have vX-alt in one of your branches, also preferably merged to master,
have the original series also in a separate branch. Let all the boards
be tested, by those who have (I have only omap3evm, beagle board that
is supported in mainline, in addition to beaglebone, am335x evm, but
these won't boot on mainline), add fixes due to problems on
boards (if), incorporate review comments onto vX-alt branch, once we
are sure that all boards work, revert hacks in vX-alt branch and
finally revise proper v4 to vX having decent set of patches such that,

git diff vX-alt..vX is zero.

If with v4 directly, all boards work properly, we may not have to
go through all these, but I realize, that may not happen in the first
try itself. But I am not so pessimistic though, as all the test were
initially done on omap3evm (SMSC911x, NAND & OneNAND, last two were
tested using private patches on new & old omap3evm), and upon adding
board modification for beagleboard, NAND directly worked, in addition
to the surprise that HWMOD on OMAP3 did work properly first time.

I would prefer directly using single patch series for converting all
the boards, but if you prefer an alternative path to be on safer side,
above is my suggestion, or if you have any other plans, let me know.

Please let me know whether you are fine in taking patch series
as in v4 (that converts all boards at once, with further revisions
based on review comments).

Both v4 & v4-alt series are available as tags gpmc-v4 & gpmc-v4-alt,
repectively @git://gitorious.org/x0148406-public/linux-kernel.git

Regards
Afzal


Afzal Mohammed (6):
  ARM: OMAP2+: gpmc: driver conversion
  ARM: OMAP2+: gpmc: Adapt to HWMOD
  ARM: OMAP3: hwmod data: add gpmc
  ARM: OMAP2+: gpmc: driver migration hack
  ARM: OMAP2+: gpmc-smsc911x: Add helper for driver conversion
  ARM: OMAP2+: board omap3evm: gpmc driver adaptation

 arch/arm/mach-omap2/board-omap3evm.c            |   14 +-
 arch/arm/mach-omap2/gpmc-smsc911x.c             |   70 ++
 arch/arm/mach-omap2/gpmc.c                      |  951 ++++++++++++++++++++---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c      |   52 ++
 arch/arm/plat-omap/include/plat/gpmc-smsc911x.h |    9 +
 arch/arm/plat-omap/include/plat/gpmc.h          |   94 ++-
 6 files changed, 1078 insertions(+), 112 deletions(-)

-- 
1.7.10


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

* [PATCH v4-alt 1/6] ARM: OMAP2+: gpmc: driver conversion
  2012-05-02  8:45 [PATCH v4-alt 0/6] GPMC driver migrate one Afzal Mohammed
@ 2012-05-02  8:45 ` Afzal Mohammed
  2012-05-02  8:46 ` [PATCH v4-alt 2/6] ARM: OMAP2+: gpmc: Adapt to HWMOD Afzal Mohammed
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Afzal Mohammed @ 2012-05-02  8:45 UTC (permalink / raw)
  To: tony; +Cc: linux-omap, Afzal Mohammed, Vaibhav Hiremath, Jon Hunter

Convert GPMC code to driver. Boards using GPMC should provide driver
with type of configuration, timing, CS. Platform devices would then be
created for each connected peripheral (details also to be passed by
board so that it reaches respective driver). And GPMC driver would
populate memory resource details for the connected peripheral driver.
Boards should inform gpmc driver with platform data destined for
peripheral driver. gpmc driver will provide the same information to
peripheral driver.

A peripheral connected to GPMC can have multiple address spaces using
different chip select. Hence GPMC driver has been provided capability
to create platform device for peripheral using mutiple CS. The
peripheral that made it necessary was tusb6010.

Interrupts of GPMC are presented to drivers of connected peripherals
as resource. A fictitious interrupt controller chip handles these
interrupts at GPMC hardware level. Clients can use normal interrupt
APIs. Platform information of peripheral passed to GPMC driver should
indicate interrupts to be used via flags.

Driver is capable of configuring waitpin, waitpin details has to be
provided per CS. Wait pin has been considered as exclusive resource
as multiple peripherals should not using the same pin, at the same
it is valid for mutiple CS to use same waitpin provided they are
a part of single peripheral (eg. tusb6010)

An exported symbol for reconfiguring GPMC settings has been provided.
OneNAND is the one that neccessitated this.

Acquiring CS# for NAND is done on a few boards. It means, depending
on bootloader to embed this information. Probably CS# being used can
be set in the Kernel, and acquiring it can be removed. If ever this
capbility is needed, GPMC driver has to be made aware of handling it.

Modifications has been made keeping in mind that the driver would
have to move to driver folder. This explains requirement of clk_prd
field; even though clk_prd variable is not necessary as
gpmc_get_fclk_period is present in the same file as of now, this will
help in moving the driver easily to drivers folder.

Code related to GPMC clock may have to continue live in platform
folders as input clock is beyond the control of GPMC and calculating
timing for the peripheral may need other helpers. This explains
presence of 'gpmc_cs_calc_divider' along with 'gpmc_calc_divider',
both doing same work, latter meant to go with driver, former for
calculation in platform code.

Thanks to Vaibhav Hiremath & Jonathan Hunter on their various good
suggestions which resulted in improving the code.

Cc: Vaibhav Hiremath <hvaibhav@ti.com>
Cc: Jon Hunter <jon-hunter@ti.com>
Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/gpmc.c             |  877 ++++++++++++++++++++++++++++----
 arch/arm/plat-omap/include/plat/gpmc.h |   93 +++-
 2 files changed, 872 insertions(+), 98 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 580e684..12916f3 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -14,8 +14,11 @@
  */
 #undef DEBUG
 
+#include <linux/platform_device.h>
+
 #include <linux/irq.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -53,6 +56,45 @@
 #define GPMC_CS0_OFFSET		0x60
 #define GPMC_CS_SIZE		0x30
 
+/* GPMC register bits */
+#define	GPMC_CONFIG1_TIMEPARAGRANULARITY	BIT(4)
+#define	GPMC_CONFIG1_DEVICETYPE_NAND		GPMC_CONFIG1_DEVICETYPE(0x2)
+#define	GPMC_CONFIG1_WAIT_PIN_SEL_MASK		GPMC_CONFIG1_WAIT_PIN_SEL(0x3)
+#define	GPMC_CONFIG1_WAIT_MON_TIME(val)		((val & 0x3) << 18)
+#define	GPMC_CONFIG1_WRITEMULTIPLE		BIT(28)
+#define	GPMC_CONFIG1_READMULTIPLE		BIT(30)
+#define	GPMC_CONFIG1_WRAPBURST			BIT(31)
+#define	GPMC_CONFIG_WAITPIN_POLARITY_SHIFT	0x8
+#define	GPMC_CONFIG1_WAITPIN_MONITOR_TIME(val)	((val & 0x3) << 18)
+#define	GPMC_CONFIG1_WAITPIN_MONITOR_TIME_1	\
+				GPMC_CONFIG1_WAITPIN_MONITOR_TIME(0x1)
+#define	GPMC_CONFIG1_WAITPIN_MONITOR_TIME_2	\
+				GPMC_CONFIG1_WAITPIN_MONITOR_TIME(0x2)
+#define	GPMC_CONFIG1_CLOCKACTIVATION_TIME(val)	((val & 0x3) << 25)
+#define	GPMC_CONFIG1_CLOCKACTIVATION_TIME_1	\
+				GPMC_CONFIG1_CLOCKACTIVATION_TIME(0x1)
+#define	GPMC_CONFIG1_CLOCKACTIVATION_TIME_2	\
+				GPMC_CONFIG1_CLOCKACTIVATION_TIME(0x2)
+
+#define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)
+
+#define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)
+
+#define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)
+#define	GPMC_CONFIG4_WEEXTRADELAY		BIT(23)
+
+#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)
+#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)
+
+#define	GPMC_IRQ_BIT_FIFOEVENT		BIT(0)
+#define	GPMC_IRQ_BIT_TERMINALCOUNT	BIT(1)
+
+#define	GPMC_WAITPIN_IDX0			0x0
+#define	GPMC_WAITPIN_IDX1			0x1
+#define	GPMC_WAITPIN_IDX2			0x2
+#define	GPMC_WAITPIN_IDX3			0x3
+#define	GPMC_NR_WAITPIN				0x4
+
 #define GPMC_MEM_START		0x00000000
 #define GPMC_MEM_END		0x3FFFFFFF
 #define BOOT_ROM_SPACE		0x100000	/* 1MB */
@@ -64,6 +106,55 @@
 #define ENABLE_PREFETCH		(0x1 << 7)
 #define DMA_MPU_MODE		2
 
+#define	DRIVER_NAME	"omap-gpmc"
+
+#define	GPMC_NR_IRQ		2
+
+#define	HIGH			1
+#define	LOW			-1
+
+struct gpmc_device {
+	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;
+	unsigned		waitpin;
+	int			waitpin_polarity;
+};
+
+struct gpmc_irq	{
+	unsigned		irq;
+	u32			bitmask;
+};
+
+struct gpmc {
+	struct device		*dev;
+	unsigned long		clk_prd;
+	void __iomem		*io_base;
+	unsigned long		phys_base;
+	u32			memsize;
+	unsigned		cs_map;
+	int			ecc_used;
+	spinlock_t		mem_lock;
+	struct resource		mem_root;
+	struct resource		cs_mem[GPMC_CS_NUM];
+	/* XXX: Or allocate dynamically ? */
+	struct gpmc_device	device[GPMC_CS_NUM];
+	unsigned		num_device;
+	unsigned		master_irq;
+	unsigned		irq_start;
+	struct gpmc_irq		irq[GPMC_NR_IRQ];
+	struct irq_chip		irq_chip;
+	bool			wp;
+	unsigned		waitpin_map;
+	unsigned		revision;
+};
+
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -91,58 +182,50 @@ struct omap3_gpmc_regs {
 	struct gpmc_cs_config cs_context[GPMC_CS_NUM];
 };
 
-static struct resource	gpmc_mem_root;
-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 void __iomem *gpmc_base;
-
 static struct clk *gpmc_l3_clk;
 
-static irqreturn_t gpmc_handle_irq(int irq, void *dev);
+static struct gpmc *gpmc;
 
 static void gpmc_write_reg(int idx, u32 val)
 {
-	__raw_writel(val, gpmc_base + idx);
+	writel(val, gpmc->io_base + idx);
 }
 
 static u32 gpmc_read_reg(int idx)
 {
-	return __raw_readl(gpmc_base + idx);
+	return readl(gpmc->io_base + idx);
 }
 
 static void gpmc_cs_write_byte(int cs, int idx, u8 val)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	__raw_writeb(val, reg_addr);
+	reg_addr = gpmc->io_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	writeb(val, reg_addr);
 }
 
 static u8 gpmc_cs_read_byte(int cs, int idx)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	return __raw_readb(reg_addr);
+	reg_addr = gpmc->io_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	return readb(reg_addr);
 }
 
 void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	__raw_writel(val, reg_addr);
+	reg_addr = gpmc->io_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	writel(val, reg_addr);
 }
 
 u32 gpmc_cs_read_reg(int cs, int idx)
 {
 	void __iomem *reg_addr;
 
-	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
-	return __raw_readl(reg_addr);
+	reg_addr = gpmc->io_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
+	return readl(reg_addr);
 }
 
 /* TODO: Add support for gpmc_fck to clock framework and use it */
@@ -207,7 +290,8 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	if (time == 0)
 		ticks = 0;
 	else
-		ticks = gpmc_ns_to_ticks(time);
+		ticks = (time * 1000 + gpmc->clk_prd - 1) / gpmc->clk_prd;
+
 	nr_bits = end_bit - st_bit + 1;
 	if (ticks >= 1 << nr_bits) {
 #ifdef DEBUG
@@ -222,7 +306,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 #ifdef DEBUG
 	printk(KERN_INFO
 		"GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
-	       cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
+	       cs, name, ticks, gpmc->clk_prd * ticks / 1000,
 			(l >> st_bit) & mask, time);
 #endif
 	l &= ~(mask << st_bit);
@@ -243,6 +327,21 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 		return -1
 #endif
 
+int gpmc_calc_divider(unsigned int sync_clk)
+{
+	int div;
+	u32 l;
+
+	l = sync_clk + (gpmc->clk_prd - 1);
+	div = l / gpmc->clk_prd;
+	if (div > 4)
+		return -1;
+	if (div <= 0)
+		div = 1;
+
+	return div;
+}
+
 int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)
 {
 	int div;
@@ -258,12 +357,53 @@ int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)
 	return div;
 }
 
+static void gpmc_cs_onoff_timings(int cs, const struct gpmc_onoff_timings *p)
+{
+	u32 l;
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+	if (p->cs_extra_delay)
+		l |= GPMC_CONFIG2_CSEXTRADELAY;
+	else
+		l &= ~GPMC_CONFIG2_CSEXTRADELAY;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, l);
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+	if (p->adv_extra_delay)
+		l |= GPMC_CONFIG3_ADVEXTRADELAY;
+	else
+		l &= ~GPMC_CONFIG3_ADVEXTRADELAY;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, l);
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+	if (p->oe_extra_delay)
+		l |= GPMC_CONFIG4_OEEXTRADELAY;
+	else
+		l &= ~GPMC_CONFIG4_OEEXTRADELAY;
+	if (p->we_extra_delay)
+		l |= GPMC_CONFIG4_WEEXTRADELAY;
+	else
+		l &= ~GPMC_CONFIG4_WEEXTRADELAY;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, l);
+
+	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG6);
+	if (p->cycle2cyclesamecsen)
+		l |= GPMC_CONFIG6_CYCLE2CYCLESAMECSEN;
+	else
+		l &= ~GPMC_CONFIG6_CYCLE2CYCLESAMECSEN;
+	if (p->cycle2cyclediffcsen)
+		l |= GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN;
+	else
+		l &= ~GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN;
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, l);
+}
+
 int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 {
 	int div;
 	u32 l;
 
-	div = gpmc_cs_calc_divider(cs, t->sync_clk);
+	div = gpmc_calc_divider(t->sync_clk);
 	if (div < 0)
 		return -1;
 
@@ -286,7 +426,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()) {
+	GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
+	GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, busturnaround);
+
+	if (gpmc->revision >= 5) {
 		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
 		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
 	}
@@ -298,13 +441,15 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
 		printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-				cs, (div * gpmc_get_fclk_period()) / 1000, div);
+				cs, (div * gpmc->clk_prd) / 1000, div);
 #endif
 		l &= ~0x03;
 		l |= (div - 1);
 		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 	}
 
+	gpmc_cs_onoff_timings(cs, &t->control);
+
 	return 0;
 }
 
@@ -332,7 +477,7 @@ static void gpmc_cs_disable_mem(int cs)
 	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
 }
 
-static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
+static __devinit void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
 {
 	u32 l;
 	u32 mask;
@@ -351,23 +496,23 @@ static int gpmc_cs_mem_enabled(int cs)
 	return l & GPMC_CONFIG7_CSVALID;
 }
 
-int gpmc_cs_set_reserved(int cs, int reserved)
+static int gpmc_cs_set_reserved(int cs, int reserved)
 {
 	if (cs > GPMC_CS_NUM)
 		return -ENODEV;
 
-	gpmc_cs_map &= ~(1 << cs);
-	gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+	gpmc->cs_map &= ~(1 << cs);
+	gpmc->cs_map |= (reserved ? 1 : 0) << cs;
 
 	return 0;
 }
 
-int gpmc_cs_reserved(int cs)
+static int gpmc_cs_reserved(int cs)
 {
 	if (cs > GPMC_CS_NUM)
 		return -ENODEV;
 
-	return gpmc_cs_map & (1 << cs);
+	return gpmc->cs_map & (1 << cs);
 }
 
 static unsigned long gpmc_mem_align(unsigned long size)
@@ -384,24 +529,25 @@ static unsigned long gpmc_mem_align(unsigned long size)
 	return size;
 }
 
-static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
+static __devinit
+int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
 {
-	struct resource	*res = &gpmc_cs_mem[cs];
+	struct resource	*res = &gpmc->cs_mem[cs];
 	int r;
 
 	size = gpmc_mem_align(size);
-	spin_lock(&gpmc_mem_lock);
+	spin_lock(&gpmc->mem_lock);
 	res->start = base;
 	res->end = base + size - 1;
-	r = request_resource(&gpmc_mem_root, res);
-	spin_unlock(&gpmc_mem_lock);
+	r = request_resource(&gpmc->mem_root, res);
+	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];
+	struct resource *res = &gpmc->cs_mem[cs];
 	int r = -1;
 
 	if (cs > GPMC_CS_NUM)
@@ -411,7 +557,7 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 	if (size > (1 << GPMC_SECTION_SHIFT))
 		return -ENOMEM;
 
-	spin_lock(&gpmc_mem_lock);
+	spin_lock(&gpmc->mem_lock);
 	if (gpmc_cs_reserved(cs)) {
 		r = -EBUSY;
 		goto out;
@@ -419,7 +565,7 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 	if (gpmc_cs_mem_enabled(cs))
 		r = adjust_resource(res, res->start & ~(size - 1), size);
 	if (r < 0)
-		r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
+		r = allocate_resource(&gpmc->mem_root, res, size, 0, ~0,
 				      size, NULL, NULL);
 	if (r < 0)
 		goto out;
@@ -428,24 +574,24 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
 	*base = res->start;
 	gpmc_cs_set_reserved(cs, 1);
 out:
-	spin_unlock(&gpmc_mem_lock);
+	spin_unlock(&gpmc->mem_lock);
 	return r;
 }
 EXPORT_SYMBOL(gpmc_cs_request);
 
 void gpmc_cs_free(int cs)
 {
-	spin_lock(&gpmc_mem_lock);
+	spin_lock(&gpmc->mem_lock);
 	if (cs >= GPMC_CS_NUM || cs < 0 || !gpmc_cs_reserved(cs)) {
 		printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
 		BUG();
-		spin_unlock(&gpmc_mem_lock);
+		spin_unlock(&gpmc->mem_lock);
 		return;
 	}
 	gpmc_cs_disable_mem(cs);
-	release_resource(&gpmc_cs_mem[cs]);
+	release_resource(&gpmc->cs_mem[cs]);
 	gpmc_cs_set_reserved(cs, 0);
-	spin_unlock(&gpmc_mem_lock);
+	spin_unlock(&gpmc->mem_lock);
 }
 EXPORT_SYMBOL(gpmc_cs_free);
 
@@ -668,7 +814,7 @@ int gpmc_prefetch_reset(int cs)
 }
 EXPORT_SYMBOL(gpmc_prefetch_reset);
 
-static void __init gpmc_mem_init(void)
+static __devinit void gpmc_mem_init(void)
 {
 	int cs;
 	unsigned long boot_rom_space = 0;
@@ -680,8 +826,8 @@ static void __init gpmc_mem_init(void)
 	/* In apollon the CS0 is mapped as 0x0000 0000 */
 	if (machine_is_omap_apollon())
 		boot_rom_space = 0;
-	gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
-	gpmc_mem_root.end = GPMC_MEM_END;
+	gpmc->mem_root.start = GPMC_MEM_START + boot_rom_space;
+	gpmc->mem_root.end = GPMC_MEM_END;
 
 	/* Reserve all regions that has been set up by bootloader */
 	for (cs = 0; cs < GPMC_CS_NUM; cs++) {
@@ -697,26 +843,15 @@ static void __init gpmc_mem_init(void)
 
 static int __init gpmc_init(void)
 {
-	u32 l, irq;
-	int cs, ret = -EINVAL;
-	int gpmc_irq;
+	int ret = -EINVAL;
 	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;
 	}
 
 	if (WARN_ON(!ck))
@@ -728,53 +863,607 @@ static int __init gpmc_init(void)
 		BUG();
 	}
 
-	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();
+	clk_enable(gpmc_l3_clk);
+
+	return 0;
+}
+postcore_initcall(gpmc_init);
+
+static inline int gpmc_waitpin_is_reserved(struct gpmc *gpmc, unsigned waitpin)
+{
+	return gpmc->waitpin_map & (0x1 << waitpin);
+}
+
+static inline void gpmc_reserve_waitpin(struct gpmc *gpmc, unsigned waitpin)
+{
+	gpmc->waitpin_map &= ~(0x1 << waitpin);
+	gpmc->waitpin_map |= (0x1 << waitpin);
+}
+
+static int gpmc_waitpin_request(struct gpmc *gpmc, unsigned waitpin)
+{
+	if (!(waitpin < GPMC_NR_WAITPIN))
+		return -ENODEV;
+
+	if (gpmc_waitpin_is_reserved(gpmc, waitpin))
+		return -EBUSY;
+	else
+		gpmc_reserve_waitpin(gpmc, waitpin);
+
+	return 0;
+}
+
+static int gpmc_setup_waitpin(struct gpmc *gpmc, struct gpmc_device *gd)
+{
+	int ret;
+
+	if (!gd->have_waitpin)
+		return 0;
+
+	ret = gpmc_waitpin_request(gpmc, gd->waitpin);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(gpmc->dev, "waitpin %u reserved\n", gd->waitpin);
+		return ret;
+	} else if (gd->waitpin_polarity) {
+		u32 l = gpmc_read_reg(GPMC_CONFIG);
+		u32 shift = gd->waitpin + GPMC_CONFIG_WAITPIN_POLARITY_SHIFT;
+
+		if (gd->waitpin_polarity == HIGH)
+			l |= 1 << shift;
+		else
+			l &= ~(1 << shift);
+
+		gpmc_write_reg(GPMC_CONFIG, l);
 	}
+	return 0;
+}
 
-	clk_enable(gpmc_l3_clk);
+static int gpmc_setup_cs_waitpin(struct gpmc *gpmc, struct gpmc_device *gd,
+						unsigned cs, unsigned conf)
+{
+	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+	unsigned idx = ~0x0;
+	int polarity = 0;
 
-	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);
-	gpmc_mem_init();
+	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:
+		break;
+	default:
+		dev_err(gpmc->dev, "multiple waitpins selected on CS:%u\n", cs);
+		return -EINVAL;
+		break;
+	}
 
-	/* initalize the irq_chained */
-	irq = OMAP_GPMC_IRQ_BASE;
-	for (cs = 0; cs < GPMC_CS_NUM; cs++) {
-		irq_set_chip_and_handler(irq, &dummy_irq_chip,
-						handle_simple_irq);
-		set_irq_flags(irq, IRQF_VALID);
-		irq++;
+	switch (conf & GPMC_WAITPIN_POLARITY_MASK) {
+	case GPMC_WAITPIN_ACTIVE_LOW:
+		polarity = LOW;
+		break;
+	case GPMC_WAITPIN_ACTIVE_HIGH:
+		polarity = HIGH;
+		break;
+	/* no waitpin */
+	case 0:
+		break;
+	default:
+		dev_err(gpmc->dev, "waitpin polarity set to low & high\n");
+		return -EINVAL;
+		break;
 	}
 
-	ret = request_irq(gpmc_irq, gpmc_handle_irq, IRQF_SHARED, "gpmc", NULL);
-	if (ret)
-		pr_err("gpmc: irq-%d could not claim: err %d\n",
-						gpmc_irq, ret);
-	return ret;
+	if (idx != ~0x0) {
+		if (gd->have_waitpin) {
+			if (gd->waitpin != idx ||
+					gd->waitpin_polarity != polarity) {
+				dev_err(gpmc->dev, "error: conflict: waitpin %u with polarity %d on device %s.%d\n",
+					gd->waitpin, gd->waitpin_polarity,
+					gd->name, gd->id);
+				return -EBUSY;
+			}
+		} else {
+			gd->have_waitpin = true;
+			gd->waitpin = idx;
+			gd->waitpin_polarity = polarity;
+		}
+
+		l &= ~GPMC_CONFIG1_WAIT_PIN_SEL_MASK;
+		l |= GPMC_CONFIG1_WAIT_PIN_SEL(idx);
+		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+	} else if (polarity) {
+		dev_err(gpmc->dev, "error: waitpin polarity specified with out wait pin number on device %s.%d\n",
+							gd->name, gd->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void gpmc_setup_cs_config(struct gpmc *gpmc, unsigned cs, unsigned conf)
+{
+	u32 l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+	l &= ~(GPMC_CONFIG1_TIMEPARAGRANULARITY |
+		GPMC_CONFIG1_MUXADDDATA |
+		GPMC_CONFIG1_DEVICETYPE(~0) |
+		GPMC_CONFIG1_DEVICESIZE(~0) |
+		GPMC_CONFIG1_WAIT_WRITE_MON |
+		GPMC_CONFIG1_WAIT_READ_MON |
+		GPMC_CONFIG1_PAGE_LEN(~0) |
+		GPMC_CONFIG1_WRITETYPE_SYNC |
+		GPMC_CONFIG1_WRITEMULTIPLE |
+		GPMC_CONFIG1_READTYPE_SYNC |
+		GPMC_CONFIG1_READMULTIPLE |
+		GPMC_CONFIG1_WRAPBURST |
+		GPMC_CONFIG1_WAITPIN_MONITOR_TIME(~0) |
+		GPMC_CONFIG1_CLOCKACTIVATION_TIME(~0));
+
+	if (conf & GPMC_TIMEPARAGRANULARITY)
+		l |= GPMC_CONFIG1_TIMEPARAGRANULARITY;
+	if (conf & GPMC_MUXADDDATA)
+		l |= GPMC_CONFIG1_MUXADDDATA;
+	if (conf & GPMC_DEVICETYPE_NAND)
+		l |= GPMC_CONFIG1_DEVICETYPE_NAND;
+	if (conf & GPMC_DEVICESIZE_16)
+		l |= GPMC_CONFIG1_DEVICESIZE_16;
+	if (conf & GPMC_WAIT_WRITE_MON)
+		l |= GPMC_CONFIG1_WAIT_WRITE_MON;
+	if (conf & GPMC_WAIT_READ_MON)
+		l |= GPMC_CONFIG1_WAIT_READ_MON;
+	if (conf & GPMC_PAGE_LEN_16)
+		l |= GPMC_CONFIG1_PAGE_LEN_16;
+	else if (conf & GPMC_PAGE_LEN_8)
+		l |= GPMC_CONFIG1_PAGE_LEN_8;
+	if (conf & GPMC_WRITETYPE_SYNC)
+		l |= GPMC_CONFIG1_WRITETYPE_SYNC;
+	if (conf & GPMC_WRITEMULTIPLE)
+		l |= GPMC_CONFIG1_WRITEMULTIPLE;
+	if (conf & GPMC_READTYPE_SYNC)
+		l |= GPMC_CONFIG1_READTYPE_SYNC;
+	if (conf & GPMC_READMULTIPLE)
+		l |= GPMC_CONFIG1_READMULTIPLE;
+	if (conf & GPMC_WRAPBURST)
+		l |= GPMC_CONFIG1_WRAPBURST;
+	if (conf & GPMC_WAITPIN_MONITOR_TIME_1)
+		l |= GPMC_CONFIG1_WAITPIN_MONITOR_TIME_1;
+	else if (conf & GPMC_WAITPIN_MONITOR_TIME_2)
+		l |= GPMC_CONFIG1_WAITPIN_MONITOR_TIME_2;
+	if (conf & GPMC_CLOCKACTIVATION_TIME_1)
+		l |= GPMC_CONFIG1_CLOCKACTIVATION_TIME_1;
+	else if (conf & GPMC_CLOCKACTIVATION_TIME_2)
+		l |= GPMC_CONFIG1_CLOCKACTIVATION_TIME_2;
+
+	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
+
+	if (conf & GPMC_WRITEPROTECT)
+		gpmc->wp = true;
+}
+
+static int gpmc_setup_cs_nonres(struct gpmc *gpmc,
+			struct gpmc_device *gd, struct gpmc_cs_data *cs)
+{
+	int ret;
+
+	/* some boards rely on bootloader for configuration */
+	if (cs->have_config) {
+		gpmc_setup_cs_config(gpmc, cs->cs, cs->config);
+		ret = gpmc_setup_cs_waitpin(gpmc, gd, cs->cs, cs->config);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(gpmc->dev, "error: waitpin on CS %d\n", cs->cs);
+			return ret;
+		}
+	} else
+		dev_warn(gpmc->dev, "config not present for CS: %d\n", cs->cs);
+
+	if (cs->timing) {
+		ret = gpmc_cs_set_timings(cs->cs, cs->timing);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(gpmc->dev, "error: timing on CS: %d\n", cs->cs);
+			return ret;
+		}
+	} else
+		dev_warn(gpmc->dev, "timing not present for CS: %u\n", cs->cs);
+
+	return 0;
+}
+
+static int gpmc_match_device(struct gpmc *gpmc, char *name, int id)
+{
+	int i;
+	struct gpmc_device *gd;
+
+	for (i = 0, gd = gpmc->device; i < gpmc->num_device; i++, gd++)
+		if (!strcmp(gd->name, name) && gd->id == id)
+			return i;
+
+	return -ENOENT;
+}
+
+int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *cs)
+{
+	int i;
+
+	i = gpmc_match_device(gpmc, name, id);
+	if (IS_ERR_VALUE(i)) {
+		dev_err(gpmc->dev, "no device %s.%d to configure\n", name, id);
+		return i;
+	}
+
+	i = gpmc_setup_cs_nonres(gpmc, gpmc->device + i, cs);
+	if (IS_ERR_VALUE(i)) {
+		dev_err(gpmc->dev, "error: configure device %s.%d\n", name, id);
+		return i;
+	}
+
+	return gpmc_setup_waitpin(gpmc, gpmc->device + i);
+
+}
+EXPORT_SYMBOL_GPL(gpmc_cs_reconfigure);
+
+static inline unsigned int gpmc_bit_to_irq(unsigned bitmask)
+{
+	if (bitmask & GPMC_IRQ_BIT_FIFOEVENT)
+		return GPMC_IRQ_FIFOEVENTENABLE;
+	else if (bitmask & GPMC_IRQ_BIT_TERMINALCOUNT)
+		return GPMC_IRQ_COUNT_EVENT;
+	else
+		return 0;
+}
+
+static __devinit int gpmc_setup_cs_irq(struct gpmc *gpmc,
+			struct gpmc_cs_data *cs, struct resource *res)
+{
+	int i, n;
+
+	for (i = 0, n = 0; i < GPMC_NR_IRQ; i++)
+		if (gpmc_bit_to_irq(gpmc->irq[i].bitmask) & cs->irq_config) {
+			res[n].start = res[n].end = gpmc->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_setup_cs_mem(struct gpmc *gpmc,
+			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 1;
+}
+
+static __devinit int gpmc_setup_cs(struct gpmc *gpmc, struct gpmc_device *gd,
+			struct gpmc_cs_data *cs, struct resource *res)
+{
+	int num, ret;
+
+	num = gpmc_setup_cs_mem(gpmc, cs, res);
+	if (IS_ERR_VALUE(num))
+		return num;
+
+	ret = gpmc_setup_cs_nonres(gpmc, gd, cs);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	num += gpmc_setup_cs_irq(gpmc, cs, res + num);
+
+	return num;
+}
+
+static __devinit int gpmc_setup_device(struct gpmc *gpmc,
+		struct gpmc_device *gd, 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);
+
+	gd->gpmc_res = devm_kzalloc(gpmc->dev, sizeof(*gd->gpmc_res) * n,
+								GFP_KERNEL);
+	if (gd->gpmc_res == NULL) {
+		dev_err(gpmc->dev, "error: memory allocation\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0, cs = gdp->cs_data, gd->gpmc_res_cnt = 0;
+			i < gdp->num_cs; cs++, i++) {
+		ret = gpmc_setup_cs(gpmc, gd, cs,
+					gd->gpmc_res + gd->gpmc_res_cnt);
+		if (IS_ERR_VALUE(ret) ||
+				IS_ERR_VALUE(gpmc_setup_waitpin(gpmc, gd))) {
+			dev_err(gpmc->dev, "error: setup for %s\n", gdp->name);
+			devm_kfree(gpmc->dev, gd->gpmc_res);
+			gd->gpmc_res = NULL;
+			gd->gpmc_res_cnt = 0;
+			return -EINVAL;
+		} else
+			gd->gpmc_res_cnt += ret;
+	}
+
+	gd->name = gdp->name;
+	gd->id = gdp->id;
+	gd->pdata = gdp->pdata;
+	gd->pdata_size = gdp->pdata_size;
+	gd->per_res = gdp->per_res;
+	gd->per_res_cnt = gdp->per_res_cnt;
+
+	return 0;
+}
+
+static __devinit
+struct platform_device *gpmc_create_device(struct gpmc *gpmc,
+					struct gpmc_device *p)
+{
+	int num = p->per_res_cnt + p->gpmc_res_cnt;
+	struct resource *res;
+	struct platform_device *pdev;
+
+	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);
+
+	pdev = platform_device_register_resndata(gpmc->dev, p->name, p->id,
+					res, num, p->pdata, p->pdata_size);
+
+	devm_kfree(gpmc->dev, res);
+
+	return pdev;
 }
-postcore_initcall(gpmc_init);
 
 static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 {
-	u8 cs;
+	int i;
+	u32 regval;
+	struct gpmc *gpmc = dev;
+
+	regval = gpmc_read_reg(GPMC_IRQSTATUS);
 
-	/* check cs to invoke the irq */
-	cs = ((gpmc_read_reg(GPMC_PREFETCH_CONFIG1)) >> CS_NUM_SHIFT) & 0x7;
-	if (OMAP_GPMC_IRQ_BASE+cs <= OMAP_GPMC_IRQ_END)
-		generic_handle_irq(OMAP_GPMC_IRQ_BASE+cs);
+	for (i = 0; i < GPMC_NR_IRQ; i++)
+		if (regval & gpmc->irq[i].bitmask)
+			generic_handle_irq(gpmc->irq[i].irq);
+
+	gpmc_write_reg(GPMC_IRQSTATUS, regval);
 
 	return IRQ_HANDLED;
 }
 
+static int gpmc_irq_endis(struct gpmc *gpmc, unsigned irq, bool endis)
+{
+	int i;
+	u32 regval;
+
+	for (i = 0; i < GPMC_NR_IRQ; i++)
+		if (irq == gpmc->irq[i].irq) {
+			regval = gpmc_read_reg(GPMC_IRQENABLE);
+			if (endis)
+				regval |= gpmc->irq[i].bitmask;
+			else
+				regval &= ~gpmc->irq[i].bitmask;
+			gpmc_write_reg(GPMC_IRQENABLE, regval);
+			break;
+		}
+
+	return 0;
+}
+
+static void gpmc_irq_disable(struct irq_data *p)
+{
+	gpmc_irq_endis(irq_data_get_irq_chip_data(p), p->irq, false);
+}
+
+static void gpmc_irq_enable(struct irq_data *p)
+{
+	gpmc_irq_endis(irq_data_get_irq_chip_data(p), p->irq, true);
+}
+
+static void gpmc_irq_noop(struct irq_data *data) { }
+
+static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; }
+
+static __devinit int gpmc_setup_irq(struct gpmc *gpmc)
+{
+	int i;
+	u32 regval;
+
+	if (!gpmc->master_irq)
+		return -EINVAL;
+
+	gpmc->irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0);
+	if (IS_ERR_VALUE(gpmc->irq_start)) {
+		dev_err(gpmc->dev, "irq_alloc_descs failed\n");
+		return gpmc->irq_start;
+	}
+
+	gpmc->irq_chip.name = "gpmc";
+	gpmc->irq_chip.irq_startup = gpmc_irq_noop_ret;
+	gpmc->irq_chip.irq_enable = gpmc_irq_enable;
+	gpmc->irq_chip.irq_disable = gpmc_irq_disable;
+	gpmc->irq_chip.irq_shutdown = gpmc_irq_noop;
+	gpmc->irq_chip.irq_ack = gpmc_irq_noop;
+	gpmc->irq_chip.irq_mask = gpmc_irq_noop;
+	gpmc->irq_chip.irq_unmask = gpmc_irq_noop;
+
+	gpmc->irq[0].bitmask = GPMC_IRQ_BIT_FIFOEVENT;
+	gpmc->irq[1].bitmask = GPMC_IRQ_BIT_TERMINALCOUNT;
+
+	for (i = 0; i < GPMC_NR_IRQ; i++) {
+		gpmc->irq[i].irq = gpmc->irq_start + i;
+		irq_set_chip_and_handler(gpmc->irq[i].irq,
+					&gpmc->irq_chip, handle_simple_irq);
+		irq_set_chip_data(gpmc->irq[i].irq, gpmc);
+		set_irq_flags(gpmc->irq[i].irq, IRQF_VALID | IRQF_NOAUTOEN);
+	}
+
+	/* Disable interrupts */
+	gpmc_write_reg(GPMC_IRQENABLE, 0);
+
+	/* clear interrupts */
+	regval = gpmc_read_reg(GPMC_IRQSTATUS);
+	gpmc_write_reg(GPMC_IRQSTATUS, regval);
+
+	return request_irq(gpmc->master_irq, gpmc_handle_irq, IRQF_SHARED,
+							"gpmc", gpmc);
+}
+
+static __devinit void gpmc_setup_writeprotect(struct gpmc *gpmc)
+{
+	u32 l;
+
+	l = gpmc_read_reg(GPMC_CONFIG);
+	if (gpmc->wp == true) {
+		l &= ~GPMC_CONFIG_WRITEPROTECT;
+		dev_info(gpmc->dev, "write protect enabled\n");
+	} else
+		l |= GPMC_CONFIG_WRITEPROTECT;
+	gpmc_write_reg(GPMC_CONFIG, l);
+}
+
+static __devinit int gpmc_probe(struct platform_device *pdev)
+{
+	u32 l;
+	int i;
+	int ret = 0;
+	struct resource *res = NULL;
+	struct gpmc_pdata *gp = dev_get_platdata(&pdev->dev);
+	struct gpmc_device_pdata **gdq = NULL;
+	struct gpmc_device *gd = NULL;
+
+	gpmc = devm_kzalloc(&pdev->dev, sizeof(struct gpmc), GFP_KERNEL);
+	if (gpmc == NULL)
+		return -ENOMEM;
+
+	gpmc->dev = &pdev->dev;
+	gpmc->clk_prd = gp->clk_prd;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -ENOENT;
+
+	gpmc->phys_base = res->start;
+	gpmc->memsize = resource_size(res);
+
+	gpmc->io_base = devm_request_and_ioremap(gpmc->dev, res);
+	if (!gpmc->io_base)
+		return -EADDRNOTAVAIL;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL)
+		dev_warn(gpmc->dev, "Failed to get resource: irq\n");
+	else
+		gpmc->master_irq = res->start;
+
+	if (IS_ERR_VALUE(gpmc_setup_irq(gpmc)))
+		dev_warn(gpmc->dev, "gpmc_setup_irq failed\n");
+
+	gpmc->ecc_used = -EINVAL;
+	spin_lock_init(&gpmc->mem_lock);
+	platform_set_drvdata(pdev, gpmc);
+
+	l = gpmc_read_reg(GPMC_REVISION);
+	gpmc->revision = (l >> 4) & 0xf;
+	dev_info(gpmc->dev, "GPMC revision %u.%u\n", gpmc->revision, l & 0x0f);
+
+	gpmc_mem_init();
+
+	for (i = 0, gdq = gp->device_pdata, gd = gpmc->device;
+			(i < gp->num_device) && (*gdq); i++, gdq++) {
+		ret = gpmc_setup_device(gpmc, gd, *gdq);
+		if (IS_ERR_VALUE(ret))
+			dev_err(gpmc->dev, "gpmc setup on %s failed\n",
+								(*gdq)->name);
+		else
+			gd++;
+	}
+	gpmc->num_device = gd - gpmc->device;
+
+	gpmc_setup_writeprotect(gpmc);
+
+	for (i = 0, gd = gpmc->device; i < gpmc->num_device; i++, gd++)
+		if (IS_ERR(gpmc_create_device(gpmc, gd)))
+			dev_err(gpmc->dev, "device creation on %s failed\n",
+								gd->name);
+
+	return 0;
+}
+
+static __devexit int gpmc_free_irq(struct gpmc *gpmc)
+{
+	int i;
+
+	if (gpmc->master_irq)
+		free_irq(gpmc->master_irq, gpmc);
+
+	for (i = 0; i < GPMC_NR_IRQ; i++) {
+		irq_set_handler(gpmc->irq[i].irq, NULL);
+		irq_set_chip(gpmc->irq[i].irq, &no_irq_chip);
+		irq_set_chip_data(gpmc->irq[i].irq, NULL);
+		irq_modify_status(gpmc->irq[i].irq, 0, 0);
+	}
+
+	irq_free_descs(gpmc->irq_start, GPMC_NR_IRQ);
+
+	return 0;
+}
+
+static __devexit int gpmc_remove(struct platform_device *pdev)
+{
+	struct gpmc *gpmc = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	gpmc_free_irq(gpmc);
+
+	return 0;
+}
+
+static struct platform_driver gpmc_driver = {
+	.probe		= gpmc_probe,
+	.remove		= __devexit_p(gpmc_remove),
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(gpmc_driver);
+
 #ifdef CONFIG_ARCH_OMAP3
 static struct omap3_gpmc_regs gpmc_context;
 
@@ -854,10 +1543,10 @@ int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size)
 	unsigned int val;
 
 	/* check if ecc module is in used */
-	if (gpmc_ecc_used != -EINVAL)
+	if (gpmc->ecc_used != -EINVAL)
 		return -EINVAL;
 
-	gpmc_ecc_used = cs;
+	gpmc->ecc_used = cs;
 
 	/* clear ecc and enable bits */
 	val = ((0x00000001<<8) | 0x00000001);
@@ -905,7 +1594,7 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
 {
 	unsigned int val = 0x0;
 
-	if (gpmc_ecc_used != cs)
+	if (gpmc->ecc_used != cs)
 		return -EINVAL;
 
 	/* read ecc result */
@@ -915,7 +1604,7 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
 	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
 	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
 
-	gpmc_ecc_used = -EINVAL;
+	gpmc->ecc_used = -EINVAL;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(gpmc_calculate_ecc);
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 1527929..2eedd99 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -11,6 +11,44 @@
 #ifndef __OMAP2_GPMC_H
 #define __OMAP2_GPMC_H
 
+/* configuration flags */
+#define	GPMC_WRITEPROTECT		BIT(0)
+#define	GPMC_TIMEPARAGRANULARITY	BIT(1)
+#define	GPMC_MUXADDDATA			BIT(2)
+#define	GPMC_DEVICETYPE_NOR		BIT(3)
+#define	GPMC_DEVICETYPE_NAND		BIT(4)
+#define	GPMC_DEVICESIZE_8		BIT(5)
+#define	GPMC_DEVICESIZE_16		BIT(6)
+#define	GPMC_WAIT_WRITE_MON		BIT(7)
+#define	GPMC_WAIT_READ_MON		BIT(8)
+#define	GPMC_PAGE_LEN_4			BIT(9)
+#define	GPMC_PAGE_LEN_8			BIT(10)
+#define	GPMC_PAGE_LEN_16		BIT(11)
+#define	GPMC_CLOCKACTIVATIONTIME_0	BIT(12)
+#define	GPMC_CLOCKACTIVATIONTIME_1	BIT(13)
+#define	GPMC_CLOCKACTIVATIONTIME_2	BIT(14)
+#define	GPMC_WRITETYPE_SYNC		BIT(15)
+#define	GPMC_WRITEMULTIPLE		BIT(16)
+#define	GPMC_READTYPE_SYNC		BIT(17)
+#define	GPMC_READMULTIPLE		BIT(18)
+#define	GPMC_WRAPBURST			BIT(19)
+#define	GPMC_WAITPIN_0			BIT(20)
+#define	GPMC_WAITPIN_1			BIT(21)
+#define	GPMC_WAITPIN_2			BIT(22)
+#define	GPMC_WAITPIN_3			BIT(23)
+#define	GPMC_WAITPIN_MASK		(GPMC_WAITPIN_0 | GPMC_WAITPIN_1 | \
+					GPMC_WAITPIN_2 | GPMC_WAITPIN_3)
+#define	GPMC_WAITPIN_ACTIVE_LOW		BIT(24)
+#define	GPMC_WAITPIN_ACTIVE_HIGH	BIT(25)
+#define	GPMC_WAITPIN_POLARITY_MASK	(GPMC_WAITPIN_ACTIVE_LOW | \
+					GPMC_WAITPIN_ACTIVE_HIGH)
+#define	GPMC_WAITPIN_MONITOR_TIME_1	BIT(26)
+#define	GPMC_WAITPIN_MONITOR_TIME_2	BIT(27)
+#define	GPMC_CLOCKACTIVATION_TIME_1	BIT(28)
+#define	GPMC_CLOCKACTIVATION_TIME_2	BIT(29)
+#define	GPMC_READTYPE_ASYNC		BIT(30)
+#define	GPMC_WRITETYPE_ASYNC		BIT(31)
+
 /* Maximum Number of Chip Selects */
 #define GPMC_CS_NUM		8
 
@@ -56,7 +94,11 @@
 #define GPMC_CONFIG1_WRITETYPE_ASYNC    (0 << 27)
 #define GPMC_CONFIG1_WRITETYPE_SYNC     (1 << 27)
 #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME_1	(1 << 25)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME_2	(1 << 26)
 #define GPMC_CONFIG1_PAGE_LEN(val)      ((val & 3) << 23)
+#define GPMC_CONFIG1_PAGE_LEN_16	(0x1 << 24)
+#define GPMC_CONFIG1_PAGE_LEN_8		(0x1 << 23)
 #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)
@@ -73,8 +115,6 @@
 #define GPMC_CONFIG1_FCLK_DIV4          (GPMC_CONFIG1_FCLK_DIV(3))
 #define GPMC_CONFIG7_CSVALID		(1 << 6)
 
-#define GPMC_DEVICETYPE_NOR		0
-#define GPMC_DEVICETYPE_NAND		2
 #define GPMC_CONFIG_WRITEPROTECT	0x00000010
 #define GPMC_STATUS_BUFF_EMPTY		0x00000001
 #define WR_RD_PIN_MONITORING		0x00600000
@@ -94,6 +134,16 @@ enum omap_ecc {
 	OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
 };
 
+/* turn on/off type timings */
+struct gpmc_onoff_timings {
+	bool cycle2cyclediffcsen;
+	bool cycle2cyclesamecsen;
+	bool we_extra_delay;
+	bool oe_extra_delay;
+	bool adv_extra_delay;
+	bool cs_extra_delay;
+};
+
 /*
  * Note that all values in this struct are in nanoseconds except sync_clk
  * (which is in picoseconds), while the register values are in gpmc_fck cycles.
@@ -126,11 +176,48 @@ struct gpmc_timings {
 	u16 rd_cycle;		/* Total read cycle time */
 	u16 wr_cycle;		/* Total write cycle time */
 
+	u16 cycle2cycle_delay;
+	u16 busturnaround;
+
 	/* The following are only on OMAP3430 */
 	u16 wr_access;		/* WRACCESSTIME */
 	u16 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+
+	struct gpmc_onoff_timings control;
+};
+
+struct gpmc_cs_data {
+	unsigned		cs;
+	unsigned long		mem_size;
+	unsigned long		mem_offset;
+	/* some boards rely on bootloader for configuration */
+	bool			have_config;
+	unsigned		config;
+	struct gpmc_timings	*timing;
+	unsigned		irq_config;
+};
+
+struct gpmc_device_pdata {
+	char			*name;
+	int			id;
+	void			*pdata;
+	unsigned		pdata_size;
+	/* resources configured via GPMC will be created by GPMC driver */
+	struct resource		*per_res;
+	unsigned		per_res_cnt;
+	struct gpmc_cs_data	*cs_data;
+	unsigned		num_cs;
 };
 
+struct gpmc_pdata {
+	/* GPMC_FCLK period in picoseconds */
+	unsigned long			clk_prd;
+	unsigned			num_device;
+	struct gpmc_device_pdata	**device_pdata;
+};
+
+extern int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *cs);
+
 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);
@@ -143,8 +230,6 @@ extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk);
 extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
 extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
-extern int gpmc_cs_set_reserved(int cs, int reserved);
-extern int gpmc_cs_reserved(int cs);
 extern int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
 					unsigned int u32_count, int is_write);
 extern int gpmc_prefetch_reset(int cs);
-- 
1.7.10


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

* [PATCH v4-alt 2/6] ARM: OMAP2+: gpmc: Adapt to HWMOD
  2012-05-02  8:45 [PATCH v4-alt 0/6] GPMC driver migrate one Afzal Mohammed
  2012-05-02  8:45 ` [PATCH v4-alt 1/6] ARM: OMAP2+: gpmc: driver conversion Afzal Mohammed
@ 2012-05-02  8:46 ` Afzal Mohammed
  2012-05-02  8:46 ` [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc Afzal Mohammed
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Afzal Mohammed @ 2012-05-02  8:46 UTC (permalink / raw)
  To: tony; +Cc: linux-omap, Afzal Mohammed

Create API for platforms to adapt gpmc to HWMOD

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

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 12916f3..c8d07bb 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -33,6 +33,8 @@
 
 #include <plat/sdrc.h>
 
+#include <plat/omap_device.h>
+
 /* GPMC register offsets */
 #define GPMC_REVISION		0x00
 #define GPMC_SYSCONFIG		0x10
@@ -276,6 +278,31 @@ unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
 	return ticks * gpmc_get_fclk_period() / 1000;
 }
 
+int __init omap_init_gpmc(struct gpmc_pdata *pdata)
+{
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	char *name = "omap-gpmc";
+	char *oh_name = "gpmc";
+
+	pdata->clk_prd = gpmc_get_fclk_period();
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
+
+	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;
+}
 #ifdef DEBUG
 static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 			       int time, const char *name)
@@ -843,24 +870,19 @@ static __devinit void gpmc_mem_init(void)
 
 static int __init gpmc_init(void)
 {
-	int ret = -EINVAL;
-	char *ck = NULL;
-
-	if (cpu_is_omap24xx()) {
-		ck = "core_l3_ck";
-	} else if (cpu_is_omap34xx()) {
-		ck = "gpmc_fck";
-	} else if (cpu_is_omap44xx()) {
-		ck = "gpmc_ck";
-	}
+	char *oh_name = "gpmc";
+	struct omap_hwmod *oh;
 
-	if (WARN_ON(!ck))
-		return ret;
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up %s\n", oh_name);
+		return -ENODEV;
+	}
 
-	gpmc_l3_clk = clk_get(NULL, ck);
+	gpmc_l3_clk = clk_get(NULL, oh->main_clk);
 	if (IS_ERR(gpmc_l3_clk)) {
-		printk(KERN_ERR "Could not get GPMC clock %s\n", ck);
-		BUG();
+		pr_err("error: clk_get on %s\n", oh->main_clk);
+		return -EINVAL;
 	}
 
 	clk_enable(gpmc_l3_clk);
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 2eedd99..c5cf020 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -217,6 +217,7 @@ struct gpmc_pdata {
 };
 
 extern int gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *cs);
+extern int omap_init_gpmc(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);
-- 
1.7.10


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

* [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-02  8:45 [PATCH v4-alt 0/6] GPMC driver migrate one Afzal Mohammed
  2012-05-02  8:45 ` [PATCH v4-alt 1/6] ARM: OMAP2+: gpmc: driver conversion Afzal Mohammed
  2012-05-02  8:46 ` [PATCH v4-alt 2/6] ARM: OMAP2+: gpmc: Adapt to HWMOD Afzal Mohammed
@ 2012-05-02  8:46 ` Afzal Mohammed
  2012-05-06  2:04   ` Paul Walmsley
  2012-05-02  8:46 ` [PATCH v4-alt 4/6] ARM: OMAP2+: gpmc: driver migration hack Afzal Mohammed
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 26+ messages in thread
From: Afzal Mohammed @ 2012-05-02  8:46 UTC (permalink / raw)
  To: tony; +Cc: linux-omap, Afzal Mohammed

Add gpmc hwmod and associated interconnect data

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

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 0c65079..4da8394 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -1981,6 +1981,40 @@ static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod = {
 };
 
 /*
+ * 'gpmc' class
+ * general purpose memory controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_gpmc_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_gpmc_hwmod_class = {
+	.name	= "gpmc",
+	.sysc	= &omap3xxx_gpmc_sysc,
+};
+
+static struct omap_hwmod_irq_info omap3xxx_gpmc_irqs[] = {
+	{ .irq = 20 },
+	{ .irq = -1 }
+};
+
+static struct omap_hwmod omap3xxx_gpmc_hwmod = {
+	.name		= "gpmc",
+	.class		= &omap3xxx_gpmc_hwmod_class,
+	.clkdm_name	= "l3_init_clkdm",
+	.mpu_irqs	= omap3xxx_gpmc_irqs,
+	.main_clk	= "gpmc_fck",
+	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+};
+
+/*
  * interfaces
  */
 
@@ -3059,6 +3093,23 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__usb_tll_hs = {
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = {
+	{
+		.pa_start	= 0x6E000000,
+		.pa_end		= 0x6E000FFF,
+		.flags		= ADDR_TYPE_RT
+	},
+	{ }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l3_main__gpmc = {
+	.master		= &omap3xxx_l3_main_hwmod,
+	.slave		= &omap3xxx_gpmc_hwmod,
+	.clk		= "core_l3_ick",
+	.addr		= omap3xxx_gpmc_addrs,
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
 	&omap3xxx_l3_main__l4_core,
 	&omap3xxx_l3_main__l4_per,
@@ -3103,6 +3154,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
 	&omap34xx_l4_core__mcspi2,
 	&omap34xx_l4_core__mcspi3,
 	&omap34xx_l4_core__mcspi4,
+	&omap3xxx_l3_main__gpmc,
 	NULL,
 };
 
-- 
1.7.10


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

* [PATCH v4-alt 4/6] ARM: OMAP2+: gpmc: driver migration hack
  2012-05-02  8:45 [PATCH v4-alt 0/6] GPMC driver migrate one Afzal Mohammed
                   ` (2 preceding siblings ...)
  2012-05-02  8:46 ` [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc Afzal Mohammed
@ 2012-05-02  8:46 ` Afzal Mohammed
  2012-05-02  8:46 ` [PATCH v4-alt 5/6] ARM: OMAP2+: gpmc-smsc911x: Add helper for driver conversion Afzal Mohammed
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 26+ messages in thread
From: Afzal Mohammed @ 2012-05-02  8:46 UTC (permalink / raw)
  To: tony; +Cc: linux-omap, Afzal Mohammed

This has been made for migrating boards one by one so that
old & new interface can coexist. As a board is migrated to
new interface, return from gpmc_driver_migration w/o doing
anything; add a machine_is_ check for that board to return

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

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c8d07bb..4dcc141 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -868,6 +868,18 @@ static __devinit void gpmc_mem_init(void)
 	}
 }
 
+static void gpmc_driver_migration(void)
+{
+	static struct gpmc_device_pdata *gpmc_device_data[1];
+	static struct gpmc_pdata gpmc_data = {
+		.device_pdata	= gpmc_device_data,
+	};
+
+	omap_init_gpmc(&gpmc_data);
+}
+
+static int gpmc_module_init(void);
+
 static int __init gpmc_init(void)
 {
 	char *oh_name = "gpmc";
@@ -887,7 +899,9 @@ static int __init gpmc_init(void)
 
 	clk_enable(gpmc_l3_clk);
 
-	return 0;
+	gpmc_driver_migration();
+
+	return gpmc_module_init();
 }
 postcore_initcall(gpmc_init);
 
@@ -1484,7 +1498,16 @@ static struct platform_driver gpmc_driver = {
 	},
 };
 
-module_platform_driver(gpmc_driver);
+static __init int gpmc_module_init(void)
+{
+	return platform_driver_register(&gpmc_driver);
+}
+
+static __exit void gpmc_tmp_exit(void)
+{
+	platform_driver_unregister(&gpmc_driver);
+}
+module_exit(gpmc_tmp_exit);
 
 #ifdef CONFIG_ARCH_OMAP3
 static struct omap3_gpmc_regs gpmc_context;
-- 
1.7.10


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

* [PATCH v4-alt 5/6] ARM: OMAP2+: gpmc-smsc911x: Add helper for driver conversion
  2012-05-02  8:45 [PATCH v4-alt 0/6] GPMC driver migrate one Afzal Mohammed
                   ` (3 preceding siblings ...)
  2012-05-02  8:46 ` [PATCH v4-alt 4/6] ARM: OMAP2+: gpmc: driver migration hack Afzal Mohammed
@ 2012-05-02  8:46 ` Afzal Mohammed
  2012-05-02  8:46 ` [PATCH v4-alt 6/6] ARM: OMAP2+: board omap3evm: gpmc driver adaptation Afzal Mohammed
  2012-05-08 21:36 ` [PATCH v4-alt 0/6] GPMC driver migrate one Tony Lindgren
  6 siblings, 0 replies; 26+ messages in thread
From: Afzal Mohammed @ 2012-05-02  8:46 UTC (permalink / raw)
  To: tony; +Cc: linux-omap, Afzal Mohammed

New interface for working with gpmc driver has been added
without modifying the existing interface. Latter has been kept
for migrating boards one by one, once all boards are migrated
to use the new interace, old interface to be deleted along with
renaming of new interface to old one

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

diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
index b6c77be..3b33b48 100644
--- a/arch/arm/mach-omap2/gpmc-smsc911x.c
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.c
@@ -99,3 +99,73 @@ free1:
 
 	pr_err("Could not initialize smsc911x device\n");
 }
+
+static struct resource gpmc_smsc911x_resources_new = {
+	.flags		= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+};
+
+__init struct gpmc_device_pdata *
+gpmc_smsc911x_init_new(struct omap_smsc911x_platform_data *gpmc_cfg)
+{
+	int ret;
+	struct gpmc_device_pdata *gpmc_pdev;
+	struct gpmc_cs_data *gpmc_cs;
+
+	gpmc_pdev = kzalloc(sizeof(*gpmc_pdev), GFP_KERNEL);
+	if (gpmc_pdev == NULL)
+		return gpmc_pdev;
+
+	gpmc_cs = kzalloc(sizeof(*gpmc_cs), GFP_KERNEL);
+	if (gpmc_pdev == NULL) {
+		kfree(gpmc_pdev);
+		return NULL;
+	}
+
+	gpmc_pdev->cs_data = gpmc_cs;
+	gpmc_pdev->num_cs = 1;
+	gpmc_pdev->name = "smsc911x";
+	gpmc_pdev->id = gpmc_cfg->id;
+	gpmc_pdev->pdata = &gpmc_smsc911x_config;
+	gpmc_pdev->pdata_size = sizeof(gpmc_smsc911x_config);
+
+	gpmc_cs->cs = gpmc_cfg->cs;
+	gpmc_cs->mem_size = 0x100;
+
+	gpmc_pdev->per_res = &gpmc_smsc911x_resources_new;
+	gpmc_pdev->per_res_cnt = 1;
+
+	if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "smsc911x irq")) {
+		pr_err("Failed to request IRQ GPIO%d\n", gpmc_cfg->gpio_irq);
+		goto free1;
+	}
+
+	gpmc_smsc911x_resources_new.start = gpio_to_irq(gpmc_cfg->gpio_irq);
+
+	if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
+		ret = gpio_request_one(gpmc_cfg->gpio_reset,
+				       GPIOF_OUT_INIT_HIGH, "smsc911x reset");
+		if (ret) {
+			pr_err("Failed to request reset GPIO%d\n",
+			       gpmc_cfg->gpio_reset);
+			goto free2;
+		}
+
+		gpio_set_value(gpmc_cfg->gpio_reset, 0);
+		msleep(100);
+		gpio_set_value(gpmc_cfg->gpio_reset, 1);
+	}
+
+	gpmc_smsc911x_config.flags = gpmc_cfg->flags ? : SMSC911X_USE_16BIT;
+
+	return gpmc_pdev;
+
+free2:
+	gpio_free(gpmc_cfg->gpio_irq);
+free1:
+	kfree(gpmc_cs);
+	kfree(gpmc_pdev);
+
+	pr_err("Could not initialize smsc911x device\n");
+
+	return NULL;
+}
diff --git a/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h b/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
index ea6c9c8..2e28e52 100644
--- a/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
+++ b/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
@@ -25,11 +25,20 @@ struct omap_smsc911x_platform_data {
 
 extern void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d);
 
+extern struct gpmc_device_pdata *
+gpmc_smsc911x_init_new(struct omap_smsc911x_platform_data *d);
+
 #else
 
 static inline void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d)
 {
 }
 
+static inline struct gpmc_device_pdata *
+gpmc_smsc911x_init_new(struct omap_smsc911x_platform_data *d)
+{
+	return NULL;
+}
+
 #endif
 #endif
-- 
1.7.10


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

* [PATCH v4-alt 6/6] ARM: OMAP2+: board omap3evm: gpmc driver adaptation
  2012-05-02  8:45 [PATCH v4-alt 0/6] GPMC driver migrate one Afzal Mohammed
                   ` (4 preceding siblings ...)
  2012-05-02  8:46 ` [PATCH v4-alt 5/6] ARM: OMAP2+: gpmc-smsc911x: Add helper for driver conversion Afzal Mohammed
@ 2012-05-02  8:46 ` Afzal Mohammed
  2012-05-08 21:36 ` [PATCH v4-alt 0/6] GPMC driver migrate one Tony Lindgren
  6 siblings, 0 replies; 26+ messages in thread
From: Afzal Mohammed @ 2012-05-02  8:46 UTC (permalink / raw)
  To: tony; +Cc: linux-omap, Afzal Mohammed

gpmc code has been converted to driver. Modify the board
code to provide gpmc driver with required information

Note: This uses new interface for initializing smsc911x,
old interface should be removed once all boards are
converted to use new interface. So also machine_is_
check in gpmc.c as well as the patch,
"ARM: OMAP2+: gpmc: driver migration hack"

Signed-off-by: Afzal Mohammed <afzal@ti.com>
---
 arch/arm/mach-omap2/board-omap3evm.c |   14 +++++++++++++-
 arch/arm/mach-omap2/gpmc.c           |    3 +++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index fd1b481..7c83c45 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -43,6 +43,7 @@
 
 #include <plat/board.h>
 #include <plat/usb.h>
+#include <plat/gpmc.h>
 #include "common.h"
 #include <plat/mcspi.h>
 #include <video/omapdss.h>
@@ -102,6 +103,12 @@ static void __init omap3_evm_get_revision(void)
 	}
 }
 
+static struct gpmc_device_pdata *gpmc_device_data[1];
+
+static struct gpmc_pdata gpmc_data = {
+	.device_pdata = gpmc_device_data,
+};
+
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #include <plat/gpmc-smsc911x.h>
 
@@ -122,7 +129,11 @@ static inline void __init omap3evm_init_smsc911x(void)
 			smsc911x_cfg.gpio_reset = OMAP3EVM_GEN2_ETHR_GPIO_RST;
 	}
 
-	gpmc_smsc911x_init(&smsc911x_cfg);
+	*gpmc_device_data = gpmc_smsc911x_init_new(&smsc911x_cfg);
+	if (*gpmc_device_data)
+		gpmc_data.num_device++;
+	else
+		pr_err("error: unable to initilaize gpmc smsc911x\n");
 }
 
 #else
@@ -679,6 +690,7 @@ static void __init omap3_evm_init(void)
 	usbhs_init(&usbhs_bdata);
 	omap_ads7846_init(1, OMAP3_EVM_TS_GPIO, 310, NULL);
 	omap3evm_init_smsc911x();
+	omap_init_gpmc(&gpmc_data);
 	omap3_evm_display_init();
 	omap3_evm_wl12xx_init();
 }
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 4dcc141..eb7580d 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -875,6 +875,9 @@ static void gpmc_driver_migration(void)
 		.device_pdata	= gpmc_device_data,
 	};
 
+	if (machine_is_omap3evm())
+		return;
+
 	omap_init_gpmc(&gpmc_data);
 }
 
-- 
1.7.10


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

* Re: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-02  8:46 ` [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc Afzal Mohammed
@ 2012-05-06  2:04   ` Paul Walmsley
  2012-05-07 11:12     ` Mohammed, Afzal
  0 siblings, 1 reply; 26+ messages in thread
From: Paul Walmsley @ 2012-05-06  2:04 UTC (permalink / raw)
  To: Afzal Mohammed; +Cc: tony, linux-omap

Hello Afzal

a few comments

On Wed, 2 May 2012, Afzal Mohammed wrote:

> Add gpmc hwmod and associated interconnect data
> 
> Signed-off-by: Afzal Mohammed <afzal@ti.com>

Did you notice the warning that this patch generates on boot?

omap_hwmod: gpmc: cannot be enabled for reset (3)

The HWMOD_NO_IDLEST hwmod flag is needed, since there is no GPMC IDLEST 
bit.

...

Also, the OMAP2xxx GPMC hwmod data is missing.  It can be combined 
with this patch.

...

Also:

> +static struct omap_hwmod omap3xxx_gpmc_hwmod = {
> +	.name		= "gpmc",
> +	.class		= &omap3xxx_gpmc_hwmod_class,
> +	.clkdm_name	= "l3_init_clkdm",
> +	.mpu_irqs	= omap3xxx_gpmc_irqs,
> +	.main_clk	= "gpmc_fck",
> +	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
> +};

Is there some reason why you are setting the HWMOD_INIT_NO_RESET flag 
here?  Seems to me that the kernel should not rely on the bootloader GPMC 
configuration, but should use a configuration from the board file or DT.


- Paul

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-06  2:04   ` Paul Walmsley
@ 2012-05-07 11:12     ` Mohammed, Afzal
  2012-05-08 13:12       ` Mohammed, Afzal
  2012-05-08 15:32       ` Paul Walmsley
  0 siblings, 2 replies; 26+ messages in thread
From: Mohammed, Afzal @ 2012-05-07 11:12 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: tony, linux-omap

Hi Paul,

On Sun, May 06, 2012 at 07:34:07, Paul Walmsley wrote:
> Did you notice the warning that this patch generates on boot?
> 
> omap_hwmod: gpmc: cannot be enabled for reset (3)
> 
> The HWMOD_NO_IDLEST hwmod flag is needed, since there is no GPMC IDLEST 
> bit.

Yes, putting that flag makes warning go away, Thanks

> 
> ...
> 
> Also, the OMAP2xxx GPMC hwmod data is missing.  It can be combined 
> with this patch.

In v4, it has been sent as two patches - one for 3xxx & one for 2xxx,
do you want to combine both ?

> > +static struct omap_hwmod omap3xxx_gpmc_hwmod = {
> > +	.name		= "gpmc",
> > +	.class		= &omap3xxx_gpmc_hwmod_class,
> > +	.clkdm_name	= "l3_init_clkdm",
> > +	.mpu_irqs	= omap3xxx_gpmc_irqs,
> > +	.main_clk	= "gpmc_fck",
> > +	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
> > +};
> 
> Is there some reason why you are setting the HWMOD_INIT_NO_RESET flag 
> here?  Seems to me that the kernel should not rely on the bootloader GPMC 
> configuration, but should use a configuration from the board file or DT.


Major reason was that there are some boards that rely on bootloader
settings, eg. kernel does not do any setting for smsc911x. I did not
want to break those, at least it causes problem with omap3evm, see below

Another was that this was created based on,
"eb42b5d ARM: OMAP4: hwmod data: add GPMC" and an internal one for AM335X,
Both had HWMOD_INIT_NO_RESET flag.

Removing it causes multiple problems, one is that CS0 is valid after reset
of module, with base address starting from zero, which causes requesting
resource failure for CS0, with the way it is currently coded (GPMC resource
starts from 1MB). Even upon skipping CS0, kernel oops at seemingly unrelated
location as follows, probably due to gpmc reset, as bootloader configured
values are modified to reset value. Omap3 evm uses smsc911x.

[    2.660095] WARNING: at /home/afzal/dev/SA/src/-kernel/kernel/lockdep.c:956 __bfs+0x1f0/0x230()
[    2.669708] Modules linked in:
[    2.672973] [<c001a568>] (unwind_backtrace+0x0/0xf0) from [<c003cfec>] (warn_slowpath_common+0x4c/0x64)
[    2.682891] [<c003cfec>] (warn_slowpath_common+0x4c/0x64) from [<c003d020>] (warn_slowpath_null+0x1c/0x24)
[    2.693084] [<c003d020>] (warn_slowpath_null+0x1c/0x24) from [<c00827d0>] (__bfs+0x1f0/0x230)
[    2.702087] [<c00827d0>] (__bfs+0x1f0/0x230) from [<c0084a74>] (check_usage_forwards+0x60/0x10c)
[    2.711364] [<c0084a74>] (check_usage_forwards+0x60/0x10c) from [<c00857b8>] (mark_lock+0x1bc/0x64c)
[    2.720977] [<c00857b8>] (mark_lock+0x1bc/0x64c) from [<c0086634>] (__lock_acquire+0x9ec/0x1c64)
[    2.730255] [<c0086634>] (__lock_acquire+0x9ec/0x1c64) from [<c0087e3c>] (lock_acquire+0x98/0x100)
[    2.739715] [<c0087e3c>] (lock_acquire+0x98/0x100) from [<c004a5f8>] (run_timer_softirq+0x13c/0x378)
[    2.749359] [<c004a5f8>] (run_timer_softirq+0x13c/0x378) from [<c00438b0>] (__do_softirq+0xc8/0x1f4)
[    2.759002] [<c00438b0>] (__do_softirq+0xc8/0x1f4) from [<c0043e64>] (irq_exit+0x90/0x98)
[    2.767639] [<c0043e64>] (irq_exit+0x90/0x98) from [<c00141dc>] (handle_IRQ+0x50/0xac)
[    2.776000] [<c00141dc>] (handle_IRQ+0x50/0xac) from [<c00086fc>] (omap3_intc_handle_irq+0x54/0x68)
[    2.785552] [<c00086fc>] (omap3_intc_handle_irq+0x54/0x68) from [<c0425724>] (__irq_svc+0x4


Another issue on OMAP3EVM is the detection of evm revision based on phy id,
by reading hardcoded address, 0x2c000000. It had to be skipped to reach till
above mentioned.

Regards
Afzal

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-07 11:12     ` Mohammed, Afzal
@ 2012-05-08 13:12       ` Mohammed, Afzal
  2012-05-08 15:37         ` Paul Walmsley
  2012-05-08 15:32       ` Paul Walmsley
  1 sibling, 1 reply; 26+ messages in thread
From: Mohammed, Afzal @ 2012-05-08 13:12 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: tony, linux-omap

Hi Paul,

On Mon, May 07, 2012 at 16:42:16, Mohammed, Afzal wrote:

> > > +static struct omap_hwmod omap3xxx_gpmc_hwmod = {
> > > +	.name		= "gpmc",
> > > +	.class		= &omap3xxx_gpmc_hwmod_class,
> > > +	.clkdm_name	= "l3_init_clkdm",
> > > +	.mpu_irqs	= omap3xxx_gpmc_irqs,
> > > +	.main_clk	= "gpmc_fck",
> > > +	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
> > > +};
> > 
> > Is there some reason why you are setting the HWMOD_INIT_NO_RESET flag 
> > here?  Seems to me that the kernel should not rely on the bootloader GPMC 
> > configuration, but should use a configuration from the board file or DT.
> 
> 
> Major reason was that there are some boards that rely on bootloader
> settings, eg. kernel does not do any setting for smsc911x. I did not
> want to break those, at least it causes problem with omap3evm

If HWMOD_NO_INIT_RESET is not present, it would break GPMC on
many of the existing boards.

New version of GPMC HWMOD patch has been posted with HWMOD_NO_IDLEST flag,
which is a squashed one with OMAP2xxx HWMOD

Regards
AFzal

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-07 11:12     ` Mohammed, Afzal
  2012-05-08 13:12       ` Mohammed, Afzal
@ 2012-05-08 15:32       ` Paul Walmsley
  2012-05-10  6:03         ` Mohammed, Afzal
  1 sibling, 1 reply; 26+ messages in thread
From: Paul Walmsley @ 2012-05-08 15:32 UTC (permalink / raw)
  To: Mohammed, Afzal; +Cc: tony, linux-omap

On Mon, 7 May 2012, Mohammed, Afzal wrote:

> On Sun, May 06, 2012 at 07:34:07, Paul Walmsley wrote:

(attribution lost)

> > > +static struct omap_hwmod omap3xxx_gpmc_hwmod = {
> > > +	.name		= "gpmc",
> > > +	.class		= &omap3xxx_gpmc_hwmod_class,
> > > +	.clkdm_name	= "l3_init_clkdm",
> > > +	.mpu_irqs	= omap3xxx_gpmc_irqs,
> > > +	.main_clk	= "gpmc_fck",
> > > +	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
> > > +};
> > 
> > Is there some reason why you are setting the HWMOD_INIT_NO_RESET flag 
> > here?  Seems to me that the kernel should not rely on the bootloader GPMC 
> > configuration, but should use a configuration from the board file or DT.
> 
> Major reason was that there are some boards that rely on bootloader
> settings, eg. kernel does not do any setting for smsc911x. I did not
> want to break those, at least it causes problem with omap3evm, see below

But this is the whole point.  The Linux GPMC driver and integration code 
should be setting up the GPMC registers based on board file and/or DT 
data, before the kernel touches any GPMC devices.

We don't want to rely on the bootloader settings unless we absolutely have 
no other choice.  Otherwise, the stability of the kernel could easily be 
impacted by the bootloader's GPMC timings and other register settings, and 
we want to minimize those potential sources of variation.

So if we absolutely have no choice than to keep HWMOD_INIT_NO_RESET here, 
which doesn't sound like the case so far, we need to understand exactly 
why this is so.

> Removing it causes multiple problems, one is that CS0 is valid after 
> reset of module, with base address starting from zero, which causes 
> requesting resource failure for CS0, with the way it is currently coded 
> (GPMC resource starts from 1MB).

Can't this be handled by using a custom hwmod reset function for the GPMC?

> Even upon skipping CS0, kernel oops at seemingly unrelated location as 
> follows, probably due to gpmc reset, as bootloader configured values are 
> modified to reset value.  Omap3 evm uses smsc911x.

Sounds like you've got a good test platform, then :-)

> Another issue on OMAP3EVM is the detection of evm revision based on phy id,
> by reading hardcoded address, 0x2c000000. It had to be skipped to reach till
> above mentioned.

Looking at omap3_evm_get_revision() it seems that the OMAP3EVM detection 
happens by reading the Ethernet chip's revision register.  So can't this 
be fixed by programming the GPMC appropriately to access the Ethernet 
chip first?


- Paul

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-08 13:12       ` Mohammed, Afzal
@ 2012-05-08 15:37         ` Paul Walmsley
  0 siblings, 0 replies; 26+ messages in thread
From: Paul Walmsley @ 2012-05-08 15:37 UTC (permalink / raw)
  To: Mohammed, Afzal; +Cc: tony, linux-omap

Hi

On Tue, 8 May 2012, Mohammed, Afzal wrote:

> If HWMOD_NO_INIT_RESET is not present, it would break GPMC on
> many of the existing boards.

IMHO, that should also be fixed as part of your changes, to remove what 
seems to be an unnecessary bootloader dependency.

http://marc.info/?l=linux-omap&m=133649129220098&w=2


- Paul

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

* Re: [PATCH v4-alt 0/6] GPMC driver migrate one
  2012-05-02  8:45 [PATCH v4-alt 0/6] GPMC driver migrate one Afzal Mohammed
                   ` (5 preceding siblings ...)
  2012-05-02  8:46 ` [PATCH v4-alt 6/6] ARM: OMAP2+: board omap3evm: gpmc driver adaptation Afzal Mohammed
@ 2012-05-08 21:36 ` Tony Lindgren
  2012-05-10  6:35   ` Mohammed, Afzal
  6 siblings, 1 reply; 26+ messages in thread
From: Tony Lindgren @ 2012-05-08 21:36 UTC (permalink / raw)
  To: Afzal Mohammed; +Cc: linux-omap

* Afzal Mohammed <afzal@ti.com> [120502 02:05]:
> Hi Tony,
> 
> As you would have already seen, v4 of GPMC driver conversion has been
> posted (this is v4-alt). I undertand the risk involved in converting
> all board files to use new interface in a single patch series. But to
> have a decent set of patches, I feel this is required. But this may
> bring us to a point where GPMC may not work on some boards.
> 
> To resolve this and as per your earlier question on whether old along
> with new interface can be made to work parallely, here is suggestion
> from my end to deal with it.

I think this is the only way to keep this all building and booting
for each patch in the series, no? If so, then we should select this
option. The first patch should be broken up into more readable patches,
it seems that you can do that without breaking things.
 
> Please let me know whether you are fine in taking patch series
> as in v4 (that converts all boards at once, with further revisions
> based on review comments).

It seems that there are still some pending comments and we need to
have the hwmod entries merged first by Paul.

Regards,

Tony

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-08 15:32       ` Paul Walmsley
@ 2012-05-10  6:03         ` Mohammed, Afzal
  2012-05-12  4:23           ` Mohammed, Afzal
  2012-05-22  6:47           ` Paul Walmsley
  0 siblings, 2 replies; 26+ messages in thread
From: Mohammed, Afzal @ 2012-05-10  6:03 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: tony, linux-omap

Hi Paul,

On Tue, May 08, 2012 at 21:02:33, Paul Walmsley wrote:

> > Major reason was that there are some boards that rely on bootloader
> > settings, eg. kernel does not do any setting for smsc911x. I did not
> > want to break those, at least it causes problem with omap3evm, see below
> 
> But this is the whole point.  The Linux GPMC driver and integration code 
> should be setting up the GPMC registers based on board file and/or DT 
> data, before the kernel touches any GPMC devices.
> 
> We don't want to rely on the bootloader settings unless we absolutely have 
> no other choice.  Otherwise, the stability of the kernel could easily be 
> impacted by the bootloader's GPMC timings and other register settings, and 
> we want to minimize those potential sources of variation.
> 
> So if we absolutely have no choice than to keep HWMOD_INIT_NO_RESET here, 
> which doesn't sound like the case so far, we need to understand exactly 
> why this is so.

There are 14 out of 20 boards partially or fully relying on bootloader
settings. I will try to do configuration for smsc911x in Kernel itself,
this is the only one that can be tested from my side (on omap3evm), but
there are other peripherals like NOR, quaduart, onenand-flash (different
from omap-onenand), then smc91x (timings are not set from kernel for
sdp boards), these would affect 7 boards of both omap2 & omap3. To
get configuration done from Kernel properly without having these boards
is too tough for me.

So I request you to keep HWMOD_INIT_NO_RESET (I will add configuration
for smsc911x), please let me know your comments.

> > Removing it causes multiple problems, one is that CS0 is valid after 
> > reset of module, with base address starting from zero, which causes 
> > requesting resource failure for CS0, with the way it is currently coded 
> > (GPMC resource starts from 1MB).
> 
> Can't this be handled by using a custom hwmod reset function for the GPMC?

No too familiar with hwmod, let me try that

> > Another issue on OMAP3EVM is the detection of evm revision based on phy id,
> > by reading hardcoded address, 0x2c000000. It had to be skipped to reach till
> > above mentioned.
> 
> Looking at omap3_evm_get_revision() it seems that the OMAP3EVM detection 
> happens by reading the Ethernet chip's revision register.  So can't this 
> be fixed by programming the GPMC appropriately to access the Ethernet 
> chip first?

I did not get you, may be let me explain the problem once again,

0x2c000000 is physical address configured by bootloader. And omap3evm board
file depends on this value to read eth chip revision register. Ideally this
register should be accessed by smsc911x driver only.

Once gpmc is reset, physical address for smsc911x can vary. With gpmc
driver conversion, address of smsc911x register would be available only
to smsc911x driver, and this address would not be setup until gpmc driver
is probed, and so would not available for omap3_evm_get_revision, which
has to be called before gpmc device registration.

And here we are depending on eth revision register to find board revision.

Regards
Afzal

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

* RE: [PATCH v4-alt 0/6] GPMC driver migrate one
  2012-05-08 21:36 ` [PATCH v4-alt 0/6] GPMC driver migrate one Tony Lindgren
@ 2012-05-10  6:35   ` Mohammed, Afzal
  2012-05-11 20:00     ` Tony Lindgren
  0 siblings, 1 reply; 26+ messages in thread
From: Mohammed, Afzal @ 2012-05-10  6:35 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap

Hi Tony,

On Wed, May 09, 2012 at 03:06:26, Tony Lindgren wrote:

> > To resolve this and as per your earlier question on whether old along
> > with new interface can be made to work parallely, here is suggestion
> > from my end to deal with it.
> 
> I think this is the only way to keep this all building and booting
> for each patch in the series, no? If so, then we should select this
> option. The first patch should be broken up into more readable patches,
> it seems that you can do that without breaking things.

Bisectability has been maintained in the patches.

Ok, I will proceed by keeping old & new interface together, will
try to achieve it in smaller patches and without hacks.

> > Please let me know whether you are fine in taking patch series
> > as in v4 (that converts all boards at once, with further revisions
> > based on review comments).
> 
> It seems that there are still some pending comments and we need to
> have the hwmod entries merged first by Paul.

Ok, first I will try to get hwmod in.

Regards
Afzal

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

* Re: [PATCH v4-alt 0/6] GPMC driver migrate one
  2012-05-10  6:35   ` Mohammed, Afzal
@ 2012-05-11 20:00     ` Tony Lindgren
  2012-05-14  4:59       ` Mohammed, Afzal
  0 siblings, 1 reply; 26+ messages in thread
From: Tony Lindgren @ 2012-05-11 20:00 UTC (permalink / raw)
  To: Mohammed, Afzal; +Cc: linux-omap

* Mohammed, Afzal <afzal@ti.com> [120509 23:39]:
> Hi Tony,
> 
> On Wed, May 09, 2012 at 03:06:26, Tony Lindgren wrote:
> 
> > > To resolve this and as per your earlier question on whether old along
> > > with new interface can be made to work parallely, here is suggestion
> > > from my end to deal with it.
> > 
> > I think this is the only way to keep this all building and booting
> > for each patch in the series, no? If so, then we should select this
> > option. The first patch should be broken up into more readable patches,
> > it seems that you can do that without breaking things.
> 
> Bisectability has been maintained in the patches.
> 
> Ok, I will proceed by keeping old & new interface together, will
> try to achieve it in smaller patches and without hacks.
> 
> > > Please let me know whether you are fine in taking patch series
> > > as in v4 (that converts all boards at once, with further revisions
> > > based on review comments).
> > 
> > It seems that there are still some pending comments and we need to
> > have the hwmod entries merged first by Paul.
> 
> Ok, first I will try to get hwmod in.

Let's try to get merged these into l-o master around -rc2 so we can
have them tested properly for a few weeks before v3.6 merge window.

Regards,

Tony

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-10  6:03         ` Mohammed, Afzal
@ 2012-05-12  4:23           ` Mohammed, Afzal
  2012-05-22  6:47           ` Paul Walmsley
  1 sibling, 0 replies; 26+ messages in thread
From: Mohammed, Afzal @ 2012-05-12  4:23 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: tony, linux-omap

Hi Paul,

On Thu, May 10, 2012 at 11:33:44, Mohammed, Afzal wrote:
> Hi Paul,
> 
> On Tue, May 08, 2012 at 21:02:33, Paul Walmsley wrote:
> 
> > > Major reason was that there are some boards that rely on bootloader
> > > settings, eg. kernel does not do any setting for smsc911x. I did not
> > > want to break those, at least it causes problem with omap3evm, see below
> > 
> > But this is the whole point.  The Linux GPMC driver and integration code 
> > should be setting up the GPMC registers based on board file and/or DT 
> > data, before the kernel touches any GPMC devices.
> > 
> > We don't want to rely on the bootloader settings unless we absolutely have 
> > no other choice.  Otherwise, the stability of the kernel could easily be 
> > impacted by the bootloader's GPMC timings and other register settings, and 
> > we want to minimize those potential sources of variation.
> > 
> > So if we absolutely have no choice than to keep HWMOD_INIT_NO_RESET here, 
> > which doesn't sound like the case so far, we need to understand exactly 
> > why this is so.
> 
> There are 14 out of 20 boards partially or fully relying on bootloader
> settings. I will try to do configuration for smsc911x in Kernel itself,
> this is the only one that can be tested from my side (on omap3evm), but
> there are other peripherals like NOR, quaduart, onenand-flash (different
> from omap-onenand), then smc91x (timings are not set from kernel for
> sdp boards), these would affect 7 boards of both omap2 & omap3. To
> get configuration done from Kernel properly without having these boards
> is too tough for me.
> 
> So I request you to keep HWMOD_INIT_NO_RESET (I will add configuration
> for smsc911x), please let me know your comments.

ping

Regards
Afzal

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

* RE: [PATCH v4-alt 0/6] GPMC driver migrate one
  2012-05-11 20:00     ` Tony Lindgren
@ 2012-05-14  4:59       ` Mohammed, Afzal
  0 siblings, 0 replies; 26+ messages in thread
From: Mohammed, Afzal @ 2012-05-14  4:59 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-omap

Hi Tony,

On Sat, May 12, 2012 at 01:30:49, Tony Lindgren wrote:

> Let's try to get merged these into l-o master around -rc2 so we can
> have them tested properly for a few weeks before v3.6 merge window.

Sure, this will be my goal

Regards
Afzal

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-10  6:03         ` Mohammed, Afzal
  2012-05-12  4:23           ` Mohammed, Afzal
@ 2012-05-22  6:47           ` Paul Walmsley
  2012-05-22 11:35             ` Mohammed, Afzal
  2012-05-22 16:42             ` Tony Lindgren
  1 sibling, 2 replies; 26+ messages in thread
From: Paul Walmsley @ 2012-05-22  6:47 UTC (permalink / raw)
  To: Mohammed, Afzal; +Cc: tony, khilman, linux-omap

Hi Afzal

On Thu, 10 May 2012, Mohammed, Afzal wrote:

> On Tue, May 08, 2012 at 21:02:33, Paul Walmsley wrote:

(attribution lost)

> 
> > > Major reason was that there are some boards that rely on bootloader
> > > settings, eg. kernel does not do any setting for smsc911x. I did not
> > > want to break those, at least it causes problem with omap3evm, see below
> > 
> > But this is the whole point.  The Linux GPMC driver and integration code 
> > should be setting up the GPMC registers based on board file and/or DT 
> > data, before the kernel touches any GPMC devices.
> > 
> > We don't want to rely on the bootloader settings unless we absolutely have 
> > no other choice.  Otherwise, the stability of the kernel could easily be 
> > impacted by the bootloader's GPMC timings and other register settings, and 
> > we want to minimize those potential sources of variation.
> > 
> > So if we absolutely have no choice than to keep HWMOD_INIT_NO_RESET here, 
> > which doesn't sound like the case so far, we need to understand exactly 
> > why this is so.
> 
> There are 14 out of 20 boards partially or fully relying on bootloader
> settings. I will try to do configuration for smsc911x in Kernel itself,
> this is the only one that can be tested from my side (on omap3evm), but
> there are other peripherals like NOR, quaduart, onenand-flash (different
> from omap-onenand), then smc91x (timings are not set from kernel for
> sdp boards), these would affect 7 boards of both omap2 & omap3. To
> get configuration done from Kernel properly without having these boards
> is too tough for me.

I'd suggest implementing two ways of programming the GPMC from the kernel.

The first, preferred, method would be used with boards that we have timing 
data for that is independent from the GPMC clock rate -- i.e., timing 
data in nanoseconds or picoseconds.  These boards will be capable of CORE 
DVFS.

The second, deprecated, method would be used with boards that we only have 
GPMC clock rate-dependent timing data for -- i.e., raw GPMC register data.
These boards will not be CORE DVFS-capable.

It should be possible for the kernel to configure the GPMC with either one 
of these methods, either from DT or from platform_data.

I'd suggest starting by adding code to allow a board file/DT to configure 
the GPMC to set the timings for a given chip-select based on clock 
rate-independent data (the first method above).  Some good starting points 
for this code would be in the arch/arm/mach-omap2/gpmc-*.c files.  Then 
the rate-independent data can be added for the boards which have available 
schematics or for which we have the data.  For the DT case, you'll 
probably need to define a clock rate-independent binding if you haven't 
already.

Next, I'd suggest implementing the code to allow GPMC timing configuration 
from raw register data (the second method above).  This is hackish but for 
some boards, this is all we'll have.  This will also presumably require 
some extra DT bindings for the register data.  If this method is used, 
this code should also call a PM function to block clock rate changes on 
the GPMC clock, and an explanatory warning should be logged to the 
console.

For boards that we don't have access to, and all someone would have are 
the register values set by the bootloader, I'd propose a phased approach:

1. The kernel should log the bootloader-provided GPMC timing registers to 
the console during boot, along with a warning message that indicates that 
GPMC for these boards will cease to function in the near future unless 
patches are provided to update the kernel board file and/or DT data with 
the GPMC register contents.  This should allow people who have those 
boards and who care about them to submit kernel patches to allow the 
GPMC-attached devices to continue to function.

2. A patch to Documentation/feature-removal-schedule.txt should be
submitted which states that support for implicit bootloader GPMC timings
will be removed within two or three kernel releases.

3. The board maintainers and anyone who has contributed to the mainline 
git tree for those boards who seems to actually have the board should be 
contacted with a short E-mail message asking them to update their board 
GPMC timings.

4. When the expiration date specified in #2 is released, 
HWMOD_INIT_NO_RESET would be removed from the GPMC hwmod, and the GPMC 
code should refuse to initialize unless explicit timing data has been 
provided.

If this protocol is followed, I wouldn't have a significant objection to 
specifying HWMOD_INIT_NO_RESET for the GPMC.  That's because, under these 
conditions, the flag will only be present for a short period of time, and 
there will be a strong incentive for people with those boards to update 
the mainline board file/DT data with the GPMC timings.  Otherwise their 
boards will be broken.

> > > Another issue on OMAP3EVM is the detection of evm revision based on 
> > > phy id, by reading hardcoded address, 0x2c000000. It had to be 
> > > skipped to reach till above mentioned.
> > 
> > Looking at omap3_evm_get_revision() it seems that the OMAP3EVM 
> > detection happens by reading the Ethernet chip's revision register.  
> > So can't this be fixed by programming the GPMC appropriately to access 
> > the Ethernet chip first?
> 
> I did not get you, may be let me explain the problem once again,
> 
> 0x2c000000 is physical address configured by bootloader. And omap3evm board
> file depends on this value to read eth chip revision register. Ideally this
> register should be accessed by smsc911x driver only.
> 
> Once gpmc is reset, physical address for smsc911x can vary.  With gpmc 
> driver conversion, address of smsc911x register would be available only 
> to smsc911x driver, and this address would not be setup until gpmc 
> driver is probed, and so would not available for omap3_evm_get_revision, 
> which has to be called before gpmc device registration.
> 
> And here we are depending on eth revision register to find board revision.

Perhaps I am misunderstanding you.  Are you stating that the Ethernet 
controller is wired to appear at different physical addresses, depending 
on the board revision?  And that there is no other way to determine the 
board revision, other than to attempt to access the Ethernet controller?

If that is the case, then that board's hardware design seems broken.  
There should be an unambiguous, side-effect-free way to determine the 
board revision.  That said, there still seem to be ways to work around it.  
For non-DT kernels, I'd suggest defining a kernel command line option 
which would specify the board revision to this specific board file, which 
then could configure the GPMC appropriately.  The bootloader could pass 
this flag.  For DT kernels, the GPMC setup information should be passed in 
the DT data.


- Paul

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-22  6:47           ` Paul Walmsley
@ 2012-05-22 11:35             ` Mohammed, Afzal
  2012-05-22 16:42             ` Tony Lindgren
  1 sibling, 0 replies; 26+ messages in thread
From: Mohammed, Afzal @ 2012-05-22 11:35 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: tony, Hilman, Kevin, linux-omap

Hi Paul,

On Tue, May 22, 2012 at 12:17:30, Paul Walmsley wrote:
> Hi Afzal
> 
> On Thu, 10 May 2012, Mohammed, Afzal wrote:
> 
> > On Tue, May 08, 2012 at 21:02:33, Paul Walmsley wrote:
> 
> (attribution lost)

Hmm, second time, normally I try to delete as much as possible contents from
the original mail to make it more readable while keeping the core

> 
> I'd suggest implementing two ways of programming the GPMC from the kernel.
> 
> The first, preferred, method would be used with boards that we have timing 
> data for that is independent from the GPMC clock rate -- i.e., timing 
> data in nanoseconds or picoseconds.  These boards will be capable of CORE 
> DVFS.
> 
> The second, deprecated, method would be used with boards that we only have 
> GPMC clock rate-dependent timing data for -- i.e., raw GPMC register data.
> These boards will not be CORE DVFS-capable.
> 
> It should be possible for the kernel to configure the GPMC with either one 
> of these methods, either from DT or from platform_data.
> 
> I'd suggest starting by adding code to allow a board file/DT to configure 
> the GPMC to set the timings for a given chip-select based on clock 
> rate-independent data (the first method above).  Some good starting points 
> for this code would be in the arch/arm/mach-omap2/gpmc-*.c files.  Then 
> the rate-independent data can be added for the boards which have available 
> schematics or for which we have the data.  For the DT case, you'll 
> probably need to define a clock rate-independent binding if you haven't 
> already.
> 
> Next, I'd suggest implementing the code to allow GPMC timing configuration 
> from raw register data (the second method above).  This is hackish but for 
> some boards, this is all we'll have.  This will also presumably require 
> some extra DT bindings for the register data.  If this method is used, 
> this code should also call a PM function to block clock rate changes on 
> the GPMC clock, and an explanatory warning should be logged to the 
> console.
> 
> For boards that we don't have access to, and all someone would have are 
> the register values set by the bootloader, I'd propose a phased approach:
> 
> 1. The kernel should log the bootloader-provided GPMC timing registers to 
> the console during boot, along with a warning message that indicates that 
> GPMC for these boards will cease to function in the near future unless 
> patches are provided to update the kernel board file and/or DT data with 
> the GPMC register contents.  This should allow people who have those 
> boards and who care about them to submit kernel patches to allow the 
> GPMC-attached devices to continue to function.
> 
> 2. A patch to Documentation/feature-removal-schedule.txt should be
> submitted which states that support for implicit bootloader GPMC timings
> will be removed within two or three kernel releases.
> 
> 3. The board maintainers and anyone who has contributed to the mainline 
> git tree for those boards who seems to actually have the board should be 
> contacted with a short E-mail message asking them to update their board 
> GPMC timings.
> 
> 4. When the expiration date specified in #2 is released, 
> HWMOD_INIT_NO_RESET would be removed from the GPMC hwmod, and the GPMC 
> code should refuse to initialize unless explicit timing data has been 
> provided.
> 
> If this protocol is followed, I wouldn't have a significant objection to 
> specifying HWMOD_INIT_NO_RESET for the GPMC.  That's because, under these 
> conditions, the flag will only be present for a short period of time, and 
> there will be a strong incentive for people with those boards to update 
> the mainline board file/DT data with the GPMC timings.  Otherwise their 
> boards will be broken.

Summarized GPMC tasks as per my understanding based on Tony's & yours
comments and that I am working on as follows,

1. convert to driver
2. remove dependency of bootloader for configuration

Approach being taken is to migrate to driver while keeping old interface w.r.t
boards intact (i.e. configuring gpmc in board files for old interface can be
done the way it is done now, tasks now achieved in gpmc_init would be done by
probe, only that much, but that would not make any difference for boards using
old interface) along with having new interface till all boards are converted to
use new interface. Once all boards are converted to use new interface, old
interface would be removed. For boards using new interface, in probe, in addition
to the tasks presently done by gpmc_init, it would do configuring for boards,
creating platform devices for the peripherals connected.

Configuration that is not presently done in Kernel would be handled the way
you have suggested; first preference clk rate independent, if not possible
then use register values, if that also not possible do as per your points
1-4. GPMC configuration that would be added newly in the Kernel would be
using new interface

Tony, Paul, please let me know if you have any divergent views on the above.

> 
> > > > Another issue on OMAP3EVM is the detection of evm revision based on 
> > > > phy id, by reading hardcoded address, 0x2c000000. It had to be 
> > > > skipped to reach till above mentioned.
> > > 
> > > Looking at omap3_evm_get_revision() it seems that the OMAP3EVM 
> > > detection happens by reading the Ethernet chip's revision register.  
> > > So can't this be fixed by programming the GPMC appropriately to access 
> > > the Ethernet chip first?
> > 
> > I did not get you, may be let me explain the problem once again,
> > 
> > 0x2c000000 is physical address configured by bootloader. And omap3evm board
> > file depends on this value to read eth chip revision register. Ideally this
> > register should be accessed by smsc911x driver only.
> > 
> > Once gpmc is reset, physical address for smsc911x can vary.  With gpmc 
> > driver conversion, address of smsc911x register would be available only 
> > to smsc911x driver, and this address would not be setup until gpmc 
> > driver is probed, and so would not available for omap3_evm_get_revision, 
> > which has to be called before gpmc device registration.
> > 
> > And here we are depending on eth revision register to find board revision.
> 
> Perhaps I am misunderstanding you.  Are you stating that the Ethernet 
> controller is wired to appear at different physical addresses, depending 
> on the board revision?  And that there is no other way to determine the 
> board revision, other than to attempt to access the Ethernet controller?
> 
> If that is the case, then that board's hardware design seems broken.  
> There should be an unambiguous, side-effect-free way to determine the 
> board revision.  That said, there still seem to be ways to work around it.  
> For non-DT kernels, I'd suggest defining a kernel command line option 
> which would specify the board revision to this specific board file, which 
> then could configure the GPMC appropriately.  The bootloader could pass 
> this flag.  For DT kernels, the GPMC setup information should be passed in 
> the DT data.

No, physical address is same, init_machine would no longer have same physical
address valid if reset is done by hwmod, hence address with which omap3evm
tried to find eth revision register would no longer be valid as address is
hardcoded. Once gpmc driver is probed we can have a valid physical address, but
it may differ from what is hardcoded & would not be available at init_machine

I will try whether omap3evm board revision can be found some other way.

Thank you for the detailed reply.

Regards
Afzal

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

* Re: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-22  6:47           ` Paul Walmsley
  2012-05-22 11:35             ` Mohammed, Afzal
@ 2012-05-22 16:42             ` Tony Lindgren
  2012-05-23 14:51               ` Paul Walmsley
  2012-06-12 11:36               ` Mohammed, Afzal
  1 sibling, 2 replies; 26+ messages in thread
From: Tony Lindgren @ 2012-05-22 16:42 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: Mohammed, Afzal, khilman, linux-omap

* Paul Walmsley <paul@pwsan.com> [120521 23:51]:
> 
> Next, I'd suggest implementing the code to allow GPMC timing configuration 
> from raw register data (the second method above).  This is hackish but for 
> some boards, this is all we'll have.  This will also presumably require 
> some extra DT bindings for the register data.  If this method is used, 
> this code should also call a PM function to block clock rate changes on 
> the GPMC clock, and an explanatory warning should be logged to the 
> console.

Also something to note here is that generating dynamic timings from the
fixed GPMC register values won't work for other frequencies.

As far as I remember, the main problem trying to convert fixed value
GPMC timings into dynamic timings is the fact that some GPMC values
calculated depend on clock cycles, while other values depend on time.

So the cycle values remain unknown trying to upsample from fixed timings.
 
> For boards that we don't have access to, and all someone would have are 
> the register values set by the bootloader, I'd propose a phased approach:
> 
> 1. The kernel should log the bootloader-provided GPMC timing registers to 
> the console during boot, along with a warning message that indicates that 
> GPMC for these boards will cease to function in the near future unless 
> patches are provided to update the kernel board file and/or DT data with 
> the GPMC register contents.  This should allow people who have those 
> boards and who care about them to submit kernel patches to allow the 
> GPMC-attached devices to continue to function.

Unfortunately for many of the older boards these values will probably
remain unknown.

So the better approach here is to just disable frequency scaling
for these cases. Otherwise we'll be breaking old boards with smsc911x
where the timings for the FPGA controlling smsc911x are unknown.

If we somehow manage to get those values without breaking support for
these boards, then yes I agree we should deprecate hardcoded and
bootloader values.
 
> 2. A patch to Documentation/feature-removal-schedule.txt should be
> submitted which states that support for implicit bootloader GPMC timings
> will be removed within two or three kernel releases.

I'm fine with that assuming we somehow first have the values for the
most commonly used boards for smsc911x. But before that happens, we can't
really deprecate bootloader set GPMC values.

Regards,

Tony 

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

* Re: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-22 16:42             ` Tony Lindgren
@ 2012-05-23 14:51               ` Paul Walmsley
  2012-05-25  7:26                 ` Tony Lindgren
  2012-06-12 11:36               ` Mohammed, Afzal
  1 sibling, 1 reply; 26+ messages in thread
From: Paul Walmsley @ 2012-05-23 14:51 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: Mohammed, Afzal, khilman, linux-omap

On Tue, 22 May 2012, Tony Lindgren wrote:

> * Paul Walmsley <paul@pwsan.com> [120521 23:51]:
> > 
> > Next, I'd suggest implementing the code to allow GPMC timing configuration 
> > from raw register data (the second method above).  This is hackish but for 
> > some boards, this is all we'll have.  This will also presumably require 
> > some extra DT bindings for the register data.  If this method is used, 
> > this code should also call a PM function to block clock rate changes on 
> > the GPMC clock, and an explanatory warning should be logged to the 
> > console.
> 
> Also something to note here is that generating dynamic timings from the
> fixed GPMC register values won't work for other frequencies.
> 
> As far as I remember, the main problem trying to convert fixed value
> GPMC timings into dynamic timings is the fact that some GPMC values
> calculated depend on clock cycles, while other values depend on time.
> 
> So the cycle values remain unknown trying to upsample from fixed timings.

Yep indeed.  That's why clock rate changes have to be blocked on the GPMC 
clock.  If we don't have GPMC clock rate-independent timing data, then 
I think we'll have to keep the GPMC clock rate fixed.

> > For boards that we don't have access to, and all someone would have are 
> > the register values set by the bootloader, I'd propose a phased approach:
> > 
> > 1. The kernel should log the bootloader-provided GPMC timing registers to 
> > the console during boot, along with a warning message that indicates that 
> > GPMC for these boards will cease to function in the near future unless 
> > patches are provided to update the kernel board file and/or DT data with 
> > the GPMC register contents.  This should allow people who have those 
> > boards and who care about them to submit kernel patches to allow the 
> > GPMC-attached devices to continue to function.
> 
> Unfortunately for many of the older boards these values will probably
> remain unknown.
> 
> So the better approach here is to just disable frequency scaling
> for these cases. Otherwise we'll be breaking old boards with smsc911x
> where the timings for the FPGA controlling smsc911x are unknown.
> 
> If we somehow manage to get those values without breaking support for
> these boards, then yes I agree we should deprecate hardcoded and
> bootloader values.

I was thinking that if we log the register values supplied by the 
bootloader to the console, then someone can write a patch to the board 
file or DT data to set those register values explicitly in the kernel, 
once they're known.  Or at least just report them to the l-o list.

So then that should reduce the problem cases down to boards which no one 
reports the data to the mailing list within a few mainline kernel releases 
-- i.e., boards which are unmaintained.  For those boards, I'd suggest 
that we just drop GPMC support until someone shows up who has a board and 
can test-boot it.  Or just drop the board completely ;-)


- Paul

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

* Re: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-23 14:51               ` Paul Walmsley
@ 2012-05-25  7:26                 ` Tony Lindgren
  2012-05-25 10:15                   ` Mohammed, Afzal
  0 siblings, 1 reply; 26+ messages in thread
From: Tony Lindgren @ 2012-05-25  7:26 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: Mohammed, Afzal, khilman, linux-omap

* Paul Walmsley <paul@pwsan.com> [120523 17:55]:
> On Tue, 22 May 2012, Tony Lindgren wrote:
> > 
> > Unfortunately for many of the older boards these values will probably
> > remain unknown.
> > 
> > So the better approach here is to just disable frequency scaling
> > for these cases. Otherwise we'll be breaking old boards with smsc911x
> > where the timings for the FPGA controlling smsc911x are unknown.
> > 
> > If we somehow manage to get those values without breaking support for
> > these boards, then yes I agree we should deprecate hardcoded and
> > bootloader values.
> 
> I was thinking that if we log the register values supplied by the 
> bootloader to the console, then someone can write a patch to the board 
> file or DT data to set those register values explicitly in the kernel, 
> once they're known.  Or at least just report them to the l-o list.
> 
> So then that should reduce the problem cases down to boards which no one 
> reports the data to the mailing list within a few mainline kernel releases 
> -- i.e., boards which are unmaintained.  For those boards, I'd suggest 
> that we just drop GPMC support until someone shows up who has a board and 
> can test-boot it.  Or just drop the board completely ;-)

OK seems fair to me. It still allows us to boot the older boards with
minimal changes (but without L3 frequency scaling).

Sounds like those registers should be dumped only if no configuration
is specified to avoid spamming the console.

Regards,

Tony

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-25  7:26                 ` Tony Lindgren
@ 2012-05-25 10:15                   ` Mohammed, Afzal
  2012-06-05  7:13                     ` Tony Lindgren
  0 siblings, 1 reply; 26+ messages in thread
From: Mohammed, Afzal @ 2012-05-25 10:15 UTC (permalink / raw)
  To: Tony Lindgren, Paul Walmsley; +Cc: Hilman, Kevin, linux-omap

Hi Tony,

On Fri, May 25, 2012 at 12:56:59, Tony Lindgren wrote:
> * Paul Walmsley <paul@pwsan.com> [120523 17:55]:
> > On Tue, 22 May 2012, Tony Lindgren wrote:
> > > 
> > > Unfortunately for many of the older boards these values will probably
> > > remain unknown.
> > > 
> > > So the better approach here is to just disable frequency scaling
> > > for these cases. Otherwise we'll be breaking old boards with smsc911x
> > > where the timings for the FPGA controlling smsc911x are unknown.
> > > 
> > > If we somehow manage to get those values without breaking support for
> > > these boards, then yes I agree we should deprecate hardcoded and
> > > bootloader values.
> > 
> > I was thinking that if we log the register values supplied by the 
> > bootloader to the console, then someone can write a patch to the board 
> > file or DT data to set those register values explicitly in the kernel, 
> > once they're known.  Or at least just report them to the l-o list.
> > 
> > So then that should reduce the problem cases down to boards which no one 
> > reports the data to the mailing list within a few mainline kernel releases 
> > -- i.e., boards which are unmaintained.  For those boards, I'd suggest 
> > that we just drop GPMC support until someone shows up who has a board and 
> > can test-boot it.  Or just drop the board completely ;-)
> 
> OK seems fair to me. It still allows us to boot the older boards with
> minimal changes (but without L3 frequency scaling).
> 
> Sounds like those registers should be dumped only if no configuration
> is specified to avoid spamming the console.

Shall I take it as go ahead to create a patch on
Documentation/feature-removal-schedule.txt in the next version of gpmc
series stating that implicit boot loader GPMC timings will be removed
in three Kernel releases ? (i.e. as per Paul's suggestion, along with
other points he has mentioned)

Regards
Afzal

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

* Re: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-25 10:15                   ` Mohammed, Afzal
@ 2012-06-05  7:13                     ` Tony Lindgren
  0 siblings, 0 replies; 26+ messages in thread
From: Tony Lindgren @ 2012-06-05  7:13 UTC (permalink / raw)
  To: Mohammed, Afzal; +Cc: Paul Walmsley, Hilman, Kevin, linux-omap

* Mohammed, Afzal <afzal@ti.com> [120525 03:20]:
> Hi Tony,
> 
> On Fri, May 25, 2012 at 12:56:59, Tony Lindgren wrote:
> > * Paul Walmsley <paul@pwsan.com> [120523 17:55]:
> > > On Tue, 22 May 2012, Tony Lindgren wrote:
> > > > 
> > > > Unfortunately for many of the older boards these values will probably
> > > > remain unknown.
> > > > 
> > > > So the better approach here is to just disable frequency scaling
> > > > for these cases. Otherwise we'll be breaking old boards with smsc911x
> > > > where the timings for the FPGA controlling smsc911x are unknown.
> > > > 
> > > > If we somehow manage to get those values without breaking support for
> > > > these boards, then yes I agree we should deprecate hardcoded and
> > > > bootloader values.
> > > 
> > > I was thinking that if we log the register values supplied by the 
> > > bootloader to the console, then someone can write a patch to the board 
> > > file or DT data to set those register values explicitly in the kernel, 
> > > once they're known.  Or at least just report them to the l-o list.
> > > 
> > > So then that should reduce the problem cases down to boards which no one 
> > > reports the data to the mailing list within a few mainline kernel releases 
> > > -- i.e., boards which are unmaintained.  For those boards, I'd suggest 
> > > that we just drop GPMC support until someone shows up who has a board and 
> > > can test-boot it.  Or just drop the board completely ;-)
> > 
> > OK seems fair to me. It still allows us to boot the older boards with
> > minimal changes (but without L3 frequency scaling).
> > 
> > Sounds like those registers should be dumped only if no configuration
> > is specified to avoid spamming the console.
> 
> Shall I take it as go ahead to create a patch on
> Documentation/feature-removal-schedule.txt in the next version of gpmc
> series stating that implicit boot loader GPMC timings will be removed
> in three Kernel releases ? (i.e. as per Paul's suggestion, along with
> other points he has mentioned)

Yes sure as long as we can see what needs to be set in the kernel.

The GPMC timings should only come from the bootloader in the device tree
case BTW, so that's also something to consider here.

Regards,

Tony

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

* RE: [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc
  2012-05-22 16:42             ` Tony Lindgren
  2012-05-23 14:51               ` Paul Walmsley
@ 2012-06-12 11:36               ` Mohammed, Afzal
  1 sibling, 0 replies; 26+ messages in thread
From: Mohammed, Afzal @ 2012-06-12 11:36 UTC (permalink / raw)
  To: Tony Lindgren, Paul Walmsley; +Cc: Hilman, Kevin, linux-omap

Hi Tony,

On Tue, May 22, 2012 at 22:12:15, Tony Lindgren wrote:

> for these cases. Otherwise we'll be breaking old boards with smsc911x
> where the timings for the FPGA controlling smsc911x are unknown.

Were you actually referring to sdp boards that work with smc91x driver
using 91c96 ?

Regards
Afzal

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

end of thread, other threads:[~2012-06-12 11:36 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-02  8:45 [PATCH v4-alt 0/6] GPMC driver migrate one Afzal Mohammed
2012-05-02  8:45 ` [PATCH v4-alt 1/6] ARM: OMAP2+: gpmc: driver conversion Afzal Mohammed
2012-05-02  8:46 ` [PATCH v4-alt 2/6] ARM: OMAP2+: gpmc: Adapt to HWMOD Afzal Mohammed
2012-05-02  8:46 ` [PATCH v4-alt 3/6] ARM: OMAP3: hwmod data: add gpmc Afzal Mohammed
2012-05-06  2:04   ` Paul Walmsley
2012-05-07 11:12     ` Mohammed, Afzal
2012-05-08 13:12       ` Mohammed, Afzal
2012-05-08 15:37         ` Paul Walmsley
2012-05-08 15:32       ` Paul Walmsley
2012-05-10  6:03         ` Mohammed, Afzal
2012-05-12  4:23           ` Mohammed, Afzal
2012-05-22  6:47           ` Paul Walmsley
2012-05-22 11:35             ` Mohammed, Afzal
2012-05-22 16:42             ` Tony Lindgren
2012-05-23 14:51               ` Paul Walmsley
2012-05-25  7:26                 ` Tony Lindgren
2012-05-25 10:15                   ` Mohammed, Afzal
2012-06-05  7:13                     ` Tony Lindgren
2012-06-12 11:36               ` Mohammed, Afzal
2012-05-02  8:46 ` [PATCH v4-alt 4/6] ARM: OMAP2+: gpmc: driver migration hack Afzal Mohammed
2012-05-02  8:46 ` [PATCH v4-alt 5/6] ARM: OMAP2+: gpmc-smsc911x: Add helper for driver conversion Afzal Mohammed
2012-05-02  8:46 ` [PATCH v4-alt 6/6] ARM: OMAP2+: board omap3evm: gpmc driver adaptation Afzal Mohammed
2012-05-08 21:36 ` [PATCH v4-alt 0/6] GPMC driver migrate one Tony Lindgren
2012-05-10  6:35   ` Mohammed, Afzal
2012-05-11 20:00     ` Tony Lindgren
2012-05-14  4:59       ` 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.