mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v2] OMAP gpmc bus driver support
@ 2013-11-26 12:17 Sascha Hauer
  2013-11-26 12:17 ` [PATCH 1/3] string: Add (x)memdup Sascha Hauer
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Sascha Hauer @ 2013-11-26 12:17 UTC (permalink / raw)
  To: barebox

This adds OMAP gpmc bus driver support. Unlike the last version
this one sets the device_node of the registered nand device correctly
so that the partitions can be populated from the devicetree.

Sascha

----------------------------------------------------------------
Sascha Hauer (3):
      string: Add (x)memdup
      device: Add functions to add resources
      bus: Add omap gpmc driver

 arch/arm/mach-omap/include/mach/gpmc_nand.h |   3 +
 drivers/base/resource.c                     |  60 +++-
 drivers/bus/Kconfig                         |   6 +
 drivers/bus/Makefile                        |   1 +
 drivers/bus/omap-gpmc.c                     | 480 ++++++++++++++++++++++++++++
 include/driver.h                            |   9 +
 include/string.h                            |   2 +
 include/xfuncs.h                            |   1 +
 lib/string.c                                |  14 +
 lib/xfuncs.c                                |  10 +
 10 files changed, 573 insertions(+), 13 deletions(-)
 create mode 100644 drivers/bus/omap-gpmc.c

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 1/3] string: Add (x)memdup
  2013-11-26 12:17 [PATCH v2] OMAP gpmc bus driver support Sascha Hauer
@ 2013-11-26 12:17 ` Sascha Hauer
  2013-11-26 12:17 ` [PATCH 2/3] device: Add functions to add resources Sascha Hauer
  2013-11-26 12:17 ` [PATCH 3/3] bus: Add omap gpmc driver Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2013-11-26 12:17 UTC (permalink / raw)
  To: barebox

It's a common task to duplicate some memory. Add (x)memdup functions.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/string.h |  2 ++
 include/xfuncs.h |  1 +
 lib/string.c     | 14 ++++++++++++++
 lib/xfuncs.c     | 10 ++++++++++
 4 files changed, 27 insertions(+)

diff --git a/include/string.h b/include/string.h
index b906e15..a833da1 100644
--- a/include/string.h
+++ b/include/string.h
@@ -3,4 +3,6 @@
 
 #include <linux/string.h>
 
+void *memdup(const void *, size_t);
+
 #endif /* __STRING_H */
diff --git a/include/xfuncs.h b/include/xfuncs.h
index 261aaa5..8efc99d 100644
--- a/include/xfuncs.h
+++ b/include/xfuncs.h
@@ -8,5 +8,6 @@ void *xrealloc(void *ptr, size_t size);
 void *xzalloc(size_t size);
 char *xstrdup(const char *s);
 void* xmemalign(size_t alignment, size_t bytes);
+void* xmemdup(const void *orig, size_t size);
 
 #endif /* __XFUNCS_H */
diff --git a/lib/string.c b/lib/string.c
index eeec137..ceced7f 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -725,3 +725,17 @@ void *memchr_inv(const void *start, int c, size_t bytes)
 	return check_bytes8(start, value, bytes % 8);
 }
 EXPORT_SYMBOL(memchr_inv);
+
+void *memdup(const void *orig, size_t size)
+{
+	void *buf;
+
+	buf = malloc(size);
+	if (!buf)
+		return NULL;
+
+	memcpy(buf, orig, size);
+
+	return buf;
+}
+EXPORT_SYMBOL(memdup);
diff --git a/lib/xfuncs.c b/lib/xfuncs.c
index db85720..86d0013 100644
--- a/lib/xfuncs.c
+++ b/lib/xfuncs.c
@@ -75,3 +75,13 @@ void* xmemalign(size_t alignment, size_t bytes)
 	return p;
 }
 EXPORT_SYMBOL(xmemalign);
