1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
3 // This file is provided under a dual BSD/GPLv2 license. When using or
4 // redistributing this file, you may do so under either license.
6 // Copyright(c) 2021 Advanced Micro Devices, Inc.
8 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
11 * Generic interface for ACP audio blck PCM component
14 #include <linux/platform_device.h>
15 #include <linux/module.h>
16 #include <linux/err.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
20 #include <sound/soc-dai.h>
21 #include <linux/dma-mapping.h>
24 #include "../mach-config.h"
27 #define DRV_NAME "acp_i2s_dma"
29 static const struct snd_pcm_hardware acp_pcm_hardware_playback
= {
30 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
31 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
32 SNDRV_PCM_INFO_BATCH
|
33 SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
34 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
,
35 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S8
|
36 SNDRV_PCM_FMTBIT_U8
| SNDRV_PCM_FMTBIT_S24_LE
|
37 SNDRV_PCM_FMTBIT_S32_LE
,
40 .rates
= SNDRV_PCM_RATE_8000_96000
,
43 .buffer_bytes_max
= PLAYBACK_MAX_NUM_PERIODS
* PLAYBACK_MAX_PERIOD_SIZE
,
44 .period_bytes_min
= PLAYBACK_MIN_PERIOD_SIZE
,
45 .period_bytes_max
= PLAYBACK_MAX_PERIOD_SIZE
,
46 .periods_min
= PLAYBACK_MIN_NUM_PERIODS
,
47 .periods_max
= PLAYBACK_MAX_NUM_PERIODS
,
50 static const struct snd_pcm_hardware acp_pcm_hardware_capture
= {
51 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
52 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
53 SNDRV_PCM_INFO_BATCH
|
54 SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
55 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
,
56 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S8
|
57 SNDRV_PCM_FMTBIT_U8
| SNDRV_PCM_FMTBIT_S24_LE
|
58 SNDRV_PCM_FMTBIT_S32_LE
,
61 .rates
= SNDRV_PCM_RATE_8000_48000
,
64 .buffer_bytes_max
= CAPTURE_MAX_NUM_PERIODS
* CAPTURE_MAX_PERIOD_SIZE
,
65 .period_bytes_min
= CAPTURE_MIN_PERIOD_SIZE
,
66 .period_bytes_max
= CAPTURE_MAX_PERIOD_SIZE
,
67 .periods_min
= CAPTURE_MIN_NUM_PERIODS
,
68 .periods_max
= CAPTURE_MAX_NUM_PERIODS
,
71 static const struct snd_pcm_hardware acp6x_pcm_hardware_playback
= {
72 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
73 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
74 SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
75 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
,
76 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S8
|
77 SNDRV_PCM_FMTBIT_U8
| SNDRV_PCM_FMTBIT_S24_LE
|
78 SNDRV_PCM_FMTBIT_S32_LE
,
81 .rates
= SNDRV_PCM_RATE_8000_192000
,
84 .buffer_bytes_max
= PLAYBACK_MAX_NUM_PERIODS
* PLAYBACK_MAX_PERIOD_SIZE
,
85 .period_bytes_min
= PLAYBACK_MIN_PERIOD_SIZE
,
86 .period_bytes_max
= PLAYBACK_MAX_PERIOD_SIZE
,
87 .periods_min
= PLAYBACK_MIN_NUM_PERIODS
,
88 .periods_max
= PLAYBACK_MAX_NUM_PERIODS
,
91 static const struct snd_pcm_hardware acp6x_pcm_hardware_capture
= {
92 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
93 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
94 SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
95 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
,
96 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S8
|
97 SNDRV_PCM_FMTBIT_U8
| SNDRV_PCM_FMTBIT_S24_LE
|
98 SNDRV_PCM_FMTBIT_S32_LE
,
101 .rates
= SNDRV_PCM_RATE_8000_192000
,
104 .buffer_bytes_max
= CAPTURE_MAX_NUM_PERIODS
* CAPTURE_MAX_PERIOD_SIZE
,
105 .period_bytes_min
= CAPTURE_MIN_PERIOD_SIZE
,
106 .period_bytes_max
= CAPTURE_MAX_PERIOD_SIZE
,
107 .periods_min
= CAPTURE_MIN_NUM_PERIODS
,
108 .periods_max
= CAPTURE_MAX_NUM_PERIODS
,
111 int acp_machine_select(struct acp_dev_data
*adata
)
113 struct snd_soc_acpi_mach
*mach
;
116 if (adata
->flag
== FLAG_AMD_LEGACY_ONLY_DMIC
) {
117 platform
= adata
->acp_rev
;
118 adata
->mach_dev
= platform_device_register_data(adata
->dev
, "acp-pdm-mach",
119 PLATFORM_DEVID_NONE
, &platform
,
122 size
= sizeof(*adata
->machines
);
123 mach
= snd_soc_acpi_find_machine(adata
->machines
);
125 dev_err(adata
->dev
, "warning: No matching ASoC machine driver found\n");
128 mach
->mach_params
.subsystem_rev
= adata
->acp_rev
;
129 adata
->mach_dev
= platform_device_register_data(adata
->dev
, mach
->drv_name
,
130 PLATFORM_DEVID_NONE
, mach
, size
);
132 if (IS_ERR(adata
->mach_dev
))
133 dev_warn(adata
->dev
, "Unable to register Machine device\n");
136 EXPORT_SYMBOL_NS_GPL(acp_machine_select
, "SND_SOC_ACP_COMMON");
138 static irqreturn_t
i2s_irq_handler(int irq
, void *data
)
140 struct acp_dev_data
*adata
= data
;
141 struct acp_resource
*rsrc
= adata
->rsrc
;
142 struct acp_stream
*stream
;
144 u32 ext_intr_stat
, ext_intr_stat1
;
146 if (adata
->rsrc
->no_of_ctrls
== 2)
147 ext_intr_stat1
= readl(ACP_EXTERNAL_INTR_STAT(adata
, (rsrc
->irqp_used
- 1)));
149 ext_intr_stat
= readl(ACP_EXTERNAL_INTR_STAT(adata
, rsrc
->irqp_used
));
151 spin_lock(&adata
->acp_lock
);
152 list_for_each_entry(stream
, &adata
->stream_list
, list
) {
153 if (ext_intr_stat
& stream
->irq_bit
) {
154 writel(stream
->irq_bit
,
155 ACP_EXTERNAL_INTR_STAT(adata
, rsrc
->irqp_used
));
156 snd_pcm_period_elapsed(stream
->substream
);
159 if (adata
->rsrc
->no_of_ctrls
== 2) {
160 if (ext_intr_stat1
& stream
->irq_bit
) {
161 writel(stream
->irq_bit
, ACP_EXTERNAL_INTR_STAT(adata
,
162 (rsrc
->irqp_used
- 1)));
163 snd_pcm_period_elapsed(stream
->substream
);
168 spin_unlock(&adata
->acp_lock
);
175 void config_pte_for_stream(struct acp_dev_data
*adata
, struct acp_stream
*stream
)
177 struct acp_resource
*rsrc
= adata
->rsrc
;
180 reg_val
= rsrc
->sram_pte_offset
;
181 stream
->reg_offset
= 0x02000000;
183 writel((reg_val
+ GRP1_OFFSET
) | BIT(31), adata
->acp_base
+ ACPAXI2AXI_ATU_BASE_ADDR_GRP_1
);
184 writel(PAGE_SIZE_4K_ENABLE
, adata
->acp_base
+ ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1
);
186 writel((reg_val
+ GRP2_OFFSET
) | BIT(31), adata
->acp_base
+ ACPAXI2AXI_ATU_BASE_ADDR_GRP_2
);
187 writel(PAGE_SIZE_4K_ENABLE
, adata
->acp_base
+ ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2
);
189 writel(reg_val
| BIT(31), adata
->acp_base
+ ACPAXI2AXI_ATU_BASE_ADDR_GRP_5
);
190 writel(PAGE_SIZE_4K_ENABLE
, adata
->acp_base
+ ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5
);
192 writel(0x01, adata
->acp_base
+ ACPAXI2AXI_ATU_CTRL
);
194 EXPORT_SYMBOL_NS_GPL(config_pte_for_stream
, "SND_SOC_ACP_COMMON");
196 void config_acp_dma(struct acp_dev_data
*adata
, struct acp_stream
*stream
, int size
)
198 struct snd_pcm_substream
*substream
= stream
->substream
;
199 struct acp_resource
*rsrc
= adata
->rsrc
;
200 dma_addr_t addr
= substream
->dma_buffer
.addr
;
201 int num_pages
= (PAGE_ALIGN(size
) >> PAGE_SHIFT
);
205 switch (adata
->acp_rev
) {
208 switch (stream
->dai_id
) {
209 case I2S_SP_INSTANCE
:
210 if (stream
->dir
== SNDRV_PCM_STREAM_PLAYBACK
)
215 case I2S_BT_INSTANCE
:
216 if (stream
->dir
== SNDRV_PCM_STREAM_PLAYBACK
)
221 case I2S_HS_INSTANCE
:
222 if (stream
->dir
== SNDRV_PCM_STREAM_PLAYBACK
)
231 dev_err(adata
->dev
, "Invalid dai id %x\n", stream
->dai_id
);
236 val
= stream
->pte_offset
;
240 for (page_idx
= 0; page_idx
< num_pages
; page_idx
++) {
241 /* Load the low address of page int ACP SRAM through SRBM */
242 low
= lower_32_bits(addr
);
243 high
= upper_32_bits(addr
);
244 writel(low
, adata
->acp_base
+ rsrc
->scratch_reg_offset
+ val
);
246 writel(high
, adata
->acp_base
+ rsrc
->scratch_reg_offset
+ val
+ 4);
248 /* Move to next physically contiguous page */
253 EXPORT_SYMBOL_NS_GPL(config_acp_dma
, "SND_SOC_ACP_COMMON");
255 static int acp_dma_open(struct snd_soc_component
*component
, struct snd_pcm_substream
*substream
)
257 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
258 struct device
*dev
= component
->dev
;
259 struct acp_dev_data
*adata
= dev_get_drvdata(dev
);
260 struct acp_chip_info
*chip
;
261 struct acp_stream
*stream
;
264 stream
= kzalloc(sizeof(*stream
), GFP_KERNEL
);
268 stream
->substream
= substream
;
269 chip
= dev_get_platdata(dev
);
270 switch (chip
->acp_rev
) {
274 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
275 runtime
->hw
= acp6x_pcm_hardware_playback
;
277 runtime
->hw
= acp6x_pcm_hardware_capture
;
280 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
281 runtime
->hw
= acp_pcm_hardware_playback
;
283 runtime
->hw
= acp_pcm_hardware_capture
;
287 ret
= snd_pcm_hw_constraint_step(runtime
, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES
, DMA_SIZE
);
289 dev_err(component
->dev
, "set hw constraint HW_PARAM_PERIOD_BYTES failed\n");
294 ret
= snd_pcm_hw_constraint_step(runtime
, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES
, DMA_SIZE
);
296 dev_err(component
->dev
, "set hw constraint HW_PARAM_BUFFER_BYTES failed\n");
301 ret
= snd_pcm_hw_constraint_integer(runtime
, SNDRV_PCM_HW_PARAM_PERIODS
);
303 dev_err(component
->dev
, "set integer constraint failed\n");
307 runtime
->private_data
= stream
;
309 writel(1, ACP_EXTERNAL_INTR_ENB(adata
));
311 spin_lock_irq(&adata
->acp_lock
);
312 list_add_tail(&stream
->list
, &adata
->stream_list
);
313 spin_unlock_irq(&adata
->acp_lock
);
318 static int acp_dma_hw_params(struct snd_soc_component
*component
,
319 struct snd_pcm_substream
*substream
,
320 struct snd_pcm_hw_params
*params
)
322 struct acp_dev_data
*adata
= snd_soc_component_get_drvdata(component
);
323 struct acp_stream
*stream
= substream
->runtime
->private_data
;
324 u64 size
= params_buffer_bytes(params
);
326 /* Configure ACP DMA block with params */
327 config_pte_for_stream(adata
, stream
);
328 config_acp_dma(adata
, stream
, size
);
333 static snd_pcm_uframes_t
acp_dma_pointer(struct snd_soc_component
*component
,
334 struct snd_pcm_substream
*substream
)
336 struct device
*dev
= component
->dev
;
337 struct acp_dev_data
*adata
= dev_get_drvdata(dev
);
338 struct acp_stream
*stream
= substream
->runtime
->private_data
;
342 buffersize
= frames_to_bytes(substream
->runtime
,
343 substream
->runtime
->buffer_size
);
345 bytescount
= acp_get_byte_count(adata
, stream
->dai_id
, substream
->stream
);
347 if (bytescount
> stream
->bytescount
)
348 bytescount
-= stream
->bytescount
;
350 pos
= do_div(bytescount
, buffersize
);
352 return bytes_to_frames(substream
->runtime
, pos
);
355 static int acp_dma_new(struct snd_soc_component
*component
,
356 struct snd_soc_pcm_runtime
*rtd
)
358 struct device
*parent
= component
->dev
->parent
;
360 snd_pcm_set_managed_buffer_all(rtd
->pcm
, SNDRV_DMA_TYPE_DEV
,
361 parent
, MIN_BUFFER
, MAX_BUFFER
);
365 static int acp_dma_close(struct snd_soc_component
*component
,
366 struct snd_pcm_substream
*substream
)
368 struct device
*dev
= component
->dev
;
369 struct acp_dev_data
*adata
= dev_get_drvdata(dev
);
370 struct acp_stream
*stream
= substream
->runtime
->private_data
;
372 /* Remove entry from list */
373 spin_lock_irq(&adata
->acp_lock
);
374 list_del(&stream
->list
);
375 spin_unlock_irq(&adata
->acp_lock
);
381 static const struct snd_soc_component_driver acp_pcm_component
= {
383 .open
= acp_dma_open
,
384 .close
= acp_dma_close
,
385 .hw_params
= acp_dma_hw_params
,
386 .pointer
= acp_dma_pointer
,
387 .pcm_construct
= acp_dma_new
,
388 .legacy_dai_naming
= 1,
391 int acp_platform_register(struct device
*dev
)
393 struct acp_dev_data
*adata
= dev_get_drvdata(dev
);
394 struct snd_soc_dai_driver
;
397 status
= devm_request_irq(dev
, adata
->i2s_irq
, i2s_irq_handler
,
398 IRQF_SHARED
, "ACP_I2S_IRQ", adata
);
400 dev_err(dev
, "ACP I2S IRQ request failed\n");
404 status
= devm_snd_soc_register_component(dev
, &acp_pcm_component
,
408 dev_err(dev
, "Fail to register acp i2s component\n");
412 INIT_LIST_HEAD(&adata
->stream_list
);
413 spin_lock_init(&adata
->acp_lock
);
417 EXPORT_SYMBOL_NS_GPL(acp_platform_register
, "SND_SOC_ACP_COMMON");
419 int acp_platform_unregister(struct device
*dev
)
421 struct acp_dev_data
*adata
= dev_get_drvdata(dev
);
424 platform_device_unregister(adata
->mach_dev
);
427 EXPORT_SYMBOL_NS_GPL(acp_platform_unregister
, "SND_SOC_ACP_COMMON");
429 MODULE_DESCRIPTION("AMD ACP PCM Driver");
430 MODULE_LICENSE("Dual BSD/GPL");
431 MODULE_ALIAS(DRV_NAME
);