diff options
-rw-r--r-- | Documentation/devicetree/bindings/dma/dma.txt | 81 | ||||
-rw-r--r-- | drivers/of/Makefile | 2 | ||||
-rw-r--r-- | drivers/of/dma.c | 219 | ||||
-rw-r--r-- | include/linux/of_dma.h | 45 |
4 files changed, 346 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/dma/dma.txt b/Documentation/devicetree/bindings/dma/dma.txt new file mode 100644 index 000000000000..a4f59a5967d4 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/dma.txt | |||
@@ -0,0 +1,81 @@ | |||
1 | * Generic DMA Controller and DMA request bindings | ||
2 | |||
3 | Generic binding to provide a way for a driver using DMA Engine to retrieve the | ||
4 | DMA request or channel information that goes from a hardware device to a DMA | ||
5 | controller. | ||
6 | |||
7 | |||
8 | * DMA controller | ||
9 | |||
10 | Required property: | ||
11 | - #dma-cells: Must be at least 1. Used to provide DMA controller | ||
12 | specific information. See DMA client binding below for | ||
13 | more details. | ||
14 | |||
15 | Optional properties: | ||
16 | - #dma-channels: Number of DMA channels supported by the controller. | ||
17 | - #dma-requests: Number of DMA requests signals supported by the | ||
18 | controller. | ||
19 | |||
20 | Example: | ||
21 | |||
22 | dma: dma@48000000 { | ||
23 | compatible = "ti,omap-sdma" | ||
24 | reg = <0x48000000 0x1000>; | ||
25 | interrupts = <0 12 0x4 | ||
26 | 0 13 0x4 | ||
27 | 0 14 0x4 | ||
28 | 0 15 0x4>; | ||
29 | #dma-cells = <1>; | ||
30 | #dma-channels = <32>; | ||
31 | #dma-requests = <127>; | ||
32 | }; | ||
33 | |||
34 | |||
35 | * DMA client | ||
36 | |||
37 | Client drivers should specify the DMA property using a phandle to the controller | ||
38 | followed by DMA controller specific data. | ||
39 | |||
40 | Required property: | ||
41 | - dmas: List of one or more DMA specifiers, each consisting of | ||
42 | - A phandle pointing to DMA controller node | ||
43 | - A number of integer cells, as determined by the | ||
44 | #dma-cells property in the node referenced by phandle | ||
45 | containing DMA controller specific information. This | ||
46 | typically contains a DMA request line number or a | ||
47 | channel number, but can contain any data that is used | ||
48 | required for configuring a channel. | ||
49 | - dma-names: Contains one identifier string for each DMA specifier in | ||
50 | the dmas property. The specific strings that can be used | ||
51 | are defined in the binding of the DMA client device. | ||
52 | Multiple DMA specifiers can be used to represent | ||
53 | alternatives and in this case the dma-names for those | ||
54 | DMA specifiers must be identical (see examples). | ||
55 | |||
56 | Examples: | ||
57 | |||
58 | 1. A device with one DMA read channel, one DMA write channel: | ||
59 | |||
60 | i2c1: i2c@1 { | ||
61 | ... | ||
62 | dmas = <&dma 2 /* read channel */ | ||
63 | &dma 3>; /* write channel */ | ||
64 | dma-names = "rx", "tx" | ||
65 | ... | ||
66 | }; | ||
67 | |||
68 | 2. A single read-write channel with three alternative DMA controllers: | ||
69 | |||
70 | dmas = <&dma1 5 | ||
71 | &dma2 7 | ||
72 | &dma3 2>; | ||
73 | dma-names = "rx-tx", "rx-tx", "rx-tx" | ||
74 | |||
75 | 3. A device with three channels, one of which has two alternatives: | ||
76 | |||
77 | dmas = <&dma1 2 /* read channel */ | ||
78 | &dma1 3 /* write channel */ | ||
79 | &dma2 0 /* error read */ | ||
80 | &dma3 0>; /* alternative error read */ | ||
81 | dma-names = "rx", "tx", "error", "error"; | ||
diff --git a/drivers/of/Makefile b/drivers/of/Makefile index e027f444d10c..eafa107aed40 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y = base.o | 1 | obj-y = base.o dma.o |
2 | obj-$(CONFIG_OF_FLATTREE) += fdt.o | 2 | obj-$(CONFIG_OF_FLATTREE) += fdt.o |
3 | obj-$(CONFIG_OF_PROMTREE) += pdt.o | 3 | obj-$(CONFIG_OF_PROMTREE) += pdt.o |
4 | obj-$(CONFIG_OF_ADDRESS) += address.o | 4 | obj-$(CONFIG_OF_ADDRESS) += address.o |
diff --git a/drivers/of/dma.c b/drivers/of/dma.c new file mode 100644 index 000000000000..19ad37c066f5 --- /dev/null +++ b/drivers/of/dma.c | |||
@@ -0,0 +1,219 @@ | |||
1 | /* | ||
2 | * Device tree helpers for DMA request / controller | ||
3 | * | ||
4 | * Based on of_gpio.c | ||
5 | * | ||
6 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/rculist.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_dma.h> | ||
20 | |||
21 | static LIST_HEAD(of_dma_list); | ||
22 | |||
23 | /** | ||
24 | * of_dma_find_controller - Find a DMA controller in DT DMA helpers list | ||
25 | * @np: device node of DMA controller | ||
26 | */ | ||
27 | static struct of_dma *of_dma_find_controller(struct device_node *np) | ||
28 | { | ||
29 | struct of_dma *ofdma; | ||
30 | |||
31 | if (list_empty(&of_dma_list)) { | ||
32 | pr_err("empty DMA controller list\n"); | ||
33 | return NULL; | ||
34 | } | ||
35 | |||
36 | list_for_each_entry_rcu(ofdma, &of_dma_list, of_dma_controllers) | ||
37 | if (ofdma->of_node == np) | ||
38 | return ofdma; | ||
39 | |||
40 | return NULL; | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * of_dma_controller_register - Register a DMA controller to DT DMA helpers | ||
45 | * @np: device node of DMA controller | ||
46 | * @of_dma_xlate: translation function which converts a phandle | ||
47 | * arguments list into a dma_chan structure | ||
48 | * @data pointer to controller specific data to be used by | ||
49 | * translation function | ||
50 | * | ||
51 | * Returns 0 on success or appropriate errno value on error. | ||
52 | * | ||
53 | * Allocated memory should be freed with appropriate of_dma_controller_free() | ||
54 | * call. | ||
55 | */ | ||
56 | int of_dma_controller_register(struct device_node *np, | ||
57 | struct dma_chan *(*of_dma_xlate) | ||
58 | (struct of_phandle_args *, struct of_dma *), | ||
59 | void *data) | ||
60 | { | ||
61 | struct of_dma *ofdma; | ||
62 | int nbcells; | ||
63 | |||
64 | if (!np || !of_dma_xlate) { | ||
65 | pr_err("%s: not enough information provided\n", __func__); | ||
66 | return -EINVAL; | ||
67 | } | ||
68 | |||
69 | ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL); | ||
70 | if (!ofdma) | ||
71 | return -ENOMEM; | ||
72 | |||
73 | nbcells = be32_to_cpup(of_get_property(np, "#dma-cells", NULL)); | ||
74 | if (!nbcells) { | ||
75 | pr_err("%s: #dma-cells property is missing or invalid\n", | ||
76 | __func__); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | ofdma->of_node = np; | ||
81 | ofdma->of_dma_nbcells = nbcells; | ||
82 | ofdma->of_dma_xlate = of_dma_xlate; | ||
83 | ofdma->of_dma_data = data; | ||
84 | |||
85 | /* Now queue of_dma controller structure in list */ | ||
86 | list_add_tail_rcu(&ofdma->of_dma_controllers, &of_dma_list); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | EXPORT_SYMBOL_GPL(of_dma_controller_register); | ||
91 | |||
92 | /** | ||
93 | * of_dma_controller_free - Remove a DMA controller from DT DMA helpers list | ||
94 | * @np: device node of DMA controller | ||
95 | * | ||
96 | * Memory allocated by of_dma_controller_register() is freed here. | ||
97 | */ | ||
98 | void of_dma_controller_free(struct device_node *np) | ||
99 | { | ||
100 | struct of_dma *ofdma; | ||
101 | |||
102 | ofdma = of_dma_find_controller(np); | ||
103 | if (ofdma) { | ||
104 | list_del_rcu(&ofdma->of_dma_controllers); | ||
105 | kfree(ofdma); | ||
106 | } | ||
107 | } | ||
108 | EXPORT_SYMBOL_GPL(of_dma_controller_free); | ||
109 | |||
110 | /** | ||
111 | * of_dma_find_channel - Find a DMA channel by name | ||
112 | * @np: device node to look for DMA channels | ||
113 | * @name: name of desired channel | ||
114 | * @dma_spec: pointer to DMA specifier as found in the device tree | ||
115 | * | ||
116 | * Find a DMA channel by the name. Returns 0 on success or appropriate | ||
117 | * errno value on error. | ||
118 | */ | ||
119 | static int of_dma_find_channel(struct device_node *np, char *name, | ||
120 | struct of_phandle_args *dma_spec) | ||
121 | { | ||
122 | int count, i; | ||
123 | const char *s; | ||
124 | |||
125 | count = of_property_count_strings(np, "dma-names"); | ||
126 | if (count < 0) | ||
127 | return count; | ||
128 | |||
129 | for (i = 0; i < count; i++) { | ||
130 | if (of_property_read_string_index(np, "dma-names", i, &s)) | ||
131 | continue; | ||
132 | |||
133 | if (strcmp(name, s)) | ||
134 | continue; | ||
135 | |||
136 | if (!of_parse_phandle_with_args(np, "dmas", "#dma-cells", i, | ||
137 | dma_spec)) | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | return -ENODEV; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * of_dma_request_slave_channel - Get the DMA slave channel | ||
146 | * @np: device node to get DMA request from | ||
147 | * @name: name of desired channel | ||
148 | * | ||
149 | * Returns pointer to appropriate dma channel on success or NULL on error. | ||
150 | */ | ||
151 | struct dma_chan *of_dma_request_slave_channel(struct device_node *np, | ||
152 | char *name) | ||
153 | { | ||
154 | struct of_phandle_args dma_spec; | ||
155 | struct of_dma *ofdma; | ||
156 | struct dma_chan *chan; | ||
157 | int r; | ||
158 | |||
159 | if (!np || !name) { | ||
160 | pr_err("%s: not enough information provided\n", __func__); | ||
161 | return NULL; | ||
162 | } | ||
163 | |||
164 | do { | ||
165 | r = of_dma_find_channel(np, name, &dma_spec); | ||
166 | if (r) { | ||
167 | pr_err("%s: can't find DMA channel\n", np->full_name); | ||
168 | return NULL; | ||
169 | } | ||
170 | |||
171 | ofdma = of_dma_find_controller(dma_spec.np); | ||
172 | if (!ofdma) { | ||
173 | pr_debug("%s: can't find DMA controller %s\n", | ||
174 | np->full_name, dma_spec.np->full_name); | ||
175 | continue; | ||
176 | } | ||
177 | |||
178 | if (dma_spec.args_count != ofdma->of_dma_nbcells) { | ||
179 | pr_debug("%s: wrong #dma-cells for %s\n", np->full_name, | ||
180 | dma_spec.np->full_name); | ||
181 | continue; | ||
182 | } | ||
183 | |||
184 | chan = ofdma->of_dma_xlate(&dma_spec, ofdma); | ||
185 | |||
186 | of_node_put(dma_spec.np); | ||
187 | |||
188 | } while (!chan); | ||
189 | |||
190 | return chan; | ||
191 | } | ||
192 | |||
193 | /** | ||
194 | * of_dma_simple_xlate - Simple DMA engine translation function | ||
195 | * @dma_spec: pointer to DMA specifier as found in the device tree | ||
196 | * @of_dma: pointer to DMA controller data | ||
197 | * | ||
198 | * A simple translation function for devices that use a 32-bit value for the | ||
199 | * filter_param when calling the DMA engine dma_request_channel() function. | ||
200 | * Note that this translation function requires that #dma-cells is equal to 1 | ||
201 | * and the argument of the dma specifier is the 32-bit filter_param. Returns | ||
202 | * pointer to appropriate dma channel on success or NULL on error. | ||
203 | */ | ||
204 | struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, | ||
205 | struct of_dma *ofdma) | ||
206 | { | ||
207 | int count = dma_spec->args_count; | ||
208 | struct of_dma_filter_info *info = ofdma->of_dma_data; | ||
209 | |||
210 | if (!info || !info->filter_fn) | ||
211 | return NULL; | ||
212 | |||
213 | if (count != 1) | ||
214 | return NULL; | ||
215 | |||
216 | return dma_request_channel(info->dma_cap, info->filter_fn, | ||
217 | &dma_spec->args[0]); | ||
218 | } | ||
219 | EXPORT_SYMBOL_GPL(of_dma_simple_xlate); | ||
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h new file mode 100644 index 000000000000..337823dc6b90 --- /dev/null +++ b/include/linux/of_dma.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * OF helpers for DMA request / controller | ||
3 | * | ||
4 | * Based on of_gpio.h | ||
5 | * | ||
6 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __LINUX_OF_DMA_H | ||
14 | #define __LINUX_OF_DMA_H | ||
15 | |||
16 | #include <linux/of.h> | ||
17 | #include <linux/dmaengine.h> | ||
18 | |||
19 | struct device_node; | ||
20 | |||
21 | struct of_dma { | ||
22 | struct list_head of_dma_controllers; | ||
23 | struct device_node *of_node; | ||
24 | int of_dma_nbcells; | ||
25 | struct dma_chan *(*of_dma_xlate) | ||
26 | (struct of_phandle_args *, struct of_dma *); | ||
27 | void *of_dma_data; | ||
28 | }; | ||
29 | |||
30 | struct of_dma_filter_info { | ||
31 | dma_cap_mask_t dma_cap; | ||
32 | dma_filter_fn filter_fn; | ||
33 | }; | ||
34 | |||
35 | extern int of_dma_controller_register(struct device_node *np, | ||
36 | struct dma_chan *(*of_dma_xlate) | ||
37 | (struct of_phandle_args *, struct of_dma *), | ||
38 | void *data); | ||
39 | extern void of_dma_controller_free(struct device_node *np); | ||
40 | extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np, | ||
41 | char *name); | ||
42 | extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, | ||
43 | struct of_dma *ofdma); | ||
44 | |||
45 | #endif /* __LINUX_OF_DMA_H */ | ||