aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2013-06-18 12:16:57 -0400
committerVinod Koul <vinod.koul@intel.com>2013-07-05 02:11:00 -0400
commit67eacc1583909d0588c8d5d80c16298c899a6382 (patch)
tree093794f972e21cf084efcb734667453db1c68926
parentd0951a23383d09276f7976ed34d8f1cede629b48 (diff)
DMA: shdma: add DT support
This patch adds Device Tree support to the shdma driver. No special DT properties are used, only standard DMA DT bindings are implemented. Since shdma controllers reside on SoCs, their configuration is SoC-specific and shall be passed to the driver from the SoC platform data, using the auxdata procedure. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski+renesas@gmail.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--Documentation/devicetree/bindings/dma/shdma.txt75
-rw-r--r--drivers/dma/sh/Makefile2
-rw-r--r--drivers/dma/sh/shdma-base.c26
-rw-r--r--drivers/dma/sh/shdma-of.c82
-rw-r--r--drivers/dma/sh/shdma.c31
-rw-r--r--include/linux/shdma-base.h2
6 files changed, 205 insertions, 13 deletions
diff --git a/Documentation/devicetree/bindings/dma/shdma.txt b/Documentation/devicetree/bindings/dma/shdma.txt
new file mode 100644
index 000000000000..c15994aa1939
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/shdma.txt
@@ -0,0 +1,75 @@
1* SHDMA Device Tree bindings
2
3Sh-/r-mobile and r-car systems often have multiple identical DMA controller
4instances, capable of serving any of a common set of DMA slave devices, using
5the same configuration. To describe this topology we require all compatible
6SHDMA DT nodes to be placed under a DMA multiplexer node. All such compatible
7DMAC instances have the same number of channels and use the same DMA
8descriptors. Therefore respective DMA DT bindings can also all be placed in the
9multiplexer node. Even if there is only one such DMAC instance on a system, it
10still has to be placed under such a multiplexer node.
11
12* DMA multiplexer
13
14Required properties:
15- compatible: should be "renesas,shdma-mux"
16- #dma-cells: should be <1>, see "dmas" property below
17
18Optional properties (currently unused):
19- dma-channels: number of DMA channels
20- dma-requests: number of DMA request signals
21
22* DMA controller
23
24Required properties:
25- compatible: should be "renesas,shdma"
26
27Example:
28 dmac: dma-mux0 {
29 compatible = "renesas,shdma-mux";
30 #dma-cells = <1>;
31 dma-channels = <6>;
32 dma-requests = <256>;
33 reg = <0 0>; /* Needed for AUXDATA */
34 #address-cells = <1>;
35 #size-cells = <1>;
36 ranges;
37
38 dma0: shdma@fe008020 {
39 compatible = "renesas,shdma";
40 reg = <0xfe008020 0x270>,
41 <0xfe009000 0xc>;
42 interrupt-parent = <&gic>;
43 interrupts = <0 34 4
44 0 28 4
45 0 29 4
46 0 30 4
47 0 31 4
48 0 32 4
49 0 33 4>;
50 interrupt-names = "error",
51 "ch0", "ch1", "ch2", "ch3",
52 "ch4", "ch5";
53 };
54
55 dma1: shdma@fe018020 {
56 ...
57 };
58
59 dma2: shdma@fe028020 {
60 ...
61 };
62 };
63
64* DMA client
65
66Required properties:
67- dmas: a list of <[DMA multiplexer phandle] [MID/RID value]> pairs,
68 where MID/RID values are fixed handles, specified in the SoC
69 manual
70- dma-names: a list of DMA channel names, one per "dmas" entry
71
72Example:
73 dmas = <&dmac 0xd1
74 &dmac 0xd2>;
75 dma-names = "tx", "rx";
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index c07ca4612e46..c962138dde96 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -1,3 +1,3 @@
1obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o 1obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
2obj-$(CONFIG_SH_DMAE) += shdma.o 2obj-$(CONFIG_SH_DMAE) += shdma.o
3obj-$(CONFIG_SUDMAC) += sudmac.o 3obj-$(CONFIG_SUDMAC) += sudmac.o
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c
index 4acb85a10250..28ca36121631 100644
--- a/drivers/dma/sh/shdma-base.c
+++ b/drivers/dma/sh/shdma-base.c
@@ -175,7 +175,18 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
175{ 175{
176 struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); 176 struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
177 const struct shdma_ops *ops = sdev->ops; 177 const struct shdma_ops *ops = sdev->ops;
178 int ret; 178 int ret, match;
179
180 if (schan->dev->of_node) {
181 match = schan->hw_req;
182 ret = ops->set_slave(schan, match, true);
183 if (ret < 0)
184 return ret;
185
186 slave_id = schan->slave_id;
187 } else {
188 match = slave_id;
189 }
179 190
180 if (slave_id < 0 || slave_id >= slave_num) 191 if (slave_id < 0 || slave_id >= slave_num)
181 return -EINVAL; 192 return -EINVAL;
@@ -183,7 +194,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
183 if (test_and_set_bit(slave_id, shdma_slave_used)) 194 if (test_and_set_bit(slave_id, shdma_slave_used))
184 return -EBUSY; 195 return -EBUSY;
185 196
186 ret = ops->set_slave(schan, slave_id, false); 197 ret = ops->set_slave(schan, match, false);
187 if (ret < 0) { 198 if (ret < 0) {
188 clear_bit(slave_id, shdma_slave_used); 199 clear_bit(slave_id, shdma_slave_used);
189 return ret; 200 return ret;
@@ -206,23 +217,26 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
206 * services would have to provide their own filters, which first would check 217 * services would have to provide their own filters, which first would check
207 * the device driver, similar to how other DMAC drivers, e.g., sa11x0-dma.c, do 218 * the device driver, similar to how other DMAC drivers, e.g., sa11x0-dma.c, do
208 * this, and only then, in case of a match, call this common filter. 219 * this, and only then, in case of a match, call this common filter.
220 * NOTE 2: This filter function is also used in the DT case by shdma_of_xlate().
221 * In that case the MID-RID value is used for slave channel filtering and is
222 * passed to this function in the "arg" parameter.
209 */ 223 */
210bool shdma_chan_filter(struct dma_chan *chan, void *arg) 224bool shdma_chan_filter(struct dma_chan *chan, void *arg)
211{ 225{
212 struct shdma_chan *schan = to_shdma_chan(chan); 226 struct shdma_chan *schan = to_shdma_chan(chan);
213 struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); 227 struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
214 const struct shdma_ops *ops = sdev->ops; 228 const struct shdma_ops *ops = sdev->ops;
215 int slave_id = (int)arg; 229 int match = (int)arg;
216 int ret; 230 int ret;
217 231
218 if (slave_id < 0) 232 if (match < 0)
219 /* No slave requested - arbitrary channel */ 233 /* No slave requested - arbitrary channel */
220 return true; 234 return true;
221 235
222 if (slave_id >= slave_num) 236 if (!schan->dev->of_node && match >= slave_num)
223 return false; 237 return false;
224 238
225 ret = ops->set_slave(schan, slave_id, true); 239 ret = ops->set_slave(schan, match, true);
226 if (ret < 0) 240 if (ret < 0)
227 return false; 241 return false;
228 242
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
new file mode 100644
index 000000000000..11bcb05cd79c
--- /dev/null
+++ b/drivers/dma/sh/shdma-of.c
@@ -0,0 +1,82 @@
1/*
2 * SHDMA Device Tree glue
3 *
4 * Copyright (C) 2013 Renesas Electronics Inc.
5 * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
6 *
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/dmaengine.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_dma.h>
16#include <linux/of_platform.h>
17#include <linux/platform_device.h>
18#include <linux/shdma-base.h>
19
20#define to_shdma_chan(c) container_of(c, struct shdma_chan, dma_chan)
21
22static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
23 struct of_dma *ofdma)
24{
25 u32 id = dma_spec->args[0];
26 dma_cap_mask_t mask;
27 struct dma_chan *chan;
28
29 if (dma_spec->args_count != 1)
30 return NULL;
31
32 dma_cap_zero(mask);
33 /* Only slave DMA channels can be allocated via DT */
34 dma_cap_set(DMA_SLAVE, mask);
35
36 chan = dma_request_channel(mask, shdma_chan_filter, (void *)id);
37 if (chan)
38 to_shdma_chan(chan)->hw_req = id;
39
40 return chan;
41}
42
43static int shdma_of_probe(struct platform_device *pdev)
44{
45 const struct of_dev_auxdata *lookup = pdev->dev.platform_data;
46 int ret;
47
48 if (!lookup)
49 return -EINVAL;
50
51 ret = of_dma_controller_register(pdev->dev.of_node,
52 shdma_of_xlate, pdev);
53 if (ret < 0)
54 return ret;
55
56 ret = of_platform_populate(pdev->dev.of_node, NULL, lookup, &pdev->dev);
57 if (ret < 0)
58 of_dma_controller_free(pdev->dev.of_node);
59
60 return ret;
61}
62
63static const struct of_device_id shdma_of_match[] = {
64 { .compatible = "renesas,shdma-mux", },
65 { }
66};
67MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
68
69static struct platform_driver shdma_of = {
70 .driver = {
71 .owner = THIS_MODULE,
72 .name = "shdma-of",
73 .of_match_table = shdma_of_match,
74 },
75 .probe = shdma_of_probe,
76};
77
78module_platform_driver(shdma_of);
79
80MODULE_LICENSE("GPL v2");
81MODULE_DESCRIPTION("SH-DMA driver DT glue");
82MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c
index a5a1887c34b5..b67f45f5c271 100644
--- a/drivers/dma/sh/shdma.c
+++ b/drivers/dma/sh/shdma.c
@@ -301,20 +301,32 @@ static void sh_dmae_setup_xfer(struct shdma_chan *schan,
301 } 301 }
302} 302}
303 303
304/*
305 * Find a slave channel configuration from the contoller list by either a slave
306 * ID in the non-DT case, or by a MID/RID value in the DT case
307 */
304static const struct sh_dmae_slave_config *dmae_find_slave( 308static const struct sh_dmae_slave_config *dmae_find_slave(
305 struct sh_dmae_chan *sh_chan, int slave_id) 309 struct sh_dmae_chan *sh_chan, int match)
306{ 310{
307 struct sh_dmae_device *shdev = to_sh_dev(sh_chan); 311 struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
308 struct sh_dmae_pdata *pdata = shdev->pdata; 312 struct sh_dmae_pdata *pdata = shdev->pdata;
309 const struct sh_dmae_slave_config *cfg; 313 const struct sh_dmae_slave_config *cfg;
310 int i; 314 int i;
311 315
312 if (slave_id >= SH_DMA_SLAVE_NUMBER) 316 if (!sh_chan->shdma_chan.dev->of_node) {
313 return NULL; 317 if (match >= SH_DMA_SLAVE_NUMBER)
318 return NULL;
314 319
315 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) 320 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
316 if (cfg->slave_id == slave_id) 321 if (cfg->slave_id == match)
317 return cfg; 322 return cfg;
323 } else {
324 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
325 if (cfg->mid_rid == match) {
326 sh_chan->shdma_chan.slave_id = cfg->slave_id;
327 return cfg;
328 }
329 }
318 330
319 return NULL; 331 return NULL;
320} 332}
@@ -920,11 +932,18 @@ static int sh_dmae_remove(struct platform_device *pdev)
920 return 0; 932 return 0;
921} 933}
922 934
935static const struct of_device_id sh_dmae_of_match[] = {
936 { .compatible = "renesas,shdma", },
937 { }
938};
939MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
940
923static struct platform_driver sh_dmae_driver = { 941static struct platform_driver sh_dmae_driver = {
924 .driver = { 942 .driver = {
925 .owner = THIS_MODULE, 943 .owner = THIS_MODULE,
926 .pm = &sh_dmae_pm, 944 .pm = &sh_dmae_pm,
927 .name = SH_DMAE_DRV_NAME, 945 .name = SH_DMAE_DRV_NAME,
946 .of_match_table = sh_dmae_of_match,
928 }, 947 },
929 .remove = sh_dmae_remove, 948 .remove = sh_dmae_remove,
930 .shutdown = sh_dmae_shutdown, 949 .shutdown = sh_dmae_shutdown,
diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h
index 9a938971bc4a..382cf710ca9a 100644
--- a/include/linux/shdma-base.h
+++ b/include/linux/shdma-base.h
@@ -68,6 +68,8 @@ struct shdma_chan {
68 int id; /* Raw id of this channel */ 68 int id; /* Raw id of this channel */
69 int irq; /* Channel IRQ */ 69 int irq; /* Channel IRQ */
70 int slave_id; /* Client ID for slave DMA */ 70 int slave_id; /* Client ID for slave DMA */
71 int hw_req; /* DMA request line for slave DMA - same
72 * as MID/RID, used with DT */
71 enum shdma_pm_state pm_state; 73 enum shdma_pm_state pm_state;
72}; 74};
73 75