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 Intel Corporation
10 #include <sound/pcm_params.h>
11 #include "ipc3-priv.h"
14 #include "sof-audio.h"
16 static int sof_ipc3_pcm_hw_free(struct snd_soc_component
*component
,
17 struct snd_pcm_substream
*substream
)
19 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(component
);
20 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
21 struct sof_ipc_stream stream
;
22 struct snd_sof_pcm
*spcm
;
24 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
28 if (!spcm
->prepared
[substream
->stream
])
31 stream
.hdr
.size
= sizeof(stream
);
32 stream
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| SOF_IPC_STREAM_PCM_FREE
;
33 stream
.comp_id
= spcm
->stream
[substream
->stream
].comp_id
;
35 /* send IPC to the DSP */
36 return sof_ipc_tx_message_no_reply(sdev
->ipc
, &stream
, sizeof(stream
));
39 static int sof_ipc3_pcm_hw_params(struct snd_soc_component
*component
,
40 struct snd_pcm_substream
*substream
,
41 struct snd_pcm_hw_params
*params
,
42 struct snd_sof_platform_stream_params
*platform_params
)
44 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(component
);
45 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
46 struct sof_ipc_fw_version
*v
= &sdev
->fw_ready
.version
;
47 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
48 struct sof_ipc_pcm_params_reply ipc_params_reply
;
49 struct sof_ipc_pcm_params pcm
;
50 struct snd_sof_pcm
*spcm
;
53 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
57 memset(&pcm
, 0, sizeof(pcm
));
59 /* number of pages should be rounded up */
60 pcm
.params
.buffer
.pages
= PFN_UP(runtime
->dma_bytes
);
62 /* set IPC PCM parameters */
63 pcm
.hdr
.size
= sizeof(pcm
);
64 pcm
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| SOF_IPC_STREAM_PCM_PARAMS
;
65 pcm
.comp_id
= spcm
->stream
[substream
->stream
].comp_id
;
66 pcm
.params
.hdr
.size
= sizeof(pcm
.params
);
67 pcm
.params
.buffer
.phy_addr
= spcm
->stream
[substream
->stream
].page_table
.addr
;
68 pcm
.params
.buffer
.size
= runtime
->dma_bytes
;
69 pcm
.params
.direction
= substream
->stream
;
70 pcm
.params
.sample_valid_bytes
= params_width(params
) >> 3;
71 pcm
.params
.buffer_fmt
= SOF_IPC_BUFFER_INTERLEAVED
;
72 pcm
.params
.rate
= params_rate(params
);
73 pcm
.params
.channels
= params_channels(params
);
74 pcm
.params
.host_period_bytes
= params_period_bytes(params
);
77 ret
= snd_pcm_format_physical_width(params_format(params
));
80 pcm
.params
.sample_container_bytes
= ret
>> 3;
83 switch (params_format(params
)) {
84 case SNDRV_PCM_FORMAT_S16
:
85 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S16_LE
;
87 case SNDRV_PCM_FORMAT_S24
:
88 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S24_4LE
;
90 case SNDRV_PCM_FORMAT_S32
:
91 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S32_LE
;
93 case SNDRV_PCM_FORMAT_FLOAT
:
94 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_FLOAT
;
100 /* Update the IPC message with information from the platform */
101 pcm
.params
.stream_tag
= platform_params
->stream_tag
;
103 if (platform_params
->use_phy_address
)
104 pcm
.params
.buffer
.phy_addr
= platform_params
->phy_addr
;
106 if (platform_params
->no_ipc_position
) {
107 /* For older ABIs set host_period_bytes to zero to inform
108 * FW we don't want position updates. Newer versions use
109 * no_stream_position for this purpose.
111 if (v
->abi_version
< SOF_ABI_VER(3, 10, 0))
112 pcm
.params
.host_period_bytes
= 0;
114 pcm
.params
.no_stream_position
= 1;
117 if (platform_params
->cont_update_posn
)
118 pcm
.params
.cont_update_posn
= 1;
120 dev_dbg(component
->dev
, "stream_tag %d", pcm
.params
.stream_tag
);
122 /* send hw_params IPC to the DSP */
123 ret
= sof_ipc_tx_message(sdev
->ipc
, &pcm
, sizeof(pcm
),
124 &ipc_params_reply
, sizeof(ipc_params_reply
));
126 dev_err(component
->dev
, "HW params ipc failed for stream %d\n",
127 pcm
.params
.stream_tag
);
131 ret
= snd_sof_set_stream_data_offset(sdev
, &spcm
->stream
[substream
->stream
],
132 ipc_params_reply
.posn_offset
);
134 dev_err(component
->dev
, "%s: invalid stream data offset for PCM %d\n",
135 __func__
, spcm
->pcm
.pcm_id
);
142 static int sof_ipc3_pcm_trigger(struct snd_soc_component
*component
,
143 struct snd_pcm_substream
*substream
, int cmd
)
145 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
146 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(component
);
147 struct sof_ipc_stream stream
;
148 struct snd_sof_pcm
*spcm
;
150 spcm
= snd_sof_find_spcm_dai(component
, rtd
);
154 stream
.hdr
.size
= sizeof(stream
);
155 stream
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
;
156 stream
.comp_id
= spcm
->stream
[substream
->stream
].comp_id
;
159 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
160 stream
.hdr
.cmd
|= SOF_IPC_STREAM_TRIG_PAUSE
;
162 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
163 stream
.hdr
.cmd
|= SOF_IPC_STREAM_TRIG_RELEASE
;
165 case SNDRV_PCM_TRIGGER_START
:
166 stream
.hdr
.cmd
|= SOF_IPC_STREAM_TRIG_START
;
168 case SNDRV_PCM_TRIGGER_SUSPEND
:
170 case SNDRV_PCM_TRIGGER_STOP
:
171 stream
.hdr
.cmd
|= SOF_IPC_STREAM_TRIG_STOP
;
174 dev_err(component
->dev
, "Unhandled trigger cmd %d\n", cmd
);
178 /* send IPC to the DSP */
179 return sof_ipc_tx_message_no_reply(sdev
->ipc
, &stream
, sizeof(stream
));
182 static void ssp_dai_config_pcm_params_match(struct snd_sof_dev
*sdev
, const char *link_name
,
183 struct snd_pcm_hw_params
*params
)
185 struct sof_ipc_dai_config
*config
;
186 struct snd_sof_dai
*dai
;
190 * Search for all matching DAIs as we can have both playback and capture DAI
191 * associated with the same link.
193 list_for_each_entry(dai
, &sdev
->dai_list
, list
) {
194 if (!dai
->name
|| strcmp(link_name
, dai
->name
))
196 for (i
= 0; i
< dai
->number_configs
; i
++) {
197 struct sof_dai_private_data
*private = dai
->private;
199 config
= &private->dai_config
[i
];
200 if (config
->ssp
.fsync_rate
== params_rate(params
)) {
201 dev_dbg(sdev
->dev
, "DAI config %d matches pcm hw params\n", i
);
202 dai
->current_config
= i
;
209 static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime
*rtd
,
210 struct snd_pcm_hw_params
*params
)
212 struct snd_soc_component
*component
= snd_soc_rtdcom_lookup(rtd
, SOF_AUDIO_PCM_DRV_NAME
);
213 struct snd_interval
*channels
= hw_param_interval(params
, SNDRV_PCM_HW_PARAM_CHANNELS
);
214 struct snd_sof_dai
*dai
= snd_sof_find_dai(component
, (char *)rtd
->dai_link
->name
);
215 struct snd_interval
*rate
= hw_param_interval(params
, SNDRV_PCM_HW_PARAM_RATE
);
216 struct snd_mask
*fmt
= hw_param_mask(params
, SNDRV_PCM_HW_PARAM_FORMAT
);
217 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(component
);
218 struct sof_dai_private_data
*private;
219 struct snd_soc_dpcm
*dpcm
;
222 dev_err(component
->dev
, "%s: No DAI found with name %s\n", __func__
,
223 rtd
->dai_link
->name
);
227 private = dai
->private;
229 dev_err(component
->dev
, "%s: No private data found for DAI %s\n", __func__
,
230 rtd
->dai_link
->name
);
234 /* read format from topology */
237 switch (private->comp_dai
->config
.frame_fmt
) {
238 case SOF_IPC_FRAME_S16_LE
:
239 snd_mask_set_format(fmt
, SNDRV_PCM_FORMAT_S16_LE
);
241 case SOF_IPC_FRAME_S24_4LE
:
242 snd_mask_set_format(fmt
, SNDRV_PCM_FORMAT_S24_LE
);
244 case SOF_IPC_FRAME_S32_LE
:
245 snd_mask_set_format(fmt
, SNDRV_PCM_FORMAT_S32_LE
);
248 dev_err(component
->dev
, "No available DAI format!\n");
252 /* read rate and channels from topology */
253 switch (private->dai_config
->type
) {
254 case SOF_DAI_INTEL_SSP
:
255 /* search for config to pcm params match, if not found use default */
256 ssp_dai_config_pcm_params_match(sdev
, (char *)rtd
->dai_link
->name
, params
);
258 rate
->min
= private->dai_config
[dai
->current_config
].ssp
.fsync_rate
;
259 rate
->max
= private->dai_config
[dai
->current_config
].ssp
.fsync_rate
;
260 channels
->min
= private->dai_config
[dai
->current_config
].ssp
.tdm_slots
;
261 channels
->max
= private->dai_config
[dai
->current_config
].ssp
.tdm_slots
;
263 dev_dbg(component
->dev
, "rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
264 dev_dbg(component
->dev
, "channels_min: %d channels_max: %d\n",
265 channels
->min
, channels
->max
);
268 case SOF_DAI_INTEL_DMIC
:
269 /* DMIC only supports 16 or 32 bit formats */
270 if (private->comp_dai
->config
.frame_fmt
== SOF_IPC_FRAME_S24_4LE
) {
271 dev_err(component
->dev
, "Invalid fmt %d for DAI type %d\n",
272 private->comp_dai
->config
.frame_fmt
,
273 private->dai_config
->type
);
276 case SOF_DAI_INTEL_HDA
:
278 * HDAudio does not follow the default trigger
279 * sequence due to firmware implementation
281 for_each_dpcm_fe(rtd
, SNDRV_PCM_STREAM_PLAYBACK
, dpcm
) {
282 struct snd_soc_pcm_runtime
*fe
= dpcm
->fe
;
284 fe
->dai_link
->trigger
[SNDRV_PCM_STREAM_PLAYBACK
] =
285 SND_SOC_DPCM_TRIGGER_POST
;
288 case SOF_DAI_INTEL_ALH
:
290 * Dai could run with different channel count compared with
291 * front end, so get dai channel count from topology
293 channels
->min
= private->dai_config
->alh
.channels
;
294 channels
->max
= private->dai_config
->alh
.channels
;
296 case SOF_DAI_IMX_ESAI
:
297 rate
->min
= private->dai_config
->esai
.fsync_rate
;
298 rate
->max
= private->dai_config
->esai
.fsync_rate
;
299 channels
->min
= private->dai_config
->esai
.tdm_slots
;
300 channels
->max
= private->dai_config
->esai
.tdm_slots
;
302 dev_dbg(component
->dev
, "rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
303 dev_dbg(component
->dev
, "channels_min: %d channels_max: %d\n",
304 channels
->min
, channels
->max
);
306 case SOF_DAI_MEDIATEK_AFE
:
307 rate
->min
= private->dai_config
->afe
.rate
;
308 rate
->max
= private->dai_config
->afe
.rate
;
309 channels
->min
= private->dai_config
->afe
.channels
;
310 channels
->max
= private->dai_config
->afe
.channels
;
314 switch (private->dai_config
->afe
.format
) {
315 case SOF_IPC_FRAME_S16_LE
:
316 snd_mask_set_format(fmt
, SNDRV_PCM_FORMAT_S16_LE
);
318 case SOF_IPC_FRAME_S24_4LE
:
319 snd_mask_set_format(fmt
, SNDRV_PCM_FORMAT_S24_LE
);
321 case SOF_IPC_FRAME_S32_LE
:
322 snd_mask_set_format(fmt
, SNDRV_PCM_FORMAT_S32_LE
);
325 dev_err(component
->dev
, "Not available format!\n");
329 dev_dbg(component
->dev
, "rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
330 dev_dbg(component
->dev
, "channels_min: %d channels_max: %d\n",
331 channels
->min
, channels
->max
);
333 case SOF_DAI_IMX_SAI
:
334 rate
->min
= private->dai_config
->sai
.fsync_rate
;
335 rate
->max
= private->dai_config
->sai
.fsync_rate
;
336 channels
->min
= private->dai_config
->sai
.tdm_slots
;
337 channels
->max
= private->dai_config
->sai
.tdm_slots
;
339 dev_dbg(component
->dev
, "rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
340 dev_dbg(component
->dev
, "channels_min: %d channels_max: %d\n",
341 channels
->min
, channels
->max
);
344 rate
->min
= private->dai_config
->acpbt
.fsync_rate
;
345 rate
->max
= private->dai_config
->acpbt
.fsync_rate
;
346 channels
->min
= private->dai_config
->acpbt
.tdm_slots
;
347 channels
->max
= private->dai_config
->acpbt
.tdm_slots
;
349 dev_dbg(component
->dev
,
350 "AMD_BT rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
351 dev_dbg(component
->dev
, "AMD_BT channels_min: %d channels_max: %d\n",
352 channels
->min
, channels
->max
);
355 case SOF_DAI_AMD_SP_VIRTUAL
:
356 rate
->min
= private->dai_config
->acpsp
.fsync_rate
;
357 rate
->max
= private->dai_config
->acpsp
.fsync_rate
;
358 channels
->min
= private->dai_config
->acpsp
.tdm_slots
;
359 channels
->max
= private->dai_config
->acpsp
.tdm_slots
;
361 dev_dbg(component
->dev
,
362 "AMD_SP rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
363 dev_dbg(component
->dev
, "AMD_SP channels_min: %d channels_max: %d\n",
364 channels
->min
, channels
->max
);
367 case SOF_DAI_AMD_HS_VIRTUAL
:
368 rate
->min
= private->dai_config
->acphs
.fsync_rate
;
369 rate
->max
= private->dai_config
->acphs
.fsync_rate
;
370 channels
->min
= private->dai_config
->acphs
.tdm_slots
;
371 channels
->max
= private->dai_config
->acphs
.tdm_slots
;
373 dev_dbg(component
->dev
,
374 "AMD_HS channel_max: %d rate_max: %d\n", channels
->max
, rate
->max
);
376 case SOF_DAI_AMD_DMIC
:
377 rate
->min
= private->dai_config
->acpdmic
.pdm_rate
;
378 rate
->max
= private->dai_config
->acpdmic
.pdm_rate
;
379 channels
->min
= private->dai_config
->acpdmic
.pdm_ch
;
380 channels
->max
= private->dai_config
->acpdmic
.pdm_ch
;
382 dev_dbg(component
->dev
,
383 "AMD_DMIC rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
384 dev_dbg(component
->dev
, "AMD_DMIC channels_min: %d channels_max: %d\n",
385 channels
->min
, channels
->max
);
387 case SOF_DAI_IMX_MICFIL
:
388 rate
->min
= private->dai_config
->micfil
.pdm_rate
;
389 rate
->max
= private->dai_config
->micfil
.pdm_rate
;
390 channels
->min
= private->dai_config
->micfil
.pdm_ch
;
391 channels
->max
= private->dai_config
->micfil
.pdm_ch
;
393 dev_dbg(component
->dev
,
394 "MICFIL PDM rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
395 dev_dbg(component
->dev
, "MICFIL PDM channels_min: %d channels_max: %d\n",
396 channels
->min
, channels
->max
);
398 case SOF_DAI_AMD_SDW
:
399 /* change the default trigger sequence as per HW implementation */
400 for_each_dpcm_fe(rtd
, SNDRV_PCM_STREAM_PLAYBACK
, dpcm
) {
401 struct snd_soc_pcm_runtime
*fe
= dpcm
->fe
;
403 fe
->dai_link
->trigger
[SNDRV_PCM_STREAM_PLAYBACK
] =
404 SND_SOC_DPCM_TRIGGER_POST
;
407 for_each_dpcm_fe(rtd
, SNDRV_PCM_STREAM_CAPTURE
, dpcm
) {
408 struct snd_soc_pcm_runtime
*fe
= dpcm
->fe
;
410 fe
->dai_link
->trigger
[SNDRV_PCM_STREAM_CAPTURE
] =
411 SND_SOC_DPCM_TRIGGER_POST
;
413 rate
->min
= private->dai_config
->acp_sdw
.rate
;
414 rate
->max
= private->dai_config
->acp_sdw
.rate
;
415 channels
->min
= private->dai_config
->acp_sdw
.channels
;
416 channels
->max
= private->dai_config
->acp_sdw
.channels
;
418 dev_dbg(component
->dev
,
419 "AMD_SDW rate_min: %d rate_max: %d\n", rate
->min
, rate
->max
);
420 dev_dbg(component
->dev
, "AMD_SDW channels_min: %d channels_max: %d\n",
421 channels
->min
, channels
->max
);
424 dev_err(component
->dev
, "Invalid DAI type %d\n", private->dai_config
->type
);
431 const struct sof_ipc_pcm_ops ipc3_pcm_ops
= {
432 .hw_params
= sof_ipc3_pcm_hw_params
,
433 .hw_free
= sof_ipc3_pcm_hw_free
,
434 .trigger
= sof_ipc3_pcm_trigger
,
435 .dai_link_fixup
= sof_ipc3_pcm_dai_link_fixup
,
436 .reset_hw_params_during_stop
= true,
437 .d0i3_supported_in_s0ix
= true,