+
+void *xmemdup(const void *orig, size_t size)
+{
+	void *buf = xmalloc(size);
+
+	memcpy(buf, orig, size);
+
+	return buf;
+}
+EXPORT_SYMBOL(xmemdup);
-- 
1.8.4.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 2/3] device: Add functions to add resources
  2013-11-26 12:17 [PATCH v2] OMAP gpmc bus driver support Sascha Hauer
  2013-11-26 12:17 ` [PATCH 1/3] string: Add (x)memdup Sascha Hauer
@ 2013-11-26 12:17 ` Sascha Hauer
  2013-11-26 12:17 ` [PATCH 3/3] bus: Add omap gpmc driver Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2013-11-26 12:17 UTC (permalink / raw)
  To: barebox

We currently have functions to add a device based on function parameters.
This adds the corresponding functions to add resources to a device without
registering the device itself. This is useful to manipulate devices before
registering them.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/base/resource.c | 60 ++++++++++++++++++++++++++++++++++++++-----------
 include/driver.h        |  9 ++++++++
 2 files changed, 56 insertions(+), 13 deletions(-)

diff --git a/drivers/base/resource.c b/drivers/base/resource.c
index 2985c78..71ae0fe 100644
--- a/drivers/base/resource.c
+++ b/drivers/base/resource.c
@@ -20,33 +20,67 @@
 #include <common.h>
 #include <driver.h>
 #include <xfuncs.h>
+#include <malloc.h>
 
-static struct device_d *alloc_device(const char* devname, int id, void *pdata)
+struct device_d *device_alloc(const char *devname, int id)
 {
 	struct device_d *dev;
 
 	dev = xzalloc(sizeof(*dev));
 	strcpy(dev->name, devname);
 	dev->id = id;
-	dev->platform_data = pdata;
 
 	return dev;
 }
 
+int device_add_data(struct device_d *dev, void *data, size_t size)
+{
+	free(dev->platform_data);
+
+	if (data)
+		dev->platform_data = xmemdup(data, size);
+	else
+		dev->platform_data = NULL;
+
+	return 0;
+}
+
+int device_add_resources(struct device_d *dev, const struct resource *res, int num)
+{
+	dev->resource = xmemdup(res, sizeof(*res) * num);
+	dev->num_resources = num;
+
+	return 0;
+}
+
+int device_add_resource(struct device_d *dev, const char *resname,
+		resource_size_t start, resource_size_t size, unsigned int flags)
+{
+	struct resource res = {
+		.start = start,
+		.end = start + size - 1,
+		.flags = flags,
+	};
+
+	if (resname)
+		res.name = xstrdup(resname);
+
+	return device_add_resources(dev, &res, 1);
+}
+
 struct device_d *add_generic_device(const char* devname, int id, const char *resname,
 		resource_size_t start, resource_size_t size, unsigned int flags,
 		void *pdata)
 {
-	struct resource *res;
+	struct device_d *dev;
 
-	res = xzalloc(sizeof(struct resource));
-	if (resname)
-		res[0].name = xstrdup(resname);
-	res[0].start = start;
-	res[0].end = start + size - 1;
-	res[0].flags = flags;
+	dev = device_alloc(devname, id);
+	dev->platform_data = pdata;
+	device_add_resource(dev, resname, start, size, flags);
+
+	platform_device_register(dev);
 
-	return add_generic_device_res(devname, id, res, 1, pdata);
+	return dev;
 }
 EXPORT_SYMBOL(add_generic_device);
 
@@ -55,9 +89,9 @@ struct device_d *add_generic_device_res(const char* devname, int id,
 {
 	struct device_d *dev;
 
-	dev = alloc_device(devname, id, pdata);
-	dev->resource = res;
-	dev->num_resources = nb;
+	dev = device_alloc(devname, id);
+	dev->platform_data = pdata;
+	device_add_resources(dev, res, nb);
 
 	platform_device_register(dev);
 
diff --git a/include/driver.h b/include/driver.h
index 7f0532e..bbe789b 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -229,6 +229,15 @@ void *dev_get_mem_region(struct device_d *dev, int num);
  */
 void __iomem *dev_request_mem_region(struct device_d *dev, int num);
 
+struct device_d *device_alloc(const char *devname, int id);
+
+int device_add_resources(struct device_d *dev, const struct resource *res, int num);
+
+int device_add_resource(struct device_d *dev, const char *resname,
+		resource_size_t start, resource_size_t size, unsigned int flags);
+
+int device_add_data(struct device_d *dev, void *data, size_t size);
+
 /*
  * register a generic device
  * with only one resource
-- 
1.8.4.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 3/3] bus: Add omap gpmc driver
  2013-11-26 12:17 [PATCH v2] OMAP gpmc bus driver support Sascha Hauer
  2013-11-26 12:17 ` [PATCH 1/3] string: Add (x)memdup Sascha Hauer
  2013-11-26 12:17 ` [PATCH 2/3] device: Add functions to add resources Sascha Hauer
@ 2013-11-26 12:17 ` Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2013-11-26 12:17 UTC (permalink / raw)
  To: barebox

