1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/device.h>
14#include <linux/err.h>
15#include <linux/module.h>
16#include <linux/mutex.h>
17#include <linux/slab.h>
18#include <linux/of.h>
19#include <linux/of_dma.h>
20
21static LIST_HEAD(of_dma_list);
22static DEFINE_MUTEX(of_dma_lock);
23
24
25
26
27
28
29
30
31
32
33static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
34{
35 struct of_dma *ofdma;
36
37 list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers)
38 if (ofdma->of_node == dma_spec->np)
39 return ofdma;
40
41 pr_debug("%s: can't find DMA controller %pOF\n", __func__,
42 dma_spec->np);
43
44 return NULL;
45}
46
47
48
49
50
51
52
53
54
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
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
85
86
87 of_node_put(dma_spec_target.np);
88 return chan;
89}
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104int of_dma_controller_register(struct device_node *np,
105 struct dma_chan *(*of_dma_xlate)
106 (struct of_phandle_args *, struct of_dma *),
107 void *data)
108{
109 struct of_dma *ofdma;
110
111 if (!np || !of_dma_xlate) {
112 pr_err("%s: not enough information provided\n", __func__);
113 return -EINVAL;
114 }
115
116 ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL);
117 if (!ofdma)
118 return -ENOMEM;
119
120 ofdma->of_node = np;
121 ofdma->of_dma_xlate = of_dma_xlate;
122 ofdma->of_dma_data = data;
123
124
125 mutex_lock(&of_dma_lock);
126 list_add_tail(&ofdma->of_dma_controllers, &of_dma_list);
127 mutex_unlock(&of_dma_lock);
128
129 return 0;
130}
131EXPORT_SYMBOL_GPL(of_dma_controller_register);
132
133
134
135
136
137
138
139void of_dma_controller_free(struct device_node *np)
140{
141 struct of_dma *ofdma;
142
143 mutex_lock(&of_dma_lock);
144
145 list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers)
146 if (ofdma->of_node == np) {
147 list_del(&ofdma->of_dma_controllers);
148 kfree(ofdma);
149 break;
150 }
151
152 mutex_unlock(&of_dma_lock);
153}
154EXPORT_SYMBOL_GPL(of_dma_controller_free);
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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
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
202
203
204
205
206
207
208
209
210
211
212static int of_dma_match_channel(struct device_node *np, const char *name,
213 int index, struct of_phandle_args *dma_spec)
214{
215 const char *s;
216
217 if (of_property_read_string_index(np, "dma-names", index, &s))
218 return -ENODEV;
219
220 if (strcmp(name, s))
221 return -ENODEV;
222
223 if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
224 dma_spec))
225 return -ENODEV;
226
227 return 0;
228}
229
230
231
232
233
234
235
236
237struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
238 const char *name)
239{
240 struct of_phandle_args dma_spec;
241 struct of_dma *ofdma;
242 struct dma_chan *chan;
243 int count, i, start;
244 int ret_no_channel = -ENODEV;
245 static atomic_t last_index;
246
247 if (!np || !name) {
248 pr_err("%s: not enough information provided\n", __func__);
249 return ERR_PTR(-ENODEV);
250 }
251
252
253 if (!of_find_property(np, "dmas", NULL))
254 return ERR_PTR(-ENODEV);
255
256 count = of_property_count_strings(np, "dma-names");
257 if (count < 0) {
258 pr_err("%s: dma-names property of node '%pOF' missing or empty\n",
259 __func__, np);
260 return ERR_PTR(-ENODEV);
261 }
262
263
264
265
266
267 start = atomic_inc_return(&last_index);
268 for (i = 0; i < count; i++) {
269 if (of_dma_match_channel(np, name,
270 (i + start) % count,
271 &dma_spec))
272 continue;
273
274 mutex_lock(&of_dma_lock);
275 ofdma = of_dma_find_controller(&dma_spec);
276
277 if (ofdma) {
278 chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
279 } else {
280 ret_no_channel = -EPROBE_DEFER;
281 chan = NULL;
282 }
283
284 mutex_unlock(&of_dma_lock);
285
286 of_node_put(dma_spec.np);
287
288 if (chan)
289 return chan;
290 }
291
292 return ERR_PTR(ret_no_channel);
293}
294EXPORT_SYMBOL_GPL(of_dma_request_slave_channel);
295
296
297
298
299
300
301
302
303
304
305
306
307struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
308 struct of_dma *ofdma)
309{
310 int count = dma_spec->args_count;
311 struct of_dma_filter_info *info = ofdma->of_dma_data;
312
313 if (!info || !info->filter_fn)
314 return NULL;
315
316 if (count != 1)
317 return NULL;
318
319 return dma_request_channel(info->dma_cap, info->filter_fn,
320 &dma_spec->args[0]);
321}
322EXPORT_SYMBOL_GPL(of_dma_simple_xlate);
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
338 struct of_dma *ofdma)
339{
340 struct dma_device *dev = ofdma->of_dma_data;
341 struct dma_chan *chan, *candidate = NULL;
342
343 if (!dev || dma_spec->args_count != 1)
344 return NULL;
345
346 list_for_each_entry(chan, &dev->channels, device_node)
347 if (chan->chan_id == dma_spec->args[0]) {
348 candidate = chan;
349 break;
350 }
351
352 if (!candidate)
353 return NULL;
354
355 return dma_get_slave_channel(candidate);
356}
357EXPORT_SYMBOL_GPL(of_dma_xlate_by_chan_id);
358