aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVinod Koul <vinod.koul@intel.com>2016-12-13 22:37:07 -0500
committerVinod Koul <vinod.koul@intel.com>2016-12-13 22:37:07 -0500
commit4625d2a513d60ca9c3e8cae42c8f3d9efc1b4211 (patch)
tree12206d852d868d6ba2df3dd9bc3387555c0b4883
parent57fb7ee10c27b315600445b2bad72236a11951ad (diff)
parent3d6b3715fb5d4b7321a9ebd664991be2ed8f5f7b (diff)
Merge branch 'topic/st_fdma' into for-linus
-rw-r--r--Documentation/devicetree/bindings/dma/st_fdma.txt87
-rw-r--r--MAINTAINERS3
-rw-r--r--arch/arm/configs/multi_v7_defconfig6
-rw-r--r--drivers/dma/Kconfig14
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/st_fdma.c889
-rw-r--r--drivers/dma/st_fdma.h249
-rw-r--r--drivers/remoteproc/Kconfig25
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/st_slim_rproc.c364
-rw-r--r--include/linux/remoteproc/st_slim_rproc.h58
11 files changed, 1688 insertions, 9 deletions
diff --git a/Documentation/devicetree/bindings/dma/st_fdma.txt b/Documentation/devicetree/bindings/dma/st_fdma.txt
new file mode 100644
index 000000000000..495d853c569b
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/st_fdma.txt
@@ -0,0 +1,87 @@
1* STMicroelectronics Flexible Direct Memory Access Device Tree bindings
2
3The FDMA is a general-purpose direct memory access controller capable of
4supporting 16 independent DMA channels. It accepts up to 32 DMA requests.
5The FDMA is based on a Slim processor which requires a firmware.
6
7* FDMA Controller
8
9Required properties:
10- compatible : Should be one of
11 - st,stih407-fdma-mpe31-11, "st,slim-rproc";
12 - st,stih407-fdma-mpe31-12, "st,slim-rproc";
13 - st,stih407-fdma-mpe31-13, "st,slim-rproc";
14- reg : Should contain an entry for each name in reg-names
15- reg-names : Must contain "slimcore", "dmem", "peripherals", "imem" entries
16- interrupts : Should contain one interrupt shared by all channels
17- dma-channels : Number of channels supported by the controller
18- #dma-cells : Must be <3>. See DMA client section below
19- clocks : Must contain an entry for each clock
20See: Documentation/devicetree/bindings/clock/clock-bindings.txt
21
22
23Example:
24
25 fdma0: dma-controller@8e20000 {
26 compatible = "st,stih407-fdma-mpe31-11", "st,slim-rproc";
27 reg = <0x8e20000 0x8000>,
28 <0x8e30000 0x3000>,
29 <0x8e37000 0x1000>,
30 <0x8e38000 0x8000>;
31 reg-names = "slimcore", "dmem", "peripherals", "imem";
32 clocks = <&clk_s_c0_flexgen CLK_FDMA>,
33 <&clk_s_c0_flexgen CLK_EXT2F_A9>,
34 <&clk_s_c0_flexgen CLK_EXT2F_A9>,
35 <&clk_s_c0_flexgen CLK_EXT2F_A9>;
36 interrupts = <GIC_SPI 5 IRQ_TYPE_NONE>;
37 dma-channels = <16>;
38 #dma-cells = <3>;
39 };
40
41* DMA client
42
43Required properties:
44- dmas: Comma separated list of dma channel requests
45- dma-names: Names of the aforementioned requested channels
46
47Each dmas request consists of 4 cells:
481. A phandle pointing to the FDMA controller
492. The request line number
503. A 32bit mask specifying (see include/linux/platform_data/dma-st-fdma.h)
51 -bit 2-0: Holdoff value, dreq will be masked for
52 0x0: 0-0.5us
53 0x1: 0.5-1us
54 0x2: 1-1.5us
55 -bit 17: data swap
56 0x0: disabled
57 0x1: enabled
58 -bit 21: Increment Address
59 0x0: no address increment between transfers
60 0x1: increment address between transfers
61 -bit 22: 2 STBus Initiator Coprocessor interface
62 0x0: high priority port
63 0x1: low priority port
644. transfers type
65 0 free running
66 1 paced
67
68Example:
69
70 sti_uni_player2: sti-uni-player@2 {
71 compatible = "st,sti-uni-player";
72 status = "disabled";
73 #sound-dai-cells = <0>;
74 st,syscfg = <&syscfg_core>;
75 clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
76 assigned-clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
77 assigned-clock-parents = <&clk_s_d0_quadfs 2>;
78 assigned-clock-rates = <50000000>;
79 reg = <0x8D82000 0x158>;
80 interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
81 dmas = <&fdma0 4 0 1>;
82 dai-name = "Uni Player #1 (DAC)";
83 dma-names = "tx";
84 st,uniperiph-id = <2>;
85 st,version = <5>;
86 st,mode = "PCM";
87 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 1cd38a7e0064..e93762dda21d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1774,6 +1774,7 @@ F: drivers/char/hw_random/st-rng.c
1774F: drivers/clocksource/arm_global_timer.c 1774F: drivers/clocksource/arm_global_timer.c
1775F: drivers/clocksource/clksrc_st_lpc.c 1775F: drivers/clocksource/clksrc_st_lpc.c
1776F: drivers/cpufreq/sti-cpufreq.c 1776F: drivers/cpufreq/sti-cpufreq.c
1777F: drivers/dma/st_fdma*
1777F: drivers/i2c/busses/i2c-st.c 1778F: drivers/i2c/busses/i2c-st.c
1778F: drivers/media/rc/st_rc.c 1779F: drivers/media/rc/st_rc.c
1779F: drivers/media/platform/sti/c8sectpfe/ 1780F: drivers/media/platform/sti/c8sectpfe/
@@ -1784,6 +1785,7 @@ F: drivers/phy/phy-stih407-usb.c
1784F: drivers/phy/phy-stih41x-usb.c 1785F: drivers/phy/phy-stih41x-usb.c
1785F: drivers/pinctrl/pinctrl-st.c 1786F: drivers/pinctrl/pinctrl-st.c
1786F: drivers/remoteproc/st_remoteproc.c 1787F: drivers/remoteproc/st_remoteproc.c
1788F: drivers/remoteproc/st_slim_rproc.c
1787F: drivers/reset/sti/ 1789F: drivers/reset/sti/
1788F: drivers/rtc/rtc-st-lpc.c 1790F: drivers/rtc/rtc-st-lpc.c
1789F: drivers/tty/serial/st-asc.c 1791F: drivers/tty/serial/st-asc.c
@@ -1792,6 +1794,7 @@ F: drivers/usb/host/ehci-st.c
1792F: drivers/usb/host/ohci-st.c 1794F: drivers/usb/host/ohci-st.c
1793F: drivers/watchdog/st_lpc_wdt.c 1795F: drivers/watchdog/st_lpc_wdt.c
1794F: drivers/ata/ahci_st.c 1796F: drivers/ata/ahci_st.c
1797F: include/linux/remoteproc/st_slim_rproc.h
1795 1798
1796ARM/STM32 ARCHITECTURE 1799ARM/STM32 ARCHITECTURE
1797M: Maxime Coquelin <mcoquelin.stm32@gmail.com> 1800M: Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 437d0740dec6..a977e57886e3 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -649,6 +649,9 @@ CONFIG_SND_SOC_AK4642=m
649CONFIG_SND_SOC_SGTL5000=m 649CONFIG_SND_SOC_SGTL5000=m
650CONFIG_SND_SOC_SPDIF=m 650CONFIG_SND_SOC_SPDIF=m
651CONFIG_SND_SOC_WM8978=m 651CONFIG_SND_SOC_WM8978=m
652CONFIG_SND_SOC_STI=m
653CONFIG_SND_SOC_STI_SAS=m
654CONFIG_SND_SIMPLE_CARD=m
652CONFIG_USB=y 655CONFIG_USB=y
653CONFIG_USB_XHCI_HCD=y 656CONFIG_USB_XHCI_HCD=y
654CONFIG_USB_XHCI_MVEBU=y 657CONFIG_USB_XHCI_MVEBU=y
@@ -790,6 +793,7 @@ CONFIG_DMA_OMAP=y
790CONFIG_QCOM_BAM_DMA=y 793CONFIG_QCOM_BAM_DMA=y
791CONFIG_XILINX_DMA=y 794CONFIG_XILINX_DMA=y
792CONFIG_DMA_SUN6I=y 795CONFIG_DMA_SUN6I=y
796CONFIG_ST_FDMA=m
793CONFIG_STAGING=y 797CONFIG_STAGING=y
794CONFIG_SENSORS_ISL29018=y 798CONFIG_SENSORS_ISL29018=y
795CONFIG_SENSORS_ISL29028=y 799CONFIG_SENSORS_ISL29028=y
@@ -823,6 +827,8 @@ CONFIG_HWSPINLOCK_QCOM=y
823CONFIG_ROCKCHIP_IOMMU=y 827CONFIG_ROCKCHIP_IOMMU=y
824CONFIG_TEGRA_IOMMU_GART=y 828CONFIG_TEGRA_IOMMU_GART=y
825CONFIG_TEGRA_IOMMU_SMMU=y 829CONFIG_TEGRA_IOMMU_SMMU=y
830CONFIG_REMOTEPROC=m
831CONFIG_ST_REMOTEPROC=m
826CONFIG_PM_DEVFREQ=y 832CONFIG_PM_DEVFREQ=y
827CONFIG_ARM_TEGRA_DEVFREQ=m 833CONFIG_ARM_TEGRA_DEVFREQ=m
828CONFIG_MEMORY=y 834CONFIG_MEMORY=y
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 4595f5009244..b4cb5cb7775c 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -435,6 +435,20 @@ config STE_DMA40
435 help 435 help
436 Support for ST-Ericsson DMA40 controller 436 Support for ST-Ericsson DMA40 controller
437 437
438config ST_FDMA
439 tristate "ST FDMA dmaengine support"
440 depends on ARCH_STI
441 depends on REMOTEPROC
442 select ST_SLIM_REMOTEPROC
443 select DMA_ENGINE
444 select DMA_VIRTUAL_CHANNELS
445 help
446 Enable support for ST FDMA controller.
447 It supports 16 independent DMA channels, accepts up to 32 DMA requests
448
449 Say Y here if you have such a chipset.
450 If unsure, say N.
451
438config STM32_DMA 452config STM32_DMA
439 bool "STMicroelectronics STM32 DMA support" 453 bool "STMicroelectronics STM32 DMA support"
440 depends on ARCH_STM32 || COMPILE_TEST 454 depends on ARCH_STM32 || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index e4dc9cac7ee8..a4fa3360e609 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o
67obj-$(CONFIG_TI_EDMA) += edma.o 67obj-$(CONFIG_TI_EDMA) += edma.o
68obj-$(CONFIG_XGENE_DMA) += xgene-dma.o 68obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
69obj-$(CONFIG_ZX_DMA) += zx296702_dma.o 69obj-$(CONFIG_ZX_DMA) += zx296702_dma.o
70obj-$(CONFIG_ST_FDMA) += st_fdma.o
70 71
71obj-y += qcom/ 72obj-y += qcom/
72obj-y += xilinx/ 73obj-y += xilinx/
diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c
new file mode 100644
index 000000000000..bfb79bd0c6de
--- /dev/null
+++ b/drivers/dma/st_fdma.c
@@ -0,0 +1,889 @@
1/*
2 * DMA driver for STMicroelectronics STi FDMA controller
3 *
4 * Copyright (C) 2014 STMicroelectronics
5 *
6 * Author: Ludovic Barre <Ludovic.barre@st.com>
7 * Peter Griffin <peter.griffin@linaro.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/of_device.h>
18#include <linux/of_dma.h>
19#include <linux/platform_device.h>
20#include <linux/interrupt.h>
21#include <linux/remoteproc.h>
22
23#include "st_fdma.h"
24
25static inline struct st_fdma_chan *to_st_fdma_chan(struct dma_chan *c)
26{
27 return container_of(c, struct st_fdma_chan, vchan.chan);
28}
29
30static struct st_fdma_desc *to_st_fdma_desc(struct virt_dma_desc *vd)
31{
32 return container_of(vd, struct st_fdma_desc, vdesc);
33}
34
35static int st_fdma_dreq_get(struct st_fdma_chan *fchan)
36{
37 struct st_fdma_dev *fdev = fchan->fdev;
38 u32 req_line_cfg = fchan->cfg.req_line;
39 u32 dreq_line;
40 int try = 0;
41
42 /*
43 * dreq_mask is shared for n channels of fdma, so all accesses must be
44 * atomic. if the dreq_mask is changed between ffz and set_bit,
45 * we retry
46 */
47 do {
48 if (fdev->dreq_mask == ~0L) {
49 dev_err(fdev->dev, "No req lines available\n");
50 return -EINVAL;
51 }
52
53 if (try || req_line_cfg >= ST_FDMA_NR_DREQS) {
54 dev_err(fdev->dev, "Invalid or used req line\n");
55 return -EINVAL;
56 } else {
57 dreq_line = req_line_cfg;
58 }
59
60 try++;
61 } while (test_and_set_bit(dreq_line, &fdev->dreq_mask));
62
63 dev_dbg(fdev->dev, "get dreq_line:%d mask:%#lx\n",
64 dreq_line, fdev->dreq_mask);
65
66 return dreq_line;
67}
68
69static void st_fdma_dreq_put(struct st_fdma_chan *fchan)
70{
71 struct st_fdma_dev *fdev = fchan->fdev;
72
73 dev_dbg(fdev->dev, "put dreq_line:%#x\n", fchan->dreq_line);
74 clear_bit(fchan->dreq_line, &fdev->dreq_mask);
75}
76
77static void st_fdma_xfer_desc(struct st_fdma_chan *fchan)
78{
79 struct virt_dma_desc *vdesc;
80 unsigned long nbytes, ch_cmd, cmd;
81
82 vdesc = vchan_next_desc(&fchan->vchan);
83 if (!vdesc)
84 return;
85
86 fchan->fdesc = to_st_fdma_desc(vdesc);
87 nbytes = fchan->fdesc->node[0].desc->nbytes;
88 cmd = FDMA_CMD_START(fchan->vchan.chan.chan_id);
89 ch_cmd = fchan->fdesc->node[0].pdesc | FDMA_CH_CMD_STA_START;
90
91 /* start the channel for the descriptor */
92 fnode_write(fchan, nbytes, FDMA_CNTN_OFST);
93 fchan_write(fchan, ch_cmd, FDMA_CH_CMD_OFST);
94 writel(cmd,
95 fchan->fdev->slim_rproc->peri + FDMA_CMD_SET_OFST);
96
97 dev_dbg(fchan->fdev->dev, "start chan:%d\n", fchan->vchan.chan.chan_id);
98}
99
100static void st_fdma_ch_sta_update(struct st_fdma_chan *fchan,
101 unsigned long int_sta)
102{
103 unsigned long ch_sta, ch_err;
104 int ch_id = fchan->vchan.chan.chan_id;
105 struct st_fdma_dev *fdev = fchan->fdev;
106
107 ch_sta = fchan_read(fchan, FDMA_CH_CMD_OFST);
108 ch_err = ch_sta & FDMA_CH_CMD_ERR_MASK;
109 ch_sta &= FDMA_CH_CMD_STA_MASK;
110
111 if (int_sta & FDMA_INT_STA_ERR) {
112 dev_warn(fdev->dev, "chan:%d, error:%ld\n", ch_id, ch_err);
113 fchan->status = DMA_ERROR;
114 return;
115 }
116
117 switch (ch_sta) {
118 case FDMA_CH_CMD_STA_PAUSED:
119 fchan->status = DMA_PAUSED;
120 break;
121
122 case FDMA_CH_CMD_STA_RUNNING:
123 fchan->status = DMA_IN_PROGRESS;
124 break;
125 }
126}
127
128static irqreturn_t st_fdma_irq_handler(int irq, void *dev_id)
129{
130 struct st_fdma_dev *fdev = dev_id;
131 irqreturn_t ret = IRQ_NONE;
132 struct st_fdma_chan *fchan = &fdev->chans[0];
133 unsigned long int_sta, clr;
134
135 int_sta = fdma_read(fdev, FDMA_INT_STA_OFST);
136 clr = int_sta;
137
138 for (; int_sta != 0 ; int_sta >>= 2, fchan++) {
139 if (!(int_sta & (FDMA_INT_STA_CH | FDMA_INT_STA_ERR)))
140 continue;
141
142 spin_lock(&fchan->vchan.lock);
143 st_fdma_ch_sta_update(fchan, int_sta);
144
145 if (fchan->fdesc) {
146 if (!fchan->fdesc->iscyclic) {
147 list_del(&fchan->fdesc->vdesc.node);
148 vchan_cookie_complete(&fchan->fdesc->vdesc);
149 fchan->fdesc = NULL;
150 fchan->status = DMA_COMPLETE;
151 } else {
152 vchan_cyclic_callback(&fchan->fdesc->vdesc);
153 }
154
155 /* Start the next descriptor (if available) */
156 if (!fchan->fdesc)
157 st_fdma_xfer_desc(fchan);
158 }
159
160 spin_unlock(&fchan->vchan.lock);
161 ret = IRQ_HANDLED;
162 }
163
164 fdma_write(fdev, clr, FDMA_INT_CLR_OFST);
165
166 return ret;
167}
168
169static struct dma_chan *st_fdma_of_xlate(struct of_phandle_args *dma_spec,
170 struct of_dma *ofdma)
171{
172 struct st_fdma_dev *fdev = ofdma->of_dma_data;
173 struct dma_chan *chan;
174 struct st_fdma_chan *fchan;
175 int ret;
176
177 if (dma_spec->args_count < 1)
178 return ERR_PTR(-EINVAL);
179
180 if (fdev->dma_device.dev->of_node != dma_spec->np)
181 return ERR_PTR(-EINVAL);
182
183 ret = rproc_boot(fdev->slim_rproc->rproc);
184 if (ret == -ENOENT)
185 return ERR_PTR(-EPROBE_DEFER);
186 else if (ret)
187 return ERR_PTR(ret);
188
189 chan = dma_get_any_slave_channel(&fdev->dma_device);
190 if (!chan)
191 goto err_chan;
192
193 fchan = to_st_fdma_chan(chan);
194
195 fchan->cfg.of_node = dma_spec->np;
196 fchan->cfg.req_line = dma_spec->args[0];
197 fchan->cfg.req_ctrl = 0;
198 fchan->cfg.type = ST_FDMA_TYPE_FREE_RUN;
199
200 if (dma_spec->args_count > 1)
201 fchan->cfg.req_ctrl = dma_spec->args[1]
202 & FDMA_REQ_CTRL_CFG_MASK;
203
204 if (dma_spec->args_count > 2)
205 fchan->cfg.type = dma_spec->args[2];
206
207 if (fchan->cfg.type == ST_FDMA_TYPE_FREE_RUN) {
208 fchan->dreq_line = 0;
209 } else {
210 fchan->dreq_line = st_fdma_dreq_get(fchan);
211 if (IS_ERR_VALUE(fchan->dreq_line)) {
212 chan = ERR_PTR(fchan->dreq_line);
213 goto err_chan;
214 }
215 }
216
217 dev_dbg(fdev->dev, "xlate req_line:%d type:%d req_ctrl:%#lx\n",
218 fchan->cfg.req_line, fchan->cfg.type, fchan->cfg.req_ctrl);
219
220 return chan;
221
222err_chan:
223 rproc_shutdown(fdev->slim_rproc->rproc);
224 return chan;
225
226}
227
228static void st_fdma_free_desc(struct virt_dma_desc *vdesc)
229{
230 struct st_fdma_desc *fdesc;
231 int i;
232
233 fdesc = to_st_fdma_desc(vdesc);
234 for (i = 0; i < fdesc->n_nodes; i++)
235 dma_pool_free(fdesc->fchan->node_pool, fdesc->node[i].desc,
236 fdesc->node[i].pdesc);
237 kfree(fdesc);
238}
239
240static struct st_fdma_desc *st_fdma_alloc_desc(struct st_fdma_chan *fchan,
241 int sg_len)
242{
243 struct st_fdma_desc *fdesc;
244 int i;
245
246 fdesc = kzalloc(sizeof(*fdesc) +
247 sizeof(struct st_fdma_sw_node) * sg_len, GFP_NOWAIT);
248 if (!fdesc)
249 return NULL;
250
251 fdesc->fchan = fchan;
252 fdesc->n_nodes = sg_len;
253 for (i = 0; i < sg_len; i++) {
254 fdesc->node[i].desc = dma_pool_alloc(fchan->node_pool,
255 GFP_NOWAIT, &fdesc->node[i].pdesc);
256 if (!fdesc->node[i].desc)
257 goto err;
258 }
259 return fdesc;
260
261err:
262 while (--i >= 0)
263 dma_pool_free(fchan->node_pool, fdesc->node[i].desc,
264 fdesc->node[i].pdesc);
265 kfree(fdesc);
266 return NULL;
267}
268
269static int st_fdma_alloc_chan_res(struct dma_chan *chan)
270{
271 struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
272
273 /* Create the dma pool for descriptor allocation */
274 fchan->node_pool = dma_pool_create(dev_name(&chan->dev->device),
275 fchan->fdev->dev,
276 sizeof(struct st_fdma_hw_node),
277 __alignof__(struct st_fdma_hw_node),
278 0);
279
280 if (!fchan->node_pool) {
281 dev_err(fchan->fdev->dev, "unable to allocate desc pool\n");
282 return -ENOMEM;
283 }
284
285 dev_dbg(fchan->fdev->dev, "alloc ch_id:%d type:%d\n",
286 fchan->vchan.chan.chan_id, fchan->cfg.type);
287
288 return 0;
289}
290
291static void st_fdma_free_chan_res(struct dma_chan *chan)
292{
293 struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
294 struct rproc *rproc = fchan->fdev->slim_rproc->rproc;
295 unsigned long flags;
296
297 LIST_HEAD(head);
298
299 dev_dbg(fchan->fdev->dev, "%s: freeing chan:%d\n",
300 __func__, fchan->vchan.chan.chan_id);
301
302 if (fchan->cfg.type != ST_FDMA_TYPE_FREE_RUN)
303 st_fdma_dreq_put(fchan);
304
305 spin_lock_irqsave(&fchan->vchan.lock, flags);
306 fchan->fdesc = NULL;
307 spin_unlock_irqrestore(&fchan->vchan.lock, flags);
308
309 dma_pool_destroy(fchan->node_pool);
310 fchan->node_pool = NULL;
311 memset(&fchan->cfg, 0, sizeof(struct st_fdma_cfg));
312
313 rproc_shutdown(rproc);
314}
315
316static struct dma_async_tx_descriptor *st_fdma_prep_dma_memcpy(
317 struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
318 size_t len, unsigned long flags)
319{
320 struct st_fdma_chan *fchan;
321 struct st_fdma_desc *fdesc;
322 struct st_fdma_hw_node *hw_node;
323
324 if (!len)
325 return NULL;
326
327 fchan = to_st_fdma_chan(chan);
328
329 /* We only require a single descriptor */
330 fdesc = st_fdma_alloc_desc(fchan, 1);
331 if (!fdesc) {
332 dev_err(fchan->fdev->dev, "no memory for desc\n");
333 return NULL;
334 }
335
336 hw_node = fdesc->node[0].desc;
337 hw_node->next = 0;
338 hw_node->control = FDMA_NODE_CTRL_REQ_MAP_FREE_RUN;
339 hw_node->control |= FDMA_NODE_CTRL_SRC_INCR;
340 hw_node->control |= FDMA_NODE_CTRL_DST_INCR;
341 hw_node->control |= FDMA_NODE_CTRL_INT_EON;
342 hw_node->nbytes = len;
343 hw_node->saddr = src;
344 hw_node->daddr = dst;
345 hw_node->generic.length = len;
346 hw_node->generic.sstride = 0;
347 hw_node->generic.dstride = 0;
348
349 return vchan_tx_prep(&fchan->vchan, &fdesc->vdesc, flags);
350}
351
352static int config_reqctrl(struct st_fdma_chan *fchan,
353 enum dma_transfer_direction direction)
354{
355 u32 maxburst = 0, addr = 0;
356 enum dma_slave_buswidth width;
357 int ch_id = fchan->vchan.chan.chan_id;
358 struct st_fdma_dev *fdev = fchan->fdev;
359
360 switch (direction) {
361
362 case DMA_DEV_TO_MEM:
363 fchan->cfg.req_ctrl &= ~FDMA_REQ_CTRL_WNR;
364 maxburst = fchan->scfg.src_maxburst;
365 width = fchan->scfg.src_addr_width;
366 addr = fchan->scfg.src_addr;
367 break;
368
369 case DMA_MEM_TO_DEV:
370 fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_WNR;
371 maxburst = fchan->scfg.dst_maxburst;
372 width = fchan->scfg.dst_addr_width;
373 addr = fchan->scfg.dst_addr;
374 break;
375
376 default:
377 return -EINVAL;
378 }
379
380 fchan->cfg.req_ctrl &= ~FDMA_REQ_CTRL_OPCODE_MASK;
381
382 switch (width) {
383
384 case DMA_SLAVE_BUSWIDTH_1_BYTE:
385 fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_OPCODE_LD_ST1;
386 break;
387
388 case DMA_SLAVE_BUSWIDTH_2_BYTES:
389 fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_OPCODE_LD_ST2;
390 break;
391
392 case DMA_SLAVE_BUSWIDTH_4_BYTES:
393 fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_OPCODE_LD_ST4;
394 break;
395
396 case DMA_SLAVE_BUSWIDTH_8_BYTES:
397 fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_OPCODE_LD_ST8;
398 break;
399
400 default:
401 return -EINVAL;
402 }
403
404 fchan->cfg.req_ctrl &= ~FDMA_REQ_CTRL_NUM_OPS_MASK;
405 fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_NUM_OPS(maxburst-1);
406 dreq_write(fchan, fchan->cfg.req_ctrl, FDMA_REQ_CTRL_OFST);
407
408 fchan->cfg.dev_addr = addr;
409 fchan->cfg.dir = direction;
410
411 dev_dbg(fdev->dev, "chan:%d config_reqctrl:%#x req_ctrl:%#lx\n",
412 ch_id, addr, fchan->cfg.req_ctrl);
413
414 return 0;
415}
416
417static void fill_hw_node(struct st_fdma_hw_node *hw_node,
418 struct st_fdma_chan *fchan,
419 enum dma_transfer_direction direction)
420{
421 if (direction == DMA_MEM_TO_DEV) {
422 hw_node->control |= FDMA_NODE_CTRL_SRC_INCR;
423 hw_node->control |= FDMA_NODE_CTRL_DST_STATIC;
424 hw_node->daddr = fchan->cfg.dev_addr;
425 } else {
426 hw_node->control |= FDMA_NODE_CTRL_SRC_STATIC;
427 hw_node->control |= FDMA_NODE_CTRL_DST_INCR;
428 hw_node->saddr = fchan->cfg.dev_addr;
429 }
430
431 hw_node->generic.sstride = 0;
432 hw_node->generic.dstride = 0;
433}
434
435static inline struct st_fdma_chan *st_fdma_prep_common(struct dma_chan *chan,
436 size_t len, enum dma_transfer_direction direction)
437{
438 struct st_fdma_chan *fchan;
439
440 if (!chan || !len)
441 return NULL;
442
443 fchan = to_st_fdma_chan(chan);
444
445 if (!is_slave_direction(direction)) {
446 dev_err(fchan->fdev->dev, "bad direction?\n");
447 return NULL;
448 }
449
450 return fchan;
451}
452
453static struct dma_async_tx_descriptor *st_fdma_prep_dma_cyclic(
454 struct dma_chan *chan, dma_addr_t buf_addr, size_t len,
455 size_t period_len, enum dma_transfer_direction direction,
456 unsigned long flags)
457{
458 struct st_fdma_chan *fchan;
459 struct st_fdma_desc *fdesc;
460 int sg_len, i;
461
462 fchan = st_fdma_prep_common(chan, len, direction);
463 if (!fchan)
464 return NULL;
465
466 if (!period_len)
467 return NULL;
468
469 if (config_reqctrl(fchan, direction)) {
470 dev_err(fchan->fdev->dev, "bad width or direction\n");
471 return NULL;
472 }
473
474 /* the buffer length must be a multiple of period_len */
475 if (len % period_len != 0) {
476 dev_err(fchan->fdev->dev, "len is not multiple of period\n");
477 return NULL;
478 }
479
480 sg_len = len / period_len;
481 fdesc = st_fdma_alloc_desc(fchan, sg_len);
482 if (!fdesc) {
483 dev_err(fchan->fdev->dev, "no memory for desc\n");
484 return NULL;
485 }
486
487 fdesc->iscyclic = true;
488
489 for (i = 0; i < sg_len; i++) {
490 struct st_fdma_hw_node *hw_node = fdesc->node[i].desc;
491
492 hw_node->next = fdesc->node[(i + 1) % sg_len].pdesc;
493
494 hw_node->control =
495 FDMA_NODE_CTRL_REQ_MAP_DREQ(fchan->dreq_line);
496 hw_node->control |= FDMA_NODE_CTRL_INT_EON;
497
498 fill_hw_node(hw_node, fchan, direction);
499
500 if (direction == DMA_MEM_TO_DEV)
501 hw_node->saddr = buf_addr + (i * period_len);
502 else
503 hw_node->daddr = buf_addr + (i * period_len);
504
505 hw_node->nbytes = period_len;
506 hw_node->generic.length = period_len;
507 }
508
509 return vchan_tx_prep(&fchan->vchan, &fdesc->vdesc, flags);
510}
511
512static struct dma_async_tx_descriptor *st_fdma_prep_slave_sg(
513 struct dma_chan *chan, struct scatterlist *sgl,
514 unsigned int sg_len, enum dma_transfer_direction direction,
515 unsigned long flags, void *context)
516{
517 struct st_fdma_chan *fchan;
518 struct st_fdma_desc *fdesc;
519 struct st_fdma_hw_node *hw_node;
520 struct scatterlist *sg;
521 int i;
522
523 fchan = st_fdma_prep_common(chan, sg_len, direction);
524 if (!fchan)
525 return NULL;
526
527 if (!sgl)
528 return NULL;
529
530 fdesc = st_fdma_alloc_desc(fchan, sg_len);
531 if (!fdesc) {
532 dev_err(fchan->fdev->dev, "no memory for desc\n");
533 return NULL;
534 }
535
536 fdesc->iscyclic = false;
537
538 for_each_sg(sgl, sg, sg_len, i) {
539 hw_node = fdesc->node[i].desc;
540
541 hw_node->next = fdesc->node[(i + 1) % sg_len].pdesc;
542 hw_node->control = FDMA_NODE_CTRL_REQ_MAP_DREQ(fchan->dreq_line);
543
544 fill_hw_node(hw_node, fchan, direction);
545
546 if (direction == DMA_MEM_TO_DEV)
547 hw_node->saddr = sg_dma_address(sg);
548 else
549 hw_node->daddr = sg_dma_address(sg);
550
551 hw_node->nbytes = sg_dma_len(sg);
552 hw_node->generic.length = sg_dma_len(sg);
553 }
554
555 /* interrupt at end of last node */
556 hw_node->control |= FDMA_NODE_CTRL_INT_EON;
557
558 return vchan_tx_prep(&fchan->vchan, &fdesc->vdesc, flags);
559}
560
561static size_t st_fdma_desc_residue(struct st_fdma_chan *fchan,
562 struct virt_dma_desc *vdesc,
563 bool in_progress)
564{
565 struct st_fdma_desc *fdesc = fchan->fdesc;
566 size_t residue = 0;
567 dma_addr_t cur_addr = 0;
568 int i;
569
570 if (in_progress) {
571 cur_addr = fchan_read(fchan, FDMA_CH_CMD_OFST);
572 cur_addr &= FDMA_CH_CMD_DATA_MASK;
573 }
574
575 for (i = fchan->fdesc->n_nodes - 1 ; i >= 0; i--) {
576 if (cur_addr == fdesc->node[i].pdesc) {
577 residue += fnode_read(fchan, FDMA_CNTN_OFST);
578 break;
579 }
580 residue += fdesc->node[i].desc->nbytes;
581 }
582
583 return residue;
584}
585
586static enum dma_status st_fdma_tx_status(struct dma_chan *chan,
587 dma_cookie_t cookie,
588 struct dma_tx_state *txstate)
589{
590 struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
591 struct virt_dma_desc *vd;
592 enum dma_status ret;
593 unsigned long flags;
594
595 ret = dma_cookie_status(chan, cookie, txstate);
596 if (ret == DMA_COMPLETE || !txstate)
597 return ret;
598
599 spin_lock_irqsave(&fchan->vchan.lock, flags);
600 vd = vchan_find_desc(&fchan->vchan, cookie);
601 if (fchan->fdesc && cookie == fchan->fdesc->vdesc.tx.cookie)
602 txstate->residue = st_fdma_desc_residue(fchan, vd, true);
603 else if (vd)
604 txstate->residue = st_fdma_desc_residue(fchan, vd, false);
605 else
606 txstate->residue = 0;
607
608 spin_unlock_irqrestore(&fchan->vchan.lock, flags);
609
610 return ret;
611}
612
613static void st_fdma_issue_pending(struct dma_chan *chan)
614{
615 struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
616 unsigned long flags;
617
618 spin_lock_irqsave(&fchan->vchan.lock, flags);
619
620 if (vchan_issue_pending(&fchan->vchan) && !fchan->fdesc)
621 st_fdma_xfer_desc(fchan);
622
623 spin_unlock_irqrestore(&fchan->vchan.lock, flags);
624}
625
626static int st_fdma_pause(struct dma_chan *chan)
627{
628 unsigned long flags;
629 LIST_HEAD(head);
630 struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
631 int ch_id = fchan->vchan.chan.chan_id;
632 unsigned long cmd = FDMA_CMD_PAUSE(ch_id);
633
634 dev_dbg(fchan->fdev->dev, "pause chan:%d\n", ch_id);
635
636 spin_lock_irqsave(&fchan->vchan.lock, flags);
637 if (fchan->fdesc)
638 fdma_write(fchan->fdev, cmd, FDMA_CMD_SET_OFST);
639 spin_unlock_irqrestore(&fchan->vchan.lock, flags);
640
641 return 0;
642}
643
644static int st_fdma_resume(struct dma_chan *chan)
645{
646 unsigned long flags;
647 unsigned long val;
648 struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
649 int ch_id = fchan->vchan.chan.chan_id;
650
651 dev_dbg(fchan->fdev->dev, "resume chan:%d\n", ch_id);
652
653 spin_lock_irqsave(&fchan->vchan.lock, flags);
654 if (fchan->fdesc) {
655 val = fchan_read(fchan, FDMA_CH_CMD_OFST);
656 val &= FDMA_CH_CMD_DATA_MASK;
657 fchan_write(fchan, val, FDMA_CH_CMD_OFST);
658 }
659 spin_unlock_irqrestore(&fchan->vchan.lock, flags);
660
661 return 0;
662}
663
664static int st_fdma_terminate_all(struct dma_chan *chan)
665{
666 unsigned long flags;
667 LIST_HEAD(head);
668 struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
669 int ch_id = fchan->vchan.chan.chan_id;
670 unsigned long cmd = FDMA_CMD_PAUSE(ch_id);
671
672 dev_dbg(fchan->fdev->dev, "terminate chan:%d\n", ch_id);
673
674 spin_lock_irqsave(&fchan->vchan.lock, flags);
675 fdma_write(fchan->fdev, cmd, FDMA_CMD_SET_OFST);
676 fchan->fdesc = NULL;
677 vchan_get_all_descriptors(&fchan->vchan, &head);
678 spin_unlock_irqrestore(&fchan->vchan.lock, flags);
679 vchan_dma_desc_free_list(&fchan->vchan, &head);
680
681 return 0;
682}
683
684static int st_fdma_slave_config(struct dma_chan *chan,
685 struct dma_slave_config *slave_cfg)
686{
687 struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
688
689 memcpy(&fchan->scfg, slave_cfg, sizeof(fchan->scfg));
690 return 0;
691}
692
693static const struct st_fdma_driverdata fdma_mpe31_stih407_11 = {
694 .name = "STiH407",
695 .id = 0,
696};
697
698static const struct st_fdma_driverdata fdma_mpe31_stih407_12 = {
699 .name = "STiH407",
700 .id = 1,
701};
702
703static const struct st_fdma_driverdata fdma_mpe31_stih407_13 = {
704 .name = "STiH407",
705 .id = 2,
706};
707
708static const struct of_device_id st_fdma_match[] = {
709 { .compatible = "st,stih407-fdma-mpe31-11"
710 , .data = &fdma_mpe31_stih407_11 },
711 { .compatible = "st,stih407-fdma-mpe31-12"
712 , .data = &fdma_mpe31_stih407_12 },
713 { .compatible = "st,stih407-fdma-mpe31-13"
714 , .data = &fdma_mpe31_stih407_13 },
715 {},
716};
717MODULE_DEVICE_TABLE(of, st_fdma_match);
718
719static int st_fdma_parse_dt(struct platform_device *pdev,
720 const struct st_fdma_driverdata *drvdata,
721 struct st_fdma_dev *fdev)
722{
723 snprintf(fdev->fw_name, FW_NAME_SIZE, "fdma_%s_%d.elf",
724 drvdata->name, drvdata->id);
725
726 return of_property_read_u32(pdev->dev.of_node, "dma-channels",
727 &fdev->nr_channels);
728}
729#define FDMA_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
730 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
731 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
732 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
733
734static void st_fdma_free(struct st_fdma_dev *fdev)
735{
736 struct st_fdma_chan *fchan;
737 int i;
738
739 for (i = 0; i < fdev->nr_channels; i++) {
740 fchan = &fdev->chans[i];
741 list_del(&fchan->vchan.chan.device_node);
742 tasklet_kill(&fchan->vchan.task);
743 }
744}
745
746static int st_fdma_probe(struct platform_device *pdev)
747{
748 struct st_fdma_dev *fdev;
749 const struct of_device_id *match;
750 struct device_node *np = pdev->dev.of_node;
751 const struct st_fdma_driverdata *drvdata;
752 int ret, i;
753
754 match = of_match_device((st_fdma_match), &pdev->dev);
755 if (!match || !match->data) {
756 dev_err(&pdev->dev, "No device match found\n");
757 return -ENODEV;
758 }
759
760 drvdata = match->data;
761
762 fdev = devm_kzalloc(&pdev->dev, sizeof(*fdev), GFP_KERNEL);
763 if (!fdev)
764 return -ENOMEM;
765
766 ret = st_fdma_parse_dt(pdev, drvdata, fdev);
767 if (ret) {
768 dev_err(&pdev->dev, "unable to find platform data\n");
769 goto err;
770 }
771
772 fdev->chans = devm_kcalloc(&pdev->dev, fdev->nr_channels,
773 sizeof(struct st_fdma_chan), GFP_KERNEL);
774 if (!fdev->chans)
775 return -ENOMEM;
776
777 fdev->dev = &pdev->dev;
778 fdev->drvdata = drvdata;
779 platform_set_drvdata(pdev, fdev);
780
781 fdev->irq = platform_get_irq(pdev, 0);
782 if (fdev->irq < 0) {
783 dev_err(&pdev->dev, "Failed to get irq resource\n");
784 return -EINVAL;
785 }
786
787 ret = devm_request_irq(&pdev->dev, fdev->irq, st_fdma_irq_handler, 0,
788 dev_name(&pdev->dev), fdev);
789 if (ret) {
790 dev_err(&pdev->dev, "Failed to request irq (%d)\n", ret);
791 goto err;
792 }
793
794 fdev->slim_rproc = st_slim_rproc_alloc(pdev, fdev->fw_name);
795 if (IS_ERR(fdev->slim_rproc)) {
796 ret = PTR_ERR(fdev->slim_rproc);
797 dev_err(&pdev->dev, "slim_rproc_alloc failed (%d)\n", ret);
798 goto err;
799 }
800
801 /* Initialise list of FDMA channels */
802 INIT_LIST_HEAD(&fdev->dma_device.channels);
803 for (i = 0; i < fdev->nr_channels; i++) {
804 struct st_fdma_chan *fchan = &fdev->chans[i];
805
806 fchan->fdev = fdev;
807 fchan->vchan.desc_free = st_fdma_free_desc;
808 vchan_init(&fchan->vchan, &fdev->dma_device);
809 }
810
811 /* Initialise the FDMA dreq (reserve 0 & 31 for FDMA use) */
812 fdev->dreq_mask = BIT(0) | BIT(31);
813
814 dma_cap_set(DMA_SLAVE, fdev->dma_device.cap_mask);
815 dma_cap_set(DMA_CYCLIC, fdev->dma_device.cap_mask);
816 dma_cap_set(DMA_MEMCPY, fdev->dma_device.cap_mask);
817
818 fdev->dma_device.dev = &pdev->dev;
819 fdev->dma_device.device_alloc_chan_resources = st_fdma_alloc_chan_res;
820 fdev->dma_device.device_free_chan_resources = st_fdma_free_chan_res;
821 fdev->dma_device.device_prep_dma_cyclic = st_fdma_prep_dma_cyclic;
822 fdev->dma_device.device_prep_slave_sg = st_fdma_prep_slave_sg;
823 fdev->dma_device.device_prep_dma_memcpy = st_fdma_prep_dma_memcpy;
824 fdev->dma_device.device_tx_status = st_fdma_tx_status;
825 fdev->dma_device.device_issue_pending = st_fdma_issue_pending;
826 fdev->dma_device.device_terminate_all = st_fdma_terminate_all;
827 fdev->dma_device.device_config = st_fdma_slave_config;
828 fdev->dma_device.device_pause = st_fdma_pause;
829 fdev->dma_device.device_resume = st_fdma_resume;
830
831 fdev->dma_device.src_addr_widths = FDMA_DMA_BUSWIDTHS;
832 fdev->dma_device.dst_addr_widths = FDMA_DMA_BUSWIDTHS;
833 fdev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
834 fdev->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
835
836 ret = dma_async_device_register(&fdev->dma_device);
837 if (ret) {
838 dev_err(&pdev->dev,
839 "Failed to register DMA device (%d)\n", ret);
840 goto err_rproc;
841 }
842
843 ret = of_dma_controller_register(np, st_fdma_of_xlate, fdev);
844 if (ret) {
845 dev_err(&pdev->dev,
846 "Failed to register controller (%d)\n", ret);
847 goto err_dma_dev;
848 }
849
850 dev_info(&pdev->dev, "ST FDMA engine driver, irq:%d\n", fdev->irq);
851
852 return 0;
853
854err_dma_dev:
855 dma_async_device_unregister(&fdev->dma_device);
856err_rproc:
857 st_fdma_free(fdev);
858 st_slim_rproc_put(fdev->slim_rproc);
859err:
860 return ret;
861}
862
863static int st_fdma_remove(struct platform_device *pdev)
864{
865 struct st_fdma_dev *fdev = platform_get_drvdata(pdev);
866
867 devm_free_irq(&pdev->dev, fdev->irq, fdev);
868 st_slim_rproc_put(fdev->slim_rproc);
869 of_dma_controller_free(pdev->dev.of_node);
870 dma_async_device_unregister(&fdev->dma_device);
871
872 return 0;
873}
874
875static struct platform_driver st_fdma_platform_driver = {
876 .driver = {
877 .name = DRIVER_NAME,
878 .of_match_table = st_fdma_match,
879 },
880 .probe = st_fdma_probe,
881 .remove = st_fdma_remove,
882};
883module_platform_driver(st_fdma_platform_driver);
884
885MODULE_LICENSE("GPL v2");
886MODULE_DESCRIPTION("STMicroelectronics FDMA engine driver");
887MODULE_AUTHOR("Ludovic.barre <Ludovic.barre@st.com>");
888MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
889MODULE_ALIAS("platform: " DRIVER_NAME);
diff --git a/drivers/dma/st_fdma.h b/drivers/dma/st_fdma.h
new file mode 100644
index 000000000000..c58e00d4ab37
--- /dev/null
+++ b/drivers/dma/st_fdma.h
@@ -0,0 +1,249 @@
1/*
2 * DMA driver header for STMicroelectronics STi FDMA controller
3 *
4 * Copyright (C) 2014 STMicroelectronics
5 *
6 * Author: Ludovic Barre <Ludovic.barre@st.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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13#ifndef __DMA_ST_FDMA_H
14#define __DMA_ST_FDMA_H
15
16#include <linux/dmaengine.h>
17#include <linux/dmapool.h>
18#include <linux/io.h>
19#include <linux/remoteproc/st_slim_rproc.h>
20#include "virt-dma.h"
21
22#define ST_FDMA_NR_DREQS 32
23#define FW_NAME_SIZE 30
24#define DRIVER_NAME "st-fdma"
25
26/**
27 * struct st_fdma_generic_node - Free running/paced generic node
28 *
29 * @length: Length in bytes of a line in a 2D mem to mem
30 * @sstride: Stride, in bytes, between source lines in a 2D data move
31 * @dstride: Stride, in bytes, between destination lines in a 2D data move
32 */
33struct st_fdma_generic_node {
34 u32 length;
35 u32 sstride;
36 u32 dstride;
37};
38
39/**
40 * struct st_fdma_hw_node - Node structure used by fdma hw
41 *
42 * @next: Pointer to next node
43 * @control: Transfer Control Parameters
44 * @nbytes: Number of Bytes to read
45 * @saddr: Source address
46 * @daddr: Destination address
47 *
48 * @generic: generic node for free running/paced transfert type
49 * 2 others transfert type are possible, but not yet implemented
50 *
51 * The NODE structures must be aligned to a 32 byte boundary
52 */
53struct st_fdma_hw_node {
54 u32 next;
55 u32 control;
56 u32 nbytes;
57 u32 saddr;
58 u32 daddr;
59 union {
60 struct st_fdma_generic_node generic;
61 };
62} __aligned(32);
63
64/*
65 * node control parameters
66 */
67#define FDMA_NODE_CTRL_REQ_MAP_MASK GENMASK(4, 0)
68#define FDMA_NODE_CTRL_REQ_MAP_FREE_RUN 0x0
69#define FDMA_NODE_CTRL_REQ_MAP_DREQ(n) ((n)&FDMA_NODE_CTRL_REQ_MAP_MASK)
70#define FDMA_NODE_CTRL_REQ_MAP_EXT FDMA_NODE_CTRL_REQ_MAP_MASK
71#define FDMA_NODE_CTRL_SRC_MASK GENMASK(6, 5)
72#define FDMA_NODE_CTRL_SRC_STATIC BIT(5)
73#define FDMA_NODE_CTRL_SRC_INCR BIT(6)
74#define FDMA_NODE_CTRL_DST_MASK GENMASK(8, 7)
75#define FDMA_NODE_CTRL_DST_STATIC BIT(7)
76#define FDMA_NODE_CTRL_DST_INCR BIT(8)
77#define FDMA_NODE_CTRL_SECURE BIT(15)
78#define FDMA_NODE_CTRL_PAUSE_EON BIT(30)
79#define FDMA_NODE_CTRL_INT_EON BIT(31)
80
81/**
82 * struct st_fdma_sw_node - descriptor structure for link list
83 *
84 * @pdesc: Physical address of desc
85 * @node: link used for putting this into a channel queue
86 */
87struct st_fdma_sw_node {
88 dma_addr_t pdesc;
89 struct st_fdma_hw_node *desc;
90};
91
92#define NAME_SZ 10
93
94struct st_fdma_driverdata {
95 u32 id;
96 char name[NAME_SZ];
97};
98
99struct st_fdma_desc {
100 struct virt_dma_desc vdesc;
101 struct st_fdma_chan *fchan;
102 bool iscyclic;
103 unsigned int n_nodes;
104 struct st_fdma_sw_node node[];
105};
106
107enum st_fdma_type {
108 ST_FDMA_TYPE_FREE_RUN,
109 ST_FDMA_TYPE_PACED,
110};
111
112struct st_fdma_cfg {
113 struct device_node *of_node;
114 enum st_fdma_type type;
115 dma_addr_t dev_addr;
116 enum dma_transfer_direction dir;
117 int req_line; /* request line */
118 long req_ctrl; /* Request control */
119};
120
121struct st_fdma_chan {
122 struct st_fdma_dev *fdev;
123 struct dma_pool *node_pool;
124 struct dma_slave_config scfg;
125 struct st_fdma_cfg cfg;
126
127 int dreq_line;
128
129 struct virt_dma_chan vchan;
130 struct st_fdma_desc *fdesc;
131 enum dma_status status;
132};
133
134struct st_fdma_dev {
135 struct device *dev;
136 const struct st_fdma_driverdata *drvdata;
137 struct dma_device dma_device;
138
139 struct st_slim_rproc *slim_rproc;
140
141 int irq;
142
143 struct st_fdma_chan *chans;
144
145 spinlock_t dreq_lock;
146 unsigned long dreq_mask;
147
148 u32 nr_channels;
149 char fw_name[FW_NAME_SIZE];
150};
151
152/* Peripheral Registers*/
153
154#define FDMA_CMD_STA_OFST 0xFC0
155#define FDMA_CMD_SET_OFST 0xFC4
156#define FDMA_CMD_CLR_OFST 0xFC8
157#define FDMA_CMD_MASK_OFST 0xFCC
158#define FDMA_CMD_START(ch) (0x1 << (ch << 1))
159#define FDMA_CMD_PAUSE(ch) (0x2 << (ch << 1))
160#define FDMA_CMD_FLUSH(ch) (0x3 << (ch << 1))
161
162#define FDMA_INT_STA_OFST 0xFD0
163#define FDMA_INT_STA_CH 0x1
164#define FDMA_INT_STA_ERR 0x2
165
166#define FDMA_INT_SET_OFST 0xFD4
167#define FDMA_INT_CLR_OFST 0xFD8
168#define FDMA_INT_MASK_OFST 0xFDC
169
170#define fdma_read(fdev, name) \
171 readl((fdev)->slim_rproc->peri + name)
172
173#define fdma_write(fdev, val, name) \
174 writel((val), (fdev)->slim_rproc->peri + name)
175
176/* fchan interface (dmem) */
177#define FDMA_CH_CMD_OFST 0x200
178#define FDMA_CH_CMD_STA_MASK GENMASK(1, 0)
179#define FDMA_CH_CMD_STA_IDLE (0x0)
180#define FDMA_CH_CMD_STA_START (0x1)
181#define FDMA_CH_CMD_STA_RUNNING (0x2)
182#define FDMA_CH_CMD_STA_PAUSED (0x3)
183#define FDMA_CH_CMD_ERR_MASK GENMASK(4, 2)
184#define FDMA_CH_CMD_ERR_INT (0x0 << 2)
185#define FDMA_CH_CMD_ERR_NAND (0x1 << 2)
186#define FDMA_CH_CMD_ERR_MCHI (0x2 << 2)
187#define FDMA_CH_CMD_DATA_MASK GENMASK(31, 5)
188#define fchan_read(fchan, name) \
189 readl((fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
190 + (fchan)->vchan.chan.chan_id * 0x4 \
191 + name)
192
193#define fchan_write(fchan, val, name) \
194 writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
195 + (fchan)->vchan.chan.chan_id * 0x4 \
196 + name)
197
198/* req interface */
199#define FDMA_REQ_CTRL_OFST 0x240
200#define dreq_write(fchan, val, name) \
201 writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
202 + fchan->dreq_line * 0x04 \
203 + name)
204/* node interface */
205#define FDMA_NODE_SZ 128
206#define FDMA_PTRN_OFST 0x800
207#define FDMA_CNTN_OFST 0x808
208#define FDMA_SADDRN_OFST 0x80c
209#define FDMA_DADDRN_OFST 0x810
210#define fnode_read(fchan, name) \
211 readl((fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
212 + (fchan)->vchan.chan.chan_id * FDMA_NODE_SZ \
213 + name)
214
215#define fnode_write(fchan, val, name) \
216 writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
217 + (fchan)->vchan.chan.chan_id * FDMA_NODE_SZ \
218 + name)
219
220/*
221 * request control bits
222 */
223#define FDMA_REQ_CTRL_NUM_OPS_MASK GENMASK(31, 24)
224#define FDMA_REQ_CTRL_NUM_OPS(n) (FDMA_REQ_CTRL_NUM_OPS_MASK & \
225 ((n) << 24))
226#define FDMA_REQ_CTRL_INITIATOR_MASK BIT(22)
227#define FDMA_REQ_CTRL_INIT0 (0x0 << 22)
228#define FDMA_REQ_CTRL_INIT1 (0x1 << 22)
229#define FDMA_REQ_CTRL_INC_ADDR_ON BIT(21)
230#define FDMA_REQ_CTRL_DATA_SWAP_ON BIT(17)
231#define FDMA_REQ_CTRL_WNR BIT(14)
232#define FDMA_REQ_CTRL_OPCODE_MASK GENMASK(7, 4)
233#define FDMA_REQ_CTRL_OPCODE_LD_ST1 (0x0 << 4)
234#define FDMA_REQ_CTRL_OPCODE_LD_ST2 (0x1 << 4)
235#define FDMA_REQ_CTRL_OPCODE_LD_ST4 (0x2 << 4)
236#define FDMA_REQ_CTRL_OPCODE_LD_ST8 (0x3 << 4)
237#define FDMA_REQ_CTRL_OPCODE_LD_ST16 (0x4 << 4)
238#define FDMA_REQ_CTRL_OPCODE_LD_ST32 (0x5 << 4)
239#define FDMA_REQ_CTRL_OPCODE_LD_ST64 (0x6 << 4)
240#define FDMA_REQ_CTRL_HOLDOFF_MASK GENMASK(2, 0)
241#define FDMA_REQ_CTRL_HOLDOFF(n) ((n) & FDMA_REQ_CTRL_HOLDOFF_MASK)
242
243/* bits used by client to configure request control */
244#define FDMA_REQ_CTRL_CFG_MASK (FDMA_REQ_CTRL_HOLDOFF_MASK | \
245 FDMA_REQ_CTRL_DATA_SWAP_ON | \
246 FDMA_REQ_CTRL_INC_ADDR_ON | \
247 FDMA_REQ_CTRL_INITIATOR_MASK)
248
249#endif /* __DMA_ST_FDMA_H */
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f396bfef5d42..14d5d2d43a38 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -1,20 +1,21 @@
1menu "Remoteproc drivers" 1menu "Remoteproc drivers"
2 2
3# REMOTEPROC gets selected by whoever wants it
4config REMOTEPROC 3config REMOTEPROC
5 tristate 4 tristate "Support for Remote Processor subsystem"
6 depends on HAS_DMA 5 depends on HAS_DMA
7 select CRC32 6 select CRC32
8 select FW_LOADER 7 select FW_LOADER
9 select VIRTIO 8 select VIRTIO
10 select VIRTUALIZATION 9 select VIRTUALIZATION
11 10
11if REMOTEPROC
12
12config OMAP_REMOTEPROC 13config OMAP_REMOTEPROC
13 tristate "OMAP remoteproc support" 14 tristate "OMAP remoteproc support"
14 depends on HAS_DMA 15 depends on HAS_DMA
15 depends on ARCH_OMAP4 || SOC_OMAP5 16 depends on ARCH_OMAP4 || SOC_OMAP5
16 depends on OMAP_IOMMU 17 depends on OMAP_IOMMU
17 select REMOTEPROC 18 depends on REMOTEPROC
18 select MAILBOX 19 select MAILBOX
19 select OMAP2PLUS_MBOX 20 select OMAP2PLUS_MBOX
20 select RPMSG_VIRTIO 21 select RPMSG_VIRTIO
@@ -34,7 +35,7 @@ config OMAP_REMOTEPROC
34config STE_MODEM_RPROC 35config STE_MODEM_RPROC
35 tristate "STE-Modem remoteproc support" 36 tristate "STE-Modem remoteproc support"
36 depends on HAS_DMA 37 depends on HAS_DMA
37 select REMOTEPROC 38 depends on REMOTEPROC
38 default n 39 default n
39 help 40 help
40 Say y or m here to support STE-Modem shared memory driver. 41 Say y or m here to support STE-Modem shared memory driver.
@@ -44,7 +45,7 @@ config STE_MODEM_RPROC
44config WKUP_M3_RPROC 45config WKUP_M3_RPROC
45 tristate "AMx3xx Wakeup M3 remoteproc support" 46 tristate "AMx3xx Wakeup M3 remoteproc support"
46 depends on SOC_AM33XX || SOC_AM43XX 47 depends on SOC_AM33XX || SOC_AM43XX
47 select REMOTEPROC 48 depends on REMOTEPROC
48 help 49 help
49 Say y here to support Wakeup M3 remote processor on TI AM33xx 50 Say y here to support Wakeup M3 remote processor on TI AM33xx
50 and AM43xx family of SoCs. 51 and AM43xx family of SoCs.
@@ -57,8 +58,8 @@ config WKUP_M3_RPROC
57config DA8XX_REMOTEPROC 58config DA8XX_REMOTEPROC
58 tristate "DA8xx/OMAP-L13x remoteproc support" 59 tristate "DA8xx/OMAP-L13x remoteproc support"
59 depends on ARCH_DAVINCI_DA8XX 60 depends on ARCH_DAVINCI_DA8XX
61 depends on REMOTEPROC
60 select CMA if MMU 62 select CMA if MMU
61 select REMOTEPROC
62 select RPMSG_VIRTIO 63 select RPMSG_VIRTIO
63 help 64 help
64 Say y here to support DA8xx/OMAP-L13x remote processors via the 65 Say y here to support DA8xx/OMAP-L13x remote processors via the
@@ -84,9 +85,9 @@ config QCOM_Q6V5_PIL
84 tristate "Qualcomm Hexagon V5 Peripherial Image Loader" 85 tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
85 depends on OF && ARCH_QCOM 86 depends on OF && ARCH_QCOM
86 depends on QCOM_SMEM 87 depends on QCOM_SMEM
88 depends on REMOTEPROC
87 select MFD_SYSCON 89 select MFD_SYSCON
88 select QCOM_MDT_LOADER 90 select QCOM_MDT_LOADER
89 select REMOTEPROC
90 help 91 help
91 Say y here to support the Qualcomm Peripherial Image Loader for the 92 Say y here to support the Qualcomm Peripherial Image Loader for the
92 Hexagon V5 based remote processors. 93 Hexagon V5 based remote processors.
@@ -99,10 +100,10 @@ config QCOM_WCNSS_PIL
99 tristate "Qualcomm WCNSS Peripheral Image Loader" 100 tristate "Qualcomm WCNSS Peripheral Image Loader"
100 depends on OF && ARCH_QCOM 101 depends on OF && ARCH_QCOM
101 depends on QCOM_SMEM 102 depends on QCOM_SMEM
103 depends on REMOTEPROC
102 select QCOM_MDT_LOADER 104 select QCOM_MDT_LOADER
103 select QCOM_SCM 105 select QCOM_SCM
104 select QCOM_WCNSS_IRIS 106 select QCOM_WCNSS_IRIS
105 select REMOTEPROC
106 help 107 help
107 Say y here to support the Peripheral Image Loader for the Qualcomm 108 Say y here to support the Peripheral Image Loader for the Qualcomm
108 Wireless Connectivity Subsystem. 109 Wireless Connectivity Subsystem.
@@ -110,10 +111,16 @@ config QCOM_WCNSS_PIL
110config ST_REMOTEPROC 111config ST_REMOTEPROC
111 tristate "ST remoteproc support" 112 tristate "ST remoteproc support"
112 depends on ARCH_STI 113 depends on ARCH_STI
113 select REMOTEPROC 114 depends on REMOTEPROC
114 help 115 help
115 Say y here to support ST's adjunct processors via the remote 116 Say y here to support ST's adjunct processors via the remote
116 processor framework. 117 processor framework.
117 This can be either built-in or a loadable module. 118 This can be either built-in or a loadable module.
118 119
120config ST_SLIM_REMOTEPROC
121 tristate
122 depends on REMOTEPROC
123
124endif # REMOTEPROC
125
119endmenu 126endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 6dfb62ed643f..924f0cb25470 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o
16obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o 16obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o
17obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o 17obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o
18obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o 18obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o
19obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
new file mode 100644
index 000000000000..1484e9717946
--- /dev/null
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -0,0 +1,364 @@
1/*
2 * SLIM core rproc driver
3 *
4 * Copyright (C) 2016 STMicroelectronics
5 *
6 * Author: Peter Griffin <peter.griffin@linaro.org>
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/clk.h>
15#include <linux/err.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/of_device.h>
20#include <linux/platform_device.h>
21#include <linux/remoteproc.h>
22#include <linux/remoteproc/st_slim_rproc.h>
23#include "remoteproc_internal.h"
24
25/* SLIM core registers */
26#define SLIM_ID_OFST 0x0
27#define SLIM_VER_OFST 0x4
28
29#define SLIM_EN_OFST 0x8
30#define SLIM_EN_RUN BIT(0)
31
32#define SLIM_CLK_GATE_OFST 0xC
33#define SLIM_CLK_GATE_DIS BIT(0)
34#define SLIM_CLK_GATE_RESET BIT(2)
35
36#define SLIM_SLIM_PC_OFST 0x20
37
38/* DMEM registers */
39#define SLIM_REV_ID_OFST 0x0
40#define SLIM_REV_ID_MIN_MASK GENMASK(15, 8)
41#define SLIM_REV_ID_MIN(id) ((id & SLIM_REV_ID_MIN_MASK) >> 8)
42#define SLIM_REV_ID_MAJ_MASK GENMASK(23, 16)
43#define SLIM_REV_ID_MAJ(id) ((id & SLIM_REV_ID_MAJ_MASK) >> 16)
44
45
46/* peripherals registers */
47#define SLIM_STBUS_SYNC_OFST 0xF88
48#define SLIM_STBUS_SYNC_DIS BIT(0)
49
50#define SLIM_INT_SET_OFST 0xFD4
51#define SLIM_INT_CLR_OFST 0xFD8
52#define SLIM_INT_MASK_OFST 0xFDC
53
54#define SLIM_CMD_CLR_OFST 0xFC8
55#define SLIM_CMD_MASK_OFST 0xFCC
56
57static const char *mem_names[ST_SLIM_MEM_MAX] = {
58 [ST_SLIM_DMEM] = "dmem",
59 [ST_SLIM_IMEM] = "imem",
60};
61
62static int slim_clk_get(struct st_slim_rproc *slim_rproc, struct device *dev)
63{
64 int clk, err;
65
66 for (clk = 0; clk < ST_SLIM_MAX_CLK; clk++) {
67 slim_rproc->clks[clk] = of_clk_get(dev->of_node, clk);
68 if (IS_ERR(slim_rproc->clks[clk])) {
69 err = PTR_ERR(slim_rproc->clks[clk]);
70 if (err == -EPROBE_DEFER)
71 goto err_put_clks;
72 slim_rproc->clks[clk] = NULL;
73 break;
74 }
75 }
76
77 return 0;
78
79err_put_clks:
80 while (--clk >= 0)
81 clk_put(slim_rproc->clks[clk]);
82
83 return err;
84}
85
86static void slim_clk_disable(struct st_slim_rproc *slim_rproc)
87{
88 int clk;
89
90 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
91 clk_disable_unprepare(slim_rproc->clks[clk]);
92}
93
94static int slim_clk_enable(struct st_slim_rproc *slim_rproc)
95{
96 int clk, ret;
97
98 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) {
99 ret = clk_prepare_enable(slim_rproc->clks[clk]);
100 if (ret)
101 goto err_disable_clks;
102 }
103
104 return 0;
105
106err_disable_clks:
107 while (--clk >= 0)
108 clk_disable_unprepare(slim_rproc->clks[clk]);
109
110 return ret;
111}
112
113/*
114 * Remoteproc slim specific device handlers
115 */
116static int slim_rproc_start(struct rproc *rproc)
117{
118 struct device *dev = &rproc->dev;
119 struct st_slim_rproc *slim_rproc = rproc->priv;
120 unsigned long hw_id, hw_ver, fw_rev;
121 u32 val;
122
123 /* disable CPU pipeline clock & reset CPU pipeline */
124 val = SLIM_CLK_GATE_DIS | SLIM_CLK_GATE_RESET;
125 writel(val, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
126
127 /* disable SLIM core STBus sync */
128 writel(SLIM_STBUS_SYNC_DIS, slim_rproc->peri + SLIM_STBUS_SYNC_OFST);
129
130 /* enable cpu pipeline clock */
131 writel(!SLIM_CLK_GATE_DIS,
132 slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
133
134 /* clear int & cmd mailbox */
135 writel(~0U, slim_rproc->peri + SLIM_INT_CLR_OFST);
136 writel(~0U, slim_rproc->peri + SLIM_CMD_CLR_OFST);
137
138 /* enable all channels cmd & int */
139 writel(~0U, slim_rproc->peri + SLIM_INT_MASK_OFST);
140 writel(~0U, slim_rproc->peri + SLIM_CMD_MASK_OFST);
141
142 /* enable cpu */
143 writel(SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
144
145 hw_id = readl_relaxed(slim_rproc->slimcore + SLIM_ID_OFST);
146 hw_ver = readl_relaxed(slim_rproc->slimcore + SLIM_VER_OFST);
147
148 fw_rev = readl(slim_rproc->mem[ST_SLIM_DMEM].cpu_addr +
149 SLIM_REV_ID_OFST);
150
151 dev_info(dev, "fw rev:%ld.%ld on SLIM %ld.%ld\n",
152 SLIM_REV_ID_MAJ(fw_rev), SLIM_REV_ID_MIN(fw_rev),
153 hw_id, hw_ver);
154
155 return 0;
156}
157
158static int slim_rproc_stop(struct rproc *rproc)
159{
160 struct st_slim_rproc *slim_rproc = rproc->priv;
161 u32 val;
162
163 /* mask all (cmd & int) channels */
164 writel(0UL, slim_rproc->peri + SLIM_INT_MASK_OFST);
165 writel(0UL, slim_rproc->peri + SLIM_CMD_MASK_OFST);
166
167 /* disable cpu pipeline clock */
168 writel(SLIM_CLK_GATE_DIS, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
169
170 writel(!SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
171
172 val = readl(slim_rproc->slimcore + SLIM_EN_OFST);
173 if (val & SLIM_EN_RUN)
174 dev_warn(&rproc->dev, "Failed to disable SLIM");
175
176 dev_dbg(&rproc->dev, "slim stopped\n");
177
178 return 0;
179}
180
181static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
182{
183 struct st_slim_rproc *slim_rproc = rproc->priv;
184 void *va = NULL;
185 int i;
186
187 for (i = 0; i < ST_SLIM_MEM_MAX; i++) {
188 if (da != slim_rproc->mem[i].bus_addr)
189 continue;
190
191 if (len <= slim_rproc->mem[i].size) {
192 /* __force to make sparse happy with type conversion */
193 va = (__force void *)slim_rproc->mem[i].cpu_addr;
194 break;
195 }
196 }
197
198 dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
199
200 return va;
201}
202
203static struct rproc_ops slim_rproc_ops = {
204 .start = slim_rproc_start,
205 .stop = slim_rproc_stop,
206 .da_to_va = slim_rproc_da_to_va,
207};
208
209/*
210 * Firmware handler operations: sanity, boot address, load ...
211 */
212
213static struct resource_table empty_rsc_tbl = {
214 .ver = 1,
215 .num = 0,
216};
217
218static struct resource_table *slim_rproc_find_rsc_table(struct rproc *rproc,
219 const struct firmware *fw,
220 int *tablesz)
221{
222 *tablesz = sizeof(empty_rsc_tbl);
223 return &empty_rsc_tbl;
224}
225
226static struct rproc_fw_ops slim_rproc_fw_ops = {
227 .find_rsc_table = slim_rproc_find_rsc_table,
228};
229
230/**
231 * st_slim_rproc_alloc() - allocate and initialise slim rproc
232 * @pdev: Pointer to the platform_device struct
233 * @fw_name: Name of firmware for rproc to use
234 *
235 * Function for allocating and initialising a slim rproc for use by
236 * device drivers whose IP is based around the SLIM core. It
237 * obtains and enables any clocks required by the SLIM core and also
238 * ioremaps the various IO.
239 *
240 * Returns st_slim_rproc pointer or PTR_ERR() on error.
241 */
242
243struct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev,
244 char *fw_name)
245{
246 struct device *dev = &pdev->dev;
247 struct st_slim_rproc *slim_rproc;
248 struct device_node *np = dev->of_node;
249 struct rproc *rproc;
250 struct resource *res;
251 int err, i;
252 const struct rproc_fw_ops *elf_ops;
253
254 if (!fw_name)
255 return ERR_PTR(-EINVAL);
256
257 if (!of_device_is_compatible(np, "st,slim-rproc"))
258 return ERR_PTR(-EINVAL);
259
260 rproc = rproc_alloc(dev, np->name, &slim_rproc_ops,
261 fw_name, sizeof(*slim_rproc));
262 if (!rproc)
263 return ERR_PTR(-ENOMEM);
264
265 rproc->has_iommu = false;
266
267 slim_rproc = rproc->priv;
268 slim_rproc->rproc = rproc;
269
270 elf_ops = rproc->fw_ops;
271 /* Use some generic elf ops */
272 slim_rproc_fw_ops.load = elf_ops->load;
273 slim_rproc_fw_ops.sanity_check = elf_ops->sanity_check;
274
275 rproc->fw_ops = &slim_rproc_fw_ops;
276
277 /* get imem and dmem */
278 for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
279 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
280 mem_names[i]);
281
282 slim_rproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
283 if (IS_ERR(slim_rproc->mem[i].cpu_addr)) {
284 dev_err(&pdev->dev, "devm_ioremap_resource failed\n");
285 err = PTR_ERR(slim_rproc->mem[i].cpu_addr);
286 goto err;
287 }
288 slim_rproc->mem[i].bus_addr = res->start;
289 slim_rproc->mem[i].size = resource_size(res);
290 }
291
292 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "slimcore");
293 slim_rproc->slimcore = devm_ioremap_resource(dev, res);
294 if (IS_ERR(slim_rproc->slimcore)) {
295 dev_err(&pdev->dev, "failed to ioremap slimcore IO\n");
296 err = PTR_ERR(slim_rproc->slimcore);
297 goto err;
298 }
299
300 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "peripherals");
301 slim_rproc->peri = devm_ioremap_resource(dev, res);
302 if (IS_ERR(slim_rproc->peri)) {
303 dev_err(&pdev->dev, "failed to ioremap peripherals IO\n");
304 err = PTR_ERR(slim_rproc->peri);
305 goto err;
306 }
307
308 err = slim_clk_get(slim_rproc, dev);
309 if (err)
310 goto err;
311
312 err = slim_clk_enable(slim_rproc);
313 if (err) {
314 dev_err(dev, "Failed to enable clocks\n");
315 goto err_clk_put;
316 }
317
318 /* Register as a remoteproc device */
319 err = rproc_add(rproc);
320 if (err) {
321 dev_err(dev, "registration of slim remoteproc failed\n");
322 goto err_clk_dis;
323 }
324
325 return slim_rproc;
326
327err_clk_dis:
328 slim_clk_disable(slim_rproc);
329err_clk_put:
330 for (i = 0; i < ST_SLIM_MAX_CLK && slim_rproc->clks[i]; i++)
331 clk_put(slim_rproc->clks[i]);
332err:
333 rproc_put(rproc);
334 return ERR_PTR(err);
335}
336EXPORT_SYMBOL(st_slim_rproc_alloc);
337
338/**
339 * st_slim_rproc_put() - put slim rproc resources
340 * @slim_rproc: Pointer to the st_slim_rproc struct
341 *
342 * Function for calling respective _put() functions on slim_rproc resources.
343 *
344 */
345void st_slim_rproc_put(struct st_slim_rproc *slim_rproc)
346{
347 int clk;
348
349 if (!slim_rproc)
350 return;
351
352 slim_clk_disable(slim_rproc);
353
354 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
355 clk_put(slim_rproc->clks[clk]);
356
357 rproc_del(slim_rproc->rproc);
358 rproc_put(slim_rproc->rproc);
359}
360EXPORT_SYMBOL(st_slim_rproc_put);
361
362MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
363MODULE_DESCRIPTION("STMicroelectronics SLIM core rproc driver");
364MODULE_LICENSE("GPL v2");
diff --git a/include/linux/remoteproc/st_slim_rproc.h b/include/linux/remoteproc/st_slim_rproc.h
new file mode 100644
index 000000000000..4155556fa4b2
--- /dev/null
+++ b/include/linux/remoteproc/st_slim_rproc.h
@@ -0,0 +1,58 @@
1/*
2 * SLIM core rproc driver header
3 *
4 * Copyright (C) 2016 STMicroelectronics
5 *
6 * Author: Peter Griffin <peter.griffin@linaro.org>
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13#ifndef _ST_REMOTEPROC_SLIM_H
14#define _ST_REMOTEPROC_SLIM_H
15
16#define ST_SLIM_MEM_MAX 2
17#define ST_SLIM_MAX_CLK 4
18
19enum {
20 ST_SLIM_DMEM,
21 ST_SLIM_IMEM,
22};
23
24/**
25 * struct st_slim_mem - slim internal memory structure
26 * @cpu_addr: MPU virtual address of the memory region
27 * @bus_addr: Bus address used to access the memory region
28 * @size: Size of the memory region
29 */
30struct st_slim_mem {
31 void __iomem *cpu_addr;
32 phys_addr_t bus_addr;
33 size_t size;
34};
35
36/**
37 * struct st_slim_rproc - SLIM slim core
38 * @rproc: rproc handle
39 * @mem: slim memory information
40 * @slimcore: slim slimcore regs
41 * @peri: slim peripheral regs
42 * @clks: slim clocks
43 */
44struct st_slim_rproc {
45 struct rproc *rproc;
46 struct st_slim_mem mem[ST_SLIM_MEM_MAX];
47 void __iomem *slimcore;
48 void __iomem *peri;
49
50 /* st_slim_rproc private */
51 struct clk *clks[ST_SLIM_MAX_CLK];
52};
53
54struct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev,
55 char *fw_name);
56void st_slim_rproc_put(struct st_slim_rproc *slim_rproc);
57
58#endif