diff mbox

[v2,3/7] dmaengine: Add driver for TI DMA crossbar on DRA7x

Message ID 1426080210-841-4-git-send-email-peter.ujfalusi@ti.com (mailing list archive)
State Superseded
Headers show

Commit Message

Peter Ujfalusi March 11, 2015, 1:23 p.m. UTC
The DRA7x has more peripherals with DMA requests than the sDMA can handle:
205 vs 127. All DMA requests are routed through the DMA crossbar, which can
be configured to route selected incoming DMA requests to specific sDMA
request.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 drivers/dma/Kconfig           |   4 +
 drivers/dma/Makefile          |   1 +
 drivers/dma/ti-dma-crossbar.c | 190 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 195 insertions(+)
 create mode 100644 drivers/dma/ti-dma-crossbar.c

Comments

Vinod Koul March 26, 2015, 10:56 a.m. UTC | #1
On Wed, Mar 11, 2015 at 03:23:26PM +0200, Peter Ujfalusi wrote:
> The DRA7x has more peripherals with DMA requests than the sDMA can handle:
> 205 vs 127. All DMA requests are routed through the DMA crossbar, which can
> be configured to route selected incoming DMA requests to specific sDMA
> request.
> 
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> ---
>  drivers/dma/Kconfig           |   4 +
>  drivers/dma/Makefile          |   1 +
>  drivers/dma/ti-dma-crossbar.c | 190 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 195 insertions(+)
>  create mode 100644 drivers/dma/ti-dma-crossbar.c
> 
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> index 074ffad334a7..519657a37ca1 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -247,6 +247,9 @@ config TI_EDMA
>  	  Enable support for the TI EDMA controller. This DMA
>  	  engine is found on TI DaVinci and AM33xx parts.
>  
> +config TI_DMA_CROSSBAR
> +	bool
> +
>  config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
>  	bool
>  
> @@ -332,6 +335,7 @@ config DMA_OMAP
>  	depends on ARCH_OMAP
>  	select DMA_ENGINE
>  	select DMA_VIRTUAL_CHANNELS
> +	select TI_DMA_CROSSBAR if SOC_DRA7XX
>  
>  config DMA_BCM2835
>  	tristate "BCM2835 DMA engine support"
> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> index bf4485800c60..6ec7af6a416c 100644
> --- a/drivers/dma/Makefile
> +++ b/drivers/dma/Makefile
> @@ -39,6 +39,7 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
>  obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
>  obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
>  obj-$(CONFIG_DMA_OMAP) += omap-dma.o
> +obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o
>  obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
>  obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
>  obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
> diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c
> new file mode 100644
> index 000000000000..591307bd4370
> --- /dev/null
> +++ b/drivers/dma/ti-dma-crossbar.c
> @@ -0,0 +1,190 @@
> +/*
> + *  Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
> + *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/list.h>
> +#include <linux/io.h>
> +#include <linux/regmap.h>
> +#include <linux/idr.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_dma.h>
> +
> +#define TI_XBAR_OUTPUTS	127
> +#define TI_XBAR_INPUTS	256
Ideally this should be moved to DT. Will next revision of this chip always
support these output and inputs?

> +
> +static DEFINE_IDR(map_idr);
> +
> +struct ti_dma_xbar_data {
> +	struct dma_router dmarouter;
> +	struct regmap *regmap;
> +
> +	uint safe_val; /* Value to rest the crossbar lines */
> +	uint xbar_requests; /* number of DMA requests connected to XBAR */
> +	uint dma_requests; /* number of DMA requests forwarded to DMA */
> +
> +	void __iomem *iomem;
> +};
> +
> +struct ti_dma_xbar_map {
> +	int xbar_in;
> +	int xbar_out;
> +};
> +
> +static void ti_dma_xbar_free(struct device *dev, void *route_data)
> +{
> +	struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
> +	struct ti_dma_xbar_map *map = route_data;
> +
> +	dev_dbg(dev, "Unmapping XBAR%d (was routed to %d)\n",
> +		map->xbar_in, map->xbar_out);
> +
> +	regmap_write(xbar->regmap, map->xbar_out * 2, 0);
just out of curiosity how much do you save using regmap :)