This adds a devicetree-only driver for to configure the gpmc and its
child devices from dt. Currently only NAND is supported.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-omap/include/mach/gpmc_nand.h |   3 +
 drivers/bus/Kconfig                         |   6 +
 drivers/bus/Makefile                        |   1 +
 drivers/bus/omap-gpmc.c                     | 480 ++++++++++++++++++++++++++++
 4 files changed, 490 insertions(+)
 create mode 100644 drivers/bus/omap-gpmc.c

diff --git a/arch/arm/mach-omap/include/mach/gpmc_nand.h b/arch/arm/mach-omap/include/mach/gpmc_nand.h
index 8d138ec..8839486 100644
--- a/arch/arm/mach-omap/include/mach/gpmc_nand.h
+++ b/arch/arm/mach-omap/include/mach/gpmc_nand.h
@@ -59,6 +59,9 @@ struct gpmc_nand_platform_data {
 	struct nand_ecclayout *oob;
 	/** gpmc config for nand */
 	struct gpmc_config *nand_cfg;
+
+	struct device_node *of_node;
+	struct device_node *elm_of_node;
 };
 
 int omap_add_gpmc_nand_device(struct gpmc_nand_platform_data *pdata);
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 5938d3f..b0d3c1f 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -4,4 +4,10 @@ config IMX_WEIM
 	depends on ARCH_IMX
 	bool "i.MX WEIM driver"
 
