1 // SPDX-License-Identifier: GPL-2.0+
3 // AMD ALSA SoC PCM Driver
5 //Copyright 2016 Advanced Micro Devices, Inc.
7 #include <linux/platform_device.h>
8 #include <linux/module.h>
11 #include <linux/pm_runtime.h>
12 #include <sound/pcm_params.h>
13 #include <sound/soc.h>
14 #include <sound/soc-dai.h>
18 #define DRV_NAME "acp3x_rv_i2s_dma"
20 static const struct snd_pcm_hardware acp3x_pcm_hardware_playback
= {
21 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
22 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
23 SNDRV_PCM_INFO_BATCH
|
24 SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
25 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
,
26 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S8
|
27 SNDRV_PCM_FMTBIT_U8
| SNDRV_PCM_FMTBIT_S24_LE
|
28 SNDRV_PCM_FMTBIT_S32_LE
,
31 .rates
= SNDRV_PCM_RATE_8000_96000
,
34 .buffer_bytes_max
= PLAYBACK_MAX_NUM_PERIODS
* PLAYBACK_MAX_PERIOD_SIZE
,
35 .period_bytes_min
= PLAYBACK_MIN_PERIOD_SIZE
,
36 .period_bytes_max
= PLAYBACK_MAX_PERIOD_SIZE
,
37 .periods_min
= PLAYBACK_MIN_NUM_PERIODS
,
38 .periods_max
= PLAYBACK_MAX_NUM_PERIODS
,
41 static const struct snd_pcm_hardware acp3x_pcm_hardware_capture
= {
42 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
43 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
44 SNDRV_PCM_INFO_BATCH
|
45 SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
46 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
,
47 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S8
|
48 SNDRV_PCM_FMTBIT_U8
| SNDRV_PCM_FMTBIT_S24_LE
|
49 SNDRV_PCM_FMTBIT_S32_LE
,
52 .rates
= SNDRV_PCM_RATE_8000_48000
,
55 .buffer_bytes_max
= CAPTURE_MAX_NUM_PERIODS
* CAPTURE_MAX_PERIOD_SIZE
,
56 .period_bytes_min
= CAPTURE_MIN_PERIOD_SIZE
,
57 .period_bytes_max
= CAPTURE_MAX_PERIOD_SIZE
,
58 .periods_min
= CAPTURE_MIN_NUM_PERIODS
,
59 .periods_max
= CAPTURE_MAX_NUM_PERIODS
,
62 static irqreturn_t
i2s_irq_handler(int irq
, void *dev_id
)
64 struct i2s_dev_data
*rv_i2s_data
;
65 u16 play_flag
, cap_flag
;
74 val
= rv_readl(rv_i2s_data
->acp3x_base
+ mmACP_EXTERNAL_INTR_STAT
);
75 if ((val
& BIT(BT_TX_THRESHOLD
)) && rv_i2s_data
->play_stream
) {
76 rv_writel(BIT(BT_TX_THRESHOLD
), rv_i2s_data
->acp3x_base
+
77 mmACP_EXTERNAL_INTR_STAT
);
78 snd_pcm_period_elapsed(rv_i2s_data
->play_stream
);
81 if ((val
& BIT(I2S_TX_THRESHOLD
)) &&
82 rv_i2s_data
->i2ssp_play_stream
) {
83 rv_writel(BIT(I2S_TX_THRESHOLD
),
84 rv_i2s_data
->acp3x_base
+ mmACP_EXTERNAL_INTR_STAT
);
85 snd_pcm_period_elapsed(rv_i2s_data
->i2ssp_play_stream
);
89 if ((val
& BIT(BT_RX_THRESHOLD
)) && rv_i2s_data
->capture_stream
) {
90 rv_writel(BIT(BT_RX_THRESHOLD
), rv_i2s_data
->acp3x_base
+
91 mmACP_EXTERNAL_INTR_STAT
);
92 snd_pcm_period_elapsed(rv_i2s_data
->capture_stream
);
95 if ((val
& BIT(I2S_RX_THRESHOLD
)) &&
96 rv_i2s_data
->i2ssp_capture_stream
) {
97 rv_writel(BIT(I2S_RX_THRESHOLD
),
98 rv_i2s_data
->acp3x_base
+ mmACP_EXTERNAL_INTR_STAT
);
99 snd_pcm_period_elapsed(rv_i2s_data
->i2ssp_capture_stream
);
103 if (play_flag
| cap_flag
)
109 static void config_acp3x_dma(struct i2s_stream_instance
*rtd
, int direction
)
112 u32 low
, high
, val
, acp_fifo_addr
, reg_fifo_addr
;
113 u32 reg_dma_size
, reg_fifo_size
;
116 addr
= rtd
->dma_addr
;
118 if (direction
== SNDRV_PCM_STREAM_PLAYBACK
) {
119 switch (rtd
->i2s_instance
) {
120 case I2S_BT_INSTANCE
:
121 val
= ACP_SRAM_BT_PB_PTE_OFFSET
;
123 case I2S_SP_INSTANCE
:
125 val
= ACP_SRAM_SP_PB_PTE_OFFSET
;
128 switch (rtd
->i2s_instance
) {
129 case I2S_BT_INSTANCE
:
130 val
= ACP_SRAM_BT_CP_PTE_OFFSET
;
132 case I2S_SP_INSTANCE
:
134 val
= ACP_SRAM_SP_CP_PTE_OFFSET
;
138 rv_writel(ACP_SRAM_PTE_OFFSET
| BIT(31), rtd
->acp3x_base
+
139 mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1
);
140 rv_writel(PAGE_SIZE_4K_ENABLE
, rtd
->acp3x_base
+
141 mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1
);
143 for (page_idx
= 0; page_idx
< rtd
->num_pages
; page_idx
++) {
144 /* Load the low address of page int ACP SRAM through SRBM */
145 low
= lower_32_bits(addr
);
146 high
= upper_32_bits(addr
);
148 rv_writel(low
, rtd
->acp3x_base
+ mmACP_SCRATCH_REG_0
+ val
);
150 rv_writel(high
, rtd
->acp3x_base
+ mmACP_SCRATCH_REG_0
+ val
152 /* Move to next physically contiguos page */
157 if (direction
== SNDRV_PCM_STREAM_PLAYBACK
) {
158 switch (rtd
->i2s_instance
) {
159 case I2S_BT_INSTANCE
:
160 reg_dma_size
= mmACP_BT_TX_DMA_SIZE
;
161 acp_fifo_addr
= ACP_SRAM_PTE_OFFSET
+
162 BT_PB_FIFO_ADDR_OFFSET
;
163 reg_fifo_addr
= mmACP_BT_TX_FIFOADDR
;
164 reg_fifo_size
= mmACP_BT_TX_FIFOSIZE
;
165 rv_writel(I2S_BT_TX_MEM_WINDOW_START
,
166 rtd
->acp3x_base
+ mmACP_BT_TX_RINGBUFADDR
);
169 case I2S_SP_INSTANCE
:
171 reg_dma_size
= mmACP_I2S_TX_DMA_SIZE
;
172 acp_fifo_addr
= ACP_SRAM_PTE_OFFSET
+
173 SP_PB_FIFO_ADDR_OFFSET
;
174 reg_fifo_addr
= mmACP_I2S_TX_FIFOADDR
;
175 reg_fifo_size
= mmACP_I2S_TX_FIFOSIZE
;
176 rv_writel(I2S_SP_TX_MEM_WINDOW_START
,
177 rtd
->acp3x_base
+ mmACP_I2S_TX_RINGBUFADDR
);
180 switch (rtd
->i2s_instance
) {
181 case I2S_BT_INSTANCE
:
182 reg_dma_size
= mmACP_BT_RX_DMA_SIZE
;
183 acp_fifo_addr
= ACP_SRAM_PTE_OFFSET
+
184 BT_CAPT_FIFO_ADDR_OFFSET
;
185 reg_fifo_addr
= mmACP_BT_RX_FIFOADDR
;
186 reg_fifo_size
= mmACP_BT_RX_FIFOSIZE
;
187 rv_writel(I2S_BT_RX_MEM_WINDOW_START
,
188 rtd
->acp3x_base
+ mmACP_BT_RX_RINGBUFADDR
);
191 case I2S_SP_INSTANCE
:
193 reg_dma_size
= mmACP_I2S_RX_DMA_SIZE
;
194 acp_fifo_addr
= ACP_SRAM_PTE_OFFSET
+
195 SP_CAPT_FIFO_ADDR_OFFSET
;
196 reg_fifo_addr
= mmACP_I2S_RX_FIFOADDR
;
197 reg_fifo_size
= mmACP_I2S_RX_FIFOSIZE
;
198 rv_writel(I2S_SP_RX_MEM_WINDOW_START
,
199 rtd
->acp3x_base
+ mmACP_I2S_RX_RINGBUFADDR
);
202 rv_writel(DMA_SIZE
, rtd
->acp3x_base
+ reg_dma_size
);
203 rv_writel(acp_fifo_addr
, rtd
->acp3x_base
+ reg_fifo_addr
);
204 rv_writel(FIFO_SIZE
, rtd
->acp3x_base
+ reg_fifo_size
);
205 rv_writel(BIT(I2S_RX_THRESHOLD
) | BIT(BT_RX_THRESHOLD
)
206 | BIT(I2S_TX_THRESHOLD
) | BIT(BT_TX_THRESHOLD
),
207 rtd
->acp3x_base
+ mmACP_EXTERNAL_INTR_CNTL
);
210 static int acp3x_dma_open(struct snd_soc_component
*component
,
211 struct snd_pcm_substream
*substream
)
213 struct snd_pcm_runtime
*runtime
;
214 struct snd_soc_pcm_runtime
*prtd
;
215 struct i2s_dev_data
*adata
;
216 struct i2s_stream_instance
*i2s_data
;
219 runtime
= substream
->runtime
;
220 prtd
= asoc_substream_to_rtd(substream
);
221 component
= snd_soc_rtdcom_lookup(prtd
, DRV_NAME
);
222 adata
= dev_get_drvdata(component
->dev
);
223 i2s_data
= kzalloc(sizeof(*i2s_data
), GFP_KERNEL
);
227 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
228 runtime
->hw
= acp3x_pcm_hardware_playback
;
230 runtime
->hw
= acp3x_pcm_hardware_capture
;
232 ret
= snd_pcm_hw_constraint_integer(runtime
,
233 SNDRV_PCM_HW_PARAM_PERIODS
);
235 dev_err(component
->dev
, "set integer constraint failed\n");
240 if (!adata
->play_stream
&& !adata
->capture_stream
&&
241 !adata
->i2ssp_play_stream
&& !adata
->i2ssp_capture_stream
)
242 rv_writel(1, adata
->acp3x_base
+ mmACP_EXTERNAL_INTR_ENB
);
244 i2s_data
->acp3x_base
= adata
->acp3x_base
;
245 runtime
->private_data
= i2s_data
;
250 static int acp3x_dma_hw_params(struct snd_soc_component
*component
,
251 struct snd_pcm_substream
*substream
,
252 struct snd_pcm_hw_params
*params
)
254 struct i2s_stream_instance
*rtd
;
255 struct snd_soc_pcm_runtime
*prtd
;
256 struct snd_soc_card
*card
;
257 struct acp3x_platform_info
*pinfo
;
258 struct i2s_dev_data
*adata
;
261 prtd
= asoc_substream_to_rtd(substream
);
263 pinfo
= snd_soc_card_get_drvdata(card
);
264 adata
= dev_get_drvdata(component
->dev
);
265 rtd
= substream
->runtime
->private_data
;
270 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
271 rtd
->i2s_instance
= pinfo
->play_i2s_instance
;
272 switch (rtd
->i2s_instance
) {
273 case I2S_BT_INSTANCE
:
274 adata
->play_stream
= substream
;
276 case I2S_SP_INSTANCE
:
278 adata
->i2ssp_play_stream
= substream
;
281 rtd
->i2s_instance
= pinfo
->cap_i2s_instance
;
282 switch (rtd
->i2s_instance
) {
283 case I2S_BT_INSTANCE
:
284 adata
->capture_stream
= substream
;
286 case I2S_SP_INSTANCE
:
288 adata
->i2ssp_capture_stream
= substream
;
292 pr_err("pinfo failed\n");
294 size
= params_buffer_bytes(params
);
295 rtd
->dma_addr
= substream
->dma_buffer
.addr
;
296 rtd
->num_pages
= (PAGE_ALIGN(size
) >> PAGE_SHIFT
);
297 config_acp3x_dma(rtd
, substream
->stream
);
301 static snd_pcm_uframes_t
acp3x_dma_pointer(struct snd_soc_component
*component
,
302 struct snd_pcm_substream
*substream
)
304 struct i2s_stream_instance
*rtd
;
309 rtd
= substream
->runtime
->private_data
;
311 buffersize
= frames_to_bytes(substream
->runtime
,
312 substream
->runtime
->buffer_size
);
313 bytescount
= acp_get_byte_count(rtd
, substream
->stream
);
314 if (bytescount
> rtd
->bytescount
)
315 bytescount
-= rtd
->bytescount
;
316 pos
= do_div(bytescount
, buffersize
);
317 return bytes_to_frames(substream
->runtime
, pos
);
320 static int acp3x_dma_new(struct snd_soc_component
*component
,
321 struct snd_soc_pcm_runtime
*rtd
)
323 struct device
*parent
= component
->dev
->parent
;
324 snd_pcm_set_managed_buffer_all(rtd
->pcm
, SNDRV_DMA_TYPE_DEV
,
325 parent
, MIN_BUFFER
, MAX_BUFFER
);
329 static int acp3x_dma_mmap(struct snd_soc_component
*component
,
330 struct snd_pcm_substream
*substream
,
331 struct vm_area_struct
*vma
)
333 return snd_pcm_lib_default_mmap(substream
, vma
);
336 static int acp3x_dma_close(struct snd_soc_component
*component
,
337 struct snd_pcm_substream
*substream
)
339 struct snd_soc_pcm_runtime
*prtd
;
340 struct i2s_dev_data
*adata
;
341 struct i2s_stream_instance
*ins
;
343 prtd
= asoc_substream_to_rtd(substream
);
344 component
= snd_soc_rtdcom_lookup(prtd
, DRV_NAME
);
345 adata
= dev_get_drvdata(component
->dev
);
346 ins
= substream
->runtime
->private_data
;
350 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
351 switch (ins
->i2s_instance
) {
352 case I2S_BT_INSTANCE
:
353 adata
->play_stream
= NULL
;
355 case I2S_SP_INSTANCE
:
357 adata
->i2ssp_play_stream
= NULL
;
360 switch (ins
->i2s_instance
) {
361 case I2S_BT_INSTANCE
:
362 adata
->capture_stream
= NULL
;
364 case I2S_SP_INSTANCE
:
366 adata
->i2ssp_capture_stream
= NULL
;
370 /* Disable ACP irq, when the current stream is being closed and
371 * another stream is also not active.
373 if (!adata
->play_stream
&& !adata
->capture_stream
&&
374 !adata
->i2ssp_play_stream
&& !adata
->i2ssp_capture_stream
)
375 rv_writel(0, adata
->acp3x_base
+ mmACP_EXTERNAL_INTR_ENB
);
379 static const struct snd_soc_component_driver acp3x_i2s_component
= {
381 .open
= acp3x_dma_open
,
382 .close
= acp3x_dma_close
,
383 .hw_params
= acp3x_dma_hw_params
,
384 .pointer
= acp3x_dma_pointer
,
385 .mmap
= acp3x_dma_mmap
,
386 .pcm_construct
= acp3x_dma_new
,
389 static int acp3x_audio_probe(struct platform_device
*pdev
)
391 struct resource
*res
;
392 struct i2s_dev_data
*adata
;
393 unsigned int irqflags
;
396 if (!pdev
->dev
.platform_data
) {
397 dev_err(&pdev
->dev
, "platform_data not retrieved\n");
400 irqflags
= *((unsigned int *)(pdev
->dev
.platform_data
));
402 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
404 dev_err(&pdev
->dev
, "IORESOURCE_MEM FAILED\n");
408 adata
= devm_kzalloc(&pdev
->dev
, sizeof(*adata
), GFP_KERNEL
);
412 adata
->acp3x_base
= devm_ioremap(&pdev
->dev
, res
->start
,
414 if (!adata
->acp3x_base
)
417 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
419 dev_err(&pdev
->dev
, "IORESOURCE_IRQ FAILED\n");
423 adata
->i2s_irq
= res
->start
;
425 dev_set_drvdata(&pdev
->dev
, adata
);
426 status
= devm_snd_soc_register_component(&pdev
->dev
,
427 &acp3x_i2s_component
,
430 dev_err(&pdev
->dev
, "Fail to register acp i2s component\n");
433 status
= devm_request_irq(&pdev
->dev
, adata
->i2s_irq
, i2s_irq_handler
,
434 irqflags
, "ACP3x_I2S_IRQ", adata
);
436 dev_err(&pdev
->dev
, "ACP3x I2S IRQ request failed\n");
440 pm_runtime_set_autosuspend_delay(&pdev
->dev
, 2000);
441 pm_runtime_use_autosuspend(&pdev
->dev
);
442 pm_runtime_enable(&pdev
->dev
);
443 pm_runtime_allow(&pdev
->dev
);
447 static int acp3x_audio_remove(struct platform_device
*pdev
)
449 pm_runtime_disable(&pdev
->dev
);
453 static int acp3x_resume(struct device
*dev
)
455 struct i2s_dev_data
*adata
;
456 u32 val
, reg_val
, frmt_val
;
460 adata
= dev_get_drvdata(dev
);
462 if (adata
->play_stream
&& adata
->play_stream
->runtime
) {
463 struct i2s_stream_instance
*rtd
=
464 adata
->play_stream
->runtime
->private_data
;
465 config_acp3x_dma(rtd
, SNDRV_PCM_STREAM_PLAYBACK
);
466 switch (rtd
->i2s_instance
) {
467 case I2S_BT_INSTANCE
:
468 reg_val
= mmACP_BTTDM_ITER
;
469 frmt_val
= mmACP_BTTDM_TXFRMT
;
471 case I2S_SP_INSTANCE
:
473 reg_val
= mmACP_I2STDM_ITER
;
474 frmt_val
= mmACP_I2STDM_TXFRMT
;
476 rv_writel((rtd
->xfer_resolution
<< 3),
477 rtd
->acp3x_base
+ reg_val
);
479 if (adata
->capture_stream
&& adata
->capture_stream
->runtime
) {
480 struct i2s_stream_instance
*rtd
=
481 adata
->capture_stream
->runtime
->private_data
;
482 config_acp3x_dma(rtd
, SNDRV_PCM_STREAM_CAPTURE
);
483 switch (rtd
->i2s_instance
) {
484 case I2S_BT_INSTANCE
:
485 reg_val
= mmACP_BTTDM_IRER
;
486 frmt_val
= mmACP_BTTDM_RXFRMT
;
488 case I2S_SP_INSTANCE
:
490 reg_val
= mmACP_I2STDM_IRER
;
491 frmt_val
= mmACP_I2STDM_RXFRMT
;
493 rv_writel((rtd
->xfer_resolution
<< 3),
494 rtd
->acp3x_base
+ reg_val
);
496 if (adata
->tdm_mode
== TDM_ENABLE
) {
497 rv_writel(adata
->tdm_fmt
, adata
->acp3x_base
+ frmt_val
);
498 val
= rv_readl(adata
->acp3x_base
+ reg_val
);
499 rv_writel(val
| 0x2, adata
->acp3x_base
+ reg_val
);
501 rv_writel(1, adata
->acp3x_base
+ mmACP_EXTERNAL_INTR_ENB
);
506 static int acp3x_pcm_runtime_suspend(struct device
*dev
)
508 struct i2s_dev_data
*adata
;
510 adata
= dev_get_drvdata(dev
);
512 rv_writel(0, adata
->acp3x_base
+ mmACP_EXTERNAL_INTR_ENB
);
517 static int acp3x_pcm_runtime_resume(struct device
*dev
)
519 struct i2s_dev_data
*adata
;
521 adata
= dev_get_drvdata(dev
);
523 rv_writel(1, adata
->acp3x_base
+ mmACP_EXTERNAL_INTR_ENB
);
527 static const struct dev_pm_ops acp3x_pm_ops
= {
528 .runtime_suspend
= acp3x_pcm_runtime_suspend
,
529 .runtime_resume
= acp3x_pcm_runtime_resume
,
530 .resume
= acp3x_resume
,
533 static struct platform_driver acp3x_dma_driver
= {
534 .probe
= acp3x_audio_probe
,
535 .remove
= acp3x_audio_remove
,
537 .name
= "acp3x_rv_i2s_dma",
542 module_platform_driver(acp3x_dma_driver
);
544 MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com");
545 MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
546 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
547 MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
548 MODULE_LICENSE("GPL v2");
549 MODULE_ALIAS("platform:"DRV_NAME
);