Browse Source

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>
Olof Johansson 12 years ago
parent
commit
f54ffe0fef

+ 0 - 1
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

+ 8 - 0
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>;

+ 0 - 1
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>;

+ 3 - 0
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,

+ 3 - 41
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

+ 49 - 12
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);