summaryrefslogtreecommitdiff
path: root/sound/soc/sof/pcm.c
diff options
context:
space:
mode:
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>2021-09-27 15:05:16 +0300
committerMark Brown <broonie@kernel.org>2021-10-01 22:48:30 +0300
commit5fcdbb2d45df6afb654674379546996b0027aa3e (patch)
tree1120a17a735100b12f071208f29c8cacf1b2abe5 /sound/soc/sof/pcm.c
parent0acb48dd31e39b617bb12ca546b4fecd6ccb2972 (diff)
downloadlinux-5fcdbb2d45df6afb654674379546996b0027aa3e.tar.xz
ASoC: SOF: Add support for dynamic pipelines
Add support for dynamic pipelines by modifying the PCM hw_params ioctl implementation to determine the widgets required for a PCM stream by querying the list of connected DAPM widgets. This list is saved as part of snd_sof_pcm_stream struct and will be used to setup the widgets. The sof_widget_list_setup/free routines setup and free connected DAPM widgets when a PCM is opened/closed. These routines accept a list of connected DAPM widgets as input and determine the SOF widgets, their corresponding pipeline widgets and connections between them that need to be setup before the PCM is triggered. Please note that the dynamic pipeline feature will only be enabled for those pipelines whose dynamic_pipeline_widget flag is set in topologies. Add a new token called SOF_TKN_SCHED_DYNAMIC_PIPELINE that when set in topology will be applied to the dynamic_pipeline_widget flag of the pipeline widget. 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-12-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/pcm.c')
-rw-r--r--sound/soc/sof/pcm.c58
1 files changed, 56 insertions, 2 deletions
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index b4280459e5db..374df2dfa816 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -116,6 +116,40 @@ static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream,
return ret;
}
+static int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev,
+ struct snd_soc_pcm_runtime *rtd,
+ struct snd_sof_pcm *spcm, int dir)
+{
+ struct snd_soc_dai *dai;
+ int ret, j;
+
+ /* query DAPM for list of connected widgets and set them up */
+ for_each_rtd_cpu_dais(rtd, j, dai) {
+ struct snd_soc_dapm_widget_list *list;
+
+ ret = snd_soc_dapm_dai_get_connected_widgets(dai, dir, &list,
+ dpcm_end_walk_at_be);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: dai %s has no valid %s path\n", dai->name,
+ dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture");
+ return ret;
+ }
+
+ spcm->stream[dir].list = list;
+
+ ret = sof_widget_list_setup(sdev, spcm, dir);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n",
+ spcm->pcm.pcm_id, dir);
+ spcm->stream[dir].list = NULL;
+ snd_soc_dapm_dai_free_widgets(&list);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int sof_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
@@ -213,7 +247,14 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
- /* send IPC to the DSP */
+ /* if this is a repeated hw_params without hw_free, skip setting up widgets */
+ if (!spcm->stream[substream->stream].list) {
+ ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, substream->stream);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* send hw_params IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) {
@@ -259,6 +300,10 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
err = ret;
}
+ ret = sof_widget_list_free(sdev, spcm, substream->stream);
+ if (ret < 0)
+ err = ret;
+
cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
ret = snd_sof_pcm_platform_hw_free(sdev, substream);
@@ -316,6 +361,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
struct sof_ipc_stream stream;
struct sof_ipc_reply reply;
bool reset_hw_params = false;
+ bool free_widget_list = false;
bool ipc_first = false;
int ret;
@@ -386,6 +432,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
spcm->stream[substream->stream].suspend_ignored = true;
return 0;
}
+ free_widget_list = true;
fallthrough;
case SNDRV_PCM_TRIGGER_STOP:
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
@@ -414,8 +461,15 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
/* free PCM if reset_hw_params is set and the STOP IPC is successful */
- if (!ret && reset_hw_params)
+ if (!ret && reset_hw_params) {
ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
+ if (ret < 0)
+ return ret;
+
+ /* free widget list only for SUSPEND trigger */
+ if (free_widget_list)
+ ret = sof_widget_list_free(sdev, spcm, substream->stream);
+ }
return ret;
}