Skip to content

Commit 42dbdcc

Browse files
Peter UjfalusiVinod Koul
authored andcommitted
dmaengine: ti-dma-crossbar: Add support for crossbar on AM33xx/AM43xx
The DMA event crossbar on AM33xx/AM43xx is different from the one found in DRA7x family. Instead of a single event crossbar it has 64 identical mux attached to each eDMA event line. When the 0 event mux is selected, the default mapped event is going to be routed to the corresponding eDMA event line. If different mux is selected, then the selected event is going to be routed to the given eDMA event. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
1 parent 966a87b commit 42dbdcc

File tree

2 files changed

+234
-32
lines changed

2 files changed

+234
-32
lines changed

Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ Texas Instruments DMA Crossbar (DMA request router)
22

33
Required properties:
44
- compatible: "ti,dra7-dma-crossbar" for DRA7xx DMA crossbar
5+
"ti,am335x-edma-crossbar" for AM335x and AM437x
56
- reg: Memory map for accessing module
6-
- #dma-cells: Should be set to <1>.
7-
Clients should use the crossbar request number (input)
7+
- #dma-cells: Should be set to to match with the DMA controller's dma-cells
8+
for ti,dra7-dma-crossbar and <3> for ti,am335x-edma-crossbar.
89
- dma-requests: Number of DMA requests the crossbar can receive
910
- dma-masters: phandle pointing to the DMA controller
1011

@@ -14,6 +15,15 @@ The DMA controller node need to have the following poroperties:
1415
Optional properties:
1516
- ti,dma-safe-map: Safe routing value for unused request lines
1617

18+
Notes:
19+
When requesting channel via ti,dra7-dma-crossbar, the DMA clinet must request
20+
the DMA event number as crossbar ID (input to the DMA crossbar).
21+
22+
For ti,am335x-edma-crossbar: the meaning of parameters of dmas for clients:
23+
dmas = <&edma_xbar 12 0 1>; where <12> is the DMA request number, <0> is the TC
24+
the event should be assigned and <1> is the mux selection for in the crossbar.
25+
When mux 0 is used the DMA channel can be requested directly from edma node.
26+
1727
Example:
1828

1929
/* DMA controller */
@@ -47,6 +57,7 @@ uart1: serial@4806a000 {
4757
ti,hwmods = "uart1";
4858
clock-frequency = <48000000>;
4959
status = "disabled";
60+
/* Requesting crossbar input 49 and 50 */
5061
dmas = <&sdma_xbar 49>, <&sdma_xbar 50>;
5162
dma-names = "tx", "rx";
5263
};

drivers/dma/ti-dma-crossbar.c

Lines changed: 221 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,184 @@
1717
#include <linux/of_device.h>
1818
#include <linux/of_dma.h>
1919

