diff options
author | Vinod Koul <vinod.koul@intel.com> | 2016-12-13 22:37:07 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2016-12-13 22:37:07 -0500 |
commit | 4625d2a513d60ca9c3e8cae42c8f3d9efc1b4211 (patch) | |
tree | 12206d852d868d6ba2df3dd9bc3387555c0b4883 | |
parent | 57fb7ee10c27b315600445b2bad72236a11951ad (diff) | |
parent | 3d6b3715fb5d4b7321a9ebd664991be2ed8f5f7b (diff) |
Merge branch 'topic/st_fdma' into for-linus
-rw-r--r-- | Documentation/devicetree/bindings/dma/st_fdma.txt | 87 | ||||
-rw-r--r-- | MAINTAINERS | 3 | ||||
-rw-r--r-- | arch/arm/configs/multi_v7_defconfig | 6 | ||||
-rw-r--r-- | drivers/dma/Kconfig | 14 | ||||
-rw-r--r-- | drivers/dma/Makefile | 1 | ||||
-rw-r--r-- | drivers/dma/st_fdma.c | 889 | ||||
-rw-r--r-- | drivers/dma/st_fdma.h | 249 | ||||
-rw-r--r-- | drivers/remoteproc/Kconfig | 25 | ||||
-rw-r--r-- | drivers/remoteproc/Makefile | 1 | ||||
-rw-r--r-- | drivers/remoteproc/st_slim_rproc.c | 364 | ||||
-rw-r--r-- | include/linux/remoteproc/st_slim_rproc.h | 58 |
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 | |||
3 | The FDMA is a general-purpose direct memory access controller capable of | ||
4 | supporting 16 independent DMA channels. It accepts up to 32 DMA requests. | ||
5 | The FDMA is based on a Slim processor which requires a firmware. | ||
6 | |||
7 | * FDMA Controller | ||
8 | |||
9 | Required 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 | ||
20 | See: Documentation/devicetree/bindings/clock/clock-bindings.txt | ||
21 | |||
22 | |||
23 | Example: | ||
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 | |||
43 | Required properties: | ||
44 | - dmas: Comma separated list of dma channel requests | ||
45 | - dma-names: Names of the aforementioned requested channels | ||
46 | |||
47 | Each dmas request consists of 4 cells: | ||
48 | 1. A phandle pointing to the FDMA controller | ||
49 | 2. The request line number | ||
50 | 3. 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 | ||
64 | 4. transfers type | ||
65 | 0 free running | ||
66 | 1 paced | ||
67 | |||
68 | Example: | ||
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 | |||
1774 | F: drivers/clocksource/arm_global_timer.c | 1774 | F: drivers/clocksource/arm_global_timer.c |
1775 | F: drivers/clocksource/clksrc_st_lpc.c | 1775 | F: drivers/clocksource/clksrc_st_lpc.c |
1776 | F: drivers/cpufreq/sti-cpufreq.c | 1776 | F: drivers/cpufreq/sti-cpufreq.c |
1777 | F: drivers/dma/st_fdma* | ||
1777 | F: drivers/i2c/busses/i2c-st.c | 1778 | F: drivers/i2c/busses/i2c-st.c |
1778 | F: drivers/media/rc/st_rc.c | 1779 | F: drivers/media/rc/st_rc.c |
1779 | F: drivers/media/platform/sti/c8sectpfe/ | 1780 | F: drivers/media/platform/sti/c8sectpfe/ |
@@ -1784,6 +1785,7 @@ F: drivers/phy/phy-stih407-usb.c | |||
1784 | F: drivers/phy/phy-stih41x-usb.c | 1785 | F: drivers/phy/phy-stih41x-usb.c |
1785 | F: drivers/pinctrl/pinctrl-st.c | 1786 | F: drivers/pinctrl/pinctrl-st.c |
1786 | F: drivers/remoteproc/st_remoteproc.c | 1787 | F: drivers/remoteproc/st_remoteproc.c |
1788 | F: drivers/remoteproc/st_slim_rproc.c | ||
1787 | F: drivers/reset/sti/ | 1789 | F: drivers/reset/sti/ |
1788 | F: drivers/rtc/rtc-st-lpc.c | 1790 | F: drivers/rtc/rtc-st-lpc.c |
1789 | F: drivers/tty/serial/st-asc.c | 1791 | F: drivers/tty/serial/st-asc.c |
@@ -1792,6 +1794,7 @@ F: drivers/usb/host/ehci-st.c | |||
1792 | F: drivers/usb/host/ohci-st.c | 1794 | F: drivers/usb/host/ohci-st.c |
1793 | F: drivers/watchdog/st_lpc_wdt.c | 1795 | F: drivers/watchdog/st_lpc_wdt.c |
1794 | F: drivers/ata/ahci_st.c | 1796 | F: drivers/ata/ahci_st.c |
1797 | F: include/linux/remoteproc/st_slim_rproc.h | ||
1795 | 1798 | ||
1796 | ARM/STM32 ARCHITECTURE | 1799 | ARM/STM32 ARCHITECTURE |
1797 | M: Maxime Coquelin <mcoquelin.stm32@gmail.com> | 1800 | M: 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 | |||
649 | CONFIG_SND_SOC_SGTL5000=m | 649 | CONFIG_SND_SOC_SGTL5000=m |
650 | CONFIG_SND_SOC_SPDIF=m | 650 | CONFIG_SND_SOC_SPDIF=m |
651 | CONFIG_SND_SOC_WM8978=m | 651 | CONFIG_SND_SOC_WM8978=m |
652 | CONFIG_SND_SOC_STI=m | ||
653 | CONFIG_SND_SOC_STI_SAS=m | ||
654 | CONFIG_SND_SIMPLE_CARD=m | ||
652 | CONFIG_USB=y | 655 | CONFIG_USB=y |
653 | CONFIG_USB_XHCI_HCD=y | 656 | CONFIG_USB_XHCI_HCD=y |
654 | CONFIG_USB_XHCI_MVEBU=y | 657 | CONFIG_USB_XHCI_MVEBU=y |
@@ -790,6 +793,7 @@ CONFIG_DMA_OMAP=y | |||
790 | CONFIG_QCOM_BAM_DMA=y | 793 | CONFIG_QCOM_BAM_DMA=y |
791 | CONFIG_XILINX_DMA=y | 794 | CONFIG_XILINX_DMA=y |
792 | CONFIG_DMA_SUN6I=y | 795 | CONFIG_DMA_SUN6I=y |
796 | CONFIG_ST_FDMA=m | ||
793 | CONFIG_STAGING=y | 797 | CONFIG_STAGING=y |
794 | CONFIG_SENSORS_ISL29018=y | 798 | CONFIG_SENSORS_ISL29018=y |
795 | CONFIG_SENSORS_ISL29028=y | 799 | CONFIG_SENSORS_ISL29028=y |
@@ -823,6 +827,8 @@ CONFIG_HWSPINLOCK_QCOM=y | |||
823 | CONFIG_ROCKCHIP_IOMMU=y | 827 | CONFIG_ROCKCHIP_IOMMU=y |
824 | CONFIG_TEGRA_IOMMU_GART=y | 828 | CONFIG_TEGRA_IOMMU_GART=y |
825 | CONFIG_TEGRA_IOMMU_SMMU=y | 829 | CONFIG_TEGRA_IOMMU_SMMU=y |
830 | CONFIG_REMOTEPROC=m | ||
831 | CONFIG_ST_REMOTEPROC=m | ||
826 | CONFIG_PM_DEVFREQ=y | 832 | CONFIG_PM_DEVFREQ=y |
827 | CONFIG_ARM_TEGRA_DEVFREQ=m | 833 | CONFIG_ARM_TEGRA_DEVFREQ=m |
828 | CONFIG_MEMORY=y | 834 | CONFIG_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 | ||
438 | config 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 | |||
438 | config STM32_DMA | 452 | config 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 | |||
67 | obj-$(CONFIG_TI_EDMA) += edma.o | 67 | obj-$(CONFIG_TI_EDMA) += edma.o |
68 | obj-$(CONFIG_XGENE_DMA) += xgene-dma.o | 68 | obj-$(CONFIG_XGENE_DMA) += xgene-dma.o |
69 | obj-$(CONFIG_ZX_DMA) += zx296702_dma.o | 69 | obj-$(CONFIG_ZX_DMA) += zx296702_dma.o |
70 | obj-$(CONFIG_ST_FDMA) += st_fdma.o | ||
70 | 71 | ||
71 | obj-y += qcom/ | 72 | obj-y += qcom/ |
72 | obj-y += xilinx/ | 73 | obj-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 | |||
25 | static 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 | |||
30 | static 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 | |||
35 | static 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 | |||
69 | static 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 | |||
77 | static 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 | |||
100 | static 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 | |||
128 | static 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 | |||
169 | static 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 | |||
222 | err_chan: | ||
223 | rproc_shutdown(fdev->slim_rproc->rproc); | ||
224 | return chan; | ||
225 | |||
226 | } | ||
227 | |||
228 | static 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 | |||
240 | static 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 | |||
261 | err: | ||
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 | |||
269 | static 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 | |||
291 | static 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 | |||
316 | static 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 | |||
352 | static 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 | |||
417 | static 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 | |||
435 | static 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 | |||
453 | static 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 | |||
512 | static 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 | |||
561 | static 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 | |||
586 | static 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 | |||
613 | static 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 | |||
626 | static 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 | |||
644 | static 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 | |||
664 | static 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 | |||
684 | static 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 | |||
693 | static const struct st_fdma_driverdata fdma_mpe31_stih407_11 = { | ||
694 | .name = "STiH407", | ||
695 | .id = 0, | ||
696 | }; | ||
697 | |||
698 | static const struct st_fdma_driverdata fdma_mpe31_stih407_12 = { | ||
699 | .name = "STiH407", | ||
700 | .id = 1, | ||
701 | }; | ||
702 | |||
703 | static const struct st_fdma_driverdata fdma_mpe31_stih407_13 = { | ||
704 | .name = "STiH407", | ||
705 | .id = 2, | ||
706 | }; | ||
707 | |||
708 | static 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 | }; | ||
717 | MODULE_DEVICE_TABLE(of, st_fdma_match); | ||
718 | |||
719 | static 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 | |||
734 | static 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 | |||
746 | static 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 | |||
854 | err_dma_dev: | ||
855 | dma_async_device_unregister(&fdev->dma_device); | ||
856 | err_rproc: | ||
857 | st_fdma_free(fdev); | ||
858 | st_slim_rproc_put(fdev->slim_rproc); | ||
859 | err: | ||
860 | return ret; | ||
861 | } | ||
862 | |||
863 | static 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 | |||
875 | static 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 | }; | ||
883 | module_platform_driver(st_fdma_platform_driver); | ||
884 | |||
885 | MODULE_LICENSE("GPL v2"); | ||
886 | MODULE_DESCRIPTION("STMicroelectronics FDMA engine driver"); | ||
887 | MODULE_AUTHOR("Ludovic.barre <Ludovic.barre@st.com>"); | ||
888 | MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>"); | ||
889 | MODULE_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 | */ | ||
33 | struct 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 | */ | ||
53 | struct 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 | */ | ||
87 | struct st_fdma_sw_node { | ||
88 | dma_addr_t pdesc; | ||
89 | struct st_fdma_hw_node *desc; | ||
90 | }; | ||
91 | |||
92 | #define NAME_SZ 10 | ||
93 | |||
94 | struct st_fdma_driverdata { | ||
95 | u32 id; | ||
96 | char name[NAME_SZ]; | ||
97 | }; | ||
98 | |||
99 | struct 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 | |||
107 | enum st_fdma_type { | ||
108 | ST_FDMA_TYPE_FREE_RUN, | ||
109 | ST_FDMA_TYPE_PACED, | ||
110 | }; | ||
111 | |||
112 | struct 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 | |||
121 | struct 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 | |||
134 | struct 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 @@ | |||
1 | menu "Remoteproc drivers" | 1 | menu "Remoteproc drivers" |
2 | 2 | ||
3 | # REMOTEPROC gets selected by whoever wants it | ||
4 | config REMOTEPROC | 3 | config 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 | ||
11 | if REMOTEPROC | ||
12 | |||
12 | config OMAP_REMOTEPROC | 13 | config 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 | |||
34 | config STE_MODEM_RPROC | 35 | config 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 | |||
44 | config WKUP_M3_RPROC | 45 | config 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 | |||
57 | config DA8XX_REMOTEPROC | 58 | config 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 | |||
110 | config ST_REMOTEPROC | 111 | config 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 | ||
120 | config ST_SLIM_REMOTEPROC | ||
121 | tristate | ||
122 | depends on REMOTEPROC | ||
123 | |||
124 | endif # REMOTEPROC | ||
125 | |||
119 | endmenu | 126 | endmenu |
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 | |||
16 | obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o | 16 | obj-$(CONFIG_QCOM_WCNSS_IRIS) += qcom_wcnss_iris.o |
17 | obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o | 17 | obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss.o |
18 | obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o | 18 | obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o |
19 | obj-$(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 | |||
57 | static const char *mem_names[ST_SLIM_MEM_MAX] = { | ||
58 | [ST_SLIM_DMEM] = "dmem", | ||
59 | [ST_SLIM_IMEM] = "imem", | ||
60 | }; | ||
61 | |||
62 | static 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 | |||
79 | err_put_clks: | ||
80 | while (--clk >= 0) | ||
81 | clk_put(slim_rproc->clks[clk]); | ||
82 | |||
83 | return err; | ||
84 | } | ||
85 | |||
86 | static 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 | |||
94 | static 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 | |||
106 | err_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 | */ | ||
116 | static 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 | |||
158 | static 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 | |||
181 | static 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 | |||
203 | static 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 | |||
213 | static struct resource_table empty_rsc_tbl = { | ||
214 | .ver = 1, | ||
215 | .num = 0, | ||
216 | }; | ||
217 | |||
218 | static 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 | |||
226 | static 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 | |||
243 | struct 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 | |||
327 | err_clk_dis: | ||
328 | slim_clk_disable(slim_rproc); | ||
329 | err_clk_put: | ||
330 | for (i = 0; i < ST_SLIM_MAX_CLK && slim_rproc->clks[i]; i++) | ||
331 | clk_put(slim_rproc->clks[i]); | ||
332 | err: | ||
333 | rproc_put(rproc); | ||
334 | return ERR_PTR(err); | ||
335 | } | ||
336 | EXPORT_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 | */ | ||
345 | void 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 | } | ||
360 | EXPORT_SYMBOL(st_slim_rproc_put); | ||
361 | |||
362 | MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>"); | ||
363 | MODULE_DESCRIPTION("STMicroelectronics SLIM core rproc driver"); | ||
364 | MODULE_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 | |||
19 | enum { | ||
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 | */ | ||
30 | struct 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 | */ | ||
44 | struct 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 | |||
54 | struct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev, | ||
55 | char *fw_name); | ||
56 | void st_slim_rproc_put(struct st_slim_rproc *slim_rproc); | ||
57 | |||
58 | #endif | ||