+config BUS_OMAP_GPMC
+	depends on ARCH_OMAP
+	depends on OFDEVICE
+	depends on OMAP_GPMC
+	bool "TI OMAP/AM33xx GPMC support"
+
 endmenu
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 42a8d49..f1c5ac7 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_IMX_WEIM) += imx-weim.o
+obj-$(CONFIG_BUS_OMAP_GPMC) += omap-gpmc.o
diff --git a/drivers/bus/omap-gpmc.c b/drivers/bus/omap-gpmc.c
new file mode 100644
index 0000000..6424785
--- /dev/null
+++ b/drivers/bus/omap-gpmc.c
@@ -0,0 +1,480 @@
+/*
+ * OMAP GPMC driver. Based upon the corresponding Linux Code
+ *
+ * Copyright (C) 2013 Sascha Hauer, Pengutronix, <s.hauer@pengutronix.de>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <init.h>
+#include <sizes.h>
+#include <io.h>
+#include <of.h>
+#include <of_address.h>
+#include <of_mtd.h>
+#include <linux/clk.h>
+#include <mach/gpmc_nand.h>
+#include <mach/gpmc.h>
+
+#define GPMC_CS_NUM	8
+#define GPMC_NR_WAITPINS		4
+
+#define GPMC_CONFIG1_WRAPBURST_SUPP		(1 << 31)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP		(1 << 30)
+#define GPMC_CONFIG1_READTYPE_ASYNC		(0 << 29)
+#define GPMC_CONFIG1_READTYPE_SYNC		(1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP		(1 << 28)
+#define GPMC_CONFIG1_WRITETYPE_ASYNC		(0 << 27)
+#define GPMC_CONFIG1_WRITETYPE_SYNC		(1 << 27)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME(val)	((val & 3) << 25)
+#define GPMC_CONFIG1_PAGE_LEN(val)		((val & 3) << 23)
+#define GPMC_CONFIG1_WAIT_READ_MON		(1 << 22)
+#define GPMC_CONFIG1_WAIT_WRITE_MON		(1 << 21)
+#define GPMC_CONFIG1_WAIT_MON_IIME(val)		((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_PIN_SEL(val)		((val & 3) << 16)
+#define GPMC_CONFIG1_DEVICESIZE(val)		((val & 3) << 12)
+#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_MUXTYPE(val)		((val & 3) << 8)
+#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))
+#define GPMC_CONFIG1_FCLK_DIV3			(GPMC_CONFIG1_FCLK_DIV(2))
+#define GPMC_CONFIG1_FCLK_DIV4			(GPMC_CONFIG1_FCLK_DIV(3))
+#define	GPMC_CONFIG2_CSEXTRADELAY		(1 << 7)
+#define	GPMC_CONFIG3_ADVEXTRADELAY		(1 << 7)
+#define	GPMC_CONFIG4_OEEXTRADELAY		(1 << 7)
+#define	GPMC_CONFIG4_WEEXTRADELAY		(1 << 23)
+#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	(1 << 6)
+#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	(1 << 7)
+#define GPMC_CONFIG7_CSVALID			(1 << 6)
+
+static unsigned int gpmc_cs_num = GPMC_CS_NUM;
+static unsigned int gpmc_nr_waitpins;
+static unsigned long gpmc_l3_clk = 100000000; /* This should be a proper clock */
+static void __iomem *gpmc_base;
+
+/* bool type time settings */
+struct gpmc_bool_timings {
+	bool cycle2cyclediffcsen;
+	bool cycle2cyclesamecsen;
+	bool we_extra_delay;
+	bool oe_extra_delay;
+	bool adv_extra_delay;
+	bool cs_extra_delay;
+	bool time_para_granularity;
+};
+
+/*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+ */
+struct gpmc_timings {
+	/* Minimum clock period for synchronous mode (in picoseconds) */
+	u32 sync_clk;
+
+	/* Chip-select signal timings corresponding to 1 */
+	u32 cs_on;		/* Assertion time */
+	u32 cs_rd_off;		/* Read deassertion time */
+	u32 cs_wr_off;		/* Write deassertion time */
+
+	/* ADV signal timings corresponding to GPMC_CONFIG3 */
+	u32 adv_on;		/* Assertion time */
+	u32 adv_rd_off;		/* Read deassertion time */
+	u32 adv_wr_off;		/* Write deassertion time */
+
+	/* WE signals timings corresponding to GPMC_CONFIG4 */
+	u32 we_on;		/* WE assertion time */
+	u32 we_off;		/* WE deassertion time */
+
+	/* OE signals timings corresponding to GPMC_CONFIG4 */
+	u32 oe_on;		/* OE assertion time */
+	u32 oe_off;		/* OE deassertion time */
+
+	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
+	u32 page_burst_access;	/* Multiple access word delay */
+	u32 access;		/* Start-cycle to first data valid delay */
+	u32 rd_cycle;		/* Total read cycle time */
+	u32 wr_cycle;		/* Total write cycle time */
+
+	u32 bus_turnaround;
+	u32 cycle2cycle_delay;
+
+	u32 wait_monitoring;
+	u32 clk_activation;
+
+	/* The following are only on OMAP3430 */
+	u32 wr_access;		/* WRACCESSTIME */
+	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+
+	struct gpmc_bool_timings bool_timings;
+};
+
+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 */
+};
+
+struct imx_gpmc {
+	struct device_d *dev;
+	void __iomem *base;
+	struct imx_gpmc_devtype *devtype;
+};
+
+static void gpmc_cs_bool_timings(struct gpmc_config *gpmc_config, const struct gpmc_bool_timings *p)
+{
+	if (p->time_para_granularity)
+		gpmc_config->cfg[0] |= GPMC_CONFIG1_TIME_PARA_GRAN;
+
+	if (p->cs_extra_delay)
+		gpmc_config->cfg[1] |= GPMC_CONFIG2_CSEXTRADELAY;
+	if (p->adv_extra_delay)
+		gpmc_config->cfg[2] |= GPMC_CONFIG3_ADVEXTRADELAY;
+	if (p->oe_extra_delay)
+		gpmc_config->cfg[3] |= GPMC_CONFIG4_OEEXTRADELAY;
+	if (p->we_extra_delay)
+		gpmc_config->cfg[3] |= GPMC_CONFIG4_OEEXTRADELAY;
+	if (p->cycle2cyclesamecsen)
+		gpmc_config->cfg[5] |= GPMC_CONFIG6_CYCLE2CYCLESAMECSEN;
+	if (p->cycle2cyclediffcsen)
+		gpmc_config->cfg[5] |= GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN;
+}
+
+static unsigned long gpmc_get_fclk_period(void)
+{
+	unsigned long rate = gpmc_l3_clk;
+
+	rate /= 1000;
+	rate = 1000000000 / rate;	/* In picoseconds */
+
+	return rate;
+}
+
+static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+{
+	unsigned long tick_ps;
+
+	/* Calculate in picosecs to yield more exact results */
+	tick_ps = gpmc_get_fclk_period();
+
+	return (time_ns * 1000 + tick_ps - 1) / tick_ps;
+}
+
+int gpmc_calc_divider(unsigned int sync_clk)
+{
+	int div;
+	u32 l;
+
+	l = sync_clk + (gpmc_get_fclk_period() - 1);
+	div = l / gpmc_get_fclk_period();
+	if (div > 4)
+		return -1;
+	if (div <= 0)
+		div = 1;
+
+	return div;
+}
+
+static int set_cfg(struct gpmc_config *gpmc_config, int reg,
+		int st_bit, int end_bit, int time)
+{
+	int ticks, mask, nr_bits;
+
+	if (time == 0)
+		ticks = 0;
+	else
+		ticks = gpmc_ns_to_ticks(time);
+
+	nr_bits = end_bit - st_bit + 1;
+	if (ticks >= 1 << nr_bits)
+		return -EINVAL;
+
+	mask = (1 << nr_bits) - 1;
+	gpmc_config->cfg[reg] &= ~(mask << st_bit);
+	gpmc_config->cfg[reg] |= ticks << st_bit;
+
+	return 0;
+}
+
+static int gpmc_timings_to_config(struct gpmc_config *gpmc_config, const struct gpmc_timings *t)
+{
+	int div, ret = 0;
+
+	div = gpmc_calc_divider(t->sync_clk);
+	if (div < 0)
+		return div;
+
+	ret |= set_cfg(gpmc_config, 0, 18, 19, t->wait_monitoring);
+	ret |= set_cfg(gpmc_config, 0, 25, 26, t->clk_activation);
+
+	ret |= set_cfg(gpmc_config, 1,  0,  3, t->cs_on);
+	ret |= set_cfg(gpmc_config, 1,  8, 12, t->cs_rd_off);
+	ret |= set_cfg(gpmc_config, 1, 16, 20, t->cs_wr_off);
+
+	ret |= set_cfg(gpmc_config, 2,  0,  3, t->adv_on);
+	ret |= set_cfg(gpmc_config, 2,  8, 12, t->adv_rd_off);
+	ret |= set_cfg(gpmc_config, 2, 16, 20, t->adv_wr_off);
+
+	ret |= set_cfg(gpmc_config, 3,  0,  3, t->oe_on);
+	ret |= set_cfg(gpmc_config, 3,  8, 12, t->oe_off);
+	ret |= set_cfg(gpmc_config, 3, 16, 19, t->we_on);
+	ret |= set_cfg(gpmc_config, 3, 24, 28, t->we_off);
+
+	ret |= set_cfg(gpmc_config, 4,  0,  4, t->rd_cycle);
+	ret |= set_cfg(gpmc_config, 4,  8, 12, t->wr_cycle);
+	ret |= set_cfg(gpmc_config, 4, 16, 20, t->access);
+
+	ret |= set_cfg(gpmc_config, 4, 24, 27, t->page_burst_access);
+
+	ret |= set_cfg(gpmc_config, 5, 0, 3, t->bus_turnaround);
+	ret |= set_cfg(gpmc_config, 5, 8, 11, t->cycle2cycle_delay);
+	ret |= set_cfg(gpmc_config, 5, 16, 19, t->wr_data_mux_bus);
+	ret |= set_cfg(gpmc_config, 5, 24, 28, t->wr_access);
+
+	if (ret)
+		return ret;
+
+	gpmc_cs_bool_timings(gpmc_config, &t->bool_timings);
+
+	return 0;
+}
+
+static void gpmc_read_timings_dt(struct device_node *np,
+						struct gpmc_timings *gpmc_t)
+{
+	struct gpmc_bool_timings *p;
+
+	if (!np || !gpmc_t)
+		return;
+
+	memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+	/* minimum clock period for syncronous mode */
+	of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
+
+	/* chip select timtings */
+	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 */
+	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 */
+	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 */
+	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 */
+	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");
+}
+
+struct dt_eccmode {
+	const char *name;
+	enum gpmc_ecc_mode mode;
+};
+
+static struct dt_eccmode modes[] = {
+	{
+		.name = "ham1",
+		.mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
+	}, {
+		.name = "sw",
+		.mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
+	}, {
+		.name = "hw",
+		.mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
+	}, {
+		.name = "hw-romcode",
+		.mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
+	}, {
+		.name = "bch4",
+		.mode = OMAP_ECC_BCH4_CODE_HW,
+	}, {
+		.name = "bch8",
+		.mode = OMAP_ECC_BCH8_CODE_HW,
+	}, {
+		.name = "bch8-romcode",
+		.mode = OMAP_ECC_BCH8_CODE_HW_ROMCODE,
+	},
+};
+
+static int gpmc_probe_nand_child(struct device_d *dev,
+				 struct device_node *child)
+{
+	u32 val;
+	const char *s;
+	struct gpmc_timings gpmc_t;
+	struct gpmc_nand_platform_data gpmc_nand_data = {};
+	struct resource res;
+	int ret, i;
+
+	if (of_property_read_u32(child, "reg", &val) < 0) {
+		dev_err(dev, "%s has no 'reg' property\n",
+			child->full_name);
+		return -ENODEV;
+	}
+
+	gpmc_base = dev_get_mem_region(dev, 0);
+	if (!gpmc_base)
+		return -ENODEV;
+
+	gpmc_nand_data.cs = val;
+	gpmc_nand_data.of_node = child;
+
+	/* Detect availability of ELM module */
+	gpmc_nand_data.elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
+	if (gpmc_nand_data.elm_of_node == NULL)
+		gpmc_nand_data.elm_of_node =
+					of_parse_phandle(child, "elm_id", 0);
+	if (gpmc_nand_data.elm_of_node == NULL)
+		pr_warn("%s: ti,elm-id property not found\n", __func__);
+
+	/* select ecc-scheme for NAND */
+	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
+		pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(modes); i++) {
+		struct dt_eccmode *mode = &modes[i];
+		if (!strcmp(s, mode->name))
+			gpmc_nand_data.ecc_mode = mode->mode;
+	}
+
+	val = of_get_nand_bus_width(child);
+	if (val == 16)
+		gpmc_nand_data.device_width = NAND_BUSWIDTH_16;
+
+	gpmc_read_timings_dt(child, &gpmc_t);
+
+	gpmc_nand_data.nand_cfg = xzalloc(sizeof(*gpmc_nand_data.nand_cfg));
+
+	gpmc_timings_to_config(gpmc_nand_data.nand_cfg, &gpmc_t);
+
+	gpmc_nand_data.nand_cfg->cfg[0] |= 2 << 10;
+
+	ret = of_address_to_resource(child, 0, &res);
+	if (ret)
+		pr_err("of_address_to_resource failed\n");
+
+	gpmc_nand_data.nand_cfg->base = res.start;
+	gpmc_nand_data.nand_cfg->size = GPMC_SIZE_16M;
+
+	gpmc_cs_config(gpmc_nand_data.cs, gpmc_nand_data.nand_cfg);
+
+	dev = device_alloc("gpmc_nand", DEVICE_ID_DYNAMIC);
+	device_add_resource(dev, NULL, (resource_size_t)gpmc_base, SZ_4K, IORESOURCE_MEM);
+	device_add_data(dev, &gpmc_nand_data, sizeof(gpmc_nand_data));
+	dev->device_node = child;
+	platform_device_register(dev);
+
+	return 0;
+}
+
+static int gpmc_probe(struct device_d *dev)
+{
+	struct device_node *child, *node = dev->device_node;
+	int ret;
+
+	gpmc_generic_init(0x12);
+
+	ret = of_property_read_u32(node, "gpmc,num-cs",
+				   &gpmc_cs_num);
+	if (ret < 0)
+		return ret;
+
+	ret = of_property_read_u32(node, "gpmc,num-waitpins",
+				   &gpmc_nr_waitpins);
+	if (ret < 0)
+		return ret;
+
+	for_each_child_of_node(node, child) {
+
+		if (!child->name)
+			continue;
+
+		if (!strncmp(child->name, "nand", 4))
+			ret = gpmc_probe_nand_child(dev, child);
+		else
+			dev_warn(dev, "unhandled child %s\n", child->name);
+
+		if (ret)
+			break;
+	}
+
+	if (ret)
+		goto gpmc_err;
+
+	return 0;
+
+gpmc_err:
+	return ret;
+}
+
+static struct of_device_id gpmc_id_table[] = {
+	{ .compatible = "ti,omap2420-gpmc" },
+	{ .compatible = "ti,omap2430-gpmc" },
+	{ .compatible = "ti,omap3430-gpmc" },	/* omap3430 & omap3630 */
+	{ .compatible = "ti,omap4430-gpmc" },	/* omap4430 & omap4460 & omap543x */
+	{ .compatible = "ti,am3352-gpmc" },	/* am335x devices */
+	{ }
+};
+
+static struct driver_d gpmc_driver = {
+	.name = "omap-gpmc",
+	.of_compatible = DRV_OF_COMPAT(gpmc_id_table),
+	.probe   = gpmc_probe,
+};
+device_platform_driver(gpmc_driver);
-- 
1.8.4.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2013-11-26 12:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-26 12:17 [PATCH v2] OMAP gpmc bus driver support Sascha Hauer
2013-11-26 12:17 ` [PATCH 1/3] string: Add (x)memdup Sascha Hauer
2013-11-26 12:17 ` [PATCH 2/3] device: Add functions to add resources Sascha Hauer
2013-11-26 12:17 ` [PATCH 3/3] bus: Add omap gpmc driver Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox