1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2018 Intel Corporation. All rights reserved.
4 //
5 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 // Keyon Jie <yang.jie@linux.intel.com>
7 // Rander Wang <rander.wang@intel.com>
8 // Janusz Jankowski <janusz.jankowski@linux.intel.com>
9
10 #include <sof/common.h>
11 #include <sof/drivers/dw-dma.h>
12 #include <sof/drivers/hda-dma.h>
13 #include <sof/drivers/interrupt.h>
14 #include <sof/lib/dma.h>
15 #include <sof/lib/memory.h>
16 #include <sof/sof.h>
17 #include <sof/spinlock.h>
18
19 #if CONFIG_APOLLOLAKE
20 #define DMAC0_CLASS 1
21 #define DMAC1_CLASS 2
22 #define DMAC_HOST_OUT_CHANNELS_COUNT 6
23 #define DMAC_LINK_IN_CHANNELS_COUNT 8
24 #define DMAC_LINK_OUT_CHANNELS_COUNT 8
25 #elif CONFIG_CANNONLAKE || CONFIG_ICELAKE || CONFIG_TIGERLAKE
26 #define DMAC0_CLASS 6
27 #define DMAC1_CLASS 7
28 #define DMAC_HOST_OUT_CHANNELS_COUNT 9
29 #define DMAC_LINK_IN_CHANNELS_COUNT 9
30 #define DMAC_LINK_OUT_CHANNELS_COUNT 7
31 #elif CONFIG_SUECREEK
32 #define DMAC0_CLASS 6
33 #define DMAC1_CLASS 7
34 #endif
35
36 const struct dw_drv_plat_data dmac0 = {
37 .chan[0] = {
38 .class = DMAC0_CLASS,
39 .weight = 0,
40 },
41 .chan[1] = {
42 .class = DMAC0_CLASS,
43 .weight = 0,
44 },
45 .chan[2] = {
46 .class = DMAC0_CLASS,
47 .weight = 0,
48 },
49 .chan[3] = {
50 .class = DMAC0_CLASS,
51 .weight = 0,
52 },
53 .chan[4] = {
54 .class = DMAC0_CLASS,
55 .weight = 0,
56 },
57 .chan[5] = {
58 .class = DMAC0_CLASS,
59 .weight = 0,
60 },
61 .chan[6] = {
62 .class = DMAC0_CLASS,
63 .weight = 0,
64 },
65 .chan[7] = {
66 .class = DMAC0_CLASS,
67 .weight = 0,
68 },
69 };
70
71 const struct dw_drv_plat_data dmac1 = {
72 .chan[0] = {
73 .class = DMAC1_CLASS,
74 .weight = 0,
75 },
76 .chan[1] = {
77 .class = DMAC1_CLASS,
78 .weight = 0,
79 },
80 .chan[2] = {
81 .class = DMAC1_CLASS,
82 .weight = 0,
83 },
84 .chan[3] = {
85 .class = DMAC1_CLASS,
86 .weight = 0,
87 },
88 .chan[4] = {
89 .class = DMAC1_CLASS,
90 .weight = 0,
91 },
92 .chan[5] = {
93 .class = DMAC1_CLASS,
94 .weight = 0,
95 },
96 .chan[6] = {
97 .class = DMAC1_CLASS,
98 .weight = 0,
99 },
100 .chan[7] = {
101 .class = DMAC1_CLASS,
102 .weight = 0,
103 },
104 };
105
106 #if CONFIG_SUECREEK
107 struct SHARED_DATA dma dma[PLATFORM_NUM_DMACS] = {
108 { /* LP GP DMAC 0 */
109 .plat_data = {
110 .id = DMA_GP_LP_DMAC0,
111 .dir = DMA_DIR_MEM_TO_MEM | DMA_DIR_MEM_TO_DEV |
112 DMA_DIR_DEV_TO_MEM | DMA_DIR_DEV_TO_DEV,
113 .caps = DMA_CAP_GP_LP,
114 .devs = DMA_DEV_SSP | DMA_DEV_SSI | DMA_DEV_DMIC,
115 .base = LP_GP_DMA_BASE(0),
116 .channels = 8,
117 .irq = IRQ_EXT_LP_GPDMA0_LVL5(0),
118 .irq_name = irq_name_level5,
119 .drv_plat_data = &dmac0,
120 },
121 .ops = &dw_dma_ops,
122 },
123 { /* LP GP DMAC 1 */
124 .plat_data = {
125 .id = DMA_GP_LP_DMAC1,
126 .dir = DMA_DIR_MEM_TO_MEM | DMA_DIR_MEM_TO_DEV |
127 DMA_DIR_DEV_TO_MEM | DMA_DIR_DEV_TO_DEV,
128 .caps = DMA_CAP_GP_LP,
129 .devs = DMA_DEV_SSP | DMA_DEV_DMIC,
130 .base = LP_GP_DMA_BASE(1),
131 .channels = 8,
132 .irq = IRQ_EXT_LP_GPDMA1_LVL5(0),
133 .irq_name = irq_name_level5,
134 .drv_plat_data = &dmac1,
135 },
136 .ops = &dw_dma_ops,
137 },
138 { /* LP GP DMAC 2 */
139 .plat_data = {
140 .id = DMA_GP_LP_DMAC2,
141 .dir = DMA_DIR_MEM_TO_MEM | DMA_DIR_MEM_TO_DEV |
142 DMA_DIR_DEV_TO_MEM | DMA_DIR_DEV_TO_DEV,
143 .caps = DMA_CAP_GP_LP,
144 .devs = DMA_DEV_SSP | DMA_DEV_DMIC,
145 .base = LP_GP_DMA_BASE(1),
146 .channels = 8,
147 .irq = IRQ_EXT_LP_GPDMA1_LVL5(0),
148 .irq_name = irq_name_level5,
149 .drv_plat_data = &dmac1,
150 },
151 .ops = &dw_dma_ops,
152 },
153 };
154
155 #else
156 SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = {
157 { /* Low Power GP DMAC 0 */
158 .plat_data = {
159 .id = DMA_GP_LP_DMAC0,
160 .dir = DMA_DIR_MEM_TO_MEM | DMA_DIR_MEM_TO_DEV |
161 DMA_DIR_DEV_TO_MEM | DMA_DIR_DEV_TO_DEV,
162 .caps = DMA_CAP_GP_LP,
163 .devs = DMA_DEV_SSP | DMA_DEV_DMIC |
164 DMA_DEV_ALH,
165 .base = LP_GP_DMA_BASE(0),
166 .channels = 8,
167 .irq = IRQ_EXT_LP_GPDMA0_LVL5(0),
168 .irq_name = irq_name_level5,
169 .drv_plat_data = &dmac0,
170 },
171 .ops = &dw_dma_ops,
172 },
173 { /* Low Power GP DMAC 1 */
174 .plat_data = {
175 .id = DMA_GP_LP_DMAC1,
176 .dir = DMA_DIR_MEM_TO_MEM | DMA_DIR_MEM_TO_DEV |
177 DMA_DIR_DEV_TO_MEM | DMA_DIR_DEV_TO_DEV,
178 .caps = DMA_CAP_GP_LP,
179 .devs = DMA_DEV_SSP | DMA_DEV_DMIC |
180 DMA_DEV_ALH,
181 .base = LP_GP_DMA_BASE(1),
182 .channels = 8,
183 .irq = IRQ_EXT_LP_GPDMA1_LVL5(0),
184 .irq_name = irq_name_level5,
185 .drv_plat_data = &dmac1,
186 },
187 .ops = &dw_dma_ops,
188 },
189 { /* Host In DMAC */
190 .plat_data = {
191 .id = DMA_HOST_IN_DMAC,
192 .dir = DMA_DIR_LMEM_TO_HMEM,
193 .caps = DMA_CAP_HDA,
194 .devs = DMA_DEV_HOST,
195 .base = GTW_HOST_IN_STREAM_BASE(0),
196 .channels = 7,
197 .chan_size = GTW_HOST_IN_STREAM_SIZE,
198 },
199 .ops = &hda_host_dma_ops,
200 },
201 { /* Host out DMAC */
202 .plat_data = {
203 .id = DMA_HOST_OUT_DMAC,
204 .dir = DMA_DIR_HMEM_TO_LMEM,
205 .caps = DMA_CAP_HDA,
206 .devs = DMA_DEV_HOST,
207 .base = GTW_HOST_OUT_STREAM_BASE(0),
208 .channels = DMAC_HOST_OUT_CHANNELS_COUNT,
209 .chan_size = GTW_HOST_OUT_STREAM_SIZE,
210 },
211 .ops = &hda_host_dma_ops,
212 },
213 { /* Link In DMAC */
214 .plat_data = {
215 .id = DMA_LINK_IN_DMAC,
216 .dir = DMA_DIR_DEV_TO_MEM,
217 .caps = DMA_CAP_HDA,
218 .devs = DMA_DEV_HDA,
219 .base = GTW_LINK_IN_STREAM_BASE(0),
220 .channels = DMAC_LINK_IN_CHANNELS_COUNT,
221 .chan_size = GTW_LINK_IN_STREAM_SIZE,
222 },
223 .ops = &hda_link_dma_ops,
224 },
225 { /* Link out DMAC */
226 .plat_data = {
227 .id = DMA_LINK_OUT_DMAC,
228 .dir = DMA_DIR_MEM_TO_DEV,
229 .caps = DMA_CAP_HDA,
230 .devs = DMA_DEV_HDA,
231 .base = GTW_LINK_OUT_STREAM_BASE(0),
232 .channels = DMAC_LINK_OUT_CHANNELS_COUNT,
233 .chan_size = GTW_LINK_OUT_STREAM_SIZE,
234 },
235 .ops = &hda_link_dma_ops,
236 },};
237 #endif
238
239 const struct dma_info lib_dma = {
240 .dma_array = cache_to_uncache_init((struct dma *)dma),
241 .num_dmas = ARRAY_SIZE(dma)
242 };
243
244 /* Initialize all platform DMAC's */
dmac_init(struct sof * sof)245 int dmac_init(struct sof *sof)
246 {
247 int i;
248 /* no probing before first use */
249
250 /* TODO: dynamic init based on platform settings */
251
252 sof->dma_info = &lib_dma;
253
254 /* early lock initialization for ref counting */
255 for (i = 0; i < sof->dma_info->num_dmas; i++)
256 spinlock_init(&sof->dma_info->dma_array[i].lock);
257
258 return 0;
259 }
260