20-
#define TI_XBAR_OUTPUTS 127
21-
#define TI_XBAR_INPUTS 256
20+
#define TI_XBAR_DRA7 0
21+
#define TI_XBAR_AM335X 1
22+
23+
static const struct of_device_id ti_dma_xbar_match[] = {
24+
{
25+
.compatible = "ti,dra7-dma-crossbar",
26+
.data = (void *)TI_XBAR_DRA7,
27+
},
28+
{
29+
.compatible = "ti,am335x-edma-crossbar",
30+
.data = (void *)TI_XBAR_AM335X,
31+
},
32+
{},
33+
};
34+
35+
/* Crossbar on AM335x/AM437x family */
36+
#define TI_AM335X_XBAR_LINES 64
37+
38+
struct ti_am335x_xbar_data {
39+
void __iomem *iomem;
40+
41+
struct dma_router dmarouter;
42+
43+
u32 xbar_events; /* maximum number of events to select in xbar */
44+
u32 dma_requests; /* number of DMA requests on eDMA */
45+
};
46+
47+
struct ti_am335x_xbar_map {
48+
u16 dma_line;
49+
u16 mux_val;
50+
};
51+
52+
static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u16 val)
53+
{
54+
writeb_relaxed(val & 0x1f, iomem + event);
55+
}
56+
57+
static void ti_am335x_xbar_free(struct device *dev, void *route_data)
58+
{
59+
struct ti_am335x_xbar_data *xbar = dev_get_drvdata(dev);
60+
struct ti_am335x_xbar_map *map = route_data;
61+
62+
dev_dbg(dev, "Unmapping XBAR event %u on channel %u\n",
63+
map->mux_val, map->dma_line);
64+
65+
ti_am335x_xbar_write(xbar->iomem, map->dma_line, 0);
66+
kfree(map);
67+
}
68+
69+
static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec,
70+
struct of_dma *ofdma)
71+
{
72+
struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
73+
struct ti_am335x_xbar_data *xbar = platform_get_drvdata(pdev);
74+
struct ti_am335x_xbar_map *map;
75+
76+
if (dma_spec->args_count != 3)
77+
return ERR_PTR(-EINVAL);
78+
79+
if (dma_spec->args[2] >= xbar->xbar_events) {
80+
dev_err(&pdev->dev, "Invalid XBAR event number: %d\n",
81+
dma_spec->args[2]);
82+
return ERR_PTR(-EINVAL);
83+
}
84+
85+
if (dma_spec->args[0] >= xbar->dma_requests) {
86+
dev_err(&pdev->dev, "Invalid DMA request line number: %d\n",
87+
dma_spec->args[0]);
88+
return ERR_PTR(-EINVAL);
89+
}
90+
91+
/* The of_node_put() will be done in the core for the node */
92+
dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
93+
if (!dma_spec->np) {
94+
dev_err(&pdev->dev, "Can't get DMA master\n");
95+
return ERR_PTR(-EINVAL);
96+
}
97+
98+
map = kzalloc(sizeof(*map), GFP_KERNEL);
99+
if (!map) {
100+
of_node_put(dma_spec->np);
101+
return ERR_PTR(-ENOMEM);
102+
}
103+
104+
map->dma_line = (u16)dma_spec->args[0];
105+
map->mux_val = (u16)dma_spec->args[2];
106+
107+
dma_spec->args[2] = 0;
108+
dma_spec->args_count = 2;
109+
110+
dev_dbg(&pdev->dev, "Mapping XBAR event%u to DMA%u\n",
111+
map->mux_val, map->dma_line);
112+
113+
ti_am335x_xbar_write(xbar->iomem, map->dma_line, map->mux_val);
114+
115+
return map;
116+
}
117+
118+
static const struct of_device_id ti_am335x_master_match[] = {
119+
{ .compatible = "ti,edma3-tpcc", },
120+
{},
121+
};
122+
123+
static int ti_am335x_xbar_probe(struct platform_device *pdev)
124+
{
125+
struct device_node *node = pdev->dev.of_node;
126+
const struct of_device_id *match;
127+
struct device_node *dma_node;
128+
struct ti_am335x_xbar_data *xbar;
129+
struct resource *res;
130+
void __iomem *iomem;
131+
int i, ret;
132+
133+
if (!node)
134+
return -ENODEV;
135+
136+
xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
137+
if (!xbar)
138+
return -ENOMEM;
139+
140+
dma_node = of_parse_phandle(node, "dma-masters", 0);
141+
if (!dma_node) {
142+
dev_err(&pdev->dev, "Can't get DMA master node\n");
143+
return -ENODEV;
144+
}
145+
146+
match = of_match_node(ti_am335x_master_match, dma_node);
147+
if (!match) {
148+
dev_err(&pdev->dev, "DMA master is not supported\n");
149+
return -EINVAL;
150+
}
151+
152+
if (of_property_read_u32(dma_node, "dma-requests",
153+
&xbar->dma_requests)) {
154+
dev_info(&pdev->dev,
155+
"Missing XBAR output information, using %u.\n",
156+
TI_AM335X_XBAR_LINES);
157+
xbar->dma_requests = TI_AM335X_XBAR_LINES;
158+
}
159+
of_node_put(dma_node);
160+
161+
if (of_property_read_u32(node, "dma-requests", &xbar->xbar_events)) {
162+
dev_info(&pdev->dev,
163+
"Missing XBAR input information, using %u.\n",
164+
TI_AM335X_XBAR_LINES);
165+
xbar->xbar_events = TI_AM335X_XBAR_LINES;
166+
}
167+
168+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
169+
iomem = devm_ioremap_resource(&pdev->dev, res);
170+
if (IS_ERR(iomem))
171+
return PTR_ERR(iomem);
172+
173+
xbar->iomem = iomem;
174+
175+
xbar->dmarouter.dev = &pdev->dev;
176+
xbar->dmarouter.route_free = ti_am335x_xbar_free;
177+
178+
platform_set_drvdata(pdev, xbar);
179+
180+
/* Reset the crossbar */
181+
for (i = 0; i < xbar->dma_requests; i++)
182+
ti_am335x_xbar_write(xbar->iomem, i, 0);
183+
184+
ret = of_dma_router_register(node, ti_am335x_xbar_route_allocate,
185+
&xbar->dmarouter);
186+
187+
return ret;
188+
}
189+
190+
/* Crossbar on DRA7xx family */
191+
#define TI_DRA7_XBAR_OUTPUTS 127
192+
#define TI_DRA7_XBAR_INPUTS 256
22193

