devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Matt Porter <mporter-l0cyMroinI0@public.gmane.org>
To: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>,
	Sekhar Nori <nsekhar-l0cyMroinI0@public.gmane.org>,
	Grant Likely
	<grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org>,
	Mark Brown
	<broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>,
	Benoit Cousson <b-cousson-l0cyMroinI0@public.gmane.org>,
	Russell King <linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>,
	Vinod Koul <vinod.koul-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>,
	Rob Landley <rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org>,
	Chris Ball <cjb-2X9k7bc8m7Mdnm+yROfE0A@public.gmane.org>
Cc: Linux DaVinci Kernel List
	<davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org>,
	Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>,
	Linux Documentation List
	<linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Devicetree Discuss
	<devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org>,
	Linux MMC List
	<linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Linux Kernel Mailing List
	<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Rob Herring <rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>,
	Dan Williams <djbw-b10kYP2dOMg@public.gmane.org>,
	Linux SPI Devel List
	<spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>,
	Linux OMAP List
	<linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Linux ARM Kernel List
	<linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>
Subject: [PATCH v5 03/14] ARM: edma: add AM33XX support to the private EDMA API
Date: Tue, 15 Jan 2013 15:32:43 -0500	[thread overview]
Message-ID: <1358281974-8411-4-git-send-email-mporter@ti.com> (raw)
In-Reply-To: <1358281974-8411-1-git-send-email-mporter-l0cyMroinI0@public.gmane.org>

Adds support for parsing the TI EDMA DT data into the required
EDMA private API platform data. Enables runtime PM support to
initialize the EDMA hwmod. Adds AM33XX EMDA crossbar event mux
support.

Signed-off-by: Matt Porter <mporter-l0cyMroinI0@public.gmane.org>
---
 arch/arm/common/edma.c             |  314 ++++++++++++++++++++++++++++++++++--
 include/linux/platform_data/edma.h |    1 +
 2 files changed, 306 insertions(+), 9 deletions(-)

diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
index 2dce245..beeb1d2 100644
--- a/arch/arm/common/edma.c
+++ b/arch/arm/common/edma.c
@@ -24,6 +24,13 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/edma.h>
+#include <linux/err.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/of_irq.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/platform_data/edma.h>
 
