Skip to content

Commit b243b43

Browse files
ranj063broonie
authored andcommitted
ASoC: SOF: Add dai_link_fixup PCM op for IPC3
Define the dai_link_fixup PCM op for IPC3 and use it Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://lore.kernel.org/r/20220317175044.1752400-17-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent beac3f4 commit b243b43

2 files changed

Lines changed: 189 additions & 171 deletions

File tree

sound/soc/sof/ipc3-pcm.c

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,194 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component,
179179
sizeof(stream), &reply, sizeof(reply));
180180
}
181181

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)
184+
{
185+
struct sof_ipc_dai_config *config;
186+
struct snd_sof_dai *dai;
187+
int i;
188+
189+
/*
190+
* Search for all matching DAIs as we can have both playback and capture DAI
191+
* associated with the same link.
192+
*/
193+
list_for_each_entry(dai, &sdev->dai_list, list) {
194+
if (!dai->name || strcmp(link_name, dai->name))
195+
continue;
196+
for (i = 0; i < dai->number_configs; i++) {
197+
struct sof_dai_private_data *private = dai->private;
198+
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;
203+
break;
204+
}
205+
}
206+
}
207+
}
208+
209+
static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
210+
struct snd_pcm_hw_params *params)
211+
{
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;
220+
221+
if (!dai) {
222+
dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
223+
rtd->dai_link->name);
224+
return -EINVAL;
225+
}
226+
227+
private = dai->private;
228+
if (!private) {
229+
dev_err(component->dev, "%s: No private data found for DAI %s\n", __func__,
230+
rtd->dai_link->name);
231+
return -EINVAL;
232+
}
233+
234+
/* read format from topology */
235+
snd_mask_none(fmt);
236+
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);
240+
break;
241+
case SOF_IPC_FRAME_S24_4LE:
242+
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
243+
break;
244+
case SOF_IPC_FRAME_S32_LE:
245+
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
246+
break;
247+
default:
248+
dev_err(component->dev, "No available DAI format!\n");
249+
return -EINVAL;
250+
}
251+
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);
257+
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;
262+
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);
266+
267+
break;
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);
274+
}
275+
break;
276+
case SOF_DAI_INTEL_HDA:
277+
/*
278+
* HDAudio does not follow the default trigger
279+
* sequence due to firmware implementation
280+
*/
281+
for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
282+
struct snd_soc_pcm_runtime *fe = dpcm->fe;
283+
284+
fe->dai_link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
285+
SND_SOC_DPCM_TRIGGER_POST;
286+
}
287+
break;
288+
case SOF_DAI_INTEL_ALH:
289+
/*
290+
* Dai could run with different channel count compared with
291+
* front end, so get dai channel count from topology
292+
*/
293+
channels->min = private->dai_config->alh.channels;
294+
channels->max = private->dai_config->alh.channels;
295+
break;
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;
301+
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);
305+
break;
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;
311+
312+
dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
313+
dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
314+
channels->min, channels->max);
315+
break;
316+
case SOF_DAI_IMX_SAI:
317+
rate->min = private->dai_config->sai.fsync_rate;
318+
rate->max = private->dai_config->sai.fsync_rate;
319+
channels->min = private->dai_config->sai.tdm_slots;
320+
channels->max = private->dai_config->sai.tdm_slots;
321+
322+
dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
323+
dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
324+
channels->min, channels->max);
325+
break;
326+
case SOF_DAI_AMD_BT:
327+
rate->min = private->dai_config->acpbt.fsync_rate;
328+
rate->max = private->dai_config->acpbt.fsync_rate;
329+
channels->min = private->dai_config->acpbt.tdm_slots;
330+
channels->max = private->dai_config->acpbt.tdm_slots;
331+
332+
dev_dbg(component->dev,
333+
"AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max);
334+
dev_dbg(component->dev, "AMD_BT channels_min: %d channels_max: %d\n",
335+
channels->min, channels->max);
336+
break;
337+
case SOF_DAI_AMD_SP:
338+
rate->min = private->dai_config->acpsp.fsync_rate;
339+
rate->max = private->dai_config->acpsp.fsync_rate;
340+
channels->min = private->dai_config->acpsp.tdm_slots;
341+
channels->max = private->dai_config->acpsp.tdm_slots;
342+
343+
dev_dbg(component->dev,
344+
"AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max);
345+
dev_dbg(component->dev, "AMD_SP channels_min: %d channels_max: %d\n",
346+
channels->min, channels->max);
347+
break;
348+
case SOF_DAI_AMD_DMIC:
349+
rate->min = private->dai_config->acpdmic.fsync_rate;
350+
rate->max = private->dai_config->acpdmic.fsync_rate;
351+
channels->min = private->dai_config->acpdmic.tdm_slots;
352+
channels->max = private->dai_config->acpdmic.tdm_slots;
353+
354+
dev_dbg(component->dev,
355+
"AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
356+
dev_dbg(component->dev, "AMD_DMIC channels_min: %d channels_max: %d\n",
357+
channels->min, channels->max);
358+
break;
359+
default:
360+
dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type);
361+
break;
362+
}
363+
364+
return 0;
365+
}
366+
182367
const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
183368
.hw_params = sof_ipc3_pcm_hw_params,
184369
.hw_free = sof_ipc3_pcm_hw_free,
185370
.trigger = sof_ipc3_pcm_trigger,
371+
.dai_link_fixup = sof_ipc3_pcm_dai_link_fixup,
186372
};

