Skip to content

Commit d56c49b

Browse files
committed
ASoC: SOF: Intel: hda: Unify DAI drv ops for IPC3 and IPC4
Define the post_trigger DMA op for IPC3 and unify the DAI driver ops for IPC3 and IPC4 for HDA DAI's. Also, use the post_trigger op to stop the paused streams properly in the hda_dai_suspend() function. This fixes the suspend while paused case for IPC4 because previously we weren't resetting the pipeline when suspending the system with some paused streams. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
1 parent 1a9dd0f commit d56c49b

File tree

2 files changed

+58
-140
lines changed

2 files changed

+58
-140
lines changed

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

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,33 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
266266
return 0;
267267
}
268268

269+
static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
270+
struct snd_pcm_substream *substream, int cmd)
271+
{
272+
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
273+
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
274+
struct snd_sof_widget *swidget = w->dobj.private;
275+
276+
switch (cmd) {
277+
case SNDRV_PCM_TRIGGER_SUSPEND:
278+
case SNDRV_PCM_TRIGGER_STOP:
279+
{
280+
struct snd_sof_dai_config_data data;
281+
unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_FREE;
282+
283+
flags |= SOF_DAI_CONFIG_FLAGS_NONE << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
284+
data.dai_data = DMA_CHAN_INVALID;
285+
return tplg_ops->dai_config(sdev, swidget, flags, NULL);
286+
}
287+
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
288+
return tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
289+
default:
290+
return 0;
291+
}
292+
293+
return 0;
294+
}
295+
269296
static struct snd_sof_dai_dma_ops hda_dma_ops = {
270297
.stream_get_dma = hda_stream_get_dma,
271298
.stream_put_dma = hda_stream_put_dma,
@@ -353,9 +380,15 @@ void hda_set_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swi
353380
case SOF_IPC:
354381
{
355382
struct sof_dai_private_data *private = sdai->private;
383+
struct snd_sof_dai_dma_ops *dma_ops;
356384

357-
if (private->dai_config->type == SOF_DAI_INTEL_HDA)
385+
if (private->dai_config->type == SOF_DAI_INTEL_HDA) {
358386
sdai->ops = &hda_dai_ops;
387+
dma_ops = sdai->ops->dma_ops;
388+
389+
/* set the post DMA trigger op */
390+
dma_ops->post_trigger = hda_ipc3_post_trigger;
391+
}
359392
break;
360393
}
361394
case SOF_INTEL_IPC4:

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

Lines changed: 24 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -118,45 +118,6 @@ static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_
118118
return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
119119
}
120120

121-
static int hda_link_dma_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai,
122-
int cmd)
123-
{
124-
const struct snd_sof_dai_ops *ops = hda_dai_get_ops(substream, cpu_dai);
125-
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
126-
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
127-
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
128-
struct hdac_ext_stream *hext_stream = NULL;
129-
int ret;
130-
131-
if (ops && ops->dma_ops && ops->dma_ops->stream_get_dma)
132-
hext_stream = ops->dma_ops->stream_get_dma(sdev, cpu_dai, substream);
133-
134-
if (!hext_stream)
135-
return 0;
136-
137-
switch (cmd) {
138-
case SNDRV_PCM_TRIGGER_START:
139-
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
140-
snd_hdac_ext_stream_start(hext_stream);
141-
break;
142-
case SNDRV_PCM_TRIGGER_SUSPEND:
143-
case SNDRV_PCM_TRIGGER_STOP:
144-
snd_hdac_ext_stream_clear(hext_stream);
145-
ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
146-
if (ret < 0)
147-
return ret;
148-
149-
break;
150-
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
151-
snd_hdac_ext_stream_clear(hext_stream);
152-
153-
break;
154-
default:
155-
return -EINVAL;
156-
}
157-
return 0;
158-
}
159-
160121
static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
161122
{
162123
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
@@ -173,20 +134,6 @@ static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_
173134
return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
174135
}
175136

176-
static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
177-
int channel, bool widget_setup)
178-
{
179-
struct snd_sof_dai_config_data data;
180-
181-
data.dai_data = channel;
182-
183-
/* set up/free DAI widget and send DAI_CONFIG IPC */
184-
if (widget_setup)
185-
return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);
186-
187-
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
188-
}
189-
190137
static int hda_dai_hw_params(struct snd_pcm_substream *substream,
191138
struct snd_pcm_hw_params *params,
192139
struct snd_soc_dai *dai)
@@ -224,25 +171,6 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream,
224171
return 0;
225172
}
226173

227-
228-
static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
229-
{
230-
struct snd_sof_widget *swidget = w->dobj.private;
231-
struct snd_soc_component *component = swidget->scomp;
232-
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
233-
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
234-
int ret = 0;
235-
236-
if (tplg_ops->dai_config) {
237-
ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
238-
if (ret < 0)
239-
dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
240-
w->name);
241-
}
242-
243-
return ret;
244-
}
245-
246174
static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
247175
{
248176
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
@@ -280,61 +208,11 @@ static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
280208
return 0;
281209
}
282210