@@ -723,6 +730,9 @@ EXPORT_SYMBOL(edma_free_channel);
  */
 int edma_alloc_slot(unsigned ctlr, int slot)
 {
+	if (!edma_cc[ctlr])
+		return -EINVAL;
+
 	if (slot >= 0)
 		slot = EDMA_CHAN_SLOT(slot);
 
@@ -1366,31 +1376,291 @@ void edma_clear_event(unsigned channel)
 EXPORT_SYMBOL(edma_clear_event);
 
 /*-----------------------------------------------------------------------*/
+static int edma_of_read_u32_to_s8_array(const struct device_node *np,
+					 const char *propname, s8 *out_values,
+					 size_t sz)
+{
+	struct property *prop = of_find_property(np, propname, NULL);
+	const __be32 *val;
+
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+	if ((sz * sizeof(u32)) > prop->length)
+		return -EOVERFLOW;
+
+	val = prop->value;
+
+	while (sz--)
+		*out_values++ = (s8)(be32_to_cpup(val++) & 0xff);
+
+	/* Terminate it */
+	*out_values++ = -1;
+	*out_values++ = -1;
+
+	return 0;
+}
+
+static int edma_of_read_u32_to_s16_array(const struct device_node *np,
+					 const char *propname, s16 *out_values,
+					 size_t sz)
+{
+	struct property *prop = of_find_property(np, propname, NULL);
+	const __be32 *val;
+
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+	if ((sz * sizeof(u32)) > prop->length)
+		return -EOVERFLOW;
+
+	val = prop->value;
+
+	while (sz--)
+		*out_values++ = (s16)(be32_to_cpup(val++) & 0xffff);
+
+	/* Terminate it */
+	*out_values++ = -1;
+	*out_values++ = -1;
+
+	return 0;
+}
+
+static int edma_xbar_event_map(struct device *dev,
+			       struct device_node *node,
+			       struct edma_soc_info *pdata, int len)
+{
+	int ret = 0;
+	int i;
+	struct resource res;
+	void *xbar;
+	const s16 (*xbar_chans)[2];
+	u32 shift, offset, mux;
+
+	xbar_chans = devm_kzalloc(dev,
+				  len/sizeof(s16) + 2*sizeof(s16),
+				  GFP_KERNEL);
+	if (!xbar_chans)
+		return -ENOMEM;
+
+	ret = of_address_to_resource(node, 1, &res);
+	if (IS_ERR_VALUE(ret))
+		return -EIO;
+
+	xbar = devm_ioremap(dev, res.start, resource_size(&res));
+	if (!xbar)
+		return -ENOMEM;
+
+	ret = edma_of_read_u32_to_s16_array(node,
+					    "ti,edma-xbar-event-map",
+					    (s16 *)xbar_chans,
+					    len/sizeof(u32));
+	if (IS_ERR_VALUE(ret))
+		return -EIO;
+
+	for (i = 0; xbar_chans[i][0] != -1; i++) {
+		shift = (xbar_chans[i][1] % 4) * 8;
+		offset = xbar_chans[i][1] >> 2;
+		offset <<= 2;
+		mux = readl((void *)((u32)xbar + offset));
+		mux &= ~(0xff << shift);
+		mux |= xbar_chans[i][0] << shift;
+		writel(mux, (void *)((u32)xbar + offset));
+	}
+
+	pdata->xbar_chans = xbar_chans;
+
+	return 0;
+}
+
+static int edma_of_parse_dt(struct device *dev,
+			    struct device_node *node,
+			    struct edma_soc_info *pdata)
+{
+	int ret = 0;
+	u32 value;
+	struct property *prop;
+	size_t sz;
+	struct edma_rsv_info *rsv_info;
+	const s16 (*rsv_chans)[2], (*rsv_slots)[2];
+	const s8 (*queue_tc_map)[2], (*queue_priority_map)[2];
+
+	memset(pdata, 0, sizeof(struct edma_soc_info));
+
+	ret = of_property_read_u32(node, "dma-channels", &value);
+	if (ret < 0)
+		return ret;
+	pdata->n_channel = value;
+
+	ret = of_property_read_u32(node, "ti,edma-regions", &value);
+	if (ret < 0)
+		return ret;
+	pdata->n_region = value;
+
+	ret = of_property_read_u32(node, "ti,edma-slots", &value);
+	if (ret < 0)
+		return ret;
+	pdata->n_slot = value;
+
+	pdata->n_cc = 1;
+	pdata->n_tc = 3;
+
+	rsv_info =
+		devm_kzalloc(dev, sizeof(struct edma_rsv_info), GFP_KERNEL);
+	if (!rsv_info)
+		return -ENOMEM;
+	pdata->rsv = rsv_info;
+
+	/* Build the reserved channel/slots arrays */
+	prop = of_find_property(node, "ti,edma-reserved-channels", &sz);
+	if (prop) {
+		rsv_chans = devm_kzalloc(dev,
+					 sz/sizeof(s16) + 2*sizeof(s16),
+					 GFP_KERNEL);
+		if (!rsv_chans)
+			return -ENOMEM;
+		pdata->rsv->rsv_chans = rsv_chans;
+
+		ret = edma_of_read_u32_to_s16_array(node,
+						    "ti,edma-reserved-channels",
+						    (s16 *)rsv_chans,
+						    sz/sizeof(u32));
+		if (ret < 0)
+			return ret;
+	}
+
+	prop = of_find_property(node, "ti,edma-reserved-slots", &sz);
+	if (prop) {
+		rsv_slots = devm_kzalloc(dev,
+					 sz/sizeof(s16) + 2*sizeof(s16),
+					 GFP_KERNEL);
+		if (!rsv_slots)
+			return -ENOMEM;
+		pdata->rsv->rsv_slots = rsv_slots;
+
+		ret = edma_of_read_u32_to_s16_array(node,
+						    "ti,edma-reserved-slots",
+						    (s16 *)rsv_slots,
+						    sz/sizeof(u32));
+		if (ret < 0)
+			return ret;
+	}
+
+	prop = of_find_property(node, "ti,edma-queue-tc-map", &sz);
+	if (!prop)
+		return -EINVAL;
+
+	queue_tc_map = devm_kzalloc(dev,
+				    sz/sizeof(s8) + 2*sizeof(s8),
+				    GFP_KERNEL);
+	if (!queue_tc_map)
+		return -ENOMEM;
+	pdata->queue_tc_mapping = queue_tc_map;
+
+	ret = edma_of_read_u32_to_s8_array(node,
+					   "ti,edma-queue-tc-map",
+					   (s8 *)queue_tc_map,
+					   sz/sizeof(u32));
+	if (ret < 0)
+		return ret;
+
+	prop = of_find_property(node, "ti,edma-queue-priority-map", &sz);
+	if (!prop)
+		return -EINVAL;
+
+	queue_priority_map = devm_kzalloc(dev,
+					  sz/sizeof(s8) + 2*sizeof(s8),
+					  GFP_KERNEL);
+	if (!queue_priority_map)
+		return -ENOMEM;
+	pdata->queue_priority_mapping = queue_priority_map;
+
+	ret = edma_of_read_u32_to_s8_array(node,
+					   "ti,edma-queue-tc-map",
+					   (s8 *)queue_priority_map,
+					   sz/sizeof(u32));
+	if (ret < 0)
+		return ret;
+
+	ret = of_property_read_u32(node, "ti,edma-default-queue", &value);
+	if (ret < 0)
+		return ret;
+	pdata->default_queue = value;
+
+	prop = of_find_property(node, "ti,edma-xbar-event-map", &sz);
+	if (prop)
+		ret = edma_xbar_event_map(dev, node, pdata, sz);
+
+	return ret;
+}
+
+static struct of_dma_filter_info edma_filter_info = {
+	.filter_fn = edma_filter_fn,
+};
 
 static int edma_probe(struct platform_device *pdev)
 {
 	struct edma_soc_info	**info = pdev->dev.platform_data;
+	struct edma_soc_info	*ninfo[EDMA_MAX_CC] = {NULL, NULL};
+	struct edma_soc_info	tmpinfo;
 	const s8		(*queue_priority_mapping)[2];
 	const s8		(*queue_tc_mapping)[2];
 	int			i, j, off, ln, found = 0;
 	int			status = -1;
 	const s16		(*rsv_chans)[2];
 	const s16		(*rsv_slots)[2];
+	const s16		(*xbar_chans)[2];
 	int			irq[EDMA_MAX_CC] = {0, 0};
 	int			err_irq[EDMA_MAX_CC] = {0, 0};
-	struct resource		*r[EDMA_MAX_CC] = {NULL};
+	struct resource		*r[EDMA_MAX_CC] = {NULL, NULL};
+	struct resource		res[EDMA_MAX_CC];
 	resource_size_t		len[EDMA_MAX_CC];
 	char			res_name[10];
 	char			irq_name[10];
+	struct device_node	*node = pdev->dev.of_node;
+	struct device		*dev = &pdev->dev;
+	int			ret;
+
+	if (node) {
+		info = ninfo;
+		edma_of_parse_dt(dev, node, &tmpinfo);
+		info[0] = &tmpinfo;
+
+		dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap);
+		of_dma_controller_register(dev->of_node,
+					   of_dma_simple_xlate,
+					   &edma_filter_info);
+	}
 
 	if (!info)
 		return -ENODEV;
 
+	pm_runtime_enable(dev);
+	ret = pm_runtime_get_sync(dev);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(dev, "pm_runtime_get_sync() failed\n");
+		return ret;
+	}
+
 	for (j = 0; j < EDMA_MAX_CC; j++) {
-		sprintf(res_name, "edma_cc%d", j);
-		r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+		if (!info[j]) {
+			if (!found)
+				return -ENODEV;
+			break;
+		}
+		if (node) {
+			ret = of_address_to_resource(node, j, &res[j]);
+			if (!IS_ERR_VALUE(ret))
+				r[j] = &res[j];
+		} else {
+			sprintf(res_name, "edma_cc%d", j);
+			r[j] = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM,
 						res_name);
-		if (!r[j] || !info[j]) {
+		}
+		if (!r[j]) {
 			if (found)
 				break;
 			else
@@ -1465,8 +1735,22 @@ static int edma_probe(struct platform_device *pdev)
 			}
 		}
 
