From 80323742eab6aca28ebe91cbca84a3d5ab940f4d Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 29 Aug 2014 19:11:50 +0300 Subject: ARM: OMAP2+: gpmc: Print error message in set_gpmc_timing_reg() Simplify set_gpmc_timing_reg() and always print error message if the requested timing cannot be achieved due to a too fast GPMC functional clock, irrespective if whether DEBUG is defined or not. This should help us debug timing configuration issues, which were otherwise simply not being displayed in the kernel log. Signed-off-by: Roger Quadros Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 5fa3755261ce..45f680f965ed 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -283,13 +283,8 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p) p->cycle2cyclediffcsen); } -#ifdef DEBUG static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int time, const char *name) -#else -static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, - int time) -#endif { u32 l; int ticks, mask, nr_bits; @@ -299,15 +294,15 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, else ticks = gpmc_ns_to_ticks(time); nr_bits = end_bit - st_bit + 1; - if (ticks >= 1 << nr_bits) { -#ifdef DEBUG - printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n", - cs, name, time, ticks, 1 << nr_bits); -#endif + mask = (1 << nr_bits) - 1; + + if (ticks > mask) { + pr_err("%s: GPMC error! CS%d: %s: %d ns, %d ticks > %d\n", + __func__, cs, name, time, ticks, mask); + return -1; } - mask = (1 << nr_bits) - 1; l = gpmc_cs_read_reg(cs, reg); #ifdef DEBUG printk(KERN_INFO @@ -322,16 +317,10 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, return 0; } -#ifdef DEBUG #define GPMC_SET_ONE(reg, st, end, field) \ if (set_gpmc_timing_reg(cs, (reg), (st), (end), \ t->field, #field) < 0) \ return -1 -#else -#define GPMC_SET_ONE(reg, st, end, field) \ - if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \ - return -1 -#endif int gpmc_calc_divider(unsigned int sync_clk) { -- cgit v1.2.3-59-g8ed1b From 7604baf365a3bd46007be6fbd2e43ac4a46ce928 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 29 Aug 2014 19:11:51 +0300 Subject: ARM: OMAP2+: gpmc: Error out if timings fail in gpmc_probe_generic_child() gpmc_cs_set_timings() returns non-zero if there was an error while setting the GPMC timings. e.g. Timing was too large to be accomodated with current GPMC clock frequency and available timing range. Fail in this case, else we risk operating a NOR device with non compliant timings. Signed-off-by: Roger Quadros Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 45f680f965ed..f5d9dd256d63 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1562,7 +1562,12 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, goto err; gpmc_read_timings_dt(child, &gpmc_t); - gpmc_cs_set_timings(cs, &gpmc_t); + ret = gpmc_cs_set_timings(cs, &gpmc_t); + if (ret) { + dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n", + child->name); + goto err; + } no_timings: if (of_platform_device_create(child, NULL, &pdev->dev)) -- cgit v1.2.3-59-g8ed1b From e378d22b9c27de4af4946e4e7928fef50f9a9ff7 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 29 Aug 2014 19:11:52 +0300 Subject: ARM: OMAP2+: gpmc: Always enable A26-A11 for non NAND devices Although RESET state of LIMITEDADDRESS bit in GPMC_CONFIG register is 0 (i.e. A26-A11 enabled), faulty bootloaders might accidentally set this bit. e.g. u-boot 2014.07 with CONFIG_NOR disabled. Explicity disable LIMITEDADDRESS bit for non NAND devices so that they can always work. Signed-off-by: Roger Quadros Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index f5d9dd256d63..0ba95d3e74e5 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -85,6 +85,8 @@ #define GPMC_ECC_CTRL_ECCREG8 0x008 #define GPMC_ECC_CTRL_ECCREG9 0x009 +#define GPMC_CONFIG_LIMITEDADDRESS BIT(1) + #define GPMC_CONFIG2_CSEXTRADELAY BIT(7) #define GPMC_CONFIG3_ADVEXTRADELAY BIT(7) #define GPMC_CONFIG4_OEEXTRADELAY BIT(7) @@ -1501,6 +1503,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, struct resource res; unsigned long base; int ret, cs; + u32 val; if (of_property_read_u32(child, "reg", &cs) < 0) { dev_err(&pdev->dev, "%s has no 'reg' property\n", @@ -1569,6 +1572,11 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, goto err; } + /* Clear limited address i.e. enable A26-A11 */ + val = gpmc_read_reg(GPMC_CONFIG); + val &= ~GPMC_CONFIG_LIMITEDADDRESS; + gpmc_write_reg(GPMC_CONFIG, val); + no_timings: if (of_platform_device_create(child, NULL, &pdev->dev)) return 0; -- cgit v1.2.3-59-g8ed1b From 4cf27d2ec716fddacd02169af9a26a43ea52875e Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 29 Aug 2014 19:11:53 +0300 Subject: ARM: OMAP2+: gpmc: Keep Chip Select disabled while configuring it As per the OMAP reference manual [1], the Chip Select must be disabled (i.e. CSVALID is 0) while configuring any of the Chip select parameters. [1] - 10.1.5.1 Chip-Select Base Address and Region Size Configuration http://www.ti.com/lit/pdf/swpu177 Signed-off-by: Roger Quadros Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 0ba95d3e74e5..437fb6f6df52 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -397,7 +397,7 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) return 0; } -static int gpmc_cs_enable_mem(int cs, u32 base, u32 size) +static int gpmc_cs_set_memconf(int cs, u32 base, u32 size) { u32 l; u32 mask; @@ -421,6 +421,15 @@ static int gpmc_cs_enable_mem(int cs, u32 base, u32 size) return 0; } +static void gpmc_cs_enable_mem(int cs) +{ + u32 l; + + l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); + l |= GPMC_CONFIG7_CSVALID; + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); +} + static void gpmc_cs_disable_mem(int cs) { u32 l; @@ -532,18 +541,18 @@ static int gpmc_cs_remap(int cs, u32 base) 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; - ret = gpmc_cs_enable_mem(cs, base, size); if (ret < 0) return ret; - return 0; + ret = gpmc_cs_set_memconf(cs, base, size); + + return ret; } int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) @@ -572,12 +581,17 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) if (r < 0) goto out; - r = gpmc_cs_enable_mem(cs, res->start, resource_size(res)); + /* Disable CS while changing base address and size mask */ + gpmc_cs_disable_mem(cs); + + r = gpmc_cs_set_memconf(cs, res->start, resource_size(res)); if (r < 0) { release_resource(res); goto out; } + /* Enable CS */ + gpmc_cs_enable_mem(cs); *base = res->start; gpmc_cs_set_reserved(cs, 1); out: @@ -1539,6 +1553,9 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, goto no_timings; } + /* CS must be disabled while making changes to gpmc configuration */ + gpmc_cs_disable_mem(cs); + /* * FIXME: gpmc_cs_request() will map the CS to an arbitary * location in the gpmc address space. When booting with @@ -1577,6 +1594,9 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, val &= ~GPMC_CONFIG_LIMITEDADDRESS; gpmc_write_reg(GPMC_CONFIG, val); + /* Enable CS region */ + gpmc_cs_enable_mem(cs); + no_timings: if (of_platform_device_create(child, NULL, &pdev->dev)) return 0; -- cgit v1.2.3-59-g8ed1b From 8bf9be566ed5790003402eb1060184956788b410 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 1 Sep 2014 15:18:56 +0300 Subject: ARM: OMAP2+: gpmc: Sanity check GPMC fck on probe This prevents potential division by zero errors if GPMC fck turns out to be zero due to faulty clock data. Use resource managed clk_get() API. Signed-off-by: Roger Quadros Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 437fb6f6df52..104bc2c50987 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -204,11 +204,6 @@ static unsigned long gpmc_get_fclk_period(void) { unsigned long rate = clk_get_rate(gpmc_l3_clk); - if (rate == 0) { - printk(KERN_WARNING "gpmc_l3_clk not enabled\n"); - return 0; - } - rate /= 1000; rate = 1000000000 / rate; /* In picoseconds */ @@ -1692,13 +1687,18 @@ static int gpmc_probe(struct platform_device *pdev) else gpmc_irq = res->start; - gpmc_l3_clk = clk_get(&pdev->dev, "fck"); + gpmc_l3_clk = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(gpmc_l3_clk)) { - dev_err(&pdev->dev, "error: clk_get\n"); + dev_err(&pdev->dev, "Failed to get GPMC fck\n"); gpmc_irq = 0; return PTR_ERR(gpmc_l3_clk); } + if (!clk_get_rate(gpmc_l3_clk)) { + dev_err(&pdev->dev, "Invalid GPMC fck clock rate\n"); + return -EINVAL; + } + pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); @@ -1741,7 +1741,6 @@ static int gpmc_probe(struct platform_device *pdev) rc = gpmc_probe_dt(pdev); if (rc < 0) { pm_runtime_put_sync(&pdev->dev); - clk_put(gpmc_l3_clk); dev_err(gpmc_dev, "failed to probe DT parameters\n"); return rc; } -- cgit v1.2.3-59-g8ed1b From 9ed7a776eb50de2284dd053c719f2f6481af9027 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 3 Nov 2014 17:45:01 -0800 Subject: ARM: OMAP2+: Fix support for multiple devices on a GPMC chip select There are cases where we have multiple device instances connected to a single GPMC chip select. For example, there are four UARTs on the Zoom debug boards that all share a single chip select and a GPIO interrupt. We do have support for this already in theory, but it's broken because we're bailing out if the chip select is already taken. To be able to provide checks on the chip select usage, let's add new struct gpmc_cs_data so we can start using already registered device names for checks. Later on we probably want to start using struct gpmc_cs_data as a wrapper for all the GPMC chipselect related data. Acked-by: Roger Quadros Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 61 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 12 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 5fa3755261ce..2c5f3485e44c 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -118,6 +118,15 @@ */ #define GPMC_NR_IRQ 2 +struct gpmc_cs_data { + const char *name; + +#define GPMC_CS_RESERVED (1 << 0) + u32 flags; + + struct resource mem; +}; + struct gpmc_client_irq { unsigned irq; u32 bitmask; @@ -155,10 +164,9 @@ static struct irq_chip gpmc_irq_chip; static int gpmc_irq_start; static struct resource gpmc_mem_root; -static struct resource gpmc_cs_mem[GPMC_CS_NUM]; +static struct gpmc_cs_data gpmc_cs[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_cs_num = GPMC_CS_NUM; static unsigned int gpmc_nr_waitpins; static struct device *gpmc_dev; @@ -460,13 +468,30 @@ static int gpmc_cs_mem_enabled(int cs) static void gpmc_cs_set_reserved(int cs, int reserved) { - gpmc_cs_map &= ~(1 << cs); - gpmc_cs_map |= (reserved ? 1 : 0) << cs; + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + + gpmc->flags |= GPMC_CS_RESERVED; } static bool gpmc_cs_reserved(int cs) { - return gpmc_cs_map & (1 << cs); + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + + return gpmc->flags & GPMC_CS_RESERVED; +} + +static void gpmc_cs_set_name(int cs, const char *name) +{ + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + + gpmc->name = name; +} + +const char *gpmc_cs_get_name(int cs) +{ + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + + return gpmc->name; } static unsigned long gpmc_mem_align(unsigned long size) @@ -485,7 +510,8 @@ static unsigned long gpmc_mem_align(unsigned long size) static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size) { - struct resource *res = &gpmc_cs_mem[cs]; + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + struct resource *res = &gpmc->mem; int r; size = gpmc_mem_align(size); @@ -500,7 +526,8 @@ static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size) static int gpmc_cs_delete_mem(int cs) { - struct resource *res = &gpmc_cs_mem[cs]; + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + struct resource *res = &gpmc->mem; int r; spin_lock(&gpmc_mem_lock); @@ -557,7 +584,8 @@ static int gpmc_cs_remap(int cs, u32 base) int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) { - struct resource *res = &gpmc_cs_mem[cs]; + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + struct resource *res = &gpmc->mem; int r = -1; if (cs > gpmc_cs_num) { @@ -597,7 +625,8 @@ EXPORT_SYMBOL(gpmc_cs_request); void gpmc_cs_free(int cs) { - struct resource *res = &gpmc_cs_mem[cs]; + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + struct resource *res = &gpmc->mem; spin_lock(&gpmc_mem_lock); if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) { @@ -1511,6 +1540,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, struct gpmc_timings gpmc_t; struct resource res; unsigned long base; + const char *name; int ret, cs; if (of_property_read_u32(child, "reg", &cs) < 0) { @@ -1525,11 +1555,21 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, return -ENODEV; } + /* + * Check if we have multiple instances of the same device + * on a single chip select. If so, use the already initialized + * timings. + */ + name = gpmc_cs_get_name(cs); + if (name && child->name && of_node_cmp(child->name, name) == 0) + goto no_timings; + 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; } + gpmc_cs_set_name(cs, child->name); /* * For some GPMC devices we still need to rely on the bootloader @@ -1708,9 +1748,6 @@ static int gpmc_probe(struct platform_device *pdev) if (gpmc_setup_irq() < 0) dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); - /* Now the GPMC is initialised, unreserve the chip-selects */ - gpmc_cs_map = 0; - if (!pdev->dev.of_node) { gpmc_cs_num = GPMC_CS_NUM; gpmc_nr_waitpins = GPMC_NR_WAITPINS; -- cgit v1.2.3-59-g8ed1b From 35ac051e019431ccdfdaa9d71e08123870770de2 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 3 Nov 2014 17:45:01 -0800 Subject: ARM: OMAP2+: Show bootloader GPMC timings to allow configuring the .dts file As we still have some devices with GPMC timings missing from the .dts files, let's make it a bit easier to use the bootloader values and print them out. Note that we now need to move the parsing of the device tree provided configuration a bit earlier so we can use that for checking if anything was configured. Acked-by: Roger Quadros Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 144 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 3 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 2c5f3485e44c..eee7065a5020 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -291,6 +291,129 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p) p->cycle2cyclediffcsen); } +#ifdef DEBUG +static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, + bool raw, bool noval, int shift, + const char *name) +{ + u32 l; + int nr_bits, max_value, mask; + + l = gpmc_cs_read_reg(cs, reg); + nr_bits = end_bit - st_bit + 1; + max_value = (1 << nr_bits) - 1; + mask = max_value << st_bit; + l = (l & mask) >> st_bit; + if (shift) + l = (shift << l); + if (noval && (l == 0)) + return 0; + if (!raw) { + unsigned int time_ns_min, time_ns, time_ns_max; + + time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0); + time_ns = gpmc_ticks_to_ns(l); + time_ns_max = gpmc_ticks_to_ns(l + 1 > max_value ? + max_value : l + 1); + pr_info("gpmc,%s = <%u> (%u - %u ns, %i ticks)\n", + name, time_ns, time_ns_min, time_ns_max, l); + } else { + pr_info("gpmc,%s = <%u>\n", name, l); + } + + return l; +} + +#define GPMC_PRINT_CONFIG(cs, config) \ + pr_info("cs%i %s: 0x%08x\n", cs, #config, \ + gpmc_cs_read_reg(cs, config)) +#define GPMC_GET_RAW(reg, st, end, field) \ + get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 0, 0, field) +#define GPMC_GET_RAW_BOOL(reg, st, end, field) \ + get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, 0, field) +#define GPMC_GET_RAW_SHIFT(reg, st, end, shift, field) \ + get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, (shift), field) +#define GPMC_GET_TICKS(reg, st, end, field) \ + get_gpmc_timing_reg(cs, (reg), (st), (end), 0, 0, 0, field) + +static void gpmc_show_regs(int cs, const char *desc) +{ + pr_info("gpmc cs%i %s:\n", cs, desc); + GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG1); + GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG2); + GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG3); + GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG4); + GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG5); + GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG6); +} + +/* + * Note that gpmc,wait-pin handing wrongly assumes bit 8 is available, + * see commit c9fb809. + */ +static void gpmc_cs_show_timings(int cs, const char *desc) +{ + gpmc_show_regs(cs, desc); + + pr_info("gpmc cs%i access configuration:\n", cs); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 4, 4, "time-para-granularity"); + GPMC_GET_RAW(GPMC_CS_CONFIG1, 8, 9, "mux-add-data"); + GPMC_GET_RAW(GPMC_CS_CONFIG1, 12, 13, "device-width"); + GPMC_GET_RAW(GPMC_CS_CONFIG1, 16, 17, "wait-pin"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 21, 21, "wait-on-write"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 22, 22, "wait-on-read"); + GPMC_GET_RAW_SHIFT(GPMC_CS_CONFIG1, 23, 24, 4, "burst-length"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 27, 27, "sync-write"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 28, 28, "burst-write"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 29, 29, "gpmc,sync-read"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 30, 30, "burst-read"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 31, 31, "burst-wrap"); + + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG2, 7, 7, "cs-extra-delay"); + + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG3, 7, 7, "adv-extra-delay"); + + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG4, 23, 23, "we-extra-delay"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG4, 7, 7, "oe-extra-delay"); + + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG6, 7, 7, "cycle2cycle-samecsen"); + GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG6, 6, 6, "cycle2cycle-diffcsen"); + + pr_info("gpmc cs%i timings configuration:\n", cs); + GPMC_GET_TICKS(GPMC_CS_CONFIG2, 0, 3, "cs-on-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG2, 8, 12, "cs-rd-off-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG2, 16, 20, "cs-wr-off-ns"); + + GPMC_GET_TICKS(GPMC_CS_CONFIG3, 0, 3, "adv-on-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG3, 8, 12, "adv-rd-off-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG3, 16, 20, "adv-wr-off-ns"); + + GPMC_GET_TICKS(GPMC_CS_CONFIG4, 0, 3, "oe-on-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG4, 8, 12, "oe-off-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG4, 16, 19, "we-on-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG4, 24, 28, "we-off-ns"); + + GPMC_GET_TICKS(GPMC_CS_CONFIG5, 0, 4, "rd-cycle-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG5, 8, 12, "wr-cycle-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG5, 16, 20, "access-ns"); + + GPMC_GET_TICKS(GPMC_CS_CONFIG5, 24, 27, "page-burst-access-ns"); + + GPMC_GET_TICKS(GPMC_CS_CONFIG6, 0, 3, "bus-turnaround-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG6, 8, 11, "cycle2cycle-delay-ns"); + + GPMC_GET_TICKS(GPMC_CS_CONFIG1, 18, 19, "wait-monitoring-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG1, 25, 26, "clk-activation-ns"); + + GPMC_GET_TICKS(GPMC_CS_CONFIG6, 16, 19, "wr-data-mux-bus-ns"); + GPMC_GET_TICKS(GPMC_CS_CONFIG6, 24, 28, "wr-access-ns"); +} +#else +static inline void gpmc_cs_show_timings(int cs, const char *desc) +{ +} +#endif + #ifdef DEBUG static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int time, const char *name) @@ -361,6 +484,7 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) int div; u32 l; + gpmc_cs_show_timings(cs, "before gpmc_cs_set_timings"); div = gpmc_calc_divider(t->sync_clk); if (div < 0) return div; @@ -410,6 +534,7 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) } gpmc_cs_bool_timings(cs, &t->bool_timings); + gpmc_cs_show_timings(cs, "after gpmc_cs_set_timings"); return 0; } @@ -1571,6 +1696,22 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, } gpmc_cs_set_name(cs, child->name); + gpmc_read_settings_dt(child, &gpmc_s); + gpmc_read_timings_dt(child, &gpmc_t); + + /* + * For some GPMC devices we still need to rely on the bootloader + * timings because the devices can be connected via FPGA. + * REVISIT: Add timing support from slls644g.pdf. + */ + if (!gpmc_t.cs_rd_off) { + WARN(1, "enable GPMC debug to configure .dts timings for CS%i\n", + cs); + gpmc_cs_show_timings(cs, + "please add GPMC bootloader timings to .dts"); + goto no_timings; + } + /* * For some GPMC devices we still need to rely on the bootloader * timings because the devices can be connected via FPGA. So far @@ -1602,8 +1743,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, 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; @@ -1612,7 +1751,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, if (ret < 0) goto err; - gpmc_read_timings_dt(child, &gpmc_t); gpmc_cs_set_timings(cs, &gpmc_t); no_timings: -- cgit v1.2.3-59-g8ed1b From 9995772a6d70196ccf0295e4a1cfbb7e4c4a0ef1 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 3 Nov 2014 17:45:01 -0800 Subject: ARM: OMAP2+: Require proper GPMC timings for devices Now that we have timings in the .dts files for smc91x and 8250, we can remove the device specific checks and just print out the bootloader timings for devices that may not have timings in the .dts files. Acked-by: Roger Quadros Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index eee7065a5020..a7554ac3f37c 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1712,22 +1712,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, goto no_timings; } - /* - * For some GPMC devices we still need to rely on the bootloader - * timings because the devices can be connected via FPGA. So far - * the list is smc91x on the omap2 SDP boards, and 8250 on zooms. - * REVISIT: Add timing support from slls644g.pdf and from the - * lan91c96 manual. - */ - if (of_device_is_compatible(child, "ns16550a") || - of_device_is_compatible(child, "smsc,lan91c94") || - of_device_is_compatible(child, "smsc,lan91c111")) { - dev_warn(&pdev->dev, - "%s using bootloader timings on CS%d\n", - child->name, cs); - goto no_timings; - } - /* * FIXME: gpmc_cs_request() will map the CS to an arbitary * location in the gpmc address space. When booting with -- cgit v1.2.3-59-g8ed1b From 8f5951172b6dbda75a9cdf5990650e1cf8b1dd22 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 3 Nov 2014 17:45:01 -0800 Subject: ARM: OMAP2+: Drop legacy code for gpmc-smc91x.c This code was only used by 2430sdp, 3430sdp, and n900 development boards. The 2430sdp is already device tree only, and all the users of the 3430sdp and n900 development boards are already booting in device tree mode, so we can drop the legacy smc91x support. Acked-by: Roger Quadros Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 3 - arch/arm/mach-omap2/board-3430sdp.c | 28 ---- arch/arm/mach-omap2/board-rx51-peripherals.c | 29 ----- arch/arm/mach-omap2/gpmc-smc91x.c | 186 --------------------------- arch/arm/mach-omap2/gpmc-smc91x.h | 42 ------ 5 files changed, 288 deletions(-) delete mode 100644 arch/arm/mach-omap2/gpmc-smc91x.c delete mode 100644 arch/arm/mach-omap2/gpmc-smc91x.h (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index d9e94122073e..3e824f8fec48 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -284,9 +284,6 @@ obj-y += $(onenand-m) $(onenand-y) nand-$(CONFIG_MTD_NAND_OMAP2) := gpmc-nand.o obj-y += $(nand-m) $(nand-y) -smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o -obj-y += $(smc91x-m) $(smc91x-y) - smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o obj-y += $(smsc911x-m) $(smsc911x-y) ifneq ($(CONFIG_HWSPINLOCK_OMAP),) diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index d21a3048d06b..9857882c2f41 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -38,7 +38,6 @@ #include