23194
#define TI_XBAR_EDMA_OFFSET 0
24195
#define TI_XBAR_SDMA_OFFSET 1
25196

26-
struct ti_dma_xbar_data {
197+
struct ti_dra7_xbar_data {
27198
void __iomem *iomem;
28199

29200
struct dma_router dmarouter;
@@ -35,35 +206,35 @@ struct ti_dma_xbar_data {
35206
u32 dma_offset;
36207
};
37208

38-
struct ti_dma_xbar_map {
209+
struct ti_dra7_xbar_map {
39210
u16 xbar_in;
40211
int xbar_out;
41212
};
42213

43-
static inline void ti_dma_xbar_write(void __iomem *iomem, int xbar, u16 val)
214+
static inline void ti_dra7_xbar_write(void __iomem *iomem, int xbar, u16 val)
44215
{
45216
writew_relaxed(val, iomem + (xbar * 2));
46217
}
47218

48-
static void ti_dma_xbar_free(struct device *dev, void *route_data)
219+
static void ti_dra7_xbar_free(struct device *dev, void *route_data)
49220
{
50-
struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
51-
struct ti_dma_xbar_map *map = route_data;
221+
struct ti_dra7_xbar_data *xbar = dev_get_drvdata(dev);
222+
struct ti_dra7_xbar_map *map = route_data;
52223

53224
dev_dbg(dev, "Unmapping XBAR%u (was routed to %d)\n",
54225
map->xbar_in, map->xbar_out);
55226

56-
ti_dma_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
227+
ti_dra7_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
57228
idr_remove(&xbar->map_idr, map->xbar_out);
58229
kfree(map);
59230
}
60231

61-
static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec,
62-
struct of_dma *ofdma)
232+
static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
233+
struct of_dma *ofdma)
63234
{
64235
struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
65-
struct ti_dma_xbar_data *xbar = platform_get_drvdata(pdev);
66-
struct ti_dma_xbar_map *map;
236+
struct ti_dra7_xbar_data *xbar = platform_get_drvdata(pdev);
237+
struct ti_dra7_xbar_map *map;
67238

68239
if (dma_spec->args[0] >= xbar->xbar_requests) {
69240
dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
@@ -93,12 +264,12 @@ static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec,
93264
dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n",
94265
map->xbar_in, map->xbar_out);
95266

96-
ti_dma_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
267+
ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
97268

98269
return map;
99270
}
100271

101-
static const struct of_device_id ti_dma_master_match[] = {
272+
static const struct of_device_id ti_dra7_master_match[] = {
102273
{
103274
.compatible = "ti,omap4430-sdma",
104275
.data = (void *)TI_XBAR_SDMA_OFFSET,
@@ -110,12 +281,12 @@ static const struct of_device_id ti_dma_master_match[] = {
110281
{},
111282
};
112283

113-
static int ti_dma_xbar_probe(struct platform_device *pdev)
284+
static int ti_dra7_xbar_probe(struct platform_device *pdev)
114285
{
115286
struct device_node *node = pdev->dev.of_node;
116287
const struct of_device_id *match;
117288
struct device_node *dma_node;
118-
struct ti_dma_xbar_data *xbar;
289+
struct ti_dra7_xbar_data *xbar;
119290
struct resource *res;
120291
u32 safe_val;
121292
void __iomem *iomem;
@@ -136,7 +307,7 @@ static int ti_dma_xbar_probe(struct platform_device *pdev)
136307
return -ENODEV;
137308
}
138309

139-
match = of_match_node(ti_dma_master_match, dma_node);
310+
match = of_match_node(ti_dra7_master_match, dma_node);
140311
if (!match) {
141312
dev_err(&pdev->dev, "DMA master is not supported\n");
142313
return -EINVAL;
@@ -146,16 +317,16 @@ static int ti_dma_xbar_probe(struct platform_device *pdev)
146317
&xbar->dma_requests)) {
147318
dev_info(&pdev->dev,
148319
"Missing XBAR output information, using %u.\n",
149-
TI_XBAR_OUTPUTS);
150-
xbar->dma_requests = TI_XBAR_OUTPUTS;
320+
TI_DRA7_XBAR_OUTPUTS);
321+
xbar->dma_requests = TI_DRA7_XBAR_OUTPUTS;
151322
}
152323
of_node_put(dma_node);
153324

154325
if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
155326
dev_info(&pdev->dev,
156327
"Missing XBAR input information, using %u.\n",
157-
TI_XBAR_INPUTS);
158-
xbar->xbar_requests = TI_XBAR_INPUTS;
328+
TI_DRA7_XBAR_INPUTS);
329+
xbar->xbar_requests = TI_DRA7_XBAR_INPUTS;
159330
}
160331

