diff options
author | Olof Johansson <olof@lixom.net> | 2013-06-14 21:36:51 (GMT) |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-06-14 21:36:51 (GMT) |
commit | f54ffe0fef2b0bd635e2ee2738155fca70854675 (patch) | |
tree | 428619d8ce8cd123c2733bb96e7e641058665e6d | |
parent | ff299f1b1cb4e0c44a3f76d1f8ee4eb2f64f098f (diff) | |
parent | b3f5525c55ce5cb67af06f04dbbf28358da23a2c (diff) | |
download | linux-f54ffe0fef2b0bd635e2ee2738155fca70854675.tar.xz |
Merge tag 'omap-for-v3.11/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/drivers
From Tony Lindgren:
Omap GPMC (General Purpose Memory Controller) changes.
* tag 'omap-for-v3.11/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
ARM: OMAP2+: gpmc: Converts GPMC driver to pm_runtime capable
ARM: OMAP2+: gpmc: get number of useable GPMC chip-selects via DT
ARM: dts: OMAP2+: Simplify NAND support
ARM: OMAP2+: Allow NAND transfer mode to be specified in DT
ARM: OMAP2+: nand: reorganize gpmc timing values
Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/bus/ti-gpmc.txt | 1 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mtd/gpmc-nand.txt | 8 | ||||
-rw-r--r-- | arch/arm/boot/dts/omap3430-sdp.dts | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-flash.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc-nand.c | 44 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 61 |
6 files changed, 63 insertions, 55 deletions
diff --git a/Documentation/devicetree/bindings/bus/ti-gpmc.txt b/Documentation/devicetree/bindings/bus/ti-gpmc.txt index 4b87ea1..704be93 100644 --- a/Documentation/devicetree/bindings/bus/ti-gpmc.txt +++ b/Documentation/devicetree/bindings/bus/ti-gpmc.txt @@ -95,7 +95,6 @@ GPMC chip-select settings properties for child nodes. All are optional. - gpmc,burst-wrap Enables wrap bursting - gpmc,burst-read Enables read page/burst mode - gpmc,burst-write Enables write page/burst mode -- gpmc,device-nand Device is NAND - gpmc,device-width Total width of device(s) connected to a GPMC chip-select in bytes. The GPMC supports 8-bit and 16-bit devices and so this property must be diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt index 6a983c1..df338cb 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt @@ -29,6 +29,13 @@ Optional properties: "bch4" 4-bit BCH ecc code "bch8" 8-bit BCH ecc code + - ti,nand-xfer-type: A string setting the data transfer type. One of: + + "prefetch-polled" Prefetch polled mode (default) + "polled" Polled mode, without prefetch + "prefetch-dma" Prefetch enabled sDMA mode + "prefetch-irq" Prefetch enabled irq mode + - elm_id: Specifies elm device node. This is required to support BCH error correction using ELM module. @@ -55,6 +62,7 @@ Example for an AM33xx board: reg = <0 0 0>; /* CS0, offset 0 */ nand-bus-width = <16>; ti,nand-ecc-opt = "bch8"; + ti,nand-xfer-type = "polled"; gpmc,sync-clk-ps = <0>; gpmc,cs-on-ns = <0>; diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts index 144ae43..6076d01 100644 --- a/arch/arm/boot/dts/omap3430-sdp.dts +++ b/arch/arm/boot/dts/omap3430-sdp.dts @@ -105,7 +105,6 @@ nand-bus-width = <8>; ti,nand-ecc-opt = "sw"; - gpmc,device-nand; gpmc,cs-on-ns = <0>; gpmc,cs-rd-off-ns = <36>; gpmc,cs-wr-off-ns = <36>; diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c index c33adea..fc20a61 100644 --- a/arch/arm/mach-omap2/board-flash.c +++ b/arch/arm/mach-omap2/board-flash.c @@ -112,6 +112,9 @@ struct gpmc_timings nand_default_timings[1] = { .cs_rd_off = 36, .cs_wr_off = 36, + .we_on = 6, + .oe_on = 6, + .adv_on = 6, .adv_rd_off = 24, .adv_wr_off = 36, diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index d9c2719..662c7fd 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -43,44 +43,6 @@ static struct platform_device gpmc_nand_device = { .resource = gpmc_nand_resource, }; -static int omap2_nand_gpmc_retime( - struct omap_nand_platform_data *gpmc_nand_data, - struct gpmc_timings *gpmc_t) -{ - struct gpmc_timings t; - int err; - - memset(&t, 0, sizeof(t)); - t.sync_clk = gpmc_t->sync_clk; - t.cs_on = gpmc_t->cs_on; - t.adv_on = gpmc_t->adv_on; - - /* Read */ - t.adv_rd_off = gpmc_t->adv_rd_off; - t.oe_on = t.adv_on; - t.access = gpmc_t->access; - t.oe_off = gpmc_t->oe_off; - t.cs_rd_off = gpmc_t->cs_rd_off; - t.rd_cycle = gpmc_t->rd_cycle; - - /* Write */ - t.adv_wr_off = gpmc_t->adv_wr_off; - t.we_on = t.oe_on; - if (cpu_is_omap34xx()) { - t.wr_data_mux_bus = gpmc_t->wr_data_mux_bus; - t.wr_access = gpmc_t->wr_access; - } - t.we_off = gpmc_t->we_off; - t.cs_wr_off = gpmc_t->cs_wr_off; - t.wr_cycle = gpmc_t->wr_cycle; - - err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); - if (err) - return err; - - return 0; -} - static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) { /* support only OMAP3 class */ @@ -131,7 +93,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); if (gpmc_t) { - err = omap2_nand_gpmc_retime(gpmc_nand_data, gpmc_t); + err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t); if (err < 0) { dev_err(dev, "Unable to set gpmc timings: %d\n", err); return err; @@ -140,8 +102,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, 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; @@ -149,6 +109,8 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, } } + s.device_nand = true; + if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) s.device_width = GPMC_DEVWIDTH_16BIT; else diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 6c4da12..bac18b3 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -30,6 +30,7 @@ #include <linux/of_mtd.h> #include <linux/of_device.h> #include <linux/mtd/nand.h> +#include <linux/pm_runtime.h> #include <linux/platform_data/mtd-nand-omap2.h> @@ -155,6 +156,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_cs_num = GPMC_CS_NUM; static unsigned int gpmc_nr_waitpins; static struct device *gpmc_dev; static int gpmc_irq; @@ -521,8 +523,10 @@ static int gpmc_cs_remap(int cs, u32 base) int ret; u32 old_base, size; - if (cs > GPMC_CS_NUM) + if (cs > gpmc_cs_num) { + pr_err("%s: requested chip-select is disabled\n", __func__); return -ENODEV; + } gpmc_cs_get_memconf(cs, &old_base, &size); if (base == old_base) return 0; @@ -545,9 +549,10 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) struct resource *res = &gpmc_cs_mem[cs]; int r = -1; - if (cs > GPMC_CS_NUM) + if (cs > gpmc_cs_num) { + pr_err("%s: requested chip-select is disabled\n", __func__); return -ENODEV; - + } size = gpmc_mem_align(size); if (size > (1 << GPMC_SECTION_SHIFT)) return -ENOMEM; @@ -582,7 +587,7 @@ EXPORT_SYMBOL(gpmc_cs_request); void gpmc_cs_free(int cs) { spin_lock(&gpmc_mem_lock); - if (cs >= GPMC_CS_NUM || cs < 0 || !gpmc_cs_reserved(cs)) { + if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) { printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs); BUG(); spin_unlock(&gpmc_mem_lock); @@ -777,7 +782,7 @@ static void gpmc_mem_exit(void) { int cs; - for (cs = 0; cs < GPMC_CS_NUM; cs++) { + for (cs = 0; cs < gpmc_cs_num; cs++) { if (!gpmc_cs_mem_enabled(cs)) continue; gpmc_cs_delete_mem(cs); @@ -798,7 +803,7 @@ static void gpmc_mem_init(void) gpmc_mem_root.end = GPMC_MEM_END; /* Reserve all regions that has been set up by bootloader */ - for (cs = 0; cs < GPMC_CS_NUM; cs++) { + for (cs = 0; cs < gpmc_cs_num; cs++) { u32 base, size; if (!gpmc_cs_mem_enabled(cs)) @@ -1245,7 +1250,6 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p) 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); @@ -1345,6 +1349,13 @@ static const char * const nand_ecc_opts[] = { [OMAP_ECC_BCH8_CODE_HW] = "bch8", }; +static const char * const nand_xfer_types[] = { + [NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled", + [NAND_OMAP_POLLED] = "polled", + [NAND_OMAP_PREFETCH_DMA] = "prefetch-dma", + [NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq", +}; + static int gpmc_probe_nand_child(struct platform_device *pdev, struct device_node *child) { @@ -1374,6 +1385,13 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, break; } + if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) + for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++) + if (!strcasecmp(s, nand_xfer_types[val])) { + gpmc_nand_data->xfer_type = val; + break; + } + val = of_get_nand_bus_width(child); if (val == 16) gpmc_nand_data->devsize = NAND_BUSWIDTH_16; @@ -1513,6 +1531,20 @@ 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-cs", + &gpmc_cs_num); + if (ret < 0) { + pr_err("%s: number of chip-selects not defined\n", __func__); + return ret; + } else if (gpmc_cs_num < 1) { + pr_err("%s: all chip-selects are disabled\n", __func__); + return -EINVAL; + } else if (gpmc_cs_num > GPMC_CS_NUM) { + pr_err("%s: number of supported chip-selects cannot be > %d\n", + __func__, GPMC_CS_NUM); + return -EINVAL; + } + ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins", &gpmc_nr_waitpins); if (ret < 0) { @@ -1577,7 +1609,8 @@ static int gpmc_probe(struct platform_device *pdev) return PTR_ERR(gpmc_l3_clk); } - clk_prepare_enable(gpmc_l3_clk); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); gpmc_dev = &pdev->dev; @@ -1610,12 +1643,14 @@ 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) + if (!pdev->dev.of_node) { + gpmc_cs_num = GPMC_CS_NUM; gpmc_nr_waitpins = GPMC_NR_WAITPINS; + } rc = gpmc_probe_dt(pdev); if (rc < 0) { - clk_disable_unprepare(gpmc_l3_clk); + pm_runtime_put_sync(&pdev->dev); clk_put(gpmc_l3_clk); dev_err(gpmc_dev, "failed to probe DT parameters\n"); return rc; @@ -1628,6 +1663,8 @@ static int gpmc_remove(struct platform_device *pdev) { gpmc_free_irq(); gpmc_mem_exit(); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); gpmc_dev = NULL; return 0; } @@ -1715,7 +1752,7 @@ void omap3_gpmc_save_context(void) gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1); gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2); gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL); - for (i = 0; i < GPMC_CS_NUM; i++) { + for (i = 0; i < gpmc_cs_num; i++) { gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i); if (gpmc_context.cs_context[i].is_valid) { gpmc_context.cs_context[i].config1 = @@ -1747,7 +1784,7 @@ void omap3_gpmc_restore_context(void) gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1); gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2); gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control); - for (i = 0; i < GPMC_CS_NUM; i++) { + for (i = 0; i < gpmc_cs_num; i++) { if (gpmc_context.cs_context[i].is_valid) { gpmc_cs_write_reg(i, GPMC_CS_CONFIG1, gpmc_context.cs_context[i].config1); |