> +static int ti_dma_xbar_probe(struct platform_device *pdev)
> +{
> +	struct device_node *node = pdev->dev.of_node;
> +	struct device_node *dma_node;
> +	struct ti_dma_xbar_data *xbar;
> +	struct resource *res;
> +	void __iomem *iomem;
> +	int i, ret;
> +
> +	if (!node)
> +		return -ENODEV;
> +
> +	dma_node = of_parse_phandle(node, "dma-device", 0);
> +	if (!dma_node) {
> +		dev_err(&pdev->dev, "Can't get target DMA node\n");
> +		return -ENODEV;
> +	}
> +
> +	xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
> +	if (!xbar)
> +		return -ENOMEM;
> +
> +	if (of_property_read_u32(dma_node, "dma-requests",
> +				 &xbar->dma_requests)) {
> +		dev_info(&pdev->dev,
> +			 "Missing XBAR output information, using %u.\n",
> +			 TI_XBAR_OUTPUTS);
> +		xbar->dma_requests = TI_XBAR_OUTPUTS;
> +	}
> +	of_node_put(dma_node);
_put here?

> +int omap_dmaxbar_init(void)
> +{
> +	return platform_driver_register(&ti_dma_xbar_driver);
> +}
> +arch_initcall(omap_dmaxbar_init);
why arch_initcall?
Peter Ujfalusi March 26, 2015, 12:31 p.m. UTC | #2
On 03/26/2015 12:56 PM, Vinod Koul wrote:
>> +#define TI_XBAR_OUTPUTS	127
>> +#define TI_XBAR_INPUTS	256
> Ideally this should be moved to DT. Will next revision of this chip always
> support these output and inputs?

They are coming from DT. I'm using these as fall back values in case we can
not get this from DT and a warning will be printed in case if this unlikely
event happens.

>> +
>> +static DEFINE_IDR(map_idr);
>> +
>> +struct ti_dma_xbar_data {
>> +	struct dma_router dmarouter;
>> +	struct regmap *regmap;
>> +
>> +	uint safe_val; /* Value to rest the crossbar lines */
>> +	uint xbar_requests; /* number of DMA requests connected to XBAR */
>> +	uint dma_requests; /* number of DMA requests forwarded to DMA */
>> +
>> +	void __iomem *iomem;
>> +};
>> +
>> +struct ti_dma_xbar_map {
>> +	int xbar_in;
>> +	int xbar_out;
>> +};
>> +
>> +static void ti_dma_xbar_free(struct device *dev, void *route_data)
>> +{
>> +	struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
>> +	struct ti_dma_xbar_map *map = route_data;
>> +
>> +	dev_dbg(dev, "Unmapping XBAR%d (was routed to %d)\n",
>> +		map->xbar_in, map->xbar_out);
>> +
>> +	regmap_write(xbar->regmap, map->xbar_out * 2, 0);
> just out of curiosity how much do you save using regmap :)

good point, not much I guess. I had it implemented w/o regmap as well, but
thought why not use regmap if it is available.

>> +static int ti_dma_xbar_probe(struct platform_device *pdev)
>> +{
>> +	struct device_node *node = pdev->dev.of_node;
>> +	struct device_node *dma_node;
>> +	struct ti_dma_xbar_data *xbar;
>> +	struct resource *res;
>> +	void __iomem *iomem;
>> +	int i, ret;
>> +
>> +	if (!node)
>> +		return -ENODEV;
>> +
>> +	dma_node = of_parse_phandle(node, "dma-device", 0);
>> +	if (!dma_node) {
>> +		dev_err(&pdev->dev, "Can't get target DMA node\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
>> +	if (!xbar)
>> +		return -ENOMEM;
>> +
>> +	if (of_property_read_u32(dma_node, "dma-requests",
>> +				 &xbar->dma_requests)) {
>> +		dev_info(&pdev->dev,
>> +			 "Missing XBAR output information, using %u.\n",
>> +			 TI_XBAR_OUTPUTS);
>> +		xbar->dma_requests = TI_XBAR_OUTPUTS;
>> +	}
>> +	of_node_put(dma_node);
> _put here?

The code takes the real dma controller's node and it should be put back after
I have got the information I needed from it (number of DMA requests).

> 
>> +int omap_dmaxbar_init(void)
>> +{
>> +	return platform_driver_register(&ti_dma_xbar_driver);
>> +}
>> +arch_initcall(omap_dmaxbar_init);
> why arch_initcall?

It should be on the same init level as the real DMA controller. omap-dma at
the moment, but in some platforms this can work with the edma as well.
Since all device in the system (well most of them anyway) uses DMA it is
better to not delay their probe with deferring because the crossbar driver is
still not loaded
Tony Lindgren March 26, 2015, 3:22 p.m. UTC | #3
* Peter Ujfalusi <peter.ujfalusi@ti.com> [150326 05:32]:
> On 03/26/2015 12:56 PM, Vinod Koul wrote:
> >> +
> >> +static void ti_dma_xbar_free(struct device *dev, void *route_data)
> >> +{
> >> +	struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
> >> +	struct ti_dma_xbar_map *map = route_data;
> >> +
> >> +	dev_dbg(dev, "Unmapping XBAR%d (was routed to %d)\n",
> >> +		map->xbar_in, map->xbar_out);
> >> +
> >> +	regmap_write(xbar->regmap, map->xbar_out * 2, 0);
> > just out of curiosity how much do you save using regmap :)
> 
> good point, not much I guess. I had it implemented w/o regmap as well, but
> thought why not use regmap if it is available.

Regmap is nice for slow devices and devices in a shared register
range like the omap syscon general area. For normal use, there's
quite a bit of overhead with regmap compared to just read/write :)

Regards,

Tony
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vinod Koul March 26, 2015, 3:37 p.m. UTC | #4
On Thu, Mar 26, 2015 at 02:31:30PM +0200, Peter Ujfalusi wrote:
> On 03/26/2015 12:56 PM, Vinod Koul wrote:
> >> +#define TI_XBAR_OUTPUTS	127
> >> +#define TI_XBAR_INPUTS	256
> > Ideally this should be moved to DT. Will next revision of this chip always
> > support these output and inputs?
> 
> They are coming from DT. I'm using these as fall back values in case we can
> not get this from DT and a warning will be printed in case if this unlikely
> event happens.
Oops missed, that. Looks fine then

> 
> >> +
> >> +static DEFINE_IDR(map_idr);
> >> +
> >> +struct ti_dma_xbar_data {
> >> +	struct dma_router dmarouter;
> >> +	struct regmap *regmap;
> >> +
> >> +	uint safe_val; /* Value to rest the crossbar lines */
> >> +	uint xbar_requests; /* number of DMA requests connected to XBAR */
> >> +	uint dma_requests; /* number of DMA requests forwarded to DMA */
> >> +
> >> +	void __iomem *iomem;
> >> +};
> >> +
> >> +struct ti_dma_xbar_map {
> >> +	int xbar_in;
> >> +	int xbar_out;
> >> +};
> >> +
> >> +static void ti_dma_xbar_free(struct device *dev, void *route_data)
> >> +{
> >> +	struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
> >> +	struct ti_dma_xbar_map *map = route_data;
> >> +
> >> +	dev_dbg(dev, "Unmapping XBAR%d (was routed to %d)\n",
> >> +		map->xbar_in, map->xbar_out);
> >> +
> >> +	regmap_write(xbar->regmap, map->xbar_out * 2, 0);
> > just out of curiosity how much do you save using regmap :)
> 
> good point, not much I guess. I had it implemented w/o regmap as well, but
> thought why not use regmap if it is available.
Yes but there is overhead involved in setting it up. I though you have some
latency issues. It is okay to have it :)
Cache is anyways fastest :)

> >> +static int ti_dma_xbar_probe(struct platform_device *pdev)
> >> +{
> >> +	struct device_node *node = pdev->dev.of_node;
> >> +	struct device_node *dma_node;
> >> +	struct ti_dma_xbar_data *xbar;
> >> +	struct resource *res;
> >> +	void __iomem *iomem;
> >> +	int i, ret;
> >> +
> >> +	if (!node)
> >> +		return -ENODEV;
> >> +
> >> +	dma_node = of_parse_phandle(node, "dma-device", 0);
> >> +	if (!dma_node) {
> >> +		dev_err(&pdev->dev, "Can't get target DMA node\n");
> >> +		return -ENODEV;
> >> +	}
> >> +
> >> +	xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
> >> +	if (!xbar)
> >> +		return -ENOMEM;
> >> +
> >> +	if (of_property_read_u32(dma_node, "dma-requests",
> >> +				 &xbar->dma_requests)) {
> >> +		dev_info(&pdev->dev,
> >> +			 "Missing XBAR output information, using %u.\n",
> >> +			 TI_XBAR_OUTPUTS);
> >> +		xbar->dma_requests = TI_XBAR_OUTPUTS;
> >> +	}
> >> +	of_node_put(dma_node);
> > _put here?
> 
> The code takes the real dma controller's node and it should be put back after
> I have got the information I needed from it (number of DMA requests).
> 
> > 
> >> +int omap_dmaxbar_init(void)
> >> +{
> >> +	return platform_driver_register(&ti_dma_xbar_driver);
> >> +}
> >> +arch_initcall(omap_dmaxbar_init);
> > why arch_initcall?
> 
> It should be on the same init level as the real DMA controller. omap-dma at
> the moment, but in some platforms this can work with the edma as well.
> Since all device in the system (well most of them anyway) uses DMA it is
> better to not delay their probe with deferring because the crossbar driver is
> still not loaded
Deferring if resources not available is the right thing and helps you get rid
of init level ordering magic...
diff mbox

Patch

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 074ffad334a7..519657a37ca1 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -247,6 +247,9 @@  config TI_EDMA
 	  Enable support for the TI EDMA controller. This DMA
 	  engine is found on TI DaVinci and AM33xx parts.
 
+config TI_DMA_CROSSBAR
+	bool
+
 config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
 	bool
 
@@ -332,6 +335,7 @@  config DMA_OMAP
 	depends on ARCH_OMAP
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
+	select TI_DMA_CROSSBAR if SOC_DRA7XX
 
 config DMA_BCM2835
 	tristate "BCM2835 DMA engine support"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index bf4485800c60..6ec7af6a416c 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -39,6 +39,7 @@  obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
 obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
 obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
 obj-$(CONFIG_DMA_OMAP) += omap-dma.o
+obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o
 obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
 obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
 obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c
new file mode 100644
index 000000000000..591307bd4370
--- /dev/null
+++ b/drivers/dma/ti-dma-crossbar.c
@@ -0,0 +1,190 @@ 
+/*
+ *  Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <linux/idr.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+
+#define TI_XBAR_OUTPUTS	127
+#define TI_XBAR_INPUTS	256
+
+static DEFINE_IDR(map_idr);
+
+struct ti_dma_xbar_data {
+	struct dma_router dmarouter;
+	struct regmap *regmap;
+
+	uint safe_val; /* Value to rest the crossbar lines */
+	uint xbar_requests; /* number of DMA requests connected to XBAR */
+	uint dma_requests; /* number of DMA requests forwarded to DMA */
+
+	void __iomem *iomem;
+};
+
+struct ti_dma_xbar_map {
+	int xbar_in;
+	int xbar_out;
+};
+
+static void ti_dma_xbar_free(struct device *dev, void *route_data)
+{
+	struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
+	struct ti_dma_xbar_map *map = route_data;
+
+	dev_dbg(dev, "Unmapping XBAR%d (was routed to %d)\n",
+		map->xbar_in, map->xbar_out);
+
+	regmap_write(xbar->regmap, map->xbar_out * 2, 0);
+	idr_remove(&map_idr, map->xbar_out);
+	kfree(map);
+}
+
+static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec,
+					struct of_dma *ofdma)
+{
+	struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
+	struct ti_dma_xbar_data *xbar = platform_get_drvdata(pdev);
+	struct ti_dma_xbar_map *map;
+
+	if (dma_spec->args[0] >= xbar->xbar_requests) {
+		dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
+			dma_spec->args[0]);
+		return NULL;
+	}
+
+	map = kzalloc(sizeof(*map), GFP_KERNEL);
+	if (!map)
+		return NULL;
+
+	map->xbar_out = idr_alloc(&map_idr, NULL, 0, xbar->dma_requests,
+				  GFP_KERNEL);
+	map->xbar_in = dma_spec->args[0];
+
+	/* The DMA request is 1 based in sDMA */
+	dma_spec->args[0] = map->xbar_out + 1;
+
+	dev_dbg(&pdev->dev, "Mapping XBAR%d to DMA%d\n",
+		map->xbar_in, map->xbar_out);
+
+	regmap_write(xbar->regmap, map->xbar_out * 2, map->xbar_in);
+
+	return map;
+}
+
+static const struct regmap_config ti_dma_xbar_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 2,
+	.val_bits = 16,
+	.max_register = 0xfc,
+	.cache_type = REGCACHE_FLAT,
+};
+
+static int ti_dma_xbar_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *dma_node;
+	struct ti_dma_xbar_data *xbar;
+	struct resource *res;
+	void __iomem *iomem;
+	int i, ret;
+
+	if (!node)
+		return -ENODEV;
+
+	dma_node = of_parse_phandle(node, "dma-device", 0);
+	if (!dma_node) {
+		dev_err(&pdev->dev, "Can't get target DMA node\n");
+		return -ENODEV;
+	}
+
+	xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
+	if (!xbar)
+		return -ENOMEM;
+
+	if (of_property_read_u32(dma_node, "dma-requests",
+				 &xbar->dma_requests)) {
+		dev_info(&pdev->dev,
+			 "Missing XBAR output information, using %u.\n",
+			 TI_XBAR_OUTPUTS);
+		xbar->dma_requests = TI_XBAR_OUTPUTS;
+	}
+	of_node_put(dma_node);
+
+	if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
+		dev_info(&pdev->dev,
+			 "Missing XBAR input information, using %u.\n",
+			 TI_XBAR_INPUTS);
+		xbar->xbar_requests = TI_XBAR_INPUTS;
+	}
+
+	if (of_property_read_u32(node, "ti,dma-safe-map", &xbar->safe_val))
+		xbar->safe_val = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
+				     dev_name(&pdev->dev)))
+		return -ENODEV;
+
+	iomem = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!iomem)
+		return -ENOMEM;
+
+	xbar->regmap = devm_regmap_init_mmio(&pdev->dev, iomem,
+					    &ti_dma_xbar_regmap_config);
+	if (IS_ERR(xbar->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(xbar->regmap);
+	}
+	xbar->iomem = iomem;
+
+	xbar->dmarouter.dev = &pdev->dev;
+	xbar->dmarouter.route_free = ti_dma_xbar_free;
+
+	platform_set_drvdata(pdev, xbar);
+
+	ret = of_dma_router_register(node, ti_dma_xbar_route_allocate,
+				     &xbar->dmarouter);
+	if (ret)
+		return -ENODEV;
+
+	/* Reset the crossbar */
+	for (i = 0; i < xbar->dma_requests; i++)
+		regmap_write(xbar->regmap, i * 2, xbar->safe_val);
+
+	return 0;
+}
+
+static const struct of_device_id ti_dma_xbar_match[] = {
+	{ .compatible = "ti,dra7-dma-crossbar" },
+	{},
+};
+
+static struct platform_driver ti_dma_xbar_driver = {
+	.driver = {
+		.name = "ti-dma-crossbar",
+		.of_match_table = of_match_ptr(ti_dma_xbar_match),
+	},
+	.probe	= ti_dma_xbar_probe,
+};
+
+int omap_dmaxbar_init(void)
+{
+	return platform_driver_register(&ti_dma_xbar_driver);
+}
+arch_initcall(omap_dmaxbar_init);