161332
if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val))
@@ -169,30 +340,50 @@ static int ti_dma_xbar_probe(struct platform_device *pdev)
169340
xbar->iomem = iomem;
170341

171342
xbar->dmarouter.dev = &pdev->dev;
172-
xbar->dmarouter.route_free = ti_dma_xbar_free;
343+
xbar->dmarouter.route_free = ti_dra7_xbar_free;
173344
xbar->dma_offset = (u32)match->data;
174345

175346
platform_set_drvdata(pdev, xbar);
176347

177348
/* Reset the crossbar */
178349
for (i = 0; i < xbar->dma_requests; i++)
179-
ti_dma_xbar_write(xbar->iomem, i, xbar->safe_val);
350+
ti_dra7_xbar_write(xbar->iomem, i, xbar->safe_val);
180351

181-
ret = of_dma_router_register(node, ti_dma_xbar_route_allocate,
352+
ret = of_dma_router_register(node, ti_dra7_xbar_route_allocate,
182353
&xbar->dmarouter);
183354
if (ret) {
184355
/* Restore the defaults for the crossbar */
185356
for (i = 0; i < xbar->dma_requests; i++)
186-
ti_dma_xbar_write(xbar->iomem, i, i);
357+
ti_dra7_xbar_write(xbar->iomem, i, i);
187358
}
188359

189360
return ret;
190361
}
191362

192-
static const struct of_device_id ti_dma_xbar_match[] = {
193-
{ .compatible = "ti,dra7-dma-crossbar" },
194-
{},
195-
};
363+
static int ti_dma_xbar_probe(struct platform_device *pdev)
364+
{
365+
const struct of_device_id *match;
366+
int ret;
367+
368+
match = of_match_node(ti_dma_xbar_match, pdev->dev.of_node);
369+
if (unlikely(!match))
370+
return -EINVAL;
371+
372+
switch ((u32)match->data) {
373+
case TI_XBAR_DRA7:
374+
ret = ti_dra7_xbar_probe(pdev);
375+
break;
376+
case TI_XBAR_AM335X:
377+
ret = ti_am335x_xbar_probe(pdev);
378+
break;
379+
default:
380+
dev_err(&pdev->dev, "Unsupported crossbar\n");
381+
ret = -ENODEV;
382+
break;
383+
}
384+
385+
return ret;
386+
}
196387

197388
static struct platform_driver ti_dma_xbar_driver = {
198389
.driver = {

0 commit comments

Comments
 (0)