aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Hunter <jon-hunter@ti.com>2012-09-14 18:41:56 -0400
committerVinod Koul <vinod.koul@intel.com>2013-01-06 23:57:46 -0500
commitaa3da644c76d1c2083d085e453c18f7c51f19bc4 (patch)
treef92a6c181a229e6a694e2e763cb6ee8230e3e564
parent9a6cecc846169159bfce511f4c0034bb96eea1ca (diff)
of: Add generic device tree DMA helpers
This is based upon the work by Benoit Cousson [1] and Nicolas Ferre [2] to add some basic helpers to retrieve a DMA controller device_node and the DMA request/channel information. Aim of DMA helpers - The purpose of device-tree is to describe the capabilites of the hardware. Thinking about DMA controllers purely from the context of the hardware to begin with, we can describe a device in terms of a DMA controller as follows ... 1. Number of DMA controllers 2. Number of channels (maybe physical or logical) 3. Mapping of DMA requests signals to DMA controller 4. Number of DMA interrupts 5. Mapping of DMA interrupts to channels - With the above in mind the aim of the DT DMA helper functions is to extract the above information from the DT and provide to the appropriate driver. However, due to the vast number of DMA controllers and not all are using a common driver (such as DMA Engine) it has been seen that this is not a trivial task. In previous discussions on this topic the following concerns have been raised ... 1. How does the binding support devices with multiple DMA controllers? 2. How to support both legacy DMA controllers not using DMA Engine as well as those that support DMA Engine. 3. When using with DMA Engine how do we support the various implementations where the opaque filter function parameter differs between implementations? 4. How do we handle DMA channels that are identified with a string versus a integer? - Hence the design of the DMA helpers has to accomodate the above or align on an agreement what can be or should be supported. Design of DMA helpers 1. Registering DMA controllers In the case of DMA controllers that are using DMA Engine, requesting a channel is performed by calling the following function. struct dma_chan *dma_request_channel(dma_cap_mask_t mask, dma_filter_fn filter_fn, void *filter_param); The mask variable is used to match a type of the device controller in a list of controllers. The filter_fn and filter_param are used to identify the required dma channel and return a handle to the dma channel of type dma_chan. From the examples I have seen, the mask and filter_fn are constant for a given DMA controller and therefore, we can specify these as controller specific data when registering the DMA controller with the device-tree DMA helpers. The filter_param variable is of an unknown type and is typically specific to the DMA engine implementation for a given DMA controller. To allow some flexibility in the type and formating of this filter_param we employ an xlate to translate the device-tree binding information into the appropriate format. The xlate function used for a DMA controller can also be specified when registering the DMA controller with the device-tree DMA helpers. Based upon the above, a function for registering the DMA controller with the DMA helpers now looks like the below. The data variable is used to pass a pointer to DMA controller specific data used by the xlate function. int of_dma_controller_register(struct device_node *np, struct dma_chan *(*of_dma_xlate) (struct of_phandle_args *, struct of_dma *), void *data) For example, in the case where DMA engine is used, we define the following structure (that stores the DMA engine capability mask and filter function) and pass this to the data variable in the above function. struct of_dma_filter_info { dma_cap_mask_t dma_cap; dma_filter_fn filter_fn; }; 2. Representing and requesting channel information Please see the dma binding documentation included in this patch for a description of how DMA controllers and client information should be represented with device-tree. For more information on how this binding came about please see [3]. In addition to this, feedback received from the Linux kernel summit showed a consensus (among those who attended) to use a name to identify DMA client information [4]. A DMA channel can be requested by calling the following function, where name is a required parameter used for identifying a DMA channel. This function has been designed to return a structure of type dma_chan to work with the DMA engine driver. Note that if DMA engine is used then drivers should be using the DMA engine API dma_request_slave_channel() (implemented in part 2 of this series, "dmaengine: add helper function to request a slave DMA channel") which will in turn call the below function if device-tree is present. The aim being to have a common DMA engine interface regardless of whether device tree is being used. struct dma_chan *of_dma_request_slave_channel(struct device_node *np, char *name) 3. Supporting legacy devices not using DMA Engine These devices present a problem, as there may not be a uniform way to easily support them with regard to device tree. Ideally, these should be migrated to DMA engine. However, if this is not possible, then they should still be able to use this binding, the only constaint imposed by this implementation is that when requesting a DMA channel via of_dma_request_slave_channel(), it will return a type of dma_chan. This implementation has been tested on OMAP4430 using the kernel v3.6-rc5. I have validated that MMC is working on the PANDA board with this implementation. My development branch for testing on OMAP can be found here [5]. v6: - minor corrections in DMA binding documentation v5: - minor update to binding documentation - added loop to exhaustively search for a slave channel in the case where there could be alternative channels available v4: - revert the removal of xlate function from v3 - update the proposed binding format and APIs based upon discussions [3] v3: - avoid passing an xlate function and instead pass DMA engine parameters - define number of dma channels and requests in dma-controller node v2: - remove of_dma_to_resource API - make property #dma-cells required (no fallback anymore) - another check in of_dma_xlate_onenumbercell() function [1] http://article.gmane.org/gmane.linux.drivers.devicetree/12022 [2] http://article.gmane.org/gmane.linux.ports.arm.omap/73622 [3] http://marc.info/?l=linux-omap&m=133582085008539&w=2 [4] http://pad.linaro.org/arm-mini-summit-2012 [5] https://github.com/jonhunter/linux/tree/dev-dt-dma Cc: Nicolas Ferre <nicolas.ferre@atmel.com> Cc: Benoit Cousson <b-cousson@ti.com> Cc: Stephen Warren <swarren@nvidia.com> Cc: Grant Likely <grant.likely@secretlab.ca> Cc: Russell King <linux@arm.linux.org.uk> Cc: Rob Herring <rob.herring@calxeda.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Vinod Koul <vinod.koul@intel.com> Cc: Dan Williams <djbw@fb.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Jon Hunter <jon-hunter@ti.com> Reviewed-by: Stephen Warren <swarren@wwwdotorg.org> Acked-by: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
-rw-r--r--Documentation/devicetree/bindings/dma/dma.txt81
-rw-r--r--drivers/of/Makefile2
-rw-r--r--drivers/of/dma.c219
-rw-r--r--include/linux/of_dma.h45
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
3Generic binding to provide a way for a driver using DMA Engine to retrieve the
4DMA request or channel information that goes from a hardware device to a DMA
5controller.
6
7
8* DMA controller
9
10Required 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
15Optional 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
20Example:
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
37Client drivers should specify the DMA property using a phandle to the controller
38followed by DMA controller specific data.
39
40Required 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
56Examples:
57
581. 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
682. 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
753. 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 @@
1obj-y = base.o 1obj-y = base.o dma.o
2obj-$(CONFIG_OF_FLATTREE) += fdt.o 2obj-$(CONFIG_OF_FLATTREE) += fdt.o
3obj-$(CONFIG_OF_PROMTREE) += pdt.o 3obj-$(CONFIG_OF_PROMTREE) += pdt.o
4obj-$(CONFIG_OF_ADDRESS) += address.o 4obj-$(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
21static 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 */
27static 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 */
56int 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}
90EXPORT_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 */
98void 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}
108EXPORT_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 */
119static 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 */
151struct 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 */
204struct 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}
219EXPORT_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
19struct device_node;
20
21struct 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
30struct of_dma_filter_info {
31 dma_cap_mask_t dma_cap;
32 dma_filter_fn filter_fn;
33};
34
35extern 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);
39extern void of_dma_controller_free(struct device_node *np);
40extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
41 char *name);
42extern 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 */