sound/soc/sof/pcm.c

Lines changed: 3 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -556,33 +556,6 @@ static int sof_pcm_new(struct snd_soc_component *component,
556556
return 0;
557557
}
558558

559-
static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
560-
struct snd_pcm_hw_params *params)
561-
{
562-
struct sof_ipc_dai_config *config;
563-
struct snd_sof_dai *dai;
564-
int i;
565-
566-
/*
567-
* Search for all matching DAIs as we can have both playback and capture DAI
568-
* associated with the same link.
569-
*/
570-
list_for_each_entry(dai, &sdev->dai_list, list) {
571-
if (!dai->name || strcmp(link_name, dai->name))
572-
continue;
573-
for (i = 0; i < dai->number_configs; i++) {
574-
struct sof_dai_private_data *private = dai->private;
575-
576-
config = &private->dai_config[i];
577-
if (config->ssp.fsync_rate == params_rate(params)) {
578-
dev_dbg(sdev->dev, "DAI config %d matches pcm hw params\n", i);
579-
dai->current_config = i;
580-
break;
581-
}
582-
}
583-
}
584-
}
585-
586559
/* fixup the BE DAI link to match any values from topology */
587560
int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)
588561
{
@@ -596,8 +569,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa
596569
struct snd_sof_dai *dai =
597570
snd_sof_find_dai(component, (char *)rtd->dai_link->name);
598571
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
599-
struct sof_dai_private_data *private = dai->private;
600-
struct snd_soc_dpcm *dpcm;
572+
const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
601573

602574
/* no topology exists for this BE, try a common configuration */
603575
if (!dai) {
@@ -618,148 +590,8 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa
618590
return 0;
619591
}
620592

621-
/* read format from topology */
622-
snd_mask_none(fmt);
623-
624-
switch (private->comp_dai->config.frame_fmt) {
625-
case SOF_IPC_FRAME_S16_LE:
626-
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
627-
break;
628-
case SOF_IPC_FRAME_S24_4LE:
629-
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
630-
break;
631-
case SOF_IPC_FRAME_S32_LE:
632-
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
633-
break;
634-
default:
635-
dev_err(component->dev, "error: No available DAI format!\n");
636-
return -EINVAL;
637-
}
638-
639-
/* read rate and channels from topology */
640-
switch (private->dai_config->type) {
641-
case SOF_DAI_INTEL_SSP:
642-
/* search for config to pcm params match, if not found use default */
643-
ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
644-
645-
rate->min = private->dai_config[dai->current_config].ssp.fsync_rate;
646-
rate->max = private->dai_config[dai->current_config].ssp.fsync_rate;
647-
channels->min = private->dai_config[dai->current_config].ssp.tdm_slots;
648-
channels->max = private->dai_config[dai->current_config].ssp.tdm_slots;
649-
650-
dev_dbg(component->dev,
651-
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
652-
dev_dbg(component->dev,
653-
"channels_min: %d channels_max: %d\n",
654-
channels->min, channels->max);
655-
656-
break;
657-
case SOF_DAI_INTEL_DMIC:
658-
/* DMIC only supports 16 or 32 bit formats */
659-
if (private->comp_dai->config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
660-
dev_err(component->dev,
661-
"error: invalid fmt %d for DAI type %d\n",
662-
private->comp_dai->config.frame_fmt,
663-
private->dai_config->type);
664-
}
665-
break;
666-
case SOF_DAI_INTEL_HDA:
667-
/*
668-
* HDAudio does not follow the default trigger
669-
* sequence due to firmware implementation
670-
*/
671-
for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
672-
struct snd_soc_pcm_runtime *fe = dpcm->fe;
673-
674-
fe->dai_link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
675-
SND_SOC_DPCM_TRIGGER_POST;
676-
}
677-
break;
678-
case SOF_DAI_INTEL_ALH:
679-
/*
680-
* Dai could run with different channel count compared with
681-
* front end, so get dai channel count from topology
682-
*/
683-
channels->min = private->dai_config->alh.channels;
684-
channels->max = private->dai_config->alh.channels;
685-
break;
686-
case SOF_DAI_IMX_ESAI:
687-
rate->min = private->dai_config->esai.fsync_rate;
688-
rate->max = private->dai_config->esai.fsync_rate;
689-
channels->min = private->dai_config->esai.tdm_slots;
690-
channels->max = private->dai_config->esai.tdm_slots;
691-
692-
dev_dbg(component->dev,
693-
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
694-
dev_dbg(component->dev,
695-
"channels_min: %d channels_max: %d\n",
696-
channels->min, channels->max);
697-
break;
698-
case SOF_DAI_MEDIATEK_AFE:
699-
rate->min = private->dai_config->afe.rate;
700-
rate->max = private->dai_config->afe.rate;
701-
channels->min = private->dai_config->afe.channels;
702-
channels->max = private->dai_config->afe.channels;
703-
704-
dev_dbg(component->dev,
705-
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
706-
dev_dbg(component->dev,
707-
"channels_min: %d channels_max: %d\n",
708-
channels->min, channels->max);
709-
break;
710-
case SOF_DAI_IMX_SAI:
711-
rate->min = private->dai_config->sai.fsync_rate;
712-
rate->max = private->dai_config->sai.fsync_rate;
713-
channels->min = private->dai_config->sai.tdm_slots;
714-
channels->max = private->dai_config->sai.tdm_slots;
715-
716-
dev_dbg(component->dev,
717-
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
718-
dev_dbg(component->dev,
719-
"channels_min: %d channels_max: %d\n",
720-
channels->min, channels->max);
721-
break;
722-
case SOF_DAI_AMD_BT:
723-
rate->min = private->dai_config->acpbt.fsync_rate;
724-
rate->max = private->dai_config->acpbt.fsync_rate;
725-
channels->min = private->dai_config->acpbt.tdm_slots;
726-
channels->max = private->dai_config->acpbt.tdm_slots;
727-
728-
dev_dbg(component->dev,
729-
"AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max);
730-
dev_dbg(component->dev,
731-
"AMD_BT channels_min: %d channels_max: %d\n",
732-
channels->min, channels->max);
733-
break;
734-
case SOF_DAI_AMD_SP:
735-
rate->min = private->dai_config->acpsp.fsync_rate;
736-
rate->max = private->dai_config->acpsp.fsync_rate;
737-
channels->min = private->dai_config->acpsp.tdm_slots;
738-
channels->max = private->dai_config->acpsp.tdm_slots;
739-
740-
dev_dbg(component->dev,
741-
"AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max);
742-
dev_dbg(component->dev,
743-
"AMD_SP channels_min: %d channels_max: %d\n",
744-
channels->min, channels->max);
745-
break;
746-
case SOF_DAI_AMD_DMIC:
747-
rate->min = private->dai_config->acpdmic.fsync_rate;
748-
rate->max = private->dai_config->acpdmic.fsync_rate;
749-
channels->min = private->dai_config->acpdmic.tdm_slots;
750-
channels->max = private->dai_config->acpdmic.tdm_slots;
751-
752-
dev_dbg(component->dev,
753-
"AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
754-
dev_dbg(component->dev,
755-
"AMD_DMIC channels_min: %d channels_max: %d\n",
756-
channels->min, channels->max);
757-
break;
758-
default:
759-
dev_err(component->dev, "error: invalid DAI type %d\n",
760-
private->dai_config->type);
761-
break;
762-
}
593+
if (pcm_ops->dai_link_fixup)
594+
return pcm_ops->dai_link_fixup(rtd, params);
763595

764596
return 0;
765597
}

0 commit comments

Comments
 (0)