-		sprintf(irq_name, "edma%d", j);
-		irq[j] = platform_get_irq_byname(pdev, irq_name);
+		/* Clear the xbar mapped channels in unused list */
+		xbar_chans = info[j]->xbar_chans;
+		if (xbar_chans) {
+			for (i = 0; xbar_chans[i][1] != -1; i++) {
+				off = xbar_chans[i][1];
+				clear_bits(off, 1,
+					edma_cc[j]->edma_unused);
+			}
+		}
+
+		if (node)
+			irq[j] = irq_of_parse_and_map(node, 0);
+		else {
+			sprintf(irq_name, "edma%d", j);
+			irq[j] = platform_get_irq_byname(pdev, irq_name);
+		}
 		edma_cc[j]->irq_res_start = irq[j];
 		status = request_irq(irq[j], dma_irq_handler, 0, "edma",
 					&pdev->dev);
@@ -1476,8 +1760,12 @@ static int edma_probe(struct platform_device *pdev)
 			goto fail;
 		}
 
-		sprintf(irq_name, "edma%d_err", j);
-		err_irq[j] = platform_get_irq_byname(pdev, irq_name);
+		if (node)
+			err_irq[j] = irq_of_parse_and_map(node, 2);
+		else {
+			sprintf(irq_name, "edma%d_err", j);
+			err_irq[j] = platform_get_irq_byname(pdev, irq_name);
+		}
 		edma_cc[j]->irq_res_end = err_irq[j];
 		status = request_irq(err_irq[j], dma_ccerr_handler, 0,
 					"edma_error", &pdev->dev);
