Skip to content

Commit 0acb48d

Browse files
ranj063broonie
authored andcommitted
ASoC: SOF: Intel: hda: make sure DAI widget is set up before IPC
With the implementation of the dynamic pipeline feature, widgets will only be setup when a PCM is opened during the hw_params ioctl. The BE hw_params callback is responsible for sending the DAI_CONFIG for the DAI widgets in the DSP. With dynamic pipelines, the DAI widgets will need to set up first before sending the DAI_CONFIG IPC in the BE hw_params. Update the BE hw_params/hw_free callbacks for all ALH, HDA and SSP DAIs to set up/free the DAI widget before/after DAI_CONFIG IPC. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Link: https://lore.kernel.org/r/20210927120517.20505-11-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 8b00141 commit 0acb48d

File tree

6 files changed

+243
-119
lines changed

6 files changed

+243
-119
lines changed

sound/soc/sof/intel/hda-dai.c

Lines changed: 106 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -155,49 +155,68 @@ static int hda_link_dma_params(struct hdac_ext_stream *stream,
155155
return 0;
156156
}
157157

158-
/* Send DAI_CONFIG IPC to the DAI that matches the dai_name and direction */
159-
static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
160-
const char *dai_name, int channel, int dir)
158+
/* Update config for the DAI widget */
159+
static struct sof_ipc_dai_config *hda_dai_update_config(struct snd_soc_dapm_widget *w,
160+
int channel)
161161
{
162+
struct snd_sof_widget *swidget = w->dobj.private;
162163
struct sof_ipc_dai_config *config;
163164
struct snd_sof_dai *sof_dai;
164-
struct sof_ipc_reply reply;
165-
int ret = 0;
166165

167-
list_for_each_entry(sof_dai, &hda_stream->sdev->dai_list, list) {
168-
if (!sof_dai->cpu_dai_name)
169-
continue;
166+
if (!swidget)
167+
return NULL;
170168

171-
if (!strcmp(dai_name, sof_dai->cpu_dai_name) &&
172-
dir == sof_dai->comp_dai.direction) {
173-
config = sof_dai->dai_config;
169+
sof_dai = swidget->private;
174170

175-
if (!config) {
176-
dev_err(hda_stream->sdev->dev,
177-
"error: no config for DAI %s\n",
178-
sof_dai->name);
179-
return -EINVAL;
180-
}
171+
if (!sof_dai || !sof_dai->dai_config) {
172+
dev_err(swidget->scomp->dev, "error: No config for DAI %s\n", w->name);
173+
return NULL;
174+
}
181175

182-
/* update config with stream tag */
183-
config->hda.link_dma_ch = channel;
176+
config = &sof_dai->dai_config[sof_dai->current_config];
184177

185-
/* send IPC */
186-
ret = sof_ipc_tx_message(hda_stream->sdev->ipc,
187-
config->hdr.cmd,
188-
config,
189-
config->hdr.size,
190-
&reply, sizeof(reply));
178+
/* update config with stream tag */
179+
config->hda.link_dma_ch = channel;
191180

192-
if (ret < 0)
193-
dev_err(hda_stream->sdev->dev,
194-
"error: failed to set dai config for %s\n",
195-
sof_dai->name);
196-
return ret;
197-
}
181+
return config;
182+
}
183+
184+
static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
185+
struct snd_soc_dapm_widget *w, int channel)
186+
{
187+
struct snd_sof_dev *sdev = hda_stream->sdev;
188+
struct sof_ipc_dai_config *config;
189+
struct sof_ipc_reply reply;
190+
191+
config = hda_dai_update_config(w, channel);
192+
if (!config) {
193+
dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
194+
return -ENOENT;
195+
}
196+
197+
/* send DAI_CONFIG IPC */
198+
return sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
199+
&reply, sizeof(reply));
200+
}
201+
202+
static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream,
203+
struct snd_soc_dapm_widget *w,
204+
int channel, bool widget_setup)
205+
{
206+
struct snd_sof_dev *sdev = hda_stream->sdev;
207+
struct sof_ipc_dai_config *config;
208+
209+
config = hda_dai_update_config(w, channel);
210+
if (!config) {
211+
dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
212+
return -ENOENT;
198213
}
199214

200-
return -EINVAL;
215+
/* set up/free DAI widget and send DAI_CONFIG IPC */
216+
if (widget_setup)
217+
return hda_ctrl_dai_widget_setup(w);
218+
219+
return hda_ctrl_dai_widget_free(w);
201220
}
202221

