diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index cfd735f3035817..e82b8e74a0f2ba 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -416,10 +416,11 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: - /* - * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have - * been stopped. So, clear the started_count so that the pipeline can be reset - */ + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, + SOF_IPC4_PIPE_RESET); + if (ret < 0) + goto out; + pipeline->state = SOF_IPC4_PIPE_RESET; swidget->spipe->started_count = 0; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -638,6 +639,9 @@ static int hda_ipc4_set_up_be_pipeline(struct snd_soc_dapm_widget *w, int dir) struct snd_sof_dev *sdev = widget_to_sdev(w); int ret; + /* set the be_pipeline flag true for the pipeline */ + swidget->spipe->be_pipeline = true; + /* set up the widgets in the BE pipeline */ ret = hda_dai_set_up_widgets_in_pipeline(w, swidget->spipe, dir); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index ee274d445515b4..8f1f4525d6a77a 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -107,6 +107,7 @@ int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_st struct snd_soc_dai *cpu_dai) { const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); struct sof_intel_hda_stream *hda_stream; struct hdac_ext_link *hlink; struct snd_sof_dev *sdev; @@ -137,6 +138,9 @@ int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_st hda_stream = hstream_to_sof_hda_stream(hext_stream); hda_stream->host_reserved = 0; + if (ops->free_be_pipeline) + return ops->free_be_pipeline(w, substream->stream); + return 0; } @@ -322,9 +326,20 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); int stream = substream->stream; + int ret; + + ret = hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai); + if (ret < 0) + return ret; + + if (ops && ops->set_up_be_pipeline) + return ops->set_up_be_pipeline(w, substream->stream); + + return ret; - return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai); } static const struct snd_soc_dai_ops hda_dai_ops = { diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 18fff2df76f97e..b1629addb999d7 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -138,7 +138,7 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state, struct snd_sof_widget *pipe_widget = spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; - if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) + if (pipeline->skip_during_fe_trigger) return; switch (state) { @@ -177,7 +177,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, struct sof_ipc4_pipeline *pipeline = pipe_widget->private; int i; - if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) + if (pipeline->skip_during_fe_trigger) return; /* set state for pipeline if it was just triggered */ diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index bd05fe599a04f9..e19d9dba872ef9 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -293,6 +293,17 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc } EXPORT_SYMBOL(sof_route_setup); +/* helper function to check if the widget belong to the BE pipeline */ +static bool sof_is_be_pipeline_widget(struct snd_soc_dapm_widget *w) +{ + struct snd_sof_widget *swidget = w->dobj.private; + + if (swidget->spipe->be_pipeline) + return true; + + return false; +} + static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_list *list, int dir) { @@ -319,6 +330,12 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, continue; if (p->sink->dobj.private) { + /* + * skip routes between widgets belonging to the BE pipeline + */ + if (sof_is_be_pipeline_widget(widget) && + sof_is_be_pipeline_widget(p->sink)) + continue; ret = sof_route_setup(sdev, widget, p->sink); if (ret < 0) return ret; @@ -335,6 +352,11 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, continue; if (p->source->dobj.private) { + /* + * skip routes between widgets belonging to the BE pipeline + */ + if (sof_is_be_pipeline_widget(widget) && + sof_is_be_pipeline_widget(p->source)) ret = sof_route_setup(sdev, p->source, widget); if (ret < 0) return ret; @@ -415,8 +437,12 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg if (is_virtual_widget(sdev, widget, __func__)) return; - /* skip if the widget is in use or if it is already unprepared */ - if (!swidget || !swidget->prepared || swidget->use_count > 0) + /* + * skip if the widget is in use or if it is already unprepared or + * if it belongs to a BE pipeline. + */ + if (!swidget || !swidget->prepared || swidget->use_count > 0 || + swidget->spipe->be_pipeline) goto sink_unprepare; widget_ops = tplg_ops ? tplg_ops->widget : NULL; @@ -506,6 +532,7 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap int dir, struct snd_sof_pcm *spcm) { struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; + struct snd_sof_widget *swidget = widget->dobj.private; struct snd_soc_dapm_path *p; int err; int ret = 0; @@ -513,7 +540,8 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap if (is_virtual_widget(sdev, widget, __func__)) return 0; - if (widget->dobj.private) { + /* only free widgets that aren't part of the BE pipeline */ + if (swidget && !swidget->spipe->be_pipeline) { err = sof_widget_free(sdev, widget->dobj.private); if (err < 0) ret = err; @@ -555,7 +583,7 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d if (is_virtual_widget(sdev, widget, __func__)) return 0; - if (swidget) { + if (swidget && !swidget->spipe->be_pipeline) { int i; ret = sof_widget_setup(sdev, widget->dobj.private); @@ -594,7 +622,7 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d ret = sof_set_up_widgets_in_path(sdev, p->sink, dir, spcm); p->walking = false; if (ret < 0) { - if (swidget) + if (swidget && !swidget->spipe->be_pipeline) sof_widget_free(sdev, swidget); return ret; } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index c40bb5f85b9d9e..66e08224217fa5 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -499,6 +499,7 @@ struct snd_sof_widget { pipeline * @complete: flag used to indicate that pipeline set up is complete. * @core_mask: Mask containing target cores for all modules in the pipeline + * @be_pipeline: Flag indicating if the pipeline contains a BE DAI widget * @list: List item in sdev pipeline_list */ struct snd_sof_pipeline { @@ -507,6 +508,7 @@ struct snd_sof_pipeline { int paused_count; int complete; unsigned long core_mask; + bool be_pipeline; struct list_head list; }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 688cc7ac17148a..7bcfaa0a139ecc 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2167,6 +2167,10 @@ static int sof_set_widget_pipeline(struct snd_sof_dev *sdev, struct snd_sof_pipe swidget->spipe = spipe; swidget->dynamic_pipeline_widget = pipe_widget->dynamic_pipeline_widget; + /* set the be_pipeline flag true for the pipeline if the widget is a DAI */ + if (WIDGET_IS_DAI(swidget->id)) + spipe->be_pipeline = true; + return 0; }