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