spcm->stream[dir].list = list;
- ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
+ ret = sof_widget_list_prepare(sdev, spcm, params, platform_params, dir);
if (ret < 0) {
- spcm_err(spcm, dir, "Widget list set up failed\n");
+ spcm_err(spcm, dir, "widget list prepare failed\n");
spcm->stream[dir].list = NULL;
snd_soc_dapm_dai_free_widgets(&list);
return ret;
return 0;
}
+static struct snd_sof_widget *snd_sof_find_swidget_by_comp_id(struct snd_sof_dev *sdev,
+ int comp_id)
+{
+ struct snd_sof_widget *swidget;
+
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ if (comp_id == swidget->comp_id)
+ return swidget;
+ }
+
+ return NULL;
+}
+
static int sof_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
- struct snd_sof_platform_stream_params platform_params = { 0 };
+ struct snd_sof_platform_stream_params *platform_params;
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_sof_widget *host_widget;
struct snd_sof_pcm *spcm;
int ret;
spcm->prepared[substream->stream] = false;
}
- ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params);
+ platform_params = &spcm->platform_params[substream->stream];
+ ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, platform_params);
if (ret < 0) {
spcm_err(spcm, substream->stream, "platform hw params failed\n");
return ret;
/* 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, params, &platform_params,
+ ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, params, platform_params,
substream->stream);
if (ret < 0)
return ret;
}
+ if (!sdev->dspless_mode_selected) {
+ int host_comp_id = spcm->stream[substream->stream].comp_id;
+
+ host_widget = snd_sof_find_swidget_by_comp_id(sdev, host_comp_id);
+ if (!host_widget) {
+ spcm_err(spcm, substream->stream,
+ "failed to find host widget with comp_id %d\n", host_comp_id);
+ return -EINVAL;
+ }
+
+ /* set the host DMA ID */
+ if (tplg_ops && tplg_ops->host_config)
+ tplg_ops->host_config(sdev, host_widget, platform_params);
+ }
+
/* create compressed page table for audio firmware */
if (runtime->buffer_changed) {
struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
return ret;
}
- if (pcm_ops && pcm_ops->hw_params) {
- ret = pcm_ops->hw_params(component, substream, params, &platform_params);
- if (ret < 0)
- return ret;
- }
-
- spcm->prepared[substream->stream] = true;
-
/* save pcm hw_params */
memcpy(&spcm->params[substream->stream], params, sizeof(*params));
ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true);
+ /* unprepare and free the list of DAPM widgets */
+ sof_widget_list_unprepare(sdev, spcm, substream->stream);
+
cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
return ret;
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
+ struct snd_sof_platform_stream_params *platform_params;
+ struct snd_soc_dapm_widget_list *list;
+ struct snd_pcm_hw_params *params;
struct snd_sof_pcm *spcm;
+ int dir = substream->stream;
int ret;
/* nothing to do for BE */
return ret;
}
- /* set hw_params */
- ret = sof_pcm_hw_params(component,
- substream, &spcm->params[substream->stream]);
+ ret = sof_pcm_hw_params(component, substream, &spcm->params[substream->stream]);
if (ret < 0) {
spcm_err(spcm, substream->stream,
"failed to set hw_params after resume\n");
return ret;
}
+ list = spcm->stream[dir].list;
+ params = &spcm->params[substream->stream];
+ platform_params = &spcm->platform_params[substream->stream];
+ ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
+ if (ret < 0) {
+ dev_err(sdev->dev, "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;
+ }
+
+ if (pcm_ops && pcm_ops->hw_params) {
+ ret = pcm_ops->hw_params(component, substream, params, platform_params);
+ if (ret < 0)
+ return ret;
+ }
+
+ spcm->prepared[substream->stream] = true;
+
return 0;
}
return 0;
}
+int sof_widget_list_prepare(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
+ struct snd_pcm_hw_params *fe_params,
+ struct snd_sof_platform_stream_params *platform_params,
+ int dir)
+{
+ /*
+ * Prepare widgets for set up. The prepare step is used to allocate memory, assign
+ * instance ID and pick the widget configuration based on the runtime PCM params.
+ */
+ return sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
+ dir, SOF_WIDGET_PREPARE);
+}
+
+void sof_widget_list_unprepare(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
+{
+ struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
+
+ /* unprepare the widget */
+ sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
+
+ snd_soc_dapm_dai_free_widgets(&list);
+ spcm->stream[dir].list = NULL;
+}
+
int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
struct snd_pcm_hw_params *fe_params,
struct snd_sof_platform_stream_params *platform_params,
struct snd_soc_dapm_widget *widget;
int i, ret;
- /* nothing to set up */
- if (!list)
+ /* nothing to set up or setup has been already done */
+ if (!list || spcm->setup_done[dir])
return 0;
- /*
- * Prepare widgets for set up. The prepare step is used to allocate memory, assign
- * instance ID and pick the widget configuration based on the runtime PCM params.
- */
- ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
- dir, SOF_WIDGET_PREPARE);
- if (ret < 0)
- return ret;
-
/* Set up is used to send the IPC to the DSP to create the widget */
ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
dir, SOF_WIDGET_SETUP);
}
}
+ spcm->setup_done[dir] = true;
+
return 0;
widget_free:
int ret;
/* nothing to free */
- if (!list)
+ if (!list || !spcm->setup_done[dir])
return 0;
/* send IPC to free widget in the DSP */
ret = sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_FREE);
- /* unprepare the widget */
- sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
-
- snd_soc_dapm_dai_free_widgets(&list);
- spcm->stream[dir].list = NULL;
-
+ spcm->setup_done[dir] = false;
pipeline_list->count = 0;
return ret;
struct snd_sof_pcm_stream stream[2];
struct list_head list; /* list in sdev pcm list */
struct snd_pcm_hw_params params[2];
+ struct snd_sof_platform_stream_params platform_params[2];
bool prepared[2]; /* PCM_PARAMS set successfully */
+ bool setup_done[2]; /* the setup of the SOF PCM device is done */
bool pending_stop[2]; /* only used if (!pcm_ops->platform_stop_during_hw_free) */
/* Must be last - ends in a flex-array member. */
struct snd_pcm_hw_params *fe_params,
struct snd_sof_platform_stream_params *platform_params,
int dir);
+int sof_widget_list_prepare(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
+ struct snd_pcm_hw_params *fe_params,
+ struct snd_sof_platform_stream_params *platform_params,
+ int dir);
+void sof_widget_list_unprepare(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);
int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev,
struct snd_sof_pcm *spcm);