aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVinod Koul <vinod.koul@intel.com>2015-06-24 23:51:43 -0400
committerVinod Koul <vinod.koul@intel.com>2015-06-24 23:51:43 -0400
commit0e0fa66e39db6b2c72dbc0d8975fc2a45533a8eb (patch)
tree1b538ba40d301ba70a645d405e37e74bb5d70119
parent9324fdf5267b12f6db660fe52e882bbfffcc109a (diff)
parenta074ae38f859b90bd259f5df43784834b44412d1 (diff)
Merge branch 'topic/omap' into for-linus
-rw-r--r--Documentation/devicetree/bindings/dma/dma.txt28
-rw-r--r--Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt52
-rw-r--r--drivers/dma/Kconfig4
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/dmaengine.c7
-rw-r--r--drivers/dma/of-dma.c89
-rw-r--r--drivers/dma/omap-dma.c29
-rw-r--r--drivers/dma/ti-dma-crossbar.c188
-rw-r--r--include/linux/dmaengine.h17
-rw-r--r--include/linux/of_dma.h21
10 files changed, 430 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/dma/dma.txt b/Documentation/devicetree/bindings/dma/dma.txt
index 82104271e754..6312fb00ce8d 100644
--- a/Documentation/devicetree/bindings/dma/dma.txt
+++ b/Documentation/devicetree/bindings/dma/dma.txt
@@ -31,6 +31,34 @@ Example:
31 dma-requests = <127>; 31 dma-requests = <127>;
32 }; 32 };
33 33
34* DMA router
35
36DMA routers are transparent IP blocks used to route DMA request lines from
37devices to the DMA controller. Some SoCs (like TI DRA7x) have more peripherals
38integrated with DMA requests than what the DMA controller can handle directly.
39
40Required property:
41- dma-masters: phandle of the DMA controller or list of phandles for
42 the DMA controllers the router can direct the signal to.
43- #dma-cells: Must be at least 1. Used to provide DMA router specific
44 information. See DMA client binding below for more
45 details.
46
47Optional properties:
48- dma-requests: Number of incoming request lines the router can handle.
49- In the node pointed by the dma-masters:
50 - dma-requests: The router driver might need to look for this in order
51 to configure the routing.
52
53Example:
54 sdma_xbar: dma-router@4a002b78 {
55 compatible = "ti,dra7-dma-crossbar";
56 reg = <0x4a002b78 0xfc>;
57 #dma-cells = <1>;
58 dma-requests = <205>;
59 ti,dma-safe-map = <0>;
60 dma-masters = <&sdma>;
61 };
34 62
35* DMA client 63* DMA client
36 64
diff --git a/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt b/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
new file mode 100644
index 000000000000..63a48928f3a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
@@ -0,0 +1,52 @@
1Texas Instruments DMA Crossbar (DMA request router)
2
3Required properties:
4- compatible: "ti,dra7-dma-crossbar" for DRA7xx DMA crossbar
5- reg: Memory map for accessing module
6- #dma-cells: Should be set to <1>.
7 Clients should use the crossbar request number (input)
8- dma-requests: Number of DMA requests the crossbar can receive
9- dma-masters: phandle pointing to the DMA controller
10
11The DMA controller node need to have the following poroperties:
12- dma-requests: Number of DMA requests the controller can handle
13
14Optional properties:
15- ti,dma-safe-map: Safe routing value for unused request lines
16
17Example:
18
19/* DMA controller */
20sdma: dma-controller@4a056000 {
21 compatible = "ti,omap4430-sdma";
22 reg = <0x4a056000 0x1000>;
23 interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
24 <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
25 <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
26 <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
27 #dma-cells = <1>;
28 dma-channels = <32>;
29 dma-requests = <127>;
30};
31
32/* DMA crossbar */
33sdma_xbar: dma-router@4a002b78 {
34 compatible = "ti,dra7-dma-crossbar";
35 reg = <0x4a002b78 0xfc>;
36 #dma-cells = <1>;
37 dma-requests = <205>;
38 ti,dma-safe-map = <0>;
39 dma-masters = <&sdma>;
40};
41
42/* DMA client */
43uart1: serial@4806a000 {
44 compatible = "ti,omap4-uart";
45 reg = <0x4806a000 0x100>;
46 interrupts-extended = <&gic GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
47 ti,hwmods = "uart1";
48 clock-frequency = <48000000>;
49 status = "disabled";
50 dmas = <&sdma_xbar 49>, <&sdma_xbar 50>;
51 dma-names = "tx", "rx";
52};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index bda2cb06dc7a..0205ade0ba32 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -245,6 +245,9 @@ config TI_EDMA
245 Enable support for the TI EDMA controller. This DMA 245 Enable support for the TI EDMA controller. This DMA
246 engine is found on TI DaVinci and AM33xx parts. 246 engine is found on TI DaVinci and AM33xx parts.
247 247
248config TI_DMA_CROSSBAR
249 bool
250
248config ARCH_HAS_ASYNC_TX_FIND_CHANNEL 251config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
249 bool 252 bool
250 253
@@ -330,6 +333,7 @@ config DMA_OMAP
330 depends on ARCH_OMAP 333 depends on ARCH_OMAP
331 select DMA_ENGINE 334 select DMA_ENGINE
332 select DMA_VIRTUAL_CHANNELS 335 select DMA_VIRTUAL_CHANNELS
336 select TI_DMA_CROSSBAR if SOC_DRA7XX
333 337
334config DMA_BCM2835 338config DMA_BCM2835
335 tristate "BCM2835 DMA engine support" 339 tristate "BCM2835 DMA engine support"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 69f77d5ba53b..535919559f12 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
38obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o 38obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
39obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o 39obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
40obj-$(CONFIG_DMA_OMAP) += omap-dma.o 40obj-$(CONFIG_DMA_OMAP) += omap-dma.o
41obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o
41obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o 42obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
42obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o 43obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
43obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o 44obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index c0793818bb99..052a2bd1a5cf 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -267,6 +267,13 @@ static void dma_chan_put(struct dma_chan *chan)
267 /* This channel is not in use anymore, free it */ 267 /* This channel is not in use anymore, free it */
268 if (!chan->client_count && chan->device->device_free_chan_resources) 268 if (!chan->client_count && chan->device->device_free_chan_resources)
269 chan->device->device_free_chan_resources(chan); 269 chan->device->device_free_chan_resources(chan);
270
271 /* If the channel is used via a DMA request router, free the mapping */
272 if (chan->router && chan->router->route_free) {
273 chan->router->route_free(chan->router->dev, chan->route_data);
274 chan->router = NULL;
275 chan->route_data = NULL;
276 }
270} 277}
271 278
272enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) 279enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index cbd4a8aff120..1e1f2986eba8 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -45,6 +45,50 @@ static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
45} 45}
46 46
47/** 47/**
48 * of_dma_router_xlate - translation function for router devices
49 * @dma_spec: pointer to DMA specifier as found in the device tree
50 * @of_dma: pointer to DMA controller data (router information)
51 *
52 * The function creates new dma_spec to be passed to the router driver's
53 * of_dma_route_allocate() function to prepare a dma_spec which will be used
54 * to request channel from the real DMA controller.
55 */
56static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
57 struct of_dma *ofdma)
58{
59 struct dma_chan *chan;
60 struct of_dma *ofdma_target;
61 struct of_phandle_args dma_spec_target;
62 void *route_data;
63
64 /* translate the request for the real DMA controller */
65 memcpy(&dma_spec_target, dma_spec, sizeof(dma_spec_target));
66 route_data = ofdma->of_dma_route_allocate(&dma_spec_target, ofdma);
67 if (IS_ERR(route_data))
68 return NULL;
69
70 ofdma_target = of_dma_find_controller(&dma_spec_target);
71 if (!ofdma_target)
72 return NULL;
73
74 chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target);
75 if (chan) {
76 chan->router = ofdma->dma_router;
77 chan->route_data = route_data;
78 } else {
79 ofdma->dma_router->route_free(ofdma->dma_router->dev,
80 route_data);
81 }
82
83 /*
84 * Need to put the node back since the ofdma->of_dma_route_allocate
85 * has taken it for generating the new, translated dma_spec
86 */
87 of_node_put(dma_spec_target.np);
88 return chan;
89}
90
91/**
48 * of_dma_controller_register - Register a DMA controller to DT DMA helpers 92 * of_dma_controller_register - Register a DMA controller to DT DMA helpers
49 * @np: device node of DMA controller 93 * @np: device node of DMA controller
50 * @of_dma_xlate: translation function which converts a phandle 94 * @of_dma_xlate: translation function which converts a phandle
@@ -110,6 +154,51 @@ void of_dma_controller_free(struct device_node *np)
110EXPORT_SYMBOL_GPL(of_dma_controller_free); 154EXPORT_SYMBOL_GPL(of_dma_controller_free);
111 155
112/** 156/**
157 * of_dma_router_register - Register a DMA router to DT DMA helpers as a
158 * controller
159 * @np: device node of DMA router
160 * @of_dma_route_allocate: setup function for the router which need to
161 * modify the dma_spec for the DMA controller to
162 * use and to set up the requested route.
163 * @dma_router: pointer to dma_router structure to be used when
164 * the route need to be free up.
165 *
166 * Returns 0 on success or appropriate errno value on error.
167 *
168 * Allocated memory should be freed with appropriate of_dma_controller_free()
169 * call.
170 */
171int of_dma_router_register(struct device_node *np,
172 void *(*of_dma_route_allocate)
173 (struct of_phandle_args *, struct of_dma *),
174 struct dma_router *dma_router)
175{
176 struct of_dma *ofdma;
177
178 if (!np || !of_dma_route_allocate || !dma_router) {
179 pr_err("%s: not enough information provided\n", __func__);
180 return -EINVAL;
181 }
182
183 ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL);
184 if (!ofdma)
185 return -ENOMEM;
186
187 ofdma->of_node = np;
188 ofdma->of_dma_xlate = of_dma_router_xlate;
189 ofdma->of_dma_route_allocate = of_dma_route_allocate;
190 ofdma->dma_router = dma_router;
191
192 /* Now queue of_dma controller structure in list */
193 mutex_lock(&of_dma_lock);
194 list_add_tail(&ofdma->of_dma_controllers, &of_dma_list);
195 mutex_unlock(&of_dma_lock);
196
197 return 0;
198}
199EXPORT_SYMBOL_GPL(of_dma_router_register);
200
201/**
113 * of_dma_match_channel - Check if a DMA specifier matches name 202 * of_dma_match_channel - Check if a DMA specifier matches name
114 * @np: device node to look for DMA channels 203 * @np: device node to look for DMA channels
115 * @name: channel name to be matched 204 * @name: channel name to be matched
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index 7624a0873412..249445c8a4c6 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -22,6 +22,9 @@
22 22
23#include "virt-dma.h" 23#include "virt-dma.h"
24 24
25#define OMAP_SDMA_REQUESTS 127
26#define OMAP_SDMA_CHANNELS 32
27
25struct omap_dmadev { 28struct omap_dmadev {
26 struct dma_device ddev; 29 struct dma_device ddev;
27 spinlock_t lock; 30 spinlock_t lock;
@@ -31,9 +34,10 @@ struct omap_dmadev {
31 const struct omap_dma_reg *reg_map; 34 const struct omap_dma_reg *reg_map;
32 struct omap_system_dma_plat_info *plat; 35 struct omap_system_dma_plat_info *plat;
33 bool legacy; 36 bool legacy;
37 unsigned dma_requests;
34 spinlock_t irq_lock; 38 spinlock_t irq_lock;
35 uint32_t irq_enable_mask; 39 uint32_t irq_enable_mask;
36 struct omap_chan *lch_map[32]; 40 struct omap_chan *lch_map[OMAP_SDMA_CHANNELS];
37}; 41};
38 42
39struct omap_chan { 43struct omap_chan {
@@ -589,6 +593,7 @@ static void omap_dma_free_chan_resources(struct dma_chan *chan)
589 omap_free_dma(c->dma_ch); 593 omap_free_dma(c->dma_ch);
590 594
591 dev_dbg(od->ddev.dev, "freeing channel for %u\n", c->dma_sig); 595 dev_dbg(od->ddev.dev, "freeing channel for %u\n", c->dma_sig);
596 c->dma_sig = 0;
592} 597}
593 598
594static size_t omap_dma_sg_size(struct omap_sg *sg) 599static size_t omap_dma_sg_size(struct omap_sg *sg)
@@ -1082,7 +1087,7 @@ static int omap_dma_resume(struct dma_chan *chan)
1082 return 0; 1087 return 0;
1083} 1088}
1084 1089
1085static int omap_dma_chan_init(struct omap_dmadev *od, int dma_sig) 1090static int omap_dma_chan_init(struct omap_dmadev *od)
1086{ 1091{
1087 struct omap_chan *c; 1092 struct omap_chan *c;
1088 1093
@@ -1091,7 +1096,6 @@ static int omap_dma_chan_init(struct omap_dmadev *od, int dma_sig)
1091 return -ENOMEM; 1096 return -ENOMEM;
1092 1097
1093 c->reg_map = od->reg_map; 1098 c->reg_map = od->reg_map;
1094 c->dma_sig = dma_sig;
1095 c->vc.desc_free = omap_dma_desc_free; 1099 c->vc.desc_free = omap_dma_desc_free;
1096 vchan_init(&c->vc, &od->ddev); 1100 vchan_init(&c->vc, &od->ddev);
1097 INIT_LIST_HEAD(&c->node); 1101 INIT_LIST_HEAD(&c->node);
@@ -1163,8 +1167,17 @@ static int omap_dma_probe(struct platform_device *pdev)
1163 1167
1164 tasklet_init(&od->task, omap_dma_sched, (unsigned long)od); 1168 tasklet_init(&od->task, omap_dma_sched, (unsigned long)od);
1165 1169
1166 for (i = 0; i < 127; i++) { 1170 od->dma_requests = OMAP_SDMA_REQUESTS;
1167 rc = omap_dma_chan_init(od, i); 1171 if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node,
1172 "dma-requests",
1173 &od->dma_requests)) {
1174 dev_info(&pdev->dev,
1175 "Missing dma-requests property, using %u.\n",
1176 OMAP_SDMA_REQUESTS);
1177 }
1178
1179 for (i = 0; i < OMAP_SDMA_CHANNELS; i++) {
1180 rc = omap_dma_chan_init(od);
1168 if (rc) { 1181 if (rc) {
1169 omap_dma_free(od); 1182 omap_dma_free(od);
1170 return rc; 1183 return rc;
@@ -1255,10 +1268,14 @@ static struct platform_driver omap_dma_driver = {
1255bool omap_dma_filter_fn(struct dma_chan *chan, void *param) 1268bool omap_dma_filter_fn(struct dma_chan *chan, void *param)
1256{ 1269{
1257 if (chan->device->dev->driver == &omap_dma_driver.driver) { 1270 if (chan->device->dev->driver == &omap_dma_driver.driver) {
1271 struct omap_dmadev *od = to_omap_dma_dev(chan->device);
1258 struct omap_chan *c = to_omap_dma_chan(chan); 1272 struct omap_chan *c = to_omap_dma_chan(chan);
1259 unsigned req = *(unsigned *)param; 1273 unsigned req = *(unsigned *)param;
1260 1274
1261 return req == c->dma_sig; 1275 if (req <= od->dma_requests) {
1276 c->dma_sig = req;
1277 return true;
1278 }
1262 } 1279 }
1263 return false; 1280 return false;
1264} 1281}
diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c
new file mode 100644
index 000000000000..24f5ca2356bf
--- /dev/null
+++ b/drivers/dma/ti-dma-crossbar.c
@@ -0,0 +1,188 @@
1/*
2 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
3 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 */
10#include <linux/slab.h>
11#include <linux/err.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/io.h>
15#include <linux/idr.h>
16#include <linux/of_address.h>
17#include <linux/of_device.h>
18#include <linux/of_dma.h>
19
20#define TI_XBAR_OUTPUTS 127
21#define TI_XBAR_INPUTS 256
22
23static DEFINE_IDR(map_idr);
24
25struct ti_dma_xbar_data {
26 void __iomem *iomem;
27
28 struct dma_router dmarouter;
29
30 u16 safe_val; /* Value to rest the crossbar lines */
31 u32 xbar_requests; /* number of DMA requests connected to XBAR */
32 u32 dma_requests; /* number of DMA requests forwarded to DMA */
33};
34
35struct ti_dma_xbar_map {
36 u16 xbar_in;
37 int xbar_out;
38};
39
40static inline void ti_dma_xbar_write(void __iomem *iomem, int xbar, u16 val)
41{
42 writew_relaxed(val, iomem + (xbar * 2));
43}
44
45static void ti_dma_xbar_free(struct device *dev, void *route_data)
46{
47 struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
48 struct ti_dma_xbar_map *map = route_data;
49
50 dev_dbg(dev, "Unmapping XBAR%u (was routed to %d)\n",
51 map->xbar_in, map->xbar_out);
52
53 ti_dma_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
54 idr_remove(&map_idr, map->xbar_out);
55 kfree(map);
56}
57
58static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec,
59 struct of_dma *ofdma)
60{
61 struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
62 struct ti_dma_xbar_data *xbar = platform_get_drvdata(pdev);
63 struct ti_dma_xbar_map *map;
64
65 if (dma_spec->args[0] >= xbar->xbar_requests) {
66 dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
67 dma_spec->args[0]);
68 return ERR_PTR(-EINVAL);
69 }
70
71 /* The of_node_put() will be done in the core for the node */
72 dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
73 if (!dma_spec->np) {
74 dev_err(&pdev->dev, "Can't get DMA master\n");
75 return ERR_PTR(-EINVAL);
76 }
77
78 map = kzalloc(sizeof(*map), GFP_KERNEL);
79 if (!map) {
80 of_node_put(dma_spec->np);
81 return ERR_PTR(-ENOMEM);
82 }
83
84 map->xbar_out = idr_alloc(&map_idr, NULL, 0, xbar->dma_requests,
85 GFP_KERNEL);
86 map->xbar_in = (u16)dma_spec->args[0];
87
88 /* The DMA request is 1 based in sDMA */
89 dma_spec->args[0] = map->xbar_out + 1;
90
91 dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n",
92 map->xbar_in, map->xbar_out);
93
94 ti_dma_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
95
96 return map;
97}
98
99static int ti_dma_xbar_probe(struct platform_device *pdev)
100{
101 struct device_node *node = pdev->dev.of_node;
102 struct device_node *dma_node;
103 struct ti_dma_xbar_data *xbar;
104 struct resource *res;
105 u32 safe_val;
106 void __iomem *iomem;
107 int i, ret;
108
109 if (!node)
110 return -ENODEV;
111
112 xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
113 if (!xbar)
114 return -ENOMEM;
115
116 dma_node = of_parse_phandle(node, "dma-masters", 0);
117 if (!dma_node) {
118 dev_err(&pdev->dev, "Can't get DMA master node\n");
119 return -ENODEV;
120 }
121
122 if (of_property_read_u32(dma_node, "dma-requests",
123 &xbar->dma_requests)) {
124 dev_info(&pdev->dev,
125 "Missing XBAR output information, using %u.\n",
126 TI_XBAR_OUTPUTS);
127 xbar->dma_requests = TI_XBAR_OUTPUTS;
128 }
129 of_node_put(dma_node);
130
131 if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
132 dev_info(&pdev->dev,
133 "Missing XBAR input information, using %u.\n",
134 TI_XBAR_INPUTS);
135 xbar->xbar_requests = TI_XBAR_INPUTS;
136 }
137
138 if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val))
139 xbar->safe_val = (u16)safe_val;
140
141 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
142 if (!res)
143 return -ENODEV;
144
145 iomem = devm_ioremap_resource(&pdev->dev, res);
146 if (!iomem)
147 return -ENOMEM;
148
149 xbar->iomem = iomem;
150
151 xbar->dmarouter.dev = &pdev->dev;
152 xbar->dmarouter.route_free = ti_dma_xbar_free;
153
154 platform_set_drvdata(pdev, xbar);
155
156 /* Reset the crossbar */
157 for (i = 0; i < xbar->dma_requests; i++)
158 ti_dma_xbar_write(xbar->iomem, i, xbar->safe_val);
159
160 ret = of_dma_router_register(node, ti_dma_xbar_route_allocate,
161 &xbar->dmarouter);
162 if (ret) {
163 /* Restore the defaults for the crossbar */
164 for (i = 0; i < xbar->dma_requests; i++)
165 ti_dma_xbar_write(xbar->iomem, i, i);
166 }
167
168 return ret;
169}
170
171static const struct of_device_id ti_dma_xbar_match[] = {
172 { .compatible = "ti,dra7-dma-crossbar" },
173 {},
174};
175
176static struct platform_driver ti_dma_xbar_driver = {
177 .driver = {
178 .name = "ti-dma-crossbar",
179 .of_match_table = of_match_ptr(ti_dma_xbar_match),
180 },
181 .probe = ti_dma_xbar_probe,
182};
183
184int omap_dmaxbar_init(void)
185{
186 return platform_driver_register(&ti_dma_xbar_driver);
187}
188arch_initcall(omap_dmaxbar_init);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 5d99229c2f95..2882a201c1cb 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -231,6 +231,16 @@ struct dma_chan_percpu {
231}; 231};
232 232
233/** 233/**
234 * struct dma_router - DMA router structure
235 * @dev: pointer to the DMA router device
236 * @route_free: function to be called when the route can be disconnected
237 */
238struct dma_router {
239 struct device *dev;
240 void (*route_free)(struct device *dev, void *route_data);
241};
242
243/**
234 * struct dma_chan - devices supply DMA channels, clients use them 244 * struct dma_chan - devices supply DMA channels, clients use them
235 * @device: ptr to the dma device who supplies this channel, always !%NULL 245 * @device: ptr to the dma device who supplies this channel, always !%NULL
236 * @cookie: last cookie value returned to client 246 * @cookie: last cookie value returned to client
@@ -241,6 +251,8 @@ struct dma_chan_percpu {
241 * @local: per-cpu pointer to a struct dma_chan_percpu 251 * @local: per-cpu pointer to a struct dma_chan_percpu
242 * @client_count: how many clients are using this channel 252 * @client_count: how many clients are using this channel
243 * @table_count: number of appearances in the mem-to-mem allocation table 253 * @table_count: number of appearances in the mem-to-mem allocation table
254 * @router: pointer to the DMA router structure
255 * @route_data: channel specific data for the router
244 * @private: private data for certain client-channel associations 256 * @private: private data for certain client-channel associations
245 */ 257 */
246struct dma_chan { 258struct dma_chan {
@@ -256,6 +268,11 @@ struct dma_chan {
256 struct dma_chan_percpu __percpu *local; 268 struct dma_chan_percpu __percpu *local;
257 int client_count; 269 int client_count;
258 int table_count; 270 int table_count;
271
272 /* DMA router */
273 struct dma_router *router;
274 void *route_data;
275
259 void *private; 276 void *private;
260}; 277};
261 278
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index 56bc026c143f..98ba7525929e 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -23,6 +23,9 @@ struct of_dma {
23 struct device_node *of_node; 23 struct device_node *of_node;
24 struct dma_chan *(*of_dma_xlate) 24 struct dma_chan *(*of_dma_xlate)
25 (struct of_phandle_args *, struct of_dma *); 25 (struct of_phandle_args *, struct of_dma *);
26 void *(*of_dma_route_allocate)
27 (struct of_phandle_args *, struct of_dma *);
28 struct dma_router *dma_router;
26 void *of_dma_data; 29 void *of_dma_data;
27}; 30};
28 31
@@ -37,12 +40,20 @@ extern int of_dma_controller_register(struct device_node *np,
37 (struct of_phandle_args *, struct of_dma *), 40 (struct of_phandle_args *, struct of_dma *),
38 void *data); 41 void *data);
39extern void of_dma_controller_free(struct device_node *np); 42extern void of_dma_controller_free(struct device_node *np);
43
44extern int of_dma_router_register(struct device_node *np,
45 void *(*of_dma_route_allocate)
46 (struct of_phandle_args *, struct of_dma *),
47 struct dma_router *dma_router);
48#define of_dma_router_free of_dma_controller_free
49
40extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np, 50extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
41 const char *name); 51 const char *name);
42extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, 52extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
43 struct of_dma *ofdma); 53 struct of_dma *ofdma);
44extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec, 54extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
45 struct of_dma *ofdma); 55 struct of_dma *ofdma);
56
46#else 57#else
47static inline int of_dma_controller_register(struct device_node *np, 58static inline int of_dma_controller_register(struct device_node *np,
48 struct dma_chan *(*of_dma_xlate) 59 struct dma_chan *(*of_dma_xlate)
@@ -56,6 +67,16 @@ static inline void of_dma_controller_free(struct device_node *np)
56{ 67{
57} 68}
58 69
70static inline int of_dma_router_register(struct device_node *np,
71 void *(*of_dma_route_allocate)
72 (struct of_phandle_args *, struct of_dma *),
73 struct dma_router *dma_router)
74{
75 return -ENODEV;
76}
77
78#define of_dma_router_free of_dma_controller_free
79
59static inline struct dma_chan *of_dma_request_slave_channel(struct device_node *np, 80static inline struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
60 const char *name) 81 const char *name)
61{ 82{