1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * AMD ALSA SoC common SoundWire DMA Driver for ACP6.3, ACP7.0 and ACP7.1
4  * platforms.
5  *
6  * Copyright 2023, 2025 Advanced Micro Devices, Inc.
7  */
8 
9 #include <linux/err.h>
10 #include <linux/io.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <sound/pcm_params.h>
14 #include <sound/soc.h>
15 #include <sound/soc-dai.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/soundwire/sdw_amd.h>
18 #include "acp63.h"
19 
20 #define DRV_NAME "amd_ps_sdw_dma"
21 
22 static struct sdw_dma_ring_buf_reg acp63_sdw0_dma_reg[ACP63_SDW0_DMA_MAX_STREAMS] = {
23 	{ACP_AUDIO0_TX_DMA_SIZE, ACP_AUDIO0_TX_FIFOADDR, ACP_AUDIO0_TX_FIFOSIZE,
24 	 ACP_AUDIO0_TX_RINGBUFSIZE, ACP_AUDIO0_TX_RINGBUFADDR, ACP_AUDIO0_TX_INTR_WATERMARK_SIZE,
25 	 ACP_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH},
26 	{ACP_AUDIO1_TX_DMA_SIZE, ACP_AUDIO1_TX_FIFOADDR, ACP_AUDIO1_TX_FIFOSIZE,
27 	 ACP_AUDIO1_TX_RINGBUFSIZE, ACP_AUDIO1_TX_RINGBUFADDR, ACP_AUDIO1_TX_INTR_WATERMARK_SIZE,
28 	 ACP_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO1_TX_LINEARPOSITIONCNTR_HIGH},
29 	{ACP_AUDIO2_TX_DMA_SIZE, ACP_AUDIO2_TX_FIFOADDR, ACP_AUDIO2_TX_FIFOSIZE,
30 	 ACP_AUDIO2_TX_RINGBUFSIZE, ACP_AUDIO2_TX_RINGBUFADDR, ACP_AUDIO2_TX_INTR_WATERMARK_SIZE,
31 	 ACP_AUDIO2_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO2_TX_LINEARPOSITIONCNTR_HIGH},
32 	{ACP_AUDIO0_RX_DMA_SIZE, ACP_AUDIO0_RX_FIFOADDR, ACP_AUDIO0_RX_FIFOSIZE,
33 	 ACP_AUDIO0_RX_RINGBUFSIZE, ACP_AUDIO0_RX_RINGBUFADDR, ACP_AUDIO0_RX_INTR_WATERMARK_SIZE,
34 	 ACP_AUDIO0_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_RX_LINEARPOSITIONCNTR_HIGH},
35 	{ACP_AUDIO1_RX_DMA_SIZE, ACP_AUDIO1_RX_FIFOADDR, ACP_AUDIO1_RX_FIFOSIZE,
36 	 ACP_AUDIO1_RX_RINGBUFSIZE, ACP_AUDIO1_RX_RINGBUFADDR, ACP_AUDIO1_RX_INTR_WATERMARK_SIZE,
37 	 ACP_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH},
38 	{ACP_AUDIO2_RX_DMA_SIZE, ACP_AUDIO2_RX_FIFOADDR, ACP_AUDIO2_RX_FIFOSIZE,
39 	 ACP_AUDIO2_RX_RINGBUFSIZE, ACP_AUDIO2_RX_RINGBUFADDR, ACP_AUDIO2_RX_INTR_WATERMARK_SIZE,
40 	 ACP_AUDIO2_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO2_RX_LINEARPOSITIONCNTR_HIGH}
41 };
42 
43 /*
44  * SDW1 instance supports one TX stream and one RX stream.
45  * For TX/RX streams DMA registers programming for SDW1 instance, it uses ACP_P1_AUDIO1 register
46  * set as per hardware register documentation
47  */
48 static struct sdw_dma_ring_buf_reg acp63_sdw1_dma_reg[ACP63_SDW1_DMA_MAX_STREAMS] =  {
49 	{ACP_P1_AUDIO1_TX_DMA_SIZE, ACP_P1_AUDIO1_TX_FIFOADDR, ACP_P1_AUDIO1_TX_FIFOSIZE,
50 	 ACP_P1_AUDIO1_TX_RINGBUFSIZE, ACP_P1_AUDIO1_TX_RINGBUFADDR,
51 	 ACP_P1_AUDIO1_TX_INTR_WATERMARK_SIZE,
52 	 ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_HIGH},
53 	{ACP_P1_AUDIO1_RX_DMA_SIZE, ACP_P1_AUDIO1_RX_FIFOADDR, ACP_P1_AUDIO1_RX_FIFOSIZE,
54 	 ACP_P1_AUDIO1_RX_RINGBUFSIZE, ACP_P1_AUDIO1_RX_RINGBUFADDR,
55 	 ACP_P1_AUDIO1_RX_INTR_WATERMARK_SIZE,
56 	 ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH},
57 };
58 
59 static u32 acp63_sdw0_dma_enable_reg[ACP63_SDW0_DMA_MAX_STREAMS] = {
60 	ACP_SW0_AUDIO0_TX_EN,
61 	ACP_SW0_AUDIO1_TX_EN,
62 	ACP_SW0_AUDIO2_TX_EN,
63 	ACP_SW0_AUDIO0_RX_EN,
64 	ACP_SW0_AUDIO1_RX_EN,
65 	ACP_SW0_AUDIO2_RX_EN,
66 };
67 
68 /*
69  * SDW1 instance supports one TX stream and one RX stream.
70  * For TX/RX streams DMA enable register programming for SDW1 instance,
71  * it uses ACP_SW1_AUDIO1_TX_EN and ACP_SW1_AUDIO1_RX_EN registers
72  * as per hardware register documentation.
73  */
74 static u32 acp63_sdw1_dma_enable_reg[ACP63_SDW1_DMA_MAX_STREAMS] = {
75 	ACP_SW1_AUDIO1_TX_EN,
76 	ACP_SW1_AUDIO1_RX_EN,
77 };
78 
79 static struct sdw_dma_ring_buf_reg acp70_sdw0_dma_reg[ACP70_SDW0_DMA_MAX_STREAMS] = {
80 	{ACP_AUDIO0_TX_DMA_SIZE, ACP_AUDIO0_TX_FIFOADDR, ACP_AUDIO0_TX_FIFOSIZE,
81 	 ACP_AUDIO0_TX_RINGBUFSIZE, ACP_AUDIO0_TX_RINGBUFADDR, ACP_AUDIO0_TX_INTR_WATERMARK_SIZE,
82 	 ACP_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH},
83 	{ACP_AUDIO1_TX_DMA_SIZE, ACP_AUDIO1_TX_FIFOADDR, ACP_AUDIO1_TX_FIFOSIZE,
84 	 ACP_AUDIO1_TX_RINGBUFSIZE, ACP_AUDIO1_TX_RINGBUFADDR, ACP_AUDIO1_TX_INTR_WATERMARK_SIZE,
85 	 ACP_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO1_TX_LINEARPOSITIONCNTR_HIGH},
86 	{ACP_AUDIO2_TX_DMA_SIZE, ACP_AUDIO2_TX_FIFOADDR, ACP_AUDIO2_TX_FIFOSIZE,
87 	 ACP_AUDIO2_TX_RINGBUFSIZE, ACP_AUDIO2_TX_RINGBUFADDR, ACP_AUDIO2_TX_INTR_WATERMARK_SIZE,
88 	 ACP_AUDIO2_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO2_TX_LINEARPOSITIONCNTR_HIGH},
89 	{ACP_AUDIO0_RX_DMA_SIZE, ACP_AUDIO0_RX_FIFOADDR, ACP_AUDIO0_RX_FIFOSIZE,
90 	 ACP_AUDIO0_RX_RINGBUFSIZE, ACP_AUDIO0_RX_RINGBUFADDR, ACP_AUDIO0_RX_INTR_WATERMARK_SIZE,
91 	 ACP_AUDIO0_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_RX_LINEARPOSITIONCNTR_HIGH},
92 	{ACP_AUDIO1_RX_DMA_SIZE, ACP_AUDIO1_RX_FIFOADDR, ACP_AUDIO1_RX_FIFOSIZE,
93 	 ACP_AUDIO1_RX_RINGBUFSIZE, ACP_AUDIO1_RX_RINGBUFADDR, ACP_AUDIO1_RX_INTR_WATERMARK_SIZE,
94 	 ACP_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH},
95 	{ACP_AUDIO2_RX_DMA_SIZE, ACP_AUDIO2_RX_FIFOADDR, ACP_AUDIO2_RX_FIFOSIZE,
96 	 ACP_AUDIO2_RX_RINGBUFSIZE, ACP_AUDIO2_RX_RINGBUFADDR, ACP_AUDIO2_RX_INTR_WATERMARK_SIZE,
97 	 ACP_AUDIO2_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO2_RX_LINEARPOSITIONCNTR_HIGH}
98 };
99 
100 static struct sdw_dma_ring_buf_reg acp70_sdw1_dma_reg[ACP70_SDW1_DMA_MAX_STREAMS] = {
101 	{ACP_P1_AUDIO0_TX_DMA_SIZE, ACP_P1_AUDIO0_TX_FIFOADDR, ACP_P1_AUDIO0_TX_FIFOSIZE,
102 	 ACP_P1_AUDIO0_TX_RINGBUFSIZE, ACP_P1_AUDIO0_TX_RINGBUFADDR,
103 	 ACP_P1_AUDIO0_TX_INTR_WATERMARK_SIZE,
104 	 ACP_P1_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH},
105 	{ACP_P1_AUDIO1_TX_DMA_SIZE, ACP_P1_AUDIO1_TX_FIFOADDR, ACP_P1_AUDIO1_TX_FIFOSIZE,
106 	 ACP_P1_AUDIO1_TX_RINGBUFSIZE, ACP_P1_AUDIO1_TX_RINGBUFADDR,
107 	 ACP_P1_AUDIO1_TX_INTR_WATERMARK_SIZE,
108 	 ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_HIGH},
109 	{ACP_P1_AUDIO2_TX_DMA_SIZE, ACP_P1_AUDIO2_TX_FIFOADDR, ACP_P1_AUDIO2_TX_FIFOSIZE,
110 	 ACP_P1_AUDIO2_TX_RINGBUFSIZE, ACP_P1_AUDIO2_TX_RINGBUFADDR,
111 	 ACP_P1_AUDIO2_TX_INTR_WATERMARK_SIZE,
112 	 ACP_P1_AUDIO2_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO2_TX_LINEARPOSITIONCNTR_HIGH},
113 	{ACP_P1_AUDIO0_RX_DMA_SIZE, ACP_P1_AUDIO0_RX_FIFOADDR, ACP_P1_AUDIO0_RX_FIFOSIZE,
114 	 ACP_P1_AUDIO0_RX_RINGBUFSIZE, ACP_P1_AUDIO0_RX_RINGBUFADDR,
115 	 ACP_P1_AUDIO0_RX_INTR_WATERMARK_SIZE,
116 	 ACP_P1_AUDIO0_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO0_RX_LINEARPOSITIONCNTR_HIGH},
117 	{ACP_P1_AUDIO1_RX_DMA_SIZE, ACP_P1_AUDIO1_RX_FIFOADDR, ACP_P1_AUDIO1_RX_FIFOSIZE,
118 	 ACP_P1_AUDIO1_RX_RINGBUFSIZE, ACP_P1_AUDIO1_RX_RINGBUFADDR,
119 	 ACP_P1_AUDIO1_RX_INTR_WATERMARK_SIZE,
120 	 ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH},
121 	{ACP_P1_AUDIO2_RX_DMA_SIZE, ACP_P1_AUDIO2_RX_FIFOADDR, ACP_P1_AUDIO2_RX_FIFOSIZE,
122 	 ACP_P1_AUDIO2_RX_RINGBUFSIZE, ACP_P1_AUDIO2_RX_RINGBUFADDR,
123 	 ACP_P1_AUDIO2_RX_INTR_WATERMARK_SIZE,
124 	 ACP_P1_AUDIO2_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO2_RX_LINEARPOSITIONCNTR_HIGH}
125 };
126 
127 static u32 acp70_sdw0_dma_enable_reg[ACP70_SDW0_DMA_MAX_STREAMS] = {
128 	ACP70_SW0_AUDIO0_TX_EN,
129 	ACP70_SW0_AUDIO1_TX_EN,
130 	ACP70_SW0_AUDIO2_TX_EN,
131 	ACP70_SW0_AUDIO0_RX_EN,
132 	ACP70_SW0_AUDIO1_RX_EN,
133 	ACP70_SW0_AUDIO2_RX_EN,
134 };
135 
136 static u32 acp70_sdw1_dma_enable_reg[ACP70_SDW1_DMA_MAX_STREAMS] = {
137 	ACP70_SW1_AUDIO0_TX_EN,
138 	ACP70_SW1_AUDIO1_TX_EN,
139 	ACP70_SW1_AUDIO2_TX_EN,
140 	ACP70_SW1_AUDIO0_RX_EN,
141 	ACP70_SW1_AUDIO1_RX_EN,
142 	ACP70_SW1_AUDIO2_RX_EN,
143 };
144 
145 static const struct snd_pcm_hardware acp63_sdw_hardware_playback = {
146 	.info = SNDRV_PCM_INFO_INTERLEAVED |
147 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
148 		SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
149 		SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
150 	.formats = SNDRV_PCM_FMTBIT_S16_LE |  SNDRV_PCM_FMTBIT_S8 |
151 		   SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
152 	.channels_min = 2,
153 	.channels_max = 2,
154 	.rates = SNDRV_PCM_RATE_48000,
155 	.rate_min = 48000,
156 	.rate_max = 48000,
157 	.buffer_bytes_max = SDW_PLAYBACK_MAX_NUM_PERIODS * SDW_PLAYBACK_MAX_PERIOD_SIZE,
158 	.period_bytes_min = SDW_PLAYBACK_MIN_PERIOD_SIZE,
159 	.period_bytes_max = SDW_PLAYBACK_MAX_PERIOD_SIZE,
160 	.periods_min = SDW_PLAYBACK_MIN_NUM_PERIODS,
161 	.periods_max = SDW_PLAYBACK_MAX_NUM_PERIODS,
162 };
163 
164 static const struct snd_pcm_hardware acp63_sdw_hardware_capture = {
165 	.info = SNDRV_PCM_INFO_INTERLEAVED |
166 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
167 		SNDRV_PCM_INFO_MMAP |
168 		SNDRV_PCM_INFO_MMAP_VALID |
169 		SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
170 	.formats = SNDRV_PCM_FMTBIT_S16_LE |  SNDRV_PCM_FMTBIT_S8 |
171 		   SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
172 	.channels_min = 2,
173 	.channels_max = 2,
174 	.rates = SNDRV_PCM_RATE_48000,
175 	.rate_min = 48000,
176 	.rate_max = 48000,
177 	.buffer_bytes_max = SDW_CAPTURE_MAX_NUM_PERIODS * SDW_CAPTURE_MAX_PERIOD_SIZE,
178 	.period_bytes_min = SDW_CAPTURE_MIN_PERIOD_SIZE,
179 	.period_bytes_max = SDW_CAPTURE_MAX_PERIOD_SIZE,
180 	.periods_min = SDW_CAPTURE_MIN_NUM_PERIODS,
181 	.periods_max = SDW_CAPTURE_MAX_NUM_PERIODS,
182 };
183 
acp63_enable_disable_sdw_dma_interrupts(void __iomem * acp_base,u32 irq_mask,u32 irq_mask1,bool enable)184 static void acp63_enable_disable_sdw_dma_interrupts(void __iomem *acp_base, u32 irq_mask,
185 						    u32 irq_mask1, bool enable)
186 {
187 	u32 ext_intr_cntl, ext_intr_cntl1;
188 
189 	if (enable) {
190 		ext_intr_cntl = readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
191 		ext_intr_cntl |= irq_mask;
192 		writel(ext_intr_cntl, acp_base + ACP_EXTERNAL_INTR_CNTL);
193 		ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1);
194 		ext_intr_cntl1 |= irq_mask1;
195 		writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1);
196 	} else {
197 		ext_intr_cntl = readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
198 		ext_intr_cntl &= ~irq_mask;
199 		writel(ext_intr_cntl, acp_base + ACP_EXTERNAL_INTR_CNTL);
200 		ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1);
201 		ext_intr_cntl1 &= ~irq_mask1;
202 		writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1);
203 	}
204 }
205 
acp63_config_dma(struct acp_sdw_dma_stream * stream,void __iomem * acp_base,u32 stream_id)206 static void acp63_config_dma(struct acp_sdw_dma_stream *stream, void __iomem *acp_base,
207 			     u32 stream_id)
208 {
209 	u16 page_idx;
210 	u32 low, high, val;
211 	u32 sdw_dma_pte_offset;
212 	dma_addr_t addr;
213 
214 	addr = stream->dma_addr;
215 	sdw_dma_pte_offset = SDW_PTE_OFFSET(stream->instance);
216 	val = sdw_dma_pte_offset + (stream_id * ACP_SDW_PTE_OFFSET);
217 
218 	/* Group Enable */
219 	writel(ACP_SDW_SRAM_PTE_OFFSET | BIT(31), acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2);
220 	writel(PAGE_SIZE_4K_ENABLE, acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2);
221 	for (page_idx = 0; page_idx < stream->num_pages; page_idx++) {
222 		/* Load the low address of page int ACP SRAM through SRBM */
223 		low = lower_32_bits(addr);
224 		high = upper_32_bits(addr);
225 
226 		writel(low, acp_base + ACP_SCRATCH_REG_0 + val);
227 		high |= BIT(31);
228 		writel(high, acp_base + ACP_SCRATCH_REG_0 + val + 4);
229 		val += 8;
230 		addr += PAGE_SIZE;
231 	}
232 	writel(0x1, acp_base + ACPAXI2AXI_ATU_CTRL);
233 }
234 
acp63_configure_sdw_ringbuffer(void __iomem * acp_base,u32 stream_id,u32 size,u32 manager_instance,u32 acp_rev)235 static int acp63_configure_sdw_ringbuffer(void __iomem *acp_base, u32 stream_id, u32 size,
236 					  u32 manager_instance, u32 acp_rev)
237 {
238 	u32 reg_dma_size;
239 	u32 reg_fifo_addr;
240 	u32 reg_fifo_size;
241 	u32 reg_ring_buf_size;
242 	u32 reg_ring_buf_addr;
243 	u32 sdw_fifo_addr;
244 	u32 sdw_fifo_offset;
245 	u32 sdw_ring_buf_addr;
246 	u32 sdw_ring_buf_size;
247 	u32 sdw_mem_window_offset;
248 
249 	switch (acp_rev) {
250 	case ACP63_PCI_REV:
251 		switch (manager_instance) {
252 		case ACP_SDW0:
253 			reg_dma_size = acp63_sdw0_dma_reg[stream_id].reg_dma_size;
254 			reg_fifo_addr =	acp63_sdw0_dma_reg[stream_id].reg_fifo_addr;
255 			reg_fifo_size = acp63_sdw0_dma_reg[stream_id].reg_fifo_size;
256 			reg_ring_buf_size = acp63_sdw0_dma_reg[stream_id].reg_ring_buf_size;
257 			reg_ring_buf_addr = acp63_sdw0_dma_reg[stream_id].reg_ring_buf_addr;
258 			break;
259 		case ACP_SDW1:
260 			reg_dma_size = acp63_sdw1_dma_reg[stream_id].reg_dma_size;
261 			reg_fifo_addr =	acp63_sdw1_dma_reg[stream_id].reg_fifo_addr;
262 			reg_fifo_size = acp63_sdw1_dma_reg[stream_id].reg_fifo_size;
263 			reg_ring_buf_size = acp63_sdw1_dma_reg[stream_id].reg_ring_buf_size;
264 			reg_ring_buf_addr = acp63_sdw1_dma_reg[stream_id].reg_ring_buf_addr;
265 			break;
266 		default:
267 			return -EINVAL;
268 		}
269 		break;
270 	case ACP70_PCI_REV:
271 	case ACP71_PCI_REV:
272 		switch (manager_instance) {
273 		case ACP_SDW0:
274 			reg_dma_size = acp70_sdw0_dma_reg[stream_id].reg_dma_size;
275 			reg_fifo_addr =	acp70_sdw0_dma_reg[stream_id].reg_fifo_addr;
276 			reg_fifo_size = acp70_sdw0_dma_reg[stream_id].reg_fifo_size;
277 			reg_ring_buf_size = acp70_sdw0_dma_reg[stream_id].reg_ring_buf_size;
278 			reg_ring_buf_addr = acp70_sdw0_dma_reg[stream_id].reg_ring_buf_addr;
279 			break;
280 		case ACP_SDW1:
281 			reg_dma_size = acp70_sdw1_dma_reg[stream_id].reg_dma_size;
282 			reg_fifo_addr =	acp70_sdw1_dma_reg[stream_id].reg_fifo_addr;
283 			reg_fifo_size = acp70_sdw1_dma_reg[stream_id].reg_fifo_size;
284 			reg_ring_buf_size = acp70_sdw1_dma_reg[stream_id].reg_ring_buf_size;
285 			reg_ring_buf_addr = acp70_sdw1_dma_reg[stream_id].reg_ring_buf_addr;
286 			break;
287 		default:
288 			return -EINVAL;
289 		}
290 		break;
291 	default:
292 		return -EINVAL;
293 	}
294 	sdw_fifo_offset = ACP_SDW_FIFO_OFFSET(manager_instance);
295 	sdw_mem_window_offset = SDW_MEM_WINDOW_START(manager_instance);
296 	sdw_fifo_addr = sdw_fifo_offset + (stream_id * SDW_FIFO_OFFSET);
297 	sdw_ring_buf_addr = sdw_mem_window_offset + (stream_id * ACP_SDW_RING_BUFF_ADDR_OFFSET);
298 	sdw_ring_buf_size = size;
299 	writel(sdw_ring_buf_size, acp_base + reg_ring_buf_size);
300 	writel(sdw_ring_buf_addr, acp_base + reg_ring_buf_addr);
301 	writel(sdw_fifo_addr, acp_base + reg_fifo_addr);
302 	writel(SDW_DMA_SIZE, acp_base + reg_dma_size);
303 	writel(SDW_FIFO_SIZE, acp_base + reg_fifo_size);
304 	return 0;
305 }
306 
acp63_sdw_dma_open(struct snd_soc_component * component,struct snd_pcm_substream * substream)307 static int acp63_sdw_dma_open(struct snd_soc_component *component,
308 			      struct snd_pcm_substream *substream)
309 {
310 	struct snd_pcm_runtime *runtime;
311 	struct acp_sdw_dma_stream *stream;
312 	struct snd_soc_dai *cpu_dai;
313 	struct amd_sdw_manager *amd_manager;
314 	struct snd_soc_pcm_runtime *prtd = snd_soc_substream_to_rtd(substream);
315 	int ret;
316 
317 	runtime = substream->runtime;
318 	cpu_dai = snd_soc_rtd_to_cpu(prtd, 0);
319 	amd_manager = snd_soc_dai_get_drvdata(cpu_dai);
320 	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
321 	if (!stream)
322 		return -ENOMEM;
323 
324 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
325 		runtime->hw = acp63_sdw_hardware_playback;
326 	else
327 		runtime->hw = acp63_sdw_hardware_capture;
328 	ret = snd_pcm_hw_constraint_integer(runtime,
329 					    SNDRV_PCM_HW_PARAM_PERIODS);
330 	if (ret < 0) {
331 		dev_err(component->dev, "set integer constraint failed\n");
332 		kfree(stream);
333 		return ret;
334 	}
335 
336 	stream->stream_id = cpu_dai->id;
337 	stream->instance = amd_manager->instance;
338 	runtime->private_data = stream;
339 	return ret;
340 }
341 
acp63_sdw_dma_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)342 static int acp63_sdw_dma_hw_params(struct snd_soc_component *component,
343 				   struct snd_pcm_substream *substream,
344 				   struct snd_pcm_hw_params *params)
345 {
346 	struct acp_sdw_dma_stream *stream;
347 	struct sdw_dma_dev_data *sdw_data;
348 	u32 period_bytes;
349 	u32 water_mark_size_reg;
350 	u32 irq_mask, ext_intr_ctrl;
351 	u64 size;
352 	u32 stream_id;
353 	u32 acp_ext_intr_cntl_reg;
354 	int ret;
355 
356 	sdw_data = dev_get_drvdata(component->dev);
357 	stream = substream->runtime->private_data;
358 	if (!stream)
359 		return -EINVAL;
360 	stream_id = stream->stream_id;
361 	switch (sdw_data->acp_rev) {
362 	case ACP63_PCI_REV:
363 		switch (stream->instance) {
364 		case ACP_SDW0:
365 			sdw_data->acp63_sdw0_dma_stream[stream_id] = substream;
366 			water_mark_size_reg = acp63_sdw0_dma_reg[stream_id].water_mark_size_reg;
367 			acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL;
368 			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
369 				irq_mask = BIT(ACP63_SDW0_DMA_TX_IRQ_MASK(stream_id));
370 			else
371 				irq_mask = BIT(ACP63_SDW0_DMA_RX_IRQ_MASK(stream_id));
372 			break;
373 		case ACP_SDW1:
374 			sdw_data->acp63_sdw1_dma_stream[stream_id] = substream;
375 			acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL1;
376 			water_mark_size_reg = acp63_sdw1_dma_reg[stream_id].water_mark_size_reg;
377 			irq_mask = BIT(ACP63_SDW1_DMA_IRQ_MASK(stream_id));
378 			break;
379 		default:
380 			return -EINVAL;
381 		}
382 		break;
383 	case ACP70_PCI_REV:
384 	case ACP71_PCI_REV:
385 		switch (stream->instance) {
386 		case ACP_SDW0:
387 			sdw_data->acp70_sdw0_dma_stream[stream_id] = substream;
388 			water_mark_size_reg = acp70_sdw0_dma_reg[stream_id].water_mark_size_reg;
389 			acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL;
390 			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
391 				irq_mask = BIT(ACP70_SDW0_DMA_TX_IRQ_MASK(stream_id));
392 			else
393 				irq_mask = BIT(ACP70_SDW0_DMA_RX_IRQ_MASK(stream_id));
394 			break;
395 		case ACP_SDW1:
396 			sdw_data->acp70_sdw1_dma_stream[stream_id] = substream;
397 			acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL1;
398 			water_mark_size_reg = acp70_sdw1_dma_reg[stream_id].water_mark_size_reg;
399 			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
400 				irq_mask = BIT(ACP70_SDW1_DMA_TX_IRQ_MASK(stream_id));
401 			else
402 				irq_mask = BIT(ACP70_SDW1_DMA_RX_IRQ_MASK(stream_id));
403 
404 			break;
405 		default:
406 			return -EINVAL;
407 		}
408 		break;
409 	default:
410 		return -EINVAL;
411 	}
412 	size = params_buffer_bytes(params);
413 	period_bytes = params_period_bytes(params);
414 	stream->dma_addr = substream->runtime->dma_addr;
415 	stream->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
416 	acp63_config_dma(stream, sdw_data->acp_base, stream_id);
417 	ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, stream_id, size,
418 					     stream->instance, sdw_data->acp_rev);
419 	if (ret) {
420 		dev_err(component->dev, "Invalid DMA channel\n");
421 		return -EINVAL;
422 	}
423 	ext_intr_ctrl = readl(sdw_data->acp_base + acp_ext_intr_cntl_reg);
424 	ext_intr_ctrl |= irq_mask;
425 	writel(ext_intr_ctrl, sdw_data->acp_base + acp_ext_intr_cntl_reg);
426 	writel(period_bytes, sdw_data->acp_base + water_mark_size_reg);
427 	return 0;
428 }
429 
acp63_sdw_get_byte_count(struct acp_sdw_dma_stream * stream,void __iomem * acp_base,u32 acp_rev)430 static u64 acp63_sdw_get_byte_count(struct acp_sdw_dma_stream *stream, void __iomem *acp_base,
431 				    u32 acp_rev)
432 {
433 	union acp_sdw_dma_count byte_count;
434 	u32 pos_low_reg, pos_high_reg;
435 
436 	byte_count.bytescount = 0;
437 	switch (acp_rev) {
438 	case ACP63_PCI_REV:
439 		switch (stream->instance) {
440 		case ACP_SDW0:
441 			pos_low_reg = acp63_sdw0_dma_reg[stream->stream_id].pos_low_reg;
442 			pos_high_reg = acp63_sdw0_dma_reg[stream->stream_id].pos_high_reg;
443 			break;
444 		case ACP_SDW1:
445 			pos_low_reg = acp63_sdw1_dma_reg[stream->stream_id].pos_low_reg;
446 			pos_high_reg = acp63_sdw1_dma_reg[stream->stream_id].pos_high_reg;
447 			break;
448 		default:
449 			goto POINTER_RETURN_BYTES;
450 		}
451 		break;
452 	case ACP70_PCI_REV:
453 	case ACP71_PCI_REV:
454 		switch (stream->instance) {
455 		case ACP_SDW0:
456 			pos_low_reg = acp70_sdw0_dma_reg[stream->stream_id].pos_low_reg;
457 			pos_high_reg = acp70_sdw0_dma_reg[stream->stream_id].pos_high_reg;
458 			break;
459 		case ACP_SDW1:
460 			pos_low_reg = acp70_sdw1_dma_reg[stream->stream_id].pos_low_reg;
461 			pos_high_reg = acp70_sdw1_dma_reg[stream->stream_id].pos_high_reg;
462 			break;
463 		default:
464 			goto POINTER_RETURN_BYTES;
465 		}
466 		break;
467 	default:
468 		goto POINTER_RETURN_BYTES;
469 	}
470 	if (pos_low_reg) {
471 		byte_count.bcount.high = readl(acp_base + pos_high_reg);
472 		byte_count.bcount.low = readl(acp_base + pos_low_reg);
473 	}
474 POINTER_RETURN_BYTES:
475 	return byte_count.bytescount;
476 }
477 
acp63_sdw_dma_pointer(struct snd_soc_component * comp,struct snd_pcm_substream * substream)478 static snd_pcm_uframes_t acp63_sdw_dma_pointer(struct snd_soc_component *comp,
479 					       struct snd_pcm_substream *substream)
480 {
481 	struct sdw_dma_dev_data *sdw_data;
482 	struct acp_sdw_dma_stream *stream;
483 	u32 pos, buffersize;
484 	u64 bytescount;
485 
486 	sdw_data = dev_get_drvdata(comp->dev);
487 	stream = substream->runtime->private_data;
488 	buffersize = frames_to_bytes(substream->runtime,
489 				     substream->runtime->buffer_size);
490 	bytescount = acp63_sdw_get_byte_count(stream, sdw_data->acp_base, sdw_data->acp_rev);
491 	if (bytescount > stream->bytescount)
492 		bytescount -= stream->bytescount;
493 	pos = do_div(bytescount, buffersize);
494 	return bytes_to_frames(substream->runtime, pos);
495 }
496 
acp63_sdw_dma_new(struct snd_soc_component * component,struct snd_soc_pcm_runtime * rtd)497 static int acp63_sdw_dma_new(struct snd_soc_component *component,
498 			     struct snd_soc_pcm_runtime *rtd)
499 {
500 	struct device *parent = component->dev->parent;
501 
502 	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
503 				       parent, SDW_MIN_BUFFER, SDW_MAX_BUFFER);
504 	return 0;
505 }
506 
acp63_sdw_dma_close(struct snd_soc_component * component,struct snd_pcm_substream * substream)507 static int acp63_sdw_dma_close(struct snd_soc_component *component,
508 			       struct snd_pcm_substream *substream)
509 {
510 	struct sdw_dma_dev_data *sdw_data;
511 	struct acp_sdw_dma_stream *stream;
512 
513 	sdw_data = dev_get_drvdata(component->dev);
514 	stream = substream->runtime->private_data;
515 	if (!stream)
516 		return -EINVAL;
517 	switch (sdw_data->acp_rev) {
518 	case ACP63_PCI_REV:
519 		switch (stream->instance) {
520 		case ACP_SDW0:
521 			sdw_data->acp63_sdw0_dma_stream[stream->stream_id] = NULL;
522 			break;
523 		case ACP_SDW1:
524 			sdw_data->acp63_sdw1_dma_stream[stream->stream_id] = NULL;
525 			break;
526 		default:
527 			return -EINVAL;
528 		}
529 		break;
530 	case ACP70_PCI_REV:
531 	case ACP71_PCI_REV:
532 		switch (stream->instance) {
533 		case ACP_SDW0:
534 			sdw_data->acp70_sdw0_dma_stream[stream->stream_id] = NULL;
535 			break;
536 		case ACP_SDW1:
537 			sdw_data->acp70_sdw1_dma_stream[stream->stream_id] = NULL;
538 			break;
539 		default:
540 			return -EINVAL;
541 		}
542 		break;
543 	default:
544 		return -EINVAL;
545 	}
546 	kfree(stream);
547 	return 0;
548 }
549 
acp63_sdw_dma_enable(struct snd_pcm_substream * substream,void __iomem * acp_base,u32 acp_rev,bool sdw_dma_enable)550 static int acp63_sdw_dma_enable(struct snd_pcm_substream *substream,
551 				void __iomem *acp_base, u32 acp_rev, bool sdw_dma_enable)
552 {
553 	struct acp_sdw_dma_stream *stream;
554 	u32 stream_id;
555 	u32 sdw_dma_en_reg;
556 	u32 sdw_dma_en_stat_reg;
557 	u32 sdw_dma_stat;
558 	u32 dma_enable;
559 
560 	stream = substream->runtime->private_data;
561 	stream_id = stream->stream_id;
562 	switch (acp_rev) {
563 	case ACP63_PCI_REV:
564 		switch (stream->instance) {
565 		case ACP_SDW0:
566 			sdw_dma_en_reg = acp63_sdw0_dma_enable_reg[stream_id];
567 			break;
568 		case ACP_SDW1:
569 			sdw_dma_en_reg = acp63_sdw1_dma_enable_reg[stream_id];
570 			break;
571 		default:
572 			return -EINVAL;
573 		}
574 		break;
575 	case ACP70_PCI_REV:
576 	case ACP71_PCI_REV:
577 		switch (stream->instance) {
578 		case ACP_SDW0:
579 			sdw_dma_en_reg = acp70_sdw0_dma_enable_reg[stream_id];
580 			break;
581 		case ACP_SDW1:
582 			sdw_dma_en_reg = acp70_sdw1_dma_enable_reg[stream_id];
583 			break;
584 		default:
585 			return -EINVAL;
586 		}
587 		break;
588 	default:
589 		return -EINVAL;
590 	}
591 	sdw_dma_en_stat_reg = sdw_dma_en_reg + 4;
592 	dma_enable = sdw_dma_enable;
593 	writel(dma_enable, acp_base + sdw_dma_en_reg);
594 	return readl_poll_timeout(acp_base + sdw_dma_en_stat_reg, sdw_dma_stat,
595 				  (sdw_dma_stat == dma_enable), ACP_DELAY_US, ACP_COUNTER);
596 }
597 
acp63_sdw_dma_trigger(struct snd_soc_component * comp,struct snd_pcm_substream * substream,int cmd)598 static int acp63_sdw_dma_trigger(struct snd_soc_component *comp,
599 				 struct snd_pcm_substream *substream,
600 				 int cmd)
601 {
602 	struct sdw_dma_dev_data *sdw_data;
603 	int ret;
604 
605 	sdw_data = dev_get_drvdata(comp->dev);
606 	switch (cmd) {
607 	case SNDRV_PCM_TRIGGER_START:
608 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
609 	case SNDRV_PCM_TRIGGER_RESUME:
610 		ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, sdw_data->acp_rev, true);
611 		break;
612 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
613 	case SNDRV_PCM_TRIGGER_SUSPEND:
614 	case SNDRV_PCM_TRIGGER_STOP:
615 		ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, sdw_data->acp_rev, false);
616 		break;
617 	default:
618 		ret = -EINVAL;
619 	}
620 	if (ret)
621 		dev_err(comp->dev, "trigger %d failed: %d", cmd, ret);
622 	return ret;
623 }
624 
625 static const struct snd_soc_component_driver acp63_sdw_component = {
626 	.name		= DRV_NAME,
627 	.open		= acp63_sdw_dma_open,
628 	.close		= acp63_sdw_dma_close,
629 	.hw_params	= acp63_sdw_dma_hw_params,
630 	.trigger	= acp63_sdw_dma_trigger,
631 	.pointer	= acp63_sdw_dma_pointer,
632 	.pcm_construct	= acp63_sdw_dma_new,
633 	.use_dai_pcm_id = true,
634 
635 };
636 
acp63_sdw_platform_probe(struct platform_device * pdev)637 static int acp63_sdw_platform_probe(struct platform_device *pdev)
638 {
639 	struct resource *res;
640 	struct sdw_dma_dev_data *sdw_data;
641 	struct acp63_dev_data *acp_data;
642 	struct device *parent;
643 	int status;
644 
645 	parent = pdev->dev.parent;
646 	acp_data = dev_get_drvdata(parent);
647 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
648 	if (!res) {
649 		dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
650 		return -ENODEV;
651 	}
652 
653 	sdw_data = devm_kzalloc(&pdev->dev, sizeof(*sdw_data), GFP_KERNEL);
654 	if (!sdw_data)
655 		return -ENOMEM;
656 
657 	sdw_data->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
658 	if (!sdw_data->acp_base)
659 		return -ENOMEM;
660 
661 	sdw_data->acp_lock = &acp_data->acp_lock;
662 	sdw_data->acp_rev = acp_data->acp_rev;
663 	dev_set_drvdata(&pdev->dev, sdw_data);
664 	status = devm_snd_soc_register_component(&pdev->dev,
665 						 &acp63_sdw_component,
666 						 NULL, 0);
667 	if (status) {
668 		dev_err(&pdev->dev, "Fail to register sdw dma component\n");
669 		return status;
670 	}
671 	pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
672 	pm_runtime_use_autosuspend(&pdev->dev);
673 	pm_runtime_mark_last_busy(&pdev->dev);
674 	pm_runtime_set_active(&pdev->dev);
675 	pm_runtime_enable(&pdev->dev);
676 	return 0;
677 }
678 
acp63_sdw_platform_remove(struct platform_device * pdev)679 static void acp63_sdw_platform_remove(struct platform_device *pdev)
680 {
681 	pm_runtime_disable(&pdev->dev);
682 }
683 
acp63_restore_sdw_dma_config(struct sdw_dma_dev_data * sdw_data)684 static int acp63_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data)
685 {
686 	struct acp_sdw_dma_stream *stream;
687 	struct snd_pcm_substream *substream;
688 	struct snd_pcm_runtime *runtime;
689 	u32 period_bytes, buf_size, water_mark_size_reg;
690 	u32 stream_count, irq_mask, irq_mask1;
691 	int index, instance, ret;
692 
693 	irq_mask = ACP63_SDW_DMA_IRQ_MASK;
694 	irq_mask1 = ACP63_P1_SDW_DMA_IRQ_MASK;
695 	for (instance = 0; instance < AMD_SDW_MAX_MANAGERS; instance++) {
696 		if (instance == ACP_SDW0)
697 			stream_count = ACP63_SDW0_DMA_MAX_STREAMS;
698 		else
699 			stream_count = ACP63_SDW1_DMA_MAX_STREAMS;
700 
701 		for (index = 0; index < stream_count; index++) {
702 			if (instance == ACP_SDW0) {
703 				substream = sdw_data->acp63_sdw0_dma_stream[index];
704 				water_mark_size_reg = acp63_sdw0_dma_reg[index].water_mark_size_reg;
705 			} else {
706 				substream = sdw_data->acp63_sdw1_dma_stream[index];
707 				water_mark_size_reg = acp63_sdw1_dma_reg[index].water_mark_size_reg;
708 			}
709 
710 			if (substream && substream->runtime) {
711 				runtime = substream->runtime;
712 				stream = runtime->private_data;
713 				period_bytes = frames_to_bytes(runtime, runtime->period_size);
714 				buf_size = frames_to_bytes(runtime, runtime->buffer_size);
715 				acp63_config_dma(stream, sdw_data->acp_base, index);
716 				ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, index,
717 								     buf_size, instance,
718 								     ACP63_PCI_REV);
719 				if (ret)
720 					return ret;
721 				writel(period_bytes, sdw_data->acp_base + water_mark_size_reg);
722 			}
723 		}
724 	}
725 	acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, irq_mask, irq_mask1, true);
726 	return 0;
727 }
728 
acp70_restore_sdw_dma_config(struct sdw_dma_dev_data * sdw_data)729 static int acp70_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data)
730 {
731 	struct acp_sdw_dma_stream *stream;
732 	struct snd_pcm_substream *substream;
733 	struct snd_pcm_runtime *runtime;
734 	u32 period_bytes, buf_size, water_mark_size_reg;
735 	u32 stream_count, irq_mask, irq_mask1;
736 	int index, instance, ret;
737 
738 	irq_mask = ACP70_SDW_DMA_IRQ_MASK;
739 	irq_mask1 = ACP70_P1_SDW_DMA_IRQ_MASK;
740 	stream_count = ACP70_SDW0_DMA_MAX_STREAMS;
741 	for (instance = 0; instance < AMD_SDW_MAX_MANAGERS; instance++) {
742 		for (index = 0; index < stream_count; index++) {
743 			if (instance == ACP_SDW0) {
744 				substream = sdw_data->acp70_sdw0_dma_stream[index];
745 				water_mark_size_reg = acp70_sdw0_dma_reg[index].water_mark_size_reg;
746 			} else {
747 				substream = sdw_data->acp70_sdw1_dma_stream[index];
748 				water_mark_size_reg = acp70_sdw1_dma_reg[index].water_mark_size_reg;
749 			}
750 
751 			if (substream && substream->runtime) {
752 				runtime = substream->runtime;
753 				stream = runtime->private_data;
754 				period_bytes = frames_to_bytes(runtime, runtime->period_size);
755 				buf_size = frames_to_bytes(runtime, runtime->buffer_size);
756 				acp63_config_dma(stream, sdw_data->acp_base, index);
757 				ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, index,
758 								     buf_size, instance,
759 								     sdw_data->acp_rev);
760 				if (ret)
761 					return ret;
762 				writel(period_bytes, sdw_data->acp_base + water_mark_size_reg);
763 			}
764 		}
765 	}
766 	acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, irq_mask, irq_mask1, true);
767 	return 0;
768 }
769 
acp63_sdw_pcm_resume(struct device * dev)770 static int acp63_sdw_pcm_resume(struct device *dev)
771 {
772 	struct sdw_dma_dev_data *sdw_data;
773 
774 	sdw_data = dev_get_drvdata(dev);
775 	if (sdw_data->acp_rev == ACP63_PCI_REV)
776 		return acp63_restore_sdw_dma_config(sdw_data);
777 	else
778 		return acp70_restore_sdw_dma_config(sdw_data);
779 }
780 
781 static const struct dev_pm_ops acp63_pm_ops = {
782 	SYSTEM_SLEEP_PM_OPS(NULL, acp63_sdw_pcm_resume)
783 };
784 
785 static struct platform_driver acp63_sdw_dma_driver = {
786 	.probe = acp63_sdw_platform_probe,
787 	.remove = acp63_sdw_platform_remove,
788 	.driver = {
789 		.name = "amd_ps_sdw_dma",
790 		.pm = pm_ptr(&acp63_pm_ops),
791 	},
792 };
793 
794 module_platform_driver(acp63_sdw_dma_driver);
795 
796 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
797 MODULE_DESCRIPTION("AMD common SDW DMA Driver for ACP6.3, ACP7.0 & ACP7.1 platforms");
798 MODULE_LICENSE("GPL");
799 MODULE_ALIAS("platform:" DRV_NAME);
800