@@ -1538,9 +1826,17 @@ fail1:
 	return status;
 }
 
+static const struct of_device_id edma_of_ids[] = {
+	{ .compatible = "ti,edma3", },
+	{}
+};
 
 static struct platform_driver edma_driver = {
-	.driver.name	= "edma",
+	.driver = {
+		.name	= "edma",
+		.of_match_table = edma_of_ids,
+	},
+	.probe = edma_probe,
 };
 
 static int __init edma_init(void)
diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h
index 2344ea2..ffc1fb2 100644
--- a/include/linux/platform_data/edma.h
+++ b/include/linux/platform_data/edma.h
@@ -177,6 +177,7 @@ struct edma_soc_info {
 
 	const s8	(*queue_tc_mapping)[2];
 	const s8	(*queue_priority_mapping)[2];
+	const s16	(*xbar_chans)[2];
 };
 
 #endif
-- 
1.7.9.5


------------------------------------------------------------------------------
Master SQL Server Development, Administration, T-SQL, SSAS, SSIS, SSRS
and more. Get SQL Server skills now (including 2012) with LearnDevNow -
200+ hours of step-by-step video tutorials by Microsoft MVPs and experts.
SALE $99.99 this month only - learn more at:
http://p.sf.net/sfu/learnmore_122512

  parent reply	other threads:[~2013-01-15 20:32 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-15 20:32 [PATCH v5 00/14] DMA Engine support for AM33XX Matt Porter
     [not found] ` <1358281974-8411-1-git-send-email-mporter-l0cyMroinI0@public.gmane.org>
2013-01-15 20:32   ` [PATCH v5 01/14] ARM: davinci: move private EDMA API to arm/common Matt Porter
2013-01-15 20:32   ` [PATCH v5 02/14] ARM: edma: remove unused transfer controller handlers Matt Porter
2013-01-15 20:32   ` Matt Porter [this message]
2013-01-28 19:27     ` [PATCH v5 03/14] ARM: edma: add AM33XX support to the private EDMA API Andy Shevchenko
     [not found]       ` <CAHp75VeFZ19CCL-4huLNWbsXT-8sGrcvtxN=Dm0s+ojNA3w-3g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-01-30  6:41         ` Matt Porter
2013-01-30  7:40           ` Andy Shevchenko
2013-01-31  1:31             ` Matt Porter
2013-01-15 20:32   ` [PATCH v5 04/14] dmaengine: edma: enable build for AM33XX Matt Porter
2013-01-15 20:32   ` [PATCH v5 05/14] dmaengine: edma: Add TI EDMA device tree binding Matt Porter
2013-01-15 20:32   ` [PATCH v5 06/14] ARM: dts: add AM33XX EDMA support Matt Porter
2013-01-15 20:32   ` [PATCH v5 07/14] dmaengine: add dma_request_slave_channel_compat() Matt Porter
     [not found]     ` <1358281974-8411-8-git-send-email-mporter-l0cyMroinI0@public.gmane.org>
2013-01-23 22:28       ` Arnd Bergmann
2013-01-30  6:36         ` Matt Porter
2013-01-28 19:34     ` Andy Shevchenko
     [not found]       ` <CAHp75VeqikcTuOd14utb9E0P3b9t1mr=JsmkAbz5=3FJwU2kFA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-01-28 19:57         ` Arnd Bergmann
2013-01-15 20:32   ` [PATCH v5 08/14] mmc: omap_hsmmc: convert to dma_request_slave_channel_compat() Matt Porter
2013-01-15 20:32   ` [PATCH v5 09/14] mmc: omap_hsmmc: set max_segs based on dma engine limitations Matt Porter
2013-01-15 20:32   ` [PATCH v5 10/14] mmc: omap_hsmmc: add generic DMA request support to the DT binding Matt Porter
2013-01-15 20:32   ` [PATCH v5 11/14] ARM: dts: add AM33XX MMC support Matt Porter
2013-01-15 20:32   ` [PATCH v5 12/14] spi: omap2-mcspi: convert to dma_request_slave_channel_compat() Matt Porter
2013-01-15 20:32   ` [PATCH v5 13/14] spi: omap2-mcspi: add generic DMA request support to the DT binding Matt Porter
2013-01-15 20:32   ` [PATCH v5 14/14] ARM: dts: add AM33XX SPI DMA support Matt Porter
2013-01-22 15:56   ` [PATCH v5 00/14] DMA Engine support for AM33XX Sekhar Nori
2013-01-23  2:21     ` Mark Brown
     [not found]       ` <20130123022133.GA5727-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
2013-01-23 10:49         ` Sekhar Nori
2013-01-23 21:37         ` Matt Porter
2013-01-24  5:14           ` Sekhar Nori
     [not found]           ` <d07dbfd50690423b903803720152c0dc@DLEE74.ent.ti.com>
2013-01-24 20:42             ` Matt Porter
2013-01-23 11:07   ` Santosh Shilimkar
     [not found]     ` <50FFC48B.80902-l0cyMroinI0@public.gmane.org>
2013-01-23 20:49       ` Matt Porter
2013-01-24  5:12         ` Santosh Shilimkar
     [not found]         ` <8ea1d227d84648f68e670c56f27c481e@DFLE72.ent.ti.com>
2013-01-24 20:49           ` Matt Porter
2013-01-25  7:02             ` Santosh Shilimkar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1358281974-8411-4-git-send-email-mporter@ti.com \
    --to=mporter-l0cymroini0@public.gmane.org \
    --cc=arnd-r2nGTMty4D4@public.gmane.org \
    --cc=b-cousson-l0cyMroinI0@public.gmane.org \
    --cc=broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org \
    --cc=cjb-2X9k7bc8m7Mdnm+yROfE0A@public.gmane.org \
    --cc=davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org \
    --cc=devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org \
    --cc=djbw-b10kYP2dOMg@public.gmane.org \
    --cc=grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org \
    --cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
    --cc=linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org \
    --cc=linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=nsekhar-l0cyMroinI0@public.gmane.org \
    --cc=rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org \
    --cc=rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org \
    --cc=spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    --cc=tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org \
    --cc=vinod.koul-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).