203222
static int hda_link_hw_params(struct snd_pcm_substream *substream,
@@ -211,6 +230,7 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
211230
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
212231
struct sof_intel_hda_stream *hda_stream;
213232
struct hda_pipe_params p_params = {0};
233+
struct snd_soc_dapm_widget *w;
214234
struct hdac_ext_link *link;
215235
int stream_tag;
216236
int ret;
@@ -229,9 +249,13 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
229249

230250
hda_stream = hstream_to_sof_hda_stream(link_dev);
231251

232-
/* update the DSP with the new tag */
233-
ret = hda_link_config_ipc(hda_stream, dai->name, stream_tag - 1,
234-
substream->stream);
252+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
253+
w = dai->playback_widget;
254+
else
255+
w = dai->capture_widget;
256+
257+
/* set up the DAI widget and send the DAI_CONFIG with the new tag */
258+
ret = hda_link_dai_widget_update(hda_stream, w, stream_tag - 1, true);
235259
if (ret < 0)
236260
return ret;
237261

@@ -287,6 +311,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
287311
snd_soc_dai_get_dma_data(dai, substream);
288312
struct sof_intel_hda_stream *hda_stream;
289313
struct snd_soc_pcm_runtime *rtd;
314+
struct snd_soc_dapm_widget *w;
290315
struct hdac_ext_link *link;
291316
struct hdac_stream *hstream;
292317
struct hdac_bus *bus;
@@ -321,12 +346,16 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
321346
break;
322347
case SNDRV_PCM_TRIGGER_SUSPEND:
323348
case SNDRV_PCM_TRIGGER_STOP:
349+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
350+
w = dai->playback_widget;
351+
else
352+
w = dai->capture_widget;
353+
324354
/*
325355
* clear link DMA channel. It will be assigned when
326356
* hw_params is set up again after resume.
327357
*/
328-
ret = hda_link_config_ipc(hda_stream, dai->name,
329-
DMA_CHAN_INVALID, substream->stream);
358+
ret = hda_link_config_ipc(hda_stream, w, DMA_CHAN_INVALID);
330359
if (ret < 0)
331360
return ret;
332361

@@ -357,6 +386,7 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream,
357386
struct hdac_stream *hstream;
358387
struct snd_soc_pcm_runtime *rtd;
359388
struct hdac_ext_stream *link_dev;
389+
struct snd_soc_dapm_widget *w;
360390
int ret;
361391

362392
hstream = substream->runtime->private_data;
@@ -372,9 +402,13 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream,
372402

373403
hda_stream = hstream_to_sof_hda_stream(link_dev);
374404

375-
/* free the link DMA channel in the FW */
376-
ret = hda_link_config_ipc(hda_stream, dai->name, DMA_CHAN_INVALID,
377-
substream->stream);
405+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
406+
w = dai->playback_widget;
407+
else
408+
w = dai->capture_widget;
409+
410+
/* free the link DMA channel in the FW and the DAI widget */
411+
ret = hda_link_dai_widget_update(hda_stream, w, DMA_CHAN_INVALID, false);
378412
if (ret < 0)
379413
return ret;
380414

@@ -406,47 +440,51 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = {
406440

407441
#endif
408442

409-
static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
410-
struct snd_pcm_hw_params *params,
411-
struct snd_soc_dai *dai)
443+
static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
444+
bool setup)
412445
{
413-
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
414-
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
415-
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
416-
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
417-
struct sof_ipc_dai_config *config;
418-
struct snd_sof_dai *sof_dai;
419-
struct sof_ipc_reply reply;
420-
int ret;
446+
struct snd_soc_component *component;
447+
struct snd_sof_widget *swidget;
448+
struct snd_soc_dapm_widget *w;
449+
struct sof_ipc_fw_version *v;
450+
struct snd_sof_dev *sdev;
451+
452+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
453+
w = dai->playback_widget;
454+
else
455+
w = dai->capture_widget;
456+
457+
swidget = w->dobj.private;
458+
component = swidget->scomp;
459+
sdev = snd_soc_component_get_drvdata(component);
460+
v = &sdev->fw_ready.version;
421461

422462
/* DAI_CONFIG IPC during hw_params is not supported in older firmware */
423463
if (v->abi_version < SOF_ABI_VER(3, 18, 0))
424464
return 0;
425465

426-
list_for_each_entry(sof_dai, &sdev->dai_list, list) {
427-
if (!sof_dai->cpu_dai_name || !sof_dai->dai_config)
428-
continue;
429-
430-
if (!strcmp(dai->name, sof_dai->cpu_dai_name) &&
431-
substream->stream == sof_dai->comp_dai.direction) {
432-
config = &sof_dai->dai_config[sof_dai->current_config];
466+
if (setup)
467+
return hda_ctrl_dai_widget_setup(w);
433468

434-
/* send IPC */
435-
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config,
436-
config->hdr.size, &reply, sizeof(reply));
469+
return hda_ctrl_dai_widget_free(w);
470+
}
437471

438-
if (ret < 0)
439-
dev_err(sdev->dev, "error: failed to set DAI config for %s\n",
440-
sof_dai->name);
441-
return ret;
442-
}
443-
}
472+
static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
473+
struct snd_pcm_hw_params *params,
474+
struct snd_soc_dai *dai)
475+
{
476+
return ssp_dai_setup_or_free(substream, dai, true);
477+
}
444478

445-
return 0;
479+
static int ssp_dai_hw_free(struct snd_pcm_substream *substream,
480+
struct snd_soc_dai *dai)
481+
{
482+
return ssp_dai_setup_or_free(substream, dai, false);
446483
}
447484

448485
static const struct snd_soc_dai_ops ssp_dai_ops = {
449486
.hw_params = ssp_dai_hw_params,
487+
.hw_free = ssp_dai_hw_free,
450488
};
451489

452490
/*

0 commit comments

Comments
 (0)