Commit 5fcdbb2d authored by Ranjani Sridharan's avatar Ranjani Sridharan Committed by Mark Brown

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: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: default avatarDaniel Baluta <daniel.baluta@nxp.com>
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20210927120517.20505-12-peter.ujfalusi@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 0acb48dd
......@@ -41,17 +41,6 @@
#define EXCEPT_MAX_HDR_SIZE 0x400
#define HDA_EXT_ROM_STATUS_SIZE 8
static const struct sof_intel_dsp_desc
*get_chip_info(struct snd_sof_pdata *pdata)
{
const struct sof_dev_desc *desc = pdata->desc;
const struct sof_intel_dsp_desc *chip_info;
chip_info = desc->chip_info;
return chip_info;
}
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w)
{
struct snd_sof_widget *swidget = w->dobj.private;
......@@ -132,6 +121,17 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w)
return sof_widget_free(sdev, swidget);
}
static const struct sof_intel_dsp_desc
*get_chip_info(struct snd_sof_pdata *pdata)
{
const struct sof_dev_desc *desc = pdata->desc;
const struct sof_intel_dsp_desc *chip_info;
chip_info = desc->chip_info;
return chip_info;
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
/*
......
......@@ -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;
}
......
This diff is collapsed.
......@@ -28,6 +28,8 @@
#define DMA_CHAN_INVALID 0xFFFFFFFF
#define WIDGET_IS_DAI(id) ((id) == snd_soc_dapm_dai_in || (id) == snd_soc_dapm_dai_out)
/* PCM stream, mapped to FW component */
struct snd_sof_pcm_stream {
u32 comp_id;
......@@ -35,6 +37,7 @@ struct snd_sof_pcm_stream {
struct sof_ipc_stream_posn posn;
struct snd_pcm_substream *substream;
struct work_struct period_elapsed_work;
struct snd_soc_dapm_widget_list *list; /* list of connected DAPM widgets */
bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */
/*
* flag to indicate that the DSP pipelines should be kept
......@@ -256,4 +259,7 @@ void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata);
int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
/* PCM */
int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir);
int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment