From c9fb80942444e57c75fb26c27fd77961f9ba2570 Mon Sep 17 00:00:00 2001 From: Mark Jackson Date: Tue, 5 Mar 2013 10:13:40 +0000 Subject: ARM: OMAP: Clear GPMC bits when applying new setting. When setting the GPMC device type, make sure any previous bits are cleared down, before applying the new setting. For OMAP4+ devices MUXADDDATA is a 2-bit field (bits 9:8) where as for OMAP2/3 devices it was only a one bit field (bit 9). For OMAP2/3 devices bit 8 is reserved and the OMAP documentation says to write a 0 to this bit. So clearing bit 8 on OMAP2/3 devices should not be a problem. Hence update the code to handle both bits 8 and 9 for all devices. Signed-off-by: Mark Jackson [jon-hunter@ti.com: updated changelog] Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc.c | 4 ++++ arch/arm/mach-omap2/gpmc.h | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 6de31739b45c..98c5d413209e 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -613,6 +613,10 @@ int gpmc_cs_configure(int cs, int cmd, int wval) case GPMC_CONFIG_DEV_TYPE: regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); + /* clear 4 target bits */ + regval &= ~(GPMC_CONFIG1_DEVICETYPE(3) | + GPMC_CONFIG1_MUXTYPE(3)); + /* set the proper value */ regval |= GPMC_CONFIG1_DEVICETYPE(wval); if (wval == GPMC_DEVICETYPE_NOR) regval |= GPMC_CONFIG1_MUXADDDATA; diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h index fe0a844d5007..f79cbde76738 100644 --- a/arch/arm/mach-omap2/gpmc.h +++ b/arch/arm/mach-omap2/gpmc.h @@ -58,7 +58,10 @@ #define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1) #define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10) #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0) -#define GPMC_CONFIG1_MUXADDDATA (1 << 9) +#define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8) +#define GPMC_CONFIG1_MUXNONMUX GPMC_CONFIG1_MUXTYPE(0) +#define GPMC_CONFIG1_MUXAAD GPMC_CONFIG1_MUXTYPE(1) +#define GPMC_CONFIG1_MUXADDDATA GPMC_CONFIG1_MUXTYPE(2) #define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4) #define GPMC_CONFIG1_FCLK_DIV(val) (val & 3) #define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1)) -- cgit v1.2.1 From 3fc089e7c5ff914b2660a6e91a8d032498c1e301 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 12 Feb 2013 16:22:17 -0300 Subject: ARM: omap2: gpmc: Mark local scoped functions static This patch marks a bunch of functions that are local to gpmc.c file only as static. Signed-off-by: Ezequiel Garcia Reviewed-by: Jon Hunter Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc.c | 14 +++++++------- arch/arm/mach-omap2/gpmc.h | 7 ------- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 98c5d413209e..0837621788ab 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -181,7 +181,7 @@ void gpmc_cs_write_reg(int cs, int idx, u32 val) __raw_writel(val, reg_addr); } -u32 gpmc_cs_read_reg(int cs, int idx) +static u32 gpmc_cs_read_reg(int cs, int idx) { void __iomem *reg_addr; @@ -190,7 +190,7 @@ u32 gpmc_cs_read_reg(int cs, int idx) } /* TODO: Add support for gpmc_fck to clock framework and use it */ -unsigned long gpmc_get_fclk_period(void) +static unsigned long gpmc_get_fclk_period(void) { unsigned long rate = clk_get_rate(gpmc_l3_clk); @@ -205,7 +205,7 @@ unsigned long gpmc_get_fclk_period(void) return rate; } -unsigned int gpmc_ns_to_ticks(unsigned int time_ns) +static unsigned int gpmc_ns_to_ticks(unsigned int time_ns) { unsigned long tick_ps; @@ -215,7 +215,7 @@ unsigned int gpmc_ns_to_ticks(unsigned int time_ns) return (time_ns * 1000 + tick_ps - 1) / tick_ps; } -unsigned int gpmc_ps_to_ticks(unsigned int time_ps) +static unsigned int gpmc_ps_to_ticks(unsigned int time_ps) { unsigned long tick_ps; @@ -230,7 +230,7 @@ unsigned int gpmc_ticks_to_ns(unsigned int ticks) return ticks * gpmc_get_fclk_period() / 1000; } -unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) +static unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) { unsigned long ticks = gpmc_ns_to_ticks(time_ns); @@ -448,7 +448,7 @@ 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; @@ -459,7 +459,7 @@ int gpmc_cs_set_reserved(int cs, int reserved) return 0; } -int gpmc_cs_reserved(int cs) +static int gpmc_cs_reserved(int cs) { if (cs > GPMC_CS_NUM) return -ENODEV; diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h index f79cbde76738..697ff4225d5d 100644 --- a/arch/arm/mach-omap2/gpmc.h +++ b/arch/arm/mach-omap2/gpmc.h @@ -198,20 +198,13 @@ extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t, extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs); extern int gpmc_get_client_irq(unsigned irq_config); -extern unsigned int gpmc_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); -extern unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns); -extern unsigned long gpmc_get_fclk_period(void); extern void gpmc_cs_write_reg(int cs, int idx, u32 val); -extern u32 gpmc_cs_read_reg(int cs, int idx); extern int gpmc_calc_divider(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 void omap3_gpmc_save_context(void); extern void omap3_gpmc_restore_context(void); extern int gpmc_cs_configure(int cs, int cmd, int wval); -- cgit v1.2.1 From 7b095098ac5d28e865d179588d364a0cf8b0f81f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 12 Feb 2013 16:22:18 -0300 Subject: ARM: omap2: gpmc: Remove unused gpmc_round_ns_to_ticks() function This function is not used anywhere, so it's safe to remove it. This means less code to maintain. Signed-off-by: Ezequiel Garcia Reviewed-by: Jon Hunter Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 0837621788ab..27dd2c823efd 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -230,13 +230,6 @@ unsigned int gpmc_ticks_to_ns(unsigned int ticks) return ticks * gpmc_get_fclk_period() / 1000; } -static unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) -{ - unsigned long ticks = gpmc_ns_to_ticks(time_ns); - - return ticks * gpmc_get_fclk_period() / 1000; -} - static unsigned int gpmc_ticks_to_ps(unsigned int ticks) { return ticks * gpmc_get_fclk_period(); -- cgit v1.2.1 From ae9d908abc9e9d858a619faaf4d6647bdf3cb21f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 12 Feb 2013 16:22:19 -0300 Subject: ARM: omap2: gpmc: Fix gpmc_cs_reserved() return value Currently gpmc_cs_reserved() return value is somewhat inconsistent, returning a negative value on an error condition, a positive value if the chip select is reserved and zero if it's available. Fix this by returning a boolean value as the function name suggests: * true if the chip select is reserved, * false if it's available Suggested-by: Felipe Balbi Signed-off-by: Ezequiel Garcia Reviewed-by: Jon Hunter Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 27dd2c823efd..7c122bb5498a 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -452,10 +452,10 @@ static int gpmc_cs_set_reserved(int cs, int reserved) return 0; } -static int gpmc_cs_reserved(int cs) +static bool gpmc_cs_reserved(int cs) { if (cs > GPMC_CS_NUM) - return -ENODEV; + return true; return gpmc_cs_map & (1 << cs); } -- cgit v1.2.1 From 097c9daec339e20244a11d73f20aa5ba193501d3 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 12 Feb 2013 16:22:20 -0300 Subject: ARM: omap2: gpmc-nand: Print something useful on CS request failure If CS request fails the current error message is rather unhelpful. Fix it by printing the failing chip select and the error code. Signed-off-by: Ezequiel Garcia Reviewed-by: Jon Hunter Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc-nand.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index afc1e8c32d6c..e50e438b64aa 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -122,7 +122,8 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, (unsigned long *)&gpmc_nand_resource[0].start); if (err < 0) { - dev_err(dev, "Cannot request GPMC CS\n"); + dev_err(dev, "Cannot request GPMC CS %d, error %d\n", + gpmc_nand_data->cs, err); return err; } -- cgit v1.2.1 From 80f5d373a6ed2f1708488c8fe467890433baee81 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 12 Feb 2013 16:22:21 -0300 Subject: ARM: omap2: gpmc-onenand: Print something useful on CS request failure If CS request fails the current error message is rather unhelpful. Fix it by printing the failing chip select and the error code. Signed-off-by: Ezequiel Garcia Reviewed-by: Jon Hunter Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc-onenand.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 0d75889c0a6f..f7c9c207d71b 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -379,7 +379,8 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE, (unsigned long *)&gpmc_onenand_resource.start); if (err < 0) { - pr_err("%s: Cannot request GPMC CS\n", __func__); + pr_err("%s: Cannot request GPMC CS %d, error %d\n", + __func__, gpmc_onenand_data->cs, err); return; } -- cgit v1.2.1 From df25cb4645a12b9300d4b14ceaf9071bc0f1cad8 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 12 Feb 2013 16:22:22 -0300 Subject: ARM: omap2: gpmc-onenand: Replace pr_err() with dev_err() Do this becasue dev_err() is preferred over pr_err() and because it will match gpmc-nand, thus the code shows looks more consistent. Signed-off-by: Ezequiel Garcia Reviewed-by: Jon Hunter Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc-onenand.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index f7c9c207d71b..a78921169210 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -359,6 +359,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) { int err; + struct device *dev = &gpmc_onenand_device.dev; gpmc_onenand_data = _onenand_data; gpmc_onenand_data->onenand_setup = gpmc_onenand_setup; @@ -379,8 +380,8 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE, (unsigned long *)&gpmc_onenand_resource.start); if (err < 0) { - pr_err("%s: Cannot request GPMC CS %d, error %d\n", - __func__, gpmc_onenand_data->cs, err); + dev_err(dev, "Cannot request GPMC CS %d, error %d\n", + gpmc_onenand_data->cs, err); return; } @@ -388,7 +389,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) ONENAND_IO_SIZE - 1; if (platform_device_register(&gpmc_onenand_device) < 0) { - pr_err("%s: Unable to register OneNAND device\n", __func__); + dev_err(dev, "Unable to register OneNAND device\n"); gpmc_cs_free(gpmc_onenand_data->cs); return; } -- cgit v1.2.1 From 7ab91596a55e05410fcaab6d7d066ce0e0d0a712 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 12 Feb 2013 16:22:23 -0300 Subject: ARM: omap2: gpmc-onenand: Replace printk KERN_ERR with dev_warn() Since the condition is not an error but a warning, replace printk KERN_ERR with dev_warn. Signed-off-by: Ezequiel Garcia Reviewed-by: Jon Hunter Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc-onenand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index a78921169210..4c917522d248 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -367,7 +367,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) if (cpu_is_omap24xx() && (gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) { - printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n"); + dev_warn(dev, "OneNAND using only SYNC_READ on 24xx\n"); gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE; gpmc_onenand_data->flags |= ONENAND_SYNC_READ; } -- cgit v1.2.1 From f5d8edaf1d06e922a3c3d75c52ef5628ceec32c4 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 12 Feb 2013 16:22:24 -0300 Subject: ARM: omap2: gpmc: Remove redundant chip select out of range check This check is done before the call to gpmc_cs_reserved() and gpmc_cs_set_reserved() and it's redundant to do it again in each function. This simplifies the code a bit. Signed-off-by: Ezequiel Garcia Reviewed-by: Jon Hunter Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 7c122bb5498a..586dba7e5f23 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -441,22 +441,14 @@ static int gpmc_cs_mem_enabled(int cs) return l & GPMC_CONFIG7_CSVALID; } -static int gpmc_cs_set_reserved(int cs, int reserved) +static void 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; - - return 0; } static bool gpmc_cs_reserved(int cs) { - if (cs > GPMC_CS_NUM) - return true; - return gpmc_cs_map & (1 << cs); } -- cgit v1.2.1 From be9f10c04fb13d32fc30d599c1971a10916a2209 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 15:20:53 -0600 Subject: ARM: OMAP2+: Simplify code configuring ONENAND devices The OMAP2+ code that configures the GPMC for ONENAND devices is copying structures between functions unnecessarily. Avoid this by passing pointers instead and simplify the code. A pointer to structure "omap_onenand_platform_data" is passed to the function omap2_onenand_calc_sync_timings(), but only the flags member of the structure is used. Simplify the code by only passing the flags member and not the entire structure. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc-onenand.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 4c917522d248..db52c4b28f8b 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -47,10 +47,9 @@ static struct platform_device gpmc_onenand_device = { .resource = &gpmc_onenand_resource, }; -static struct gpmc_timings omap2_onenand_calc_async_timings(void) +static void omap2_onenand_calc_async_timings(struct gpmc_timings *t) { struct gpmc_device_timings dev_t; - struct gpmc_timings t; const int t_cer = 15; const int t_avdp = 12; @@ -76,9 +75,7 @@ static struct gpmc_timings omap2_onenand_calc_async_timings(void) dev_t.t_wpl = t_wpl * 1000; dev_t.t_wph = t_wph * 1000; - gpmc_calc_timings(&t, &dev_t); - - return t; + gpmc_calc_timings(t, &dev_t); } static int gpmc_set_async_mode(int cs, struct gpmc_timings *t) @@ -158,12 +155,11 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg, return freq; } -static struct gpmc_timings -omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, - int freq) +static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t, + unsigned int flags, + int freq) { struct gpmc_device_timings dev_t; - struct gpmc_timings t; const int t_cer = 15; const int t_avdp = 12; const int t_cez = 20; /* max of t_cez, t_oez */ @@ -172,9 +168,9 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo; int div, gpmc_clk_ns; - if (cfg->flags & ONENAND_SYNC_READ) + if (flags & ONENAND_SYNC_READ) onenand_flags = ONENAND_FLAG_SYNCREAD; - else if (cfg->flags & ONENAND_SYNC_READWRITE) + else if (flags & ONENAND_SYNC_READWRITE) onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE; switch (freq) { @@ -265,9 +261,7 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, dev_t.cyc_aavdh_oe = 1; dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period; - gpmc_calc_timings(&t, &dev_t); - - return t; + gpmc_calc_timings(t, &dev_t); } static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t) @@ -300,7 +294,7 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base) omap2_onenand_set_async_mode(onenand_base); - t = omap2_onenand_calc_async_timings(); + omap2_onenand_calc_async_timings(&t); ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t); if (ret < 0) @@ -322,7 +316,7 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr) set_onenand_cfg(onenand_base); } - t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq); + omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq); ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t); if (ret < 0) -- cgit v1.2.1 From 9f8331562aa1fd72e80dd6037c958cb3faf4cc38 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 20 Feb 2013 15:53:38 -0600 Subject: ARM: OMAP2+: Add variable to store number of GPMC waitpins The GPMC has wait-pin signals that can be assigned to a chip-select to monitor the ready signal of an external device. Add a variable to indicate the total number of wait-pins for a given device. This will allow us to detect if the wait-pin being selected is valid or not. When booting with device-tree read the number of wait-pins from the device-tree blob. When device-tree is not used set the number of wait-pins to 4 which is valid for OMAP2-5 devices. Newer devices that have less wait-pins (such as AM335x) only support booting with device-tree and so hard-coding the wait-pin number when not using device-tree is fine. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 586dba7e5f23..8833c349f23c 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -108,6 +108,8 @@ #define GPMC_HAS_WR_ACCESS 0x1 #define GPMC_HAS_WR_DATA_MUX_BUS 0x2 +#define GPMC_NR_WAITPINS 4 + /* XXX: Only NAND irq has been considered,currently these are the only ones used */ #define GPMC_NR_IRQ 2 @@ -153,6 +155,7 @@ static struct resource gpmc_cs_mem[GPMC_CS_NUM]; static DEFINE_SPINLOCK(gpmc_mem_lock); /* Define chip-selects as reserved by default until probe completes */ static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1); +static unsigned int gpmc_nr_waitpins; static struct device *gpmc_dev; static int gpmc_irq; static resource_size_t phys_base, mem_size; @@ -1294,6 +1297,13 @@ static int gpmc_probe_dt(struct platform_device *pdev) if (!of_id) return 0; + ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins", + &gpmc_nr_waitpins); + if (ret < 0) { + pr_err("%s: number of wait pins not found!\n", __func__); + return ret; + } + for_each_node_by_name(child, "nand") { ret = gpmc_probe_nand_child(pdev, child); if (ret < 0) { @@ -1372,6 +1382,9 @@ static int gpmc_probe(struct platform_device *pdev) /* Now the GPMC is initialised, unreserve the chip-selects */ gpmc_cs_map = 0; + if (!pdev->dev.of_node) + gpmc_nr_waitpins = GPMC_NR_WAITPINS; + rc = gpmc_probe_dt(pdev); if (rc < 0) { clk_disable_unprepare(gpmc_l3_clk); -- cgit v1.2.1 From c3be5b457ae1bb6dc93ef25bfa03e595969acbfc Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 13:46:22 -0600 Subject: ARM: OMAP2+: Add structure for storing GPMC settings The GPMC has various different configuration options such as bus-width, synchronous or asychronous mode selection, burst mode options etc. Currently, there is no central structure for storing all these options when configuring the GPMC for a given device. Some of the options are stored in the GPMC timing structure and some are directly programmed into the GPMC configuration register. Add a new structure to store these options and convert code to use this structure. Adding this structure will allow us to create a common function for configuring these options. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc-onenand.c | 18 ++++++++++----- arch/arm/mach-omap2/gpmc-smc91x.c | 2 +- arch/arm/mach-omap2/gpmc.c | 45 +++++++++++++++++++++++--------------- arch/arm/mach-omap2/gpmc.h | 28 ++++++++++++++++++------ arch/arm/mach-omap2/usb-tusb6010.c | 19 +++++++++------- 5 files changed, 72 insertions(+), 40 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index db52c4b28f8b..e175ceb0dc05 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -47,6 +47,15 @@ static struct platform_device gpmc_onenand_device = { .resource = &gpmc_onenand_resource, }; +static struct gpmc_settings onenand_async = { + .mux_add_data = GPMC_MUX_AD, +}; + +static struct gpmc_settings onenand_sync = { + .burst_read = true, + .mux_add_data = GPMC_MUX_AD, +}; + static void omap2_onenand_calc_async_timings(struct gpmc_timings *t) { struct gpmc_device_timings dev_t; @@ -63,7 +72,6 @@ static void omap2_onenand_calc_async_timings(struct gpmc_timings *t) memset(&dev_t, 0, sizeof(dev_t)); - dev_t.mux = true; dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000; dev_t.t_avdp_w = dev_t.t_avdp_r; dev_t.t_aavdh = t_aavdh * 1000; @@ -75,7 +83,7 @@ static void omap2_onenand_calc_async_timings(struct gpmc_timings *t) dev_t.t_wpl = t_wpl * 1000; dev_t.t_wph = t_wph * 1000; - gpmc_calc_timings(t, &dev_t); + gpmc_calc_timings(t, &onenand_async, &dev_t); } static int gpmc_set_async_mode(int cs, struct gpmc_timings *t) @@ -235,10 +243,8 @@ static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t, /* Set synchronous read timings */ memset(&dev_t, 0, sizeof(dev_t)); - dev_t.mux = true; - dev_t.sync_read = true; if (onenand_flags & ONENAND_FLAG_SYNCWRITE) { - dev_t.sync_write = true; + onenand_sync.sync_write = true; } else { dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000; dev_t.t_wpl = t_wpl * 1000; @@ -261,7 +267,7 @@ static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t, dev_t.cyc_aavdh_oe = 1; dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period; - gpmc_calc_timings(t, &dev_t); + gpmc_calc_timings(t, &onenand_sync, &dev_t); } static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t) diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c index 11d0b756f098..4b7833873311 100644 --- a/arch/arm/mach-omap2/gpmc-smc91x.c +++ b/arch/arm/mach-omap2/gpmc-smc91x.c @@ -104,7 +104,7 @@ static int smc91c96_gpmc_retime(void) dev_t.t_cez_w = t4_w * 1000; dev_t.t_wr_cycle = (t20 - t3) * 1000; - gpmc_calc_timings(&t, &dev_t); + gpmc_calc_timings(&t, NULL, &dev_t); return gpmc_cs_set_timings(gpmc_cfg->cs, &t); } diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 8833c349f23c..20747fbc686a 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -817,9 +817,9 @@ static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk) /* XXX: can the cycles be avoided ? */ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool mux) { - bool mux = dev_t->mux; u32 temp; /* adv_rd_off */ @@ -872,9 +872,9 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t, } static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool mux) { - bool mux = dev_t->mux; u32 temp; /* adv_wr_off */ @@ -934,9 +934,9 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t, } static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool mux) { - bool mux = dev_t->mux; u32 temp; /* adv_rd_off */ @@ -974,9 +974,9 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t, } static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool mux) { - bool mux = dev_t->mux; u32 temp; /* adv_wr_off */ @@ -1046,7 +1046,8 @@ static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t, } static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_device_timings *dev_t, + bool sync) { u32 temp; @@ -1060,7 +1061,7 @@ static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t, gpmc_t->cs_on + dev_t->t_ce_avd); gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp); - if (dev_t->sync_write || dev_t->sync_read) + if (sync) gpmc_calc_sync_common_timings(gpmc_t, dev_t); return 0; @@ -1095,21 +1096,29 @@ static void gpmc_convert_ps_to_ns(struct gpmc_timings *t) } int gpmc_calc_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t) + struct gpmc_settings *gpmc_s, + struct gpmc_device_timings *dev_t) { + bool mux = false, sync = false; + + if (gpmc_s) { + mux = gpmc_s->mux_add_data ? true : false; + sync = (gpmc_s->sync_read || gpmc_s->sync_write); + } + memset(gpmc_t, 0, sizeof(*gpmc_t)); - gpmc_calc_common_timings(gpmc_t, dev_t); + gpmc_calc_common_timings(gpmc_t, dev_t, sync); - if (dev_t->sync_read) - gpmc_calc_sync_read_timings(gpmc_t, dev_t); + if (gpmc_s && gpmc_s->sync_read) + gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux); else - gpmc_calc_async_read_timings(gpmc_t, dev_t); + gpmc_calc_async_read_timings(gpmc_t, dev_t, mux); - if (dev_t->sync_write) - gpmc_calc_sync_write_timings(gpmc_t, dev_t); + if (gpmc_s && gpmc_s->sync_write) + gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux); else - gpmc_calc_async_write_timings(gpmc_t, dev_t); + gpmc_calc_async_write_timings(gpmc_t, dev_t, mux); /* TODO: remove, see function definition */ gpmc_convert_ps_to_ns(gpmc_t); diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h index 697ff4225d5d..39e4e04acdc9 100644 --- a/arch/arm/mach-omap2/gpmc.h +++ b/arch/arm/mach-omap2/gpmc.h @@ -60,8 +60,8 @@ #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0) #define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8) #define GPMC_CONFIG1_MUXNONMUX GPMC_CONFIG1_MUXTYPE(0) -#define GPMC_CONFIG1_MUXAAD GPMC_CONFIG1_MUXTYPE(1) -#define GPMC_CONFIG1_MUXADDDATA GPMC_CONFIG1_MUXTYPE(2) +#define GPMC_CONFIG1_MUXAAD GPMC_CONFIG1_MUXTYPE(GPMC_MUX_AAD) +#define GPMC_CONFIG1_MUXADDDATA GPMC_CONFIG1_MUXTYPE(GPMC_MUX_AD) #define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4) #define GPMC_CONFIG1_FCLK_DIV(val) (val & 3) #define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1)) @@ -76,6 +76,8 @@ #define GPMC_IRQ_FIFOEVENTENABLE 0x01 #define GPMC_IRQ_COUNT_EVENT 0x02 +#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */ +#define GPMC_MUX_AD 2 /* Addr-Data multiplex */ /* bool type time settings */ struct gpmc_bool_timings { @@ -181,10 +183,6 @@ struct gpmc_device_timings { u8 cyc_wpl; /* write deassertion time in cycles */ u32 cyc_iaa; /* initial access time in cycles */ - bool mux; /* address & data muxed */ - bool sync_write;/* synchronous write */ - bool sync_read; /* synchronous read */ - /* extra delays */ bool ce_xdelay; bool avd_xdelay; @@ -192,8 +190,24 @@ struct gpmc_device_timings { bool we_xdelay; }; +struct gpmc_settings { + bool burst_wrap; /* enables wrap bursting */ + bool burst_read; /* enables read page/burst mode */ + bool burst_write; /* enables write page/burst mode */ + bool device_nand; /* device is NAND */ + bool sync_read; /* enables synchronous reads */ + bool sync_write; /* enables synchronous writes */ + bool wait_on_read; /* monitor wait on reads */ + bool wait_on_write; /* monitor wait on writes */ + u32 burst_len; /* page/burst length */ + u32 device_width; /* device bus width (8 or 16 bit) */ + u32 mux_add_data; /* multiplex address & data */ + u32 wait_pin; /* wait-pin to be used */ +}; + extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t, - struct gpmc_device_timings *dev_t); + struct gpmc_settings *gpmc_s, + struct gpmc_device_timings *dev_t); extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs); extern int gpmc_get_client_irq(unsigned irq_config); diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c index c5a3c6f9504e..faaf96dca0fa 100644 --- a/arch/arm/mach-omap2/usb-tusb6010.c +++ b/arch/arm/mach-omap2/usb-tusb6010.c @@ -26,6 +26,15 @@ static u8 async_cs, sync_cs; static unsigned refclk_psec; +static struct gpmc_settings tusb_async = { + .mux_add_data = GPMC_MUX_AD, +}; + +static struct gpmc_settings tusb_sync = { + .sync_read = true, + .sync_write = true, + .mux_add_data = GPMC_MUX_AD, +}; /* NOTE: timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */ @@ -37,8 +46,6 @@ static int tusb_set_async_mode(unsigned sysclk_ps) memset(&dev_t, 0, sizeof(dev_t)); - dev_t.mux = true; - dev_t.t_ceasu = 8 * 1000; dev_t.t_avdasu = t_acsnh_advnh - 7000; dev_t.t_ce_avd = 1000; @@ -52,7 +59,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps) dev_t.t_wpl = 300; dev_t.cyc_aavdh_we = 1; - gpmc_calc_timings(&t, &dev_t); + gpmc_calc_timings(&t, &tusb_async, &dev_t); return gpmc_cs_set_timings(async_cs, &t); } @@ -65,10 +72,6 @@ static int tusb_set_sync_mode(unsigned sysclk_ps) memset(&dev_t, 0, sizeof(dev_t)); - dev_t.mux = true; - dev_t.sync_read = true; - dev_t.sync_write = true; - dev_t.clk = 11100; dev_t.t_bacc = 1000; dev_t.t_ces = 1000; @@ -84,7 +87,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps) dev_t.cyc_wpl = 6; dev_t.t_ce_rdyz = 7000; - gpmc_calc_timings(&t, &dev_t); + gpmc_calc_timings(&t, &tusb_sync, &dev_t); return gpmc_cs_set_timings(sync_cs, &t); } -- cgit v1.2.1 From aa8d4767da2a2a29a628dc0dadb59a010f0ec18e Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 15:25:23 -0600 Subject: ARM: OMAP2+: Add function for configuring GPMC settings The GPMC has various different configuration options such as bus-width, synchronous or asychronous mode selection, burst mode options etc. Currently, there is no common function for configuring these options and various devices set these options by either programming the GPMC CONFIG1 register directly or by calling gpmc_cs_configure() to set some of the options. Add a new function for configuring all of the GPMC options. Having a common function for configuring this options will simplify code and ease the migration to device-tree. Also add a new capability flag to detect devices that support the address-address-data multiplexing mode. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 100 +++++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/gpmc.h | 6 +++ 2 files changed, 106 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 20747fbc686a..ee5d0e970c62 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -107,6 +107,7 @@ #define GPMC_HAS_WR_ACCESS 0x1 #define GPMC_HAS_WR_DATA_MUX_BUS 0x2 +#define GPMC_HAS_MUX_AAD 0x4 #define GPMC_NR_WAITPINS 4 @@ -1126,6 +1127,90 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t, return 0; } +/** + * gpmc_cs_program_settings - programs non-timing related settings + * @cs: GPMC chip-select to program + * @p: pointer to GPMC settings structure + * + * Programs non-timing related settings for a GPMC chip-select, such as + * bus-width, burst configuration, etc. Function should be called once + * for each chip-select that is being used and must be called before + * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1 + * register will be initialised to zero by this function. Returns 0 on + * success and appropriate negative error code on failure. + */ +int gpmc_cs_program_settings(int cs, struct gpmc_settings *p) +{ + u32 config1; + + if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) { + pr_err("%s: invalid width %d!", __func__, p->device_width); + return -EINVAL; + } + + /* Address-data multiplexing not supported for NAND devices */ + if (p->device_nand && p->mux_add_data) { + pr_err("%s: invalid configuration!\n", __func__); + return -EINVAL; + } + + if ((p->mux_add_data > GPMC_MUX_AD) || + ((p->mux_add_data == GPMC_MUX_AAD) && + !(gpmc_capability & GPMC_HAS_MUX_AAD))) { + pr_err("%s: invalid multiplex configuration!\n", __func__); + return -EINVAL; + } + + /* Page/burst mode supports lengths of 4, 8 and 16 bytes */ + if (p->burst_read || p->burst_write) { + switch (p->burst_len) { + case GPMC_BURST_4: + case GPMC_BURST_8: + case GPMC_BURST_16: + break; + default: + pr_err("%s: invalid page/burst-length (%d)\n", + __func__, p->burst_len); + return -EINVAL; + } + } + + if ((p->wait_on_read || p->wait_on_write) && + (p->wait_pin > gpmc_nr_waitpins)) { + pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin); + return -EINVAL; + } + + config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1)); + + if (p->sync_read) + config1 |= GPMC_CONFIG1_READTYPE_SYNC; + if (p->sync_write) + config1 |= GPMC_CONFIG1_WRITETYPE_SYNC; + if (p->wait_on_read) + config1 |= GPMC_CONFIG1_WAIT_READ_MON; + if (p->wait_on_write) + config1 |= GPMC_CONFIG1_WAIT_WRITE_MON; + if (p->wait_on_read || p->wait_on_write) + config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin); + if (p->device_nand) + config1 |= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND); + if (p->mux_add_data) + config1 |= GPMC_CONFIG1_MUXTYPE(p->mux_add_data); + if (p->burst_read) + config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP; + if (p->burst_write) + config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP; + if (p->burst_read || p->burst_write) { + config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3); + config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0; + } + + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1); + + return 0; +} + #ifdef CONFIG_OF static struct of_device_id gpmc_dt_ids[] = { { .compatible = "ti,omap2420-gpmc" }, @@ -1372,8 +1457,23 @@ static int gpmc_probe(struct platform_device *pdev) gpmc_dev = &pdev->dev; l = gpmc_read_reg(GPMC_REVISION); + + /* + * FIXME: Once device-tree migration is complete the below flags + * should be populated based upon the device-tree compatible + * string. For now just use the IP revision. OMAP3+ devices have + * the wr_access and wr_data_mux_bus register fields. OMAP4+ + * devices support the addr-addr-data multiplex protocol. + * + * GPMC IP revisions: + * - OMAP24xx = 2.0 + * - OMAP3xxx = 5.0 + * - OMAP44xx/54xx/AM335x = 6.0 + */ if (GPMC_REVISION_MAJOR(l) > 0x4) gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS; + if (GPMC_REVISION_MAJOR(l) > 0x5) + gpmc_capability |= GPMC_HAS_MUX_AAD; dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l), GPMC_REVISION_MINOR(l)); diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h index 39e4e04acdc9..ce6ae218f41f 100644 --- a/arch/arm/mach-omap2/gpmc.h +++ b/arch/arm/mach-omap2/gpmc.h @@ -76,6 +76,11 @@ #define GPMC_IRQ_FIFOEVENTENABLE 0x01 #define GPMC_IRQ_COUNT_EVENT 0x02 +#define GPMC_BURST_4 4 /* 4 word burst */ +#define GPMC_BURST_8 8 /* 8 word burst */ +#define GPMC_BURST_16 16 /* 16 word burst */ +#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */ +#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */ #define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */ #define GPMC_MUX_AD 2 /* Addr-Data multiplex */ @@ -217,6 +222,7 @@ extern unsigned int gpmc_ticks_to_ns(unsigned int ticks); extern void gpmc_cs_write_reg(int cs, int idx, u32 val); extern int gpmc_calc_divider(unsigned int sync_clk); extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t); +extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p); extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base); extern void gpmc_cs_free(int cs); extern void omap3_gpmc_save_context(void); -- cgit v1.2.1 From 3aef65ee5d28df4e1415be2c83fb3eb90e9cfc3f Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 12:42:22 -0600 Subject: ARM: OMAP2+: Convert ONENAND to use gpmc_cs_program_settings() Convert the OMAP2+ ONENAND code to use the gpmc_cs_program_settings() function for configuring the various GPMC options instead of directly programming the CONFIG1 register. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc-onenand.c | 61 ++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 36 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index e175ceb0dc05..46aac83d73d4 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -48,18 +48,22 @@ static struct platform_device gpmc_onenand_device = { }; static struct gpmc_settings onenand_async = { + .device_width = GPMC_DEVWIDTH_16BIT, .mux_add_data = GPMC_MUX_AD, }; static struct gpmc_settings onenand_sync = { .burst_read = true, + .burst_wrap = true, + .burst_len = GPMC_BURST_16, + .device_width = GPMC_DEVWIDTH_16BIT, .mux_add_data = GPMC_MUX_AD, + .wait_pin = 0, }; static void omap2_onenand_calc_async_timings(struct gpmc_timings *t) { struct gpmc_device_timings dev_t; - const int t_cer = 15; const int t_avdp = 12; const int t_aavdh = 7; @@ -86,16 +90,6 @@ static void omap2_onenand_calc_async_timings(struct gpmc_timings *t) gpmc_calc_timings(t, &onenand_async, &dev_t); } -static int gpmc_set_async_mode(int cs, struct gpmc_timings *t) -{ - /* Configure GPMC for asynchronous read */ - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, - GPMC_CONFIG1_DEVICESIZE_16 | - GPMC_CONFIG1_MUXADDDATA); - - return gpmc_cs_set_timings(cs, t); -} - static void omap2_onenand_set_async_mode(void __iomem *onenand_base) { u32 reg; @@ -243,8 +237,11 @@ static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t, /* Set synchronous read timings */ memset(&dev_t, 0, sizeof(dev_t)); + if (onenand_flags & ONENAND_FLAG_SYNCREAD) + onenand_sync.sync_read = true; if (onenand_flags & ONENAND_FLAG_SYNCWRITE) { onenand_sync.sync_write = true; + onenand_sync.burst_write = true; } else { dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000; dev_t.t_wpl = t_wpl * 1000; @@ -270,29 +267,6 @@ static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t, gpmc_calc_timings(t, &onenand_sync, &dev_t); } -static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t) -{ - unsigned sync_read = onenand_flags & ONENAND_FLAG_SYNCREAD; - unsigned sync_write = onenand_flags & ONENAND_FLAG_SYNCWRITE; - - /* Configure GPMC for synchronous read */ - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, - GPMC_CONFIG1_WRAPBURST_SUPP | - GPMC_CONFIG1_READMULTIPLE_SUPP | - (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) | - (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) | - (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) | - GPMC_CONFIG1_PAGE_LEN(2) | - (cpu_is_omap34xx() ? 0 : - (GPMC_CONFIG1_WAIT_READ_MON | - GPMC_CONFIG1_WAIT_PIN_SEL(0))) | - GPMC_CONFIG1_DEVICESIZE_16 | - GPMC_CONFIG1_DEVICETYPE_NOR | - GPMC_CONFIG1_MUXADDDATA); - - return gpmc_cs_set_timings(cs, t); -} - static int omap2_onenand_setup_async(void __iomem *onenand_base) { struct gpmc_timings t; @@ -302,7 +276,11 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base) omap2_onenand_calc_async_timings(&t); - ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t); + ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async); + if (ret < 0) + return ret; + + ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); if (ret < 0) return ret; @@ -322,9 +300,20 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr) set_onenand_cfg(onenand_base); } + /* + * FIXME: Appears to be legacy code from initial ONENAND commit. + * Unclear what boards this is for and if this can be removed. + */ + if (!cpu_is_omap34xx()) + onenand_sync.wait_on_read = true; + omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq); - ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t); + ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_sync); + if (ret < 0) + return ret; + + ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); if (ret < 0) return ret; -- cgit v1.2.1 From 24db7eccfba339293e1cc081cf73e06a0149784a Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 15:43:08 -0600 Subject: ARM: OMAP2+: Convert NAND to use gpmc_cs_program_settings() Convert the OMAP2+ NAND code to use the gpmc_cs_program_settings() function for configuring the various GPMC options instead of directly programming the CONFIG1 register. This moves the configuration of some GPMC options outside the nand_gpmc_retime() because these options should only need to be set once regardless of whether the gpmc timing is changing dynamically at runtime. The programming of where the wait-pin is also moved slightly, but this will not have any impact to existing devices as no boards are currently setting the dev_ready variable. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc-nand.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index e50e438b64aa..75feb9558b6d 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -74,14 +74,6 @@ static int omap2_nand_gpmc_retime( t.cs_wr_off = gpmc_t->cs_wr_off; t.wr_cycle = gpmc_t->wr_cycle; - /* Configure GPMC */ - if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 1); - else - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0); - gpmc_cs_configure(gpmc_nand_data->cs, - GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND); - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0); err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); if (err) return err; @@ -115,8 +107,11 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, struct gpmc_timings *gpmc_t) { int err = 0; + struct gpmc_settings s; struct device *dev = &gpmc_nand_device.dev; + memset(&s, 0, sizeof(struct gpmc_settings)); + gpmc_nand_device.dev.platform_data = gpmc_nand_data; err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, @@ -141,11 +136,27 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, dev_err(dev, "Unable to set gpmc timings: %d\n", err); return err; } - } - /* Enable RD PIN Monitoring Reg */ - if (gpmc_nand_data->dev_ready) { - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1); + s.device_nand = true; + + /* Enable RD PIN Monitoring Reg */ + if (gpmc_nand_data->dev_ready) { + s.wait_on_read = true; + s.wait_on_write = true; + } + + if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) + s.device_width = GPMC_DEVWIDTH_16BIT; + else + s.device_width = GPMC_DEVWIDTH_8BIT; + + err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s); + if (err < 0) + goto out_free_cs; + + err = gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0); + if (err < 0) + goto out_free_cs; } gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs); -- cgit v1.2.1 From 1119f3c3cee1b27f7d488510af5e96ddba438ee9 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 13:01:37 -0600 Subject: ARM: OMAP2+: Convert SMC91x to use gpmc_cs_program_settings() Convert the OMAP2+ SMC91x code to use the gpmc_cs_program_settings() function for configuring the various GPMC options instead of directly programming the CONFIG1 register. Move configuration of the GPMC settings outside retime function and this does not need to be done if the timings are changed dynamically at runtime. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc-smc91x.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c index 4b7833873311..61a063595e66 100644 --- a/arch/arm/mach-omap2/gpmc-smc91x.c +++ b/arch/arm/mach-omap2/gpmc-smc91x.c @@ -49,6 +49,10 @@ static struct platform_device gpmc_smc91x_device = { .resource = gpmc_smc91x_resources, }; +static struct gpmc_settings smc91x_settings = { + .device_width = GPMC_DEVWIDTH_16BIT, +}; + /* * Set the gpmc timings for smc91c96. The timings are taken * from the data sheet available at: @@ -67,18 +71,6 @@ static int smc91c96_gpmc_retime(void) const int t7 = 5; /* Figure 12.4 write */ const int t8 = 5; /* Figure 12.4 write */ const int t20 = 185; /* Figure 12.2 read and 12.4 write */ - u32 l; - - l = GPMC_CONFIG1_DEVICESIZE_16; - if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA) - l |= GPMC_CONFIG1_MUXADDDATA; - if (gpmc_cfg->flags & GPMC_READ_MON) - l |= GPMC_CONFIG1_WAIT_READ_MON; - if (gpmc_cfg->flags & GPMC_WRITE_MON) - l |= GPMC_CONFIG1_WAIT_WRITE_MON; - if (gpmc_cfg->wait_pin) - l |= GPMC_CONFIG1_WAIT_PIN_SEL(gpmc_cfg->wait_pin); - gpmc_cs_write_reg(gpmc_cfg->cs, GPMC_CS_CONFIG1, l); /* * FIXME: Calculate the address and data bus muxed timings. @@ -104,7 +96,7 @@ static int smc91c96_gpmc_retime(void) dev_t.t_cez_w = t4_w * 1000; dev_t.t_wr_cycle = (t20 - t3) * 1000; - gpmc_calc_timings(&t, NULL, &dev_t); + gpmc_calc_timings(&t, &smc91x_settings, &dev_t); return gpmc_cs_set_timings(gpmc_cfg->cs, &t); } @@ -133,6 +125,18 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data) gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f; gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK); + if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA) + smc91x_settings.mux_add_data = GPMC_MUX_AD; + if (gpmc_cfg->flags & GPMC_READ_MON) + smc91x_settings.wait_on_read = true; + if (gpmc_cfg->flags & GPMC_WRITE_MON) + smc91x_settings.wait_on_write = true; + if (gpmc_cfg->wait_pin) + smc91x_settings.wait_pin = gpmc_cfg->wait_pin; + ret = gpmc_cs_program_settings(gpmc_cfg->cs, &smc91x_settings); + if (ret < 0) + goto free1; + if (gpmc_cfg->retime) { ret = gpmc_cfg->retime(); if (ret != 0) -- cgit v1.2.1 From 012e338625f5ea58d2a16cf98a44779255b458ca Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 13:01:47 -0600 Subject: ARM: OMAP2+: Convert TUSB to use gpmc_cs_program_settings() Convert the OMAP2+ TUSB code to use the gpmc_cs_program_settings() function for configuring the various GPMC options instead of directly programming the CONFIG1 register. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/usb-tusb6010.c | 43 +++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c index faaf96dca0fa..e832bc7b8e2d 100644 --- a/arch/arm/mach-omap2/usb-tusb6010.c +++ b/arch/arm/mach-omap2/usb-tusb6010.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -27,12 +28,21 @@ static u8 async_cs, sync_cs; static unsigned refclk_psec; static struct gpmc_settings tusb_async = { + .wait_on_read = true, + .wait_on_write = true, + .device_width = GPMC_DEVWIDTH_16BIT, .mux_add_data = GPMC_MUX_AD, }; static struct gpmc_settings tusb_sync = { + .burst_read = true, + .burst_write = true, .sync_read = true, .sync_write = true, + .wait_on_read = true, + .wait_on_write = true, + .burst_len = GPMC_BURST_16, + .device_width = GPMC_DEVWIDTH_16BIT, .mux_add_data = GPMC_MUX_AD, }; @@ -168,18 +178,12 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data, return status; } tusb_resources[0].end = tusb_resources[0].start + 0x9ff; + tusb_async.wait_pin = waitpin; async_cs = async; - gpmc_cs_write_reg(async, GPMC_CS_CONFIG1, - GPMC_CONFIG1_PAGE_LEN(2) - | GPMC_CONFIG1_WAIT_READ_MON - | GPMC_CONFIG1_WAIT_WRITE_MON - | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin) - | GPMC_CONFIG1_READTYPE_ASYNC - | GPMC_CONFIG1_WRITETYPE_ASYNC - | GPMC_CONFIG1_DEVICESIZE_16 - | GPMC_CONFIG1_DEVICETYPE_NOR - | GPMC_CONFIG1_MUXADDDATA); + status = gpmc_cs_program_settings(async_cs, &tusb_async); + if (status < 0) + return status; /* SYNC region, primarily for DMA */ status = gpmc_cs_request(sync, SZ_16M, (unsigned long *) @@ -189,21 +193,12 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data, return status; } tusb_resources[1].end = tusb_resources[1].start + 0x9ff; + tusb_sync.wait_pin = waitpin; sync_cs = sync; - gpmc_cs_write_reg(sync, GPMC_CS_CONFIG1, - GPMC_CONFIG1_READMULTIPLE_SUPP - | GPMC_CONFIG1_READTYPE_SYNC - | GPMC_CONFIG1_WRITEMULTIPLE_SUPP - | GPMC_CONFIG1_WRITETYPE_SYNC - | GPMC_CONFIG1_PAGE_LEN(2) - | GPMC_CONFIG1_WAIT_READ_MON - | GPMC_CONFIG1_WAIT_WRITE_MON - | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin) - | GPMC_CONFIG1_DEVICESIZE_16 - | GPMC_CONFIG1_DEVICETYPE_NOR - | GPMC_CONFIG1_MUXADDDATA - /* fclk divider gets set later */ - ); + + status = gpmc_cs_program_settings(sync_cs, &tusb_sync); + if (status < 0) + return status; /* IRQ */ status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq"); -- cgit v1.2.1 From 3a544354d5b6e97459ba9c15e9d89dac60023553 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 13:00:21 -0600 Subject: ARM: OMAP2+: Don't configure of chip-select options in gpmc_cs_configure() With the addition of the gpmc_cs_program_settings(), we no longer need or use gpmc_cs_configure() to configure some of the GPMC chip-select options. So rename the function to gpmc_configure() and remove code that modifies options in the CONFIG1 register. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc-nand.c | 2 +- arch/arm/mach-omap2/gpmc.c | 49 ++++++----------------------------------- arch/arm/mach-omap2/gpmc.h | 5 +---- 3 files changed, 9 insertions(+), 47 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index 75feb9558b6d..12e9753f5ad9 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -154,7 +154,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, if (err < 0) goto out_free_cs; - err = gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0); + err = gpmc_configure(GPMC_CONFIG_WP, 0); if (err < 0) goto out_free_cs; } diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index ee5d0e970c62..b22771b4d9f2 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -550,16 +550,14 @@ void gpmc_cs_free(int cs) EXPORT_SYMBOL(gpmc_cs_free); /** - * gpmc_cs_configure - write request to configure gpmc - * @cs: chip select number + * gpmc_configure - write request to configure gpmc * @cmd: command type * @wval: value to write * @return status of the operation */ -int gpmc_cs_configure(int cs, int cmd, int wval) +int gpmc_configure(int cmd, int wval) { - int err = 0; - u32 regval = 0; + u32 regval; switch (cmd) { case GPMC_ENABLE_IRQ: @@ -579,47 +577,14 @@ int gpmc_cs_configure(int cs, int cmd, int wval) gpmc_write_reg(GPMC_CONFIG, regval); break; - case GPMC_CONFIG_RDY_BSY: - regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); - if (wval) - regval |= WR_RD_PIN_MONITORING; - else - regval &= ~WR_RD_PIN_MONITORING; - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval); - break; - - case GPMC_CONFIG_DEV_SIZE: - regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); - - /* clear 2 target bits */ - regval &= ~GPMC_CONFIG1_DEVICESIZE(3); - - /* set the proper value */ - regval |= GPMC_CONFIG1_DEVICESIZE(wval); - - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval); - break; - - case GPMC_CONFIG_DEV_TYPE: - regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); - /* clear 4 target bits */ - regval &= ~(GPMC_CONFIG1_DEVICETYPE(3) | - GPMC_CONFIG1_MUXTYPE(3)); - /* set the proper value */ - regval |= GPMC_CONFIG1_DEVICETYPE(wval); - if (wval == GPMC_DEVICETYPE_NOR) - regval |= GPMC_CONFIG1_MUXADDDATA; - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval); - break; - default: - printk(KERN_ERR "gpmc_configure_cs: Not supported\n"); - err = -EINVAL; + pr_err("%s: command not supported\n", __func__); + return -EINVAL; } - return err; + return 0; } -EXPORT_SYMBOL(gpmc_cs_configure); +EXPORT_SYMBOL(gpmc_configure); void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs) { diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h index ce6ae218f41f..87d2a226a3ba 100644 --- a/arch/arm/mach-omap2/gpmc.h +++ b/arch/arm/mach-omap2/gpmc.h @@ -59,9 +59,6 @@ #define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10) #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0) #define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8) -#define GPMC_CONFIG1_MUXNONMUX GPMC_CONFIG1_MUXTYPE(0) -#define GPMC_CONFIG1_MUXAAD GPMC_CONFIG1_MUXTYPE(GPMC_MUX_AAD) -#define GPMC_CONFIG1_MUXADDDATA GPMC_CONFIG1_MUXTYPE(GPMC_MUX_AD) #define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4) #define GPMC_CONFIG1_FCLK_DIV(val) (val & 3) #define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1)) @@ -227,6 +224,6 @@ extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base); extern void gpmc_cs_free(int cs); extern void omap3_gpmc_save_context(void); extern void omap3_gpmc_restore_context(void); -extern int gpmc_cs_configure(int cs, int cmd, int wval); +extern int gpmc_configure(int cmd, int wval); #endif -- cgit v1.2.1 From 8c8a77712756edcef9298444868537af42334fc0 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 20 Feb 2013 15:53:12 -0600 Subject: ARM: OMAP2+: Add function to read GPMC settings from device-tree Adds a function to read the various GPMC chip-select settings from device-tree and store them in the gpmc_settings structure. Update the GPMC device-tree binding documentation to describe these options. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 40 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/gpmc.h | 2 ++ 2 files changed, 42 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index b22771b4d9f2..85231b3a217e 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1187,6 +1187,46 @@ static struct of_device_id gpmc_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, gpmc_dt_ids); +/** + * gpmc_read_settings_dt - read gpmc settings from device-tree + * @np: pointer to device-tree node for a gpmc child device + * @p: pointer to gpmc settings structure + * + * Reads the GPMC settings for a GPMC child device from device-tree and + * stores them in the GPMC settings structure passed. The GPMC settings + * structure is initialised to zero by this function and so any + * previously stored settings will be cleared. + */ +void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p) +{ + memset(p, 0, sizeof(struct gpmc_settings)); + + p->sync_read = of_property_read_bool(np, "gpmc,sync-read"); + p->sync_write = of_property_read_bool(np, "gpmc,sync-write"); + p->device_nand = of_property_read_bool(np, "gpmc,device-nand"); + of_property_read_u32(np, "gpmc,device-width", &p->device_width); + of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data); + + if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) { + p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap"); + p->burst_read = of_property_read_bool(np, "gpmc,burst-read"); + p->burst_write = of_property_read_bool(np, "gpmc,burst-write"); + if (!p->burst_read && !p->burst_write) + pr_warn("%s: page/burst-length set but not used!\n", + __func__); + } + + if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) { + p->wait_on_read = of_property_read_bool(np, + "gpmc,wait-on-read"); + p->wait_on_write = of_property_read_bool(np, + "gpmc,wait-on-write"); + if (!p->wait_on_read && !p->wait_on_write) + pr_warn("%s: read/write wait monitoring not enabled!\n", + __func__); + } +} + static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, struct gpmc_timings *gpmc_t) { diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h index 87d2a226a3ba..707f6d58edd5 100644 --- a/arch/arm/mach-omap2/gpmc.h +++ b/arch/arm/mach-omap2/gpmc.h @@ -225,5 +225,7 @@ extern void gpmc_cs_free(int cs); extern void omap3_gpmc_save_context(void); extern void omap3_gpmc_restore_context(void); extern int gpmc_configure(int cmd, int wval); +extern void gpmc_read_settings_dt(struct device_node *np, + struct gpmc_settings *p); #endif -- cgit v1.2.1 From d36b4cd46d23dd3c283c2e11de540e4cb875255d Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 21 Feb 2013 18:51:27 -0600 Subject: ARM: OMAP2+: Add additional GPMC timing parameters Some of the GPMC timings parameters are currently missing from the GPMC device-tree binding. Add these parameters to the binding documentation as well as code to read them. Also add either "-ps" or "-ns" suffix to the GPMC timing properties to indicate whether the timing is in picoseconds or nanoseconds. The existing code in gpmc_read_timings_dt() is checking the value of of_property_read_u32() and only is successful storing the value read in the gpmc_timings structure. Checking the return value in this case is not necessary and we can simply read the value, if present, and store directly in the gpmc_timings structure. Therefore, simplify the code by removing these checks. The comment in the gpmc_read_timings_dt() function, "only for OMAP3430" is also incorrect as it is applicable to all OMAP3+ devices. So correct this too. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 94 +++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 47 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 85231b3a217e..ab658eb1419b 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1230,67 +1230,67 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p) static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, struct gpmc_timings *gpmc_t) { - u32 val; + struct gpmc_bool_timings *p; + + if (!np || !gpmc_t) + return; memset(gpmc_t, 0, sizeof(*gpmc_t)); /* minimum clock period for syncronous mode */ - if (!of_property_read_u32(np, "gpmc,sync-clk", &val)) - gpmc_t->sync_clk = val; + of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk); /* chip select timtings */ - if (!of_property_read_u32(np, "gpmc,cs-on", &val)) - gpmc_t->cs_on = val; - - if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val)) - gpmc_t->cs_rd_off = val; - - if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val)) - gpmc_t->cs_wr_off = val; + of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on); + of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off); + of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off); /* ADV signal timings */ - if (!of_property_read_u32(np, "gpmc,adv-on", &val)) - gpmc_t->adv_on = val; - - if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val)) - gpmc_t->adv_rd_off = val; - - if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val)) - gpmc_t->adv_wr_off = val; + of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on); + of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off); + of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off); /* WE signal timings */ - if (!of_property_read_u32(np, "gpmc,we-on", &val)) - gpmc_t->we_on = val; - - if (!of_property_read_u32(np, "gpmc,we-off", &val)) - gpmc_t->we_off = val; + of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on); + of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off); /* OE signal timings */ - if (!of_property_read_u32(np, "gpmc,oe-on", &val)) - gpmc_t->oe_on = val; - - if (!of_property_read_u32(np, "gpmc,oe-off", &val)) - gpmc_t->oe_off = val; + of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on); + of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off); /* access and cycle timings */ - if (!of_property_read_u32(np, "gpmc,page-burst-access", &val)) - gpmc_t->page_burst_access = val; - - if (!of_property_read_u32(np, "gpmc,access", &val)) - gpmc_t->access = val; - - if (!of_property_read_u32(np, "gpmc,rd-cycle", &val)) - gpmc_t->rd_cycle = val; - - if (!of_property_read_u32(np, "gpmc,wr-cycle", &val)) - gpmc_t->wr_cycle = val; - - /* only for OMAP3430 */ - if (!of_property_read_u32(np, "gpmc,wr-access", &val)) - gpmc_t->wr_access = val; - - if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val)) - gpmc_t->wr_data_mux_bus = val; + of_property_read_u32(np, "gpmc,page-burst-access-ns", + &gpmc_t->page_burst_access); + of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access); + of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle); + of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle); + of_property_read_u32(np, "gpmc,bus-turnaround-ns", + &gpmc_t->bus_turnaround); + of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns", + &gpmc_t->cycle2cycle_delay); + of_property_read_u32(np, "gpmc,wait-monitoring-ns", + &gpmc_t->wait_monitoring); + of_property_read_u32(np, "gpmc,clk-activation-ns", + &gpmc_t->clk_activation); + + /* only applicable to OMAP3+ */ + of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access); + of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns", + &gpmc_t->wr_data_mux_bus); + + /* bool timing parameters */ + p = &gpmc_t->bool_timings; + + p->cycle2cyclediffcsen = + of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen"); + p->cycle2cyclesamecsen = + of_property_read_bool(np, "gpmc,cycle2cycle-samecsen"); + p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay"); + p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay"); + p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay"); + p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay"); + p->time_para_granularity = + of_property_read_bool(np, "gpmc,time-para-granularity"); } #ifdef CONFIG_MTD_NAND -- cgit v1.2.1 From cdd6928c589a2dcf084bd62fa5a2b7db1516187b Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 8 Feb 2013 16:46:13 -0600 Subject: ARM: OMAP2+: Add device-tree support for NOR flash NOR flash is not currently supported when booting with device-tree on OMAP2+ devices. Add support to detect and configure NOR devices when booting with device-tree. Add documentation for the TI GPMC NOR binding. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 115 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index ab658eb1419b..c7bf6ddf04ed 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -499,6 +500,37 @@ static int gpmc_cs_delete_mem(int cs) return r; } +/** + * gpmc_cs_remap - remaps a chip-select physical base address + * @cs: chip-select to remap + * @base: physical base address to re-map chip-select to + * + * Re-maps a chip-select to a new physical base address specified by + * "base". Returns 0 on success and appropriate negative error code + * on failure. + */ +static int gpmc_cs_remap(int cs, u32 base) +{ + int ret; + u32 old_base, size; + + if (cs > GPMC_CS_NUM) + return -ENODEV; + gpmc_cs_get_memconf(cs, &old_base, &size); + if (base == old_base) + return 0; + gpmc_cs_disable_mem(cs); + ret = gpmc_cs_delete_mem(cs); + if (ret < 0) + return ret; + ret = gpmc_cs_insert_mem(cs, base, size); + if (ret < 0) + return ret; + gpmc_cs_enable_mem(cs, base, size); + + return 0; +} + int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) { struct resource *res = &gpmc_cs_mem[cs]; @@ -1386,6 +1418,80 @@ static int gpmc_probe_onenand_child(struct platform_device *pdev, } #endif +/** + * gpmc_probe_nor_child - configures the gpmc for a nor device + * @pdev: pointer to gpmc platform device + * @child: pointer to device-tree node for nor device + * + * Allocates and configures a GPMC chip-select for a NOR flash device. + * Returns 0 on success and appropriate negative error code on failure. + */ +static int gpmc_probe_nor_child(struct platform_device *pdev, + struct device_node *child) +{ + struct gpmc_settings gpmc_s; + struct gpmc_timings gpmc_t; + struct resource res; + unsigned long base; + int ret, cs; + + if (of_property_read_u32(child, "reg", &cs) < 0) { + dev_err(&pdev->dev, "%s has no 'reg' property\n", + child->full_name); + return -ENODEV; + } + + if (of_address_to_resource(child, 0, &res) < 0) { + dev_err(&pdev->dev, "%s has malformed 'reg' property\n", + child->full_name); + return -ENODEV; + } + + ret = gpmc_cs_request(cs, resource_size(&res), &base); + if (ret < 0) { + dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs); + return ret; + } + + /* + * FIXME: gpmc_cs_request() will map the CS to an arbitary + * location in the gpmc address space. When booting with + * device-tree we want the NOR flash to be mapped to the + * location specified in the device-tree blob. So remap the + * CS to this location. Once DT migration is complete should + * just make gpmc_cs_request() map a specific address. + */ + ret = gpmc_cs_remap(cs, res.start); + if (ret < 0) { + dev_err(&pdev->dev, "cannot remap GPMC CS %d to 0x%x\n", + cs, res.start); + goto err; + } + + gpmc_read_settings_dt(child, &gpmc_s); + + ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width); + if (ret < 0) + goto err; + + ret = gpmc_cs_program_settings(cs, &gpmc_s); + if (ret < 0) + goto err; + + gpmc_read_timings_dt(child, &gpmc_t); + gpmc_cs_set_timings(cs, &gpmc_t); + + if (of_platform_device_create(child, NULL, &pdev->dev)) + return 0; + + dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name); + +err: + gpmc_cs_free(cs); + + return ret; +} + static int gpmc_probe_dt(struct platform_device *pdev) { int ret; @@ -1418,6 +1524,15 @@ static int gpmc_probe_dt(struct platform_device *pdev) return ret; } } + + for_each_node_by_name(child, "nor") { + ret = gpmc_probe_nor_child(pdev, child); + if (ret < 0) { + of_node_put(child); + return ret; + } + } + return 0; } #else -- cgit v1.2.1 From acc79980c92ca9e8a39115b60ca832718a8156df Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Mon, 25 Feb 2013 11:36:47 -0600 Subject: ARM: OMAP2+: Convert NAND to retrieve GPMC settings from DT When booting with device-tree, retrieve GPMC settings for NAND from the device-tree blob. This will allow us to remove all static settings stored in the gpmc-nand.c in the future once the migration to device-tree is complete. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc-nand.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index 12e9753f5ad9..d9c27195caf0 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -137,12 +137,16 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, return err; } - s.device_nand = true; - - /* Enable RD PIN Monitoring Reg */ - if (gpmc_nand_data->dev_ready) { - s.wait_on_read = true; - s.wait_on_write = true; + if (gpmc_nand_data->of_node) { + gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); + } else { + s.device_nand = true; + + /* Enable RD PIN Monitoring Reg */ + if (gpmc_nand_data->dev_ready) { + s.wait_on_read = true; + s.wait_on_write = true; + } } if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) -- cgit v1.2.1 From 32cde0b5141030030f950a3c7e971018c81a9360 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Mon, 25 Feb 2013 11:37:58 -0600 Subject: ARM: OMAP2+: Convert ONENAND to retrieve GPMC settings from DT When booting with device-tree, retrieve GPMC settings for ONENAND from the device-tree blob. This will allow us to remove all static settings stored in the gpmc-nand.c in the future once the migration to device-tree is complete. The user must now specify the ONENAND device width in the device-tree binding so that the GPMC can be programmed correctly. Therefore, update the device-tree binding documentation for ONENAND devices connected to the GPMC to reflect this. Please note that this does not include GPMC timings for ONENAND. The timings are being calculated at runtime. There is some legacy code that only enables read wait monitoring for non-OMAP3 devices. There are no known OMAP3 device issues that prevent this feature being enabled and so when booting with device-tree use the wait-monitoring settings described in the device-tree blob. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc-onenand.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 46aac83d73d4..64b5a8346982 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -272,6 +272,10 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base) struct gpmc_timings t; int ret; + if (gpmc_onenand_data->of_node) + gpmc_read_settings_dt(gpmc_onenand_data->of_node, + &onenand_async); + omap2_onenand_set_async_mode(onenand_base); omap2_onenand_calc_async_timings(&t); @@ -300,12 +304,17 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr) set_onenand_cfg(onenand_base); } - /* - * FIXME: Appears to be legacy code from initial ONENAND commit. - * Unclear what boards this is for and if this can be removed. - */ - if (!cpu_is_omap34xx()) - onenand_sync.wait_on_read = true; + if (gpmc_onenand_data->of_node) { + gpmc_read_settings_dt(gpmc_onenand_data->of_node, + &onenand_sync); + } else { + /* + * FIXME: Appears to be legacy code from initial ONENAND commit. + * Unclear what boards this is for and if this can be removed. + */ + if (!cpu_is_omap34xx()) + onenand_sync.wait_on_read = true; + } omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq); -- cgit v1.2.1 From c71f8e9bef8a3e022537361505c09f8c357ffd18 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 6 Mar 2013 12:00:10 -0600 Subject: ARM: OMAP2+: Detect incorrectly aligned GPMC base address Each GPMC chip-select can be configured to map 16MB, 32MB, 64MB or 128MB of address space. The physical base address where a chip-select starts is also configurable and must be aligned on a boundary that is equal to or greater than the size of the address space mapped bt the chip-select. When enabling a GPMC chip-select, ensure that the base address is aligned to the appropriate boundary. Reported-by: Mark Jackson Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index c7bf6ddf04ed..5c22b5adaeb5 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -403,11 +403,18 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) return 0; } -static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) +static int gpmc_cs_enable_mem(int cs, u32 base, u32 size) { u32 l; u32 mask; + /* + * Ensure that base address is aligned on a + * boundary equal to or greater than size. + */ + if (base & (size - 1)) + return -EINVAL; + mask = (1 << GPMC_SECTION_SHIFT) - size; l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); l &= ~0x3f; @@ -416,6 +423,8 @@ static void gpmc_cs_enable_mem(int cs, u32 base, u32 size) l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8; l |= GPMC_CONFIG7_CSVALID; gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); + + return 0; } static void gpmc_cs_disable_mem(int cs) @@ -526,7 +535,9 @@ static int gpmc_cs_remap(int cs, u32 base) ret = gpmc_cs_insert_mem(cs, base, size); if (ret < 0) return ret; - gpmc_cs_enable_mem(cs, base, size); + ret = gpmc_cs_enable_mem(cs, base, size); + if (ret < 0) + return ret; return 0; } @@ -556,7 +567,12 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) if (r < 0) goto out; - gpmc_cs_enable_mem(cs, res->start, resource_size(res)); + r = gpmc_cs_enable_mem(cs, res->start, resource_size(res)); + if (r < 0) { + release_resource(res); + goto out; + } + *base = res->start; gpmc_cs_set_reserved(cs, 1); out: -- cgit v1.2.1 From bf2343974e331d1627f6f904160dedc99a81c10d Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 6 Mar 2013 14:12:59 -0600 Subject: ARM: OMAP2+: Remove unnecesssary GPMC definitions and variable With commit 21cc2bd (ARM: OMAP2+: Remove apollon board support) the variable "boot_rom_space" is now not needed and the code surrounding this variable can be cleaned up and simplified. Remove unnecessary definitions and clean-up the comment as well. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 5c22b5adaeb5..a259dc0bf063 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -92,9 +92,7 @@ #define GPMC_CS_SIZE 0x30 #define GPMC_BCH_SIZE 0x10 -#define GPMC_MEM_START 0x00000000 #define GPMC_MEM_END 0x3FFFFFFF -#define BOOT_ROM_SPACE 0x100000 /* 1MB */ #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ #define GPMC_SECTION_SHIFT 28 /* 128 MB */ @@ -790,13 +788,13 @@ static void gpmc_mem_exit(void) static int gpmc_mem_init(void) { int cs, rc; - unsigned long boot_rom_space = 0; - /* never allocate the first page, to facilitate bug detection; - * even if we didn't boot from ROM. + /* + * The first 1MB of GPMC address space is typically mapped to + * the internal ROM. Never allocate the first page, to + * facilitate bug detection; even if we didn't boot from ROM. */ - boot_rom_space = BOOT_ROM_SPACE; - gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space; + gpmc_mem_root.start = SZ_1M; gpmc_mem_root.end = GPMC_MEM_END; /* Reserve all regions that has been set up by bootloader */ -- cgit v1.2.1 From 84b00f0e2878e6b7dbfa346d496d564aa55c6175 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 6 Mar 2013 14:36:47 -0600 Subject: ARM: OMAP2+: Allow GPMC probe to complete even if CS mapping fails When the GPMC driver is probed, we call gpmc_mem_init() to see which chip-selects have already been configured and enabled by the boot-loader and allocate space for them. If we fail to allocate space for one chip-select, then we return failure from the probe and the GPMC driver will not be available. Rather than render the GPMC useless for all GPMC devices, if we fail to allocate space for one chip-select print a warning and disable the chip-select. This way other GPMC clients can still be used. There is no downside to this approach, because all GPMC clients need to request a chip-select before they can use the GPMC and on requesting a chip-select, if memory has not already been reserved for the chip-select then it will be. Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index a259dc0bf063..5f6af202807a 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -785,9 +785,9 @@ static void gpmc_mem_exit(void) } -static int gpmc_mem_init(void) +static void gpmc_mem_init(void) { - int cs, rc; + int cs; /* * The first 1MB of GPMC address space is typically mapped to @@ -804,16 +804,12 @@ static int gpmc_mem_init(void) if (!gpmc_cs_mem_enabled(cs)) continue; gpmc_cs_get_memconf(cs, &base, &size); - rc = gpmc_cs_insert_mem(cs, base, size); - if (rc < 0) { - while (--cs >= 0) - if (gpmc_cs_mem_enabled(cs)) - gpmc_cs_delete_mem(cs); - return rc; + if (gpmc_cs_insert_mem(cs, base, size)) { + pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n", + __func__, cs, base, base + size); + gpmc_cs_disable_mem(cs); } } - - return 0; } static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk) @@ -1611,13 +1607,7 @@ static int gpmc_probe(struct platform_device *pdev) dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l), GPMC_REVISION_MINOR(l)); - rc = gpmc_mem_init(); - if (rc < 0) { - clk_disable_unprepare(gpmc_l3_clk); - clk_put(gpmc_l3_clk); - dev_err(gpmc_dev, "failed to reserve memory\n"); - return rc; - } + gpmc_mem_init(); if (gpmc_setup_irq() < 0) dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); -- cgit v1.2.1 From e8ffd6fdf28ac8404acebf2759315600bfdcb5f9 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 14 Mar 2013 16:09:20 +0100 Subject: ARM: OMAP2+: return -ENODEV if GPMC child device creation fails gpmc_probe_nor_child() calls of_platform_device_create() to create a platform device for the NOR child. If this function fails the value of ret is returned to the caller but this value is zero since it was assigned the return of a previous call to gpmc_cs_program_settings() that had to succeed or otherwise gpmc_probe_nor_child() would have returned before. This means that if of_platform_device_create() fails, 0 will be returned to the caller instead of an appropriate error code. Signed-off-by: Javier Martinez Canillas Signed-off-by: Jon Hunter Tested-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 5f6af202807a..c6f0ef563817 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1495,6 +1495,7 @@ static int gpmc_probe_nor_child(struct platform_device *pdev, return 0; dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name); + ret = -ENODEV; err: gpmc_cs_free(cs); -- cgit v1.2.1 From 3af91cf7016bdfce9a6a0343ab942302e98e8f3d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 14 Mar 2013 16:09:21 +0100 Subject: ARM: OMAP2+: rename gpmc_probe_nor_child() to gpmc_probe_generic_child() The gpmc_probe_nor_child() function is used in the GPMC driver to configure the GPMC for a NOR child device node. But this function is quite generic and all the NOR specific configuration is made by the driver of the actual NOR flash memory used. Other Pseudo-SRAM devices such as ethernet controllers need a similar setup so by making this function generic it can be used for those too. Signed-off-by: Javier Martinez Canillas Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index c6f0ef563817..8a1cafb2750e 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1429,14 +1429,14 @@ static int gpmc_probe_onenand_child(struct platform_device *pdev, #endif /** - * gpmc_probe_nor_child - configures the gpmc for a nor device + * gpmc_probe_generic_child - configures the gpmc for a child device * @pdev: pointer to gpmc platform device - * @child: pointer to device-tree node for nor device + * @child: pointer to device-tree node for child device * - * Allocates and configures a GPMC chip-select for a NOR flash device. + * Allocates and configures a GPMC chip-select for a child device. * Returns 0 on success and appropriate negative error code on failure. */ -static int gpmc_probe_nor_child(struct platform_device *pdev, +static int gpmc_probe_generic_child(struct platform_device *pdev, struct device_node *child) { struct gpmc_settings gpmc_s; @@ -1537,7 +1537,7 @@ static int gpmc_probe_dt(struct platform_device *pdev) } for_each_node_by_name(child, "nor") { - ret = gpmc_probe_nor_child(pdev, child); + ret = gpmc_probe_generic_child(pdev, child); if (ret < 0) { of_node_put(child); return ret; -- cgit v1.2.1 From 5330dc161cb41e399e85d30e6908f1b93b956d1e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 14 Mar 2013 22:54:11 +0100 Subject: ARM: OMAP2+: Add GPMC DT support for Ethernet child nodes Besides being used to interface with external memory devices, the General-Purpose Memory Controller can be used to connect Pseudo-SRAM devices such as ethernet controllers to OMAP2+ processors using the TI GPMC as a data bus. This patch allows an ethernet chip to be defined as an GPMC child device node. Signed-off-by: Javier Martinez Canillas Signed-off-by: Jon Hunter --- arch/arm/mach-omap2/gpmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 8a1cafb2750e..ed946df5ad8a 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1544,6 +1544,14 @@ static int gpmc_probe_dt(struct platform_device *pdev) } } + for_each_node_by_name(child, "ethernet") { + ret = gpmc_probe_generic_child(pdev, child); + if (ret < 0) { + of_node_put(child); + return ret; + } + } + return 0; } #else -- cgit v1.2.1