283-
static int hda_dai_hw_free_ipc(int stream, /* direction */
284-
struct snd_soc_dai *dai)
285-
{
286-
struct snd_soc_dapm_widget *w;
287-
288-
w = snd_soc_dai_get_widget(dai, stream);
289-
290-
/* free the link DMA channel in the FW and the DAI widget */
291-
return hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
292-
}
293-
294-
static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
295-
int cmd, struct snd_soc_dai *dai)
296-
{
297-
struct snd_soc_dapm_widget *w;
298-
int ret;
299-
300-
dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
301-
dai->name, substream->stream);
302-
303-
ret = hda_link_dma_trigger(substream, dai, cmd);
304-
if (ret < 0)
305-
return ret;
306-
307-
w = snd_soc_dai_get_widget(dai, substream->stream);
308-
309-
switch (cmd) {
310-
case SNDRV_PCM_TRIGGER_SUSPEND:
311-
case SNDRV_PCM_TRIGGER_STOP:
312-
/*
313-
* free DAI widget during stop/suspend to keep widget use_count's balanced.
314-
*/
315-
ret = hda_dai_hw_free_ipc(substream->stream, dai);
316-
if (ret < 0)
317-
return ret;
318-
319-
break;
320-
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
321-
ret = hda_dai_config_pause_push_ipc(w);
322-
if (ret < 0)
323-
return ret;
324-
break;
325-
326-
default:
327-
break;
328-
}
329-
return 0;
330-
}
331-
332211
/*
333212
* In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
334213
* (over IPC channel) and DMA state change (direct host register changes).
335214
*/
336-
static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
337-
int cmd, struct snd_soc_dai *dai)
215+
static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
338216
{
339217
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
340218
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
@@ -412,10 +290,10 @@ static int hda_dai_hw_free(struct snd_pcm_substream *substream,
412290
return 0;
413291
}
414292

415-
static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
293+
static const struct snd_soc_dai_ops hda_dai_ops = {
416294
.hw_params = hda_dai_hw_params,
417295
.hw_free = hda_dai_hw_free,
418-
.trigger = ipc3_hda_dai_trigger,
296+
.trigger = hda_dai_trigger,
419297
.prepare = hda_dai_prepare,
420298
};
421299

@@ -438,36 +316,43 @@ static int hda_dai_suspend(struct hdac_bus *bus)
438316
* explicitly during suspend.
439317
*/
440318
if (hext_stream->link_substream) {
441-
struct snd_soc_dai *cpu_dai;
319+
const struct snd_sof_dai_ops *ops;
320+
struct snd_sof_widget *swidget;
321+
struct snd_soc_dapm_widget *w;
442322
struct snd_soc_dai *codec_dai;
323+
struct snd_soc_dai *cpu_dai;
324+
struct snd_sof_dev *sdev;
325+
struct snd_sof_dai *sdai;
443326

444327
rtd = asoc_substream_to_rtd(hext_stream->link_substream);
445328
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
446329
codec_dai = asoc_rtd_to_codec(rtd, 0);
330+
w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction);
331+
swidget = w->dobj.private;
332+
sdev = snd_soc_component_get_drvdata(swidget->scomp);
333+
sdai = swidget->private;
334+
ops = sdai->ops;
447335

448336
ret = hda_link_dma_cleanup(hext_stream->link_substream,
449337
hext_stream,
450338
cpu_dai, codec_dai);
451339
if (ret < 0)
452340
return ret;
453341

454-
/* for consistency with TRIGGER_SUSPEND we free DAI resources */
455-
ret = hda_dai_hw_free_ipc(hdac_stream(hext_stream)->direction, cpu_dai);
456-
if (ret < 0)
457-
return ret;
342+
/* for consistency with TRIGGER_SUSPEND */
343+
if (ops && ops->dma_ops && ops->dma_ops->post_trigger) {
344+
ret = ops->dma_ops->post_trigger(sdev, cpu_dai,
345+
hext_stream->link_substream,
346+
SNDRV_PCM_TRIGGER_SUSPEND);
347+
if (ret < 0)
348+
return ret;
349+
}
458350
}
459351
}
460352

461353
return 0;
462354
}
463355

464-
static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
465-
.hw_params = hda_dai_hw_params,
466-
.hw_free = hda_dai_hw_free,
467-
.trigger = ipc4_hda_dai_trigger,
468-
.prepare = hda_dai_prepare,
469-
};
470-
471356
#endif
472357

473358
/* only one flag used so far to harden hw_params/hw_free/trigger/prepare */
@@ -594,7 +479,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
594479
if (strstr(ops->drv[i].name, "iDisp") ||
595480
strstr(ops->drv[i].name, "Analog") ||
596481
strstr(ops->drv[i].name, "Digital"))
597-
ops->drv[i].ops = &ipc3_hda_dai_ops;
482+
ops->drv[i].ops = &hda_dai_ops;
598483
#endif
599484
}
600485
break;
@@ -607,7 +492,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
607492
if (strstr(ops->drv[i].name, "iDisp") ||
608493
strstr(ops->drv[i].name, "Analog") ||
609494
strstr(ops->drv[i].name, "Digital"))
610-
ops->drv[i].ops = &ipc4_hda_dai_ops;
495+
ops->drv[i].ops = &hda_dai_ops;
611496
#endif
612497
}
613498

0 commit comments

Comments
 (0)