ASoC: SOF: Make sof_widget_setup/free IPC agnostic
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Thu, 17 Mar 2022 17:50:27 +0000 (10:50 -0700)
committerMark Brown <broonie@kernel.org>
Fri, 18 Mar 2022 16:04:35 +0000 (16:04 +0000)
Add 3 new topology IPC ops for widget_setup, widget_free and dai_config
in order to make the pipeline management code IPC agnostic and implement
the ops for IPC3.

Use the newly introduced tplg dai_config op to configure the DAI during
BE DAI hw_params and hw_free.

Also, in preparation for IPC4, modify BE hw_params callback to skip
setting up the DAI widget. All widgets will be set up during FW
hw_params and the DAI_CONFIG IPC should be sent only if the widget
use_count is > 0. With setting up/freeing removed from the BE hw_params,
remove the configured flag as it is no longer needed.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220317175044.1752400-3-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/intel/hda-dai.c
sound/soc/sof/intel/hda.c
sound/soc/sof/intel/hda.h
sound/soc/sof/ipc3-topology.c
sound/soc/sof/sof-audio.c
sound/soc/sof/sof-audio.h

index 9b78eea8d76bcc26466ba9675dcccdaef5bf2c5f..f9cb9f1f0237b593938e159a54e642e84241b4e8 100644 (file)
@@ -162,58 +162,19 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
        return 0;
 }
 
-/* Update config for the DAI widget */
-static struct sof_ipc_dai_config *hda_dai_update_config(struct snd_soc_dapm_widget *w,
-                                                       int channel)
-{
-       struct snd_sof_widget *swidget = w->dobj.private;
-       struct sof_dai_private_data *private;
-       struct sof_ipc_dai_config *config;
-       struct snd_sof_dai *sof_dai;
-
-       if (!swidget)
-               return NULL;
-
-       sof_dai = swidget->private;
-
-       if (!sof_dai || !sof_dai->private) {
-               dev_err(swidget->scomp->dev, "%s: No private data for DAI %s\n", __func__,
-                       w->name);
-               return NULL;
-       }
-
-       private = sof_dai->private;
-       if (!private->dai_config) {
-               dev_err(swidget->scomp->dev, "%s: No config for DAI %s\n", __func__, w->name);
-               return NULL;
-       }
-
-       config = &private->dai_config[sof_dai->current_config];
-
-       /* update config with stream tag */
-       config->hda.link_dma_ch = channel;
-
-       return config;
-}
-
 static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream,
                                      struct snd_soc_dapm_widget *w,
                                      int channel, bool widget_setup)
 {
-       struct snd_sof_dev *sdev = hda_stream->sdev;
-       struct sof_ipc_dai_config *config;
+       struct snd_sof_dai_config_data data;
 
-       config = hda_dai_update_config(w, channel);
-       if (!config) {
-               dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
-               return -ENOENT;
-       }
+       data.dai_data = channel;
 
        /* set up/free DAI widget and send DAI_CONFIG IPC */
        if (widget_setup)
-               return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP);
+               return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);
 
-       return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
+       return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
 }
 
 static int hda_link_hw_params(struct snd_pcm_substream *substream,
@@ -302,35 +263,16 @@ static int hda_link_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
        struct snd_sof_widget *swidget = w->dobj.private;
        struct snd_soc_component *component = swidget->scomp;
        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
-       struct sof_dai_private_data *private;
-       struct sof_ipc_dai_config *config;
-       struct snd_sof_dai *sof_dai;
-       struct sof_ipc_reply reply;
-       int ret;
-
-       sof_dai = swidget->private;
-
-       if (!sof_dai || !sof_dai->private) {
-               dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
-               return -EINVAL;
-       }
+       const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
+       int ret = 0;
 
-       private = sof_dai->private;
-       if (!private->dai_config) {
-               dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
-               return -EINVAL;
+       if (tplg_ops->dai_config) {
+               ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
+               if (ret < 0)
+                       dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
+                               w->name);
        }
 
-       config = &private->dai_config[sof_dai->current_config];
-
-       /* set PAUSE command flag */
-       config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_CMD_MASK, SOF_DAI_CONFIG_FLAGS_PAUSE);
-
-       ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
-                                &reply, sizeof(reply));
-       if (ret < 0)
-               dev_err(sdev->dev, "DAI config for %s failed during pause push\n", w->name);
-
        return ret;
 }
 
@@ -470,30 +412,17 @@ struct ssp_dai_dma_data {
 static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
                                 bool setup)
 {
-       struct snd_soc_component *component;
-       struct snd_sof_widget *swidget;
        struct snd_soc_dapm_widget *w;
-       struct sof_ipc_fw_version *v;
-       struct snd_sof_dev *sdev;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                w = dai->playback_widget;
        else
                w = dai->capture_widget;
 
-       swidget = w->dobj.private;
-       component = swidget->scomp;
-       sdev = snd_soc_component_get_drvdata(component);
-       v = &sdev->fw_ready.version;
-
-       /* DAI_CONFIG IPC during hw_params is not supported in older firmware */
-       if (v->abi_version < SOF_ABI_VER(3, 18, 0))
-               return 0;
-
        if (setup)
-               return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE);
+               return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);
 
-       return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
+       return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);
 }
 
 static int ssp_dai_startup(struct snd_pcm_substream *substream,
index 7403b9848a564920363e37be2a06e0a597f7ab52..019f8d6b91d443996ac58febc0920353286a1d1a 100644 (file)
 #define EXCEPT_MAX_HDR_SIZE    0x400
 #define HDA_EXT_ROM_STATUS_SIZE 8
 
-int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags)
+int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
+                             struct snd_sof_dai_config_data *data)
 {
        struct snd_sof_widget *swidget = w->dobj.private;
        struct snd_soc_component *component = swidget->scomp;
        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
-       struct sof_ipc_dai_config *config;
-       struct sof_dai_private_data *private;
-       struct snd_sof_dai *sof_dai;
-       struct sof_ipc_reply reply;
+       const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
+       struct snd_sof_dai *sof_dai = swidget->private;
        int ret;
 
-       sof_dai = swidget->private;
-
-       if (!sof_dai || !sof_dai->private) {
-               dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
-               return -EINVAL;
-       }
-
-       private = sof_dai->private;
-       if (!private->dai_config) {
-               dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
+       if (!sof_dai) {
+               dev_err(sdev->dev, "%s: No DAI for DAI widget %s\n", __func__, w->name);
                return -EINVAL;
        }
 
-       /* DAI already configured, reset it before reconfiguring it */
-       if (sof_dai->configured) {
-               ret = hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
-               if (ret < 0)
-                       return ret;
-       }
-
-       config = &private->dai_config[sof_dai->current_config];
-
-       /*
-        * For static pipelines, the DAI widget would already be set up and calling
-        * sof_widget_setup() simply returns without doing anything.
-        * For dynamic pipelines, the DAI widget will be set up now.
-        */
-       ret = sof_widget_setup(sdev, swidget);
-       if (ret < 0) {
-               dev_err(sdev->dev, "error: failed setting up DAI widget %s\n", w->name);
-               return ret;
-       }
+       if (tplg_ops->dai_config) {
+               unsigned int flags;
 
-       /* set HW_PARAMS flag along with quirks */
-       config->flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS |
-                      quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
+               /* set HW_PARAMS flag along with quirks */
+               flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS |
+                       quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
 
-
-       /* send DAI_CONFIG IPC */
-       ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
-                                &reply, sizeof(reply));
-       if (ret < 0) {
-               dev_err(sdev->dev, "error: failed setting DAI config for %s\n", w->name);
-               return ret;
+               ret = tplg_ops->dai_config(sdev, swidget, flags, data);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
+                               w->name);
+                       return ret;
+               }
        }
 
-       sof_dai->configured = true;
-
        return 0;
 }
 
-int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags)
+int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
+                            struct snd_sof_dai_config_data *data)
 {
        struct snd_sof_widget *swidget = w->dobj.private;
        struct snd_soc_component *component = swidget->scomp;
        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
-       struct sof_dai_private_data *private;
-       struct sof_ipc_dai_config *config;
-       struct snd_sof_dai *sof_dai;
-       struct sof_ipc_reply reply;
-       int ret;
+       const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
+       struct snd_sof_dai *sof_dai = swidget->private;
 
-       sof_dai = swidget->private;
-
-       if (!sof_dai || !sof_dai->private) {
-               dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
-               return -EINVAL;
-       }
-
-       private = sof_dai->private;
-       if (!private->dai_config) {
-               dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
+       if (!sof_dai) {
+               dev_err(sdev->dev, "%s: No DAI for BE DAI widget %s\n", __func__, w->name);
                return -EINVAL;
        }
 
-       /* nothing to do if hw_free() is called without restarting the stream after resume. */
-       if (!sof_dai->configured)
-               return 0;
-
-       config = &private->dai_config[sof_dai->current_config];
+       if (tplg_ops->dai_config) {
+               unsigned int flags;
+               int ret;
 
-       /* set HW_FREE flag along with any quirks */
-       config->flags = SOF_DAI_CONFIG_FLAGS_HW_FREE |
-                      quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
+               /* set HW_FREE flag along with any quirks */
+               flags = SOF_DAI_CONFIG_FLAGS_HW_FREE |
+                       quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
 
-       ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
-                                &reply, sizeof(reply));
-       if (ret < 0)
-               dev_err(sdev->dev, "error: failed resetting DAI config for %s\n", w->name);
-
-       /*
-        * Reset the configured_flag and free the widget even if the IPC fails to keep
-        * the widget use_count balanced
-        */
-       sof_dai->configured = false;
+               ret = tplg_ops->dai_config(sdev, swidget, flags, data);
+               if (ret < 0)
+                       dev_err(sdev->dev, "%s: DAI config failed for widget '%s'\n", __func__,
+                               w->name);
+       }
 
-       return sof_widget_free(sdev, swidget);
+       return 0;
 }
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
@@ -163,69 +117,34 @@ static int sdw_clock_stop_quirks = SDW_INTEL_CLK_STOP_BUS_RESET;
 module_param(sdw_clock_stop_quirks, int, 0444);
 MODULE_PARM_DESC(sdw_clock_stop_quirks, "SOF SoundWire clock stop quirks");
 
-static int sdw_dai_config_ipc(struct snd_sof_dev *sdev,
-                             struct snd_soc_dapm_widget *w,
-                             int link_id, int alh_stream_id, int dai_id, bool setup)
-{
-       struct snd_sof_widget *swidget = w->dobj.private;
-       struct sof_dai_private_data *private;
-       struct sof_ipc_dai_config *config;
-       struct snd_sof_dai *sof_dai;
-
-       if (!swidget) {
-               dev_err(sdev->dev, "error: No private data for widget %s\n", w->name);
-               return -EINVAL;
-       }
-
-       sof_dai = swidget->private;
-
-       if (!sof_dai || !sof_dai->private) {
-               dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
-               return -EINVAL;
-       }
-
-       private = sof_dai->private;
-       if (!private->dai_config) {
-               dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
-               return -EINVAL;
-       }
-
-       config = &private->dai_config[sof_dai->current_config];
-
-       /* update config with link and stream ID */
-       config->dai_index = (link_id << 8) | dai_id;
-       config->alh.stream_id = alh_stream_id;
-
-       if (setup)
-               return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE);
-
-       return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
-}
-
 static int sdw_params_stream(struct device *dev,
                             struct sdw_intel_stream_params_data *params_data)
 {
-       struct snd_sof_dev *sdev = dev_get_drvdata(dev);
        struct snd_soc_dai *d = params_data->dai;
+       struct snd_sof_dai_config_data data;
        struct snd_soc_dapm_widget *w;
 
        w = snd_soc_dai_get_widget(d, params_data->stream);
+       data.dai_index = (params_data->link_id << 8) | d->id;
+       data.dai_data = params_data->alh_stream_id;
 
-       return sdw_dai_config_ipc(sdev, w, params_data->link_id, params_data->alh_stream_id,
-                                 d->id, true);
+       return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
 }
 
 static int sdw_free_stream(struct device *dev,
                           struct sdw_intel_stream_free_data *free_data)
 {
-       struct snd_sof_dev *sdev = dev_get_drvdata(dev);
        struct snd_soc_dai *d = free_data->dai;
+       struct snd_sof_dai_config_data data;
        struct snd_soc_dapm_widget *w;
 
        w = snd_soc_dai_get_widget(d, free_data->stream);
+       data.dai_index = (free_data->link_id << 8) | d->id;
 
        /* send invalid stream_id */
-       return sdw_dai_config_ipc(sdev, w, free_data->link_id, 0xFFFF, d->id, false);
+       data.dai_data = 0xFFFF;
+
+       return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
 }
 
 static const struct sdw_intel_ops sdw_callback = {
index 13b509c9f48143f18a160a19877c7142655631e6..05e5e158614a1ed6c0fbbb56de6c78d996e82df5 100644 (file)
@@ -17,6 +17,7 @@
 #include <sound/hda_codec.h>
 #include <sound/hdaudio_ext.h>
 #include "../sof-client-probes.h"
+#include "../sof-audio.h"
 #include "shim.h"
 
 /* PCI registers */
@@ -730,8 +731,10 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 
 struct snd_sof_dai;
 struct sof_ipc_dai_config;
-int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags);
-int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags);
+int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
+                             struct snd_sof_dai_config_data *data);
+int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
+                            struct snd_sof_dai_config_data *data);
 
 #define SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY      (0) /* previous implementation */
 #define SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS      (1) /* recommended if VC0 only */
index fe1d5a56080a0424e97cd1c5a21245784dc261c2..8d08ffb37008043c9054abc1ccaf082a4b302277 100644 (file)
@@ -1909,6 +1909,153 @@ static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_w
        return 1;
 }
 
+static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+       struct sof_ipc_free ipc_free = {
+               .hdr = {
+                       .size = sizeof(ipc_free),
+                       .cmd = SOF_IPC_GLB_TPLG_MSG,
+               },
+               .id = swidget->comp_id,
+       };
+       struct sof_ipc_reply reply;
+       int ret;
+
+       if (!swidget->private)
+               return 0;
+
+       switch (swidget->id) {
+       case snd_soc_dapm_scheduler:
+       {
+               ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
+               break;
+       }
+       case snd_soc_dapm_buffer:
+               ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
+               break;
+       default:
+               ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
+               break;
+       }
+
+       ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
+                                &reply, sizeof(reply));
+       if (ret < 0)
+               dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name);
+
+       return ret;
+}
+
+static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+                              unsigned int flags, struct snd_sof_dai_config_data *data)
+{
+       struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
+       struct snd_sof_dai *dai = swidget->private;
+       struct sof_dai_private_data *private;
+       struct sof_ipc_dai_config *config;
+       struct sof_ipc_reply reply;
+       int ret = 0;
+
+       if (!dai || !dai->private) {
+               dev_err(sdev->dev, "No private data for DAI %s\n", swidget->widget->name);
+               return -EINVAL;
+       }
+
+       private = dai->private;
+       if (!private->dai_config) {
+               dev_err(sdev->dev, "No config for DAI %s\n", dai->name);
+               return -EINVAL;
+       }
+
+       config = &private->dai_config[dai->current_config];
+       if (!config) {
+               dev_err(sdev->dev, "Invalid current config for DAI %s\n", dai->name);
+               return -EINVAL;
+       }
+
+       switch (config->type) {
+       case SOF_DAI_INTEL_SSP:
+               /*
+                * DAI_CONFIG IPC during hw_params/hw_free for SSP DAI's is not supported in older
+                * firmware
+                */
+               if (v->abi_version < SOF_ABI_VER(3, 18, 0) &&
+                   ((flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) ||
+                    (flags & SOF_DAI_CONFIG_FLAGS_HW_FREE)))
+                       return 0;
+               break;
+       case SOF_DAI_INTEL_HDA:
+               if (data)
+                       config->hda.link_dma_ch = data->dai_data;
+               break;
+       case SOF_DAI_INTEL_ALH:
+               if (data) {
+                       config->dai_index = data->dai_index;
+                       config->alh.stream_id = data->dai_data;
+               }
+               break;
+       default:
+               break;
+       }
+
+       config->flags = flags;
+
+       /* only send the IPC if the widget is set up in the DSP */
+       if (swidget->use_count > 0) {
+               ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
+                                        &reply, sizeof(reply));
+               if (ret < 0)
+                       dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
+       }
+
+       return ret;
+}
+
+static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+       struct sof_ipc_comp_reply reply;
+       int ret;
+
+       if (!swidget->private)
+               return 0;
+
+       switch (swidget->id) {
+       case snd_soc_dapm_dai_in:
+       case snd_soc_dapm_dai_out:
+       {
+               struct snd_sof_dai *dai = swidget->private;
+               struct sof_dai_private_data *dai_data = dai->private;
+               struct sof_ipc_comp *comp = &dai_data->comp_dai->comp;
+
+               ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai_data->comp_dai,
+                                        comp->hdr.size, &reply, sizeof(reply));
+               break;
+       }
+       case snd_soc_dapm_scheduler:
+       {
+               struct sof_ipc_pipe_new *pipeline;
+
+               pipeline = swidget->private;
+               ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
+                                        sizeof(*pipeline), &reply, sizeof(reply));
+               break;
+       }
+       default:
+       {
+               struct sof_ipc_cmd_hdr *hdr;
+
+               hdr = swidget->private;
+               ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size,
+                                        &reply, sizeof(reply));
+               break;
+       }
+       }
+       if (ret < 0)
+               dev_err(sdev->dev, "Failed to setup widget %s\n", swidget->widget->name);
+
+       return ret;
+}
+
 /* token list for each topology object */
 static enum sof_tokens host_token_list[] = {
        SOF_CORE_TOKENS,
@@ -2012,6 +2159,9 @@ static const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
        .control_free = sof_ipc3_control_free,
        .pipeline_complete = sof_ipc3_complete_pipeline,
        .token_list = ipc3_token_list,
+       .widget_free = sof_ipc3_widget_free,
+       .widget_setup = sof_ipc3_widget_setup,
+       .dai_config = sof_ipc3_dai_config,
 };
 
 const struct sof_ipc_ops ipc3_ops = {
index cc0d647a2d0df42117d10e06f99e593b7fd15331..7aa4ac313de33dc792310a21b0419d88709d92eb 100644 (file)
@@ -27,31 +27,6 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *
        return ret;
 }
 
-static int sof_dai_config_setup(struct snd_sof_dev *sdev, struct snd_sof_dai *dai)
-{
-       struct sof_dai_private_data *private = dai->private;
-       struct sof_ipc_dai_config *config;
-       struct sof_ipc_reply reply;
-       int ret;
-
-       config = &private->dai_config[dai->current_config];
-       if (!config) {
-               dev_err(sdev->dev, "error: no config for DAI %s\n", dai->name);
-               return -EINVAL;
-       }
-
-       /* set NONE flag to clear all previous settings */
-       config->flags = SOF_DAI_CONFIG_FLAGS_NONE;
-
-       ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
-                                &reply, sizeof(reply));
-
-       if (ret < 0)
-               dev_err(sdev->dev, "error: failed to set dai config for %s\n", dai->name);
-
-       return ret;
-}
-
 static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
 {
        struct snd_sof_control *scontrol;
@@ -96,15 +71,9 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_so
 
 int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
 {
-       struct sof_ipc_free ipc_free = {
-               .hdr = {
-                       .size = sizeof(ipc_free),
-                       .cmd = SOF_IPC_GLB_TPLG_MSG,
-               },
-               .id = swidget->comp_id,
-       };
-       struct sof_ipc_reply reply;
-       int ret, err;
+       const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
+       int err = 0;
+       int ret;
 
        if (!swidget->private)
                return 0;
@@ -113,33 +82,9 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
        if (--swidget->use_count)
                return 0;
 
-       switch (swidget->id) {
-       case snd_soc_dapm_scheduler:
-       {
-               ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
-               break;
-       }
-       case snd_soc_dapm_buffer:
-               ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
-               break;
-       case snd_soc_dapm_dai_in:
-       case snd_soc_dapm_dai_out:
-       {
-               struct snd_sof_dai *dai = swidget->private;
-
-               dai->configured = false;
-               fallthrough;
-       }
-       default:
-               ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
-               break;
-       }
-
        /* continue to disable core even if IPC fails */
-       err = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
-                                &reply, sizeof(reply));
-       if (err < 0)
-               dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name);
+       if (tplg_ops->widget_free)
+               err = tplg_ops->widget_free(sdev, swidget);
 
        /*
         * disable widget core. continue to route setup status and complete flag
@@ -176,11 +121,7 @@ EXPORT_SYMBOL(sof_widget_free);
 
 int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
 {
-       struct sof_ipc_pipe_new *pipeline;
-       struct sof_ipc_comp_reply r;
-       struct sof_ipc_cmd_hdr *hdr;
-       struct sof_ipc_comp *comp;
-       struct snd_sof_dai *dai;
+       const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
        int ret;
 
        /* skip if there is no private data */
@@ -219,53 +160,22 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
                goto pipe_widget_free;
        }
 
-       switch (swidget->id) {
-       case snd_soc_dapm_dai_in:
-       case snd_soc_dapm_dai_out:
-       {
-               struct sof_dai_private_data *dai_data;
-
-               dai = swidget->private;
-               dai_data = dai->private;
-               comp = &dai_data->comp_dai->comp;
-               dai->configured = false;
-
-               ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai_data->comp_dai,
-                                        comp->hdr.size, &r, sizeof(r));
-               if (ret < 0) {
-                       dev_err(sdev->dev, "error: failed to load widget %s\n",
-                               swidget->widget->name);
+       /* setup widget in the DSP */
+       if (tplg_ops->widget_setup) {
+               ret = tplg_ops->widget_setup(sdev, swidget);
+               if (ret < 0)
                        goto core_put;
-               }
+       }
 
-               ret = sof_dai_config_setup(sdev, dai);
-               if (ret < 0) {
-                       dev_err(sdev->dev, "error: failed to load dai config for DAI %s\n",
-                               swidget->widget->name);
+       /* send config for DAI components */
+       if (WIDGET_IS_DAI(swidget->id)) {
+               unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE;
 
-                       /*
-                        * widget use_count and core ref_count will both be decremented by
-                        * sof_widget_free()
-                        */
-                       sof_widget_free(sdev, swidget);
-                       return ret;
+               if (tplg_ops->dai_config) {
+                       ret = tplg_ops->dai_config(sdev, swidget, flags, NULL);
+                       if (ret < 0)
+                               goto widget_free;
                }
-               break;
-       }
-       case snd_soc_dapm_scheduler:
-               pipeline = swidget->private;
-               ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
-                                        sizeof(*pipeline), &r, sizeof(r));
-               break;
-       default:
-               hdr = swidget->private;
-               ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size,
-                                        &r, sizeof(r));
-               break;
-       }
-       if (ret < 0) {
-               dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name);
-               goto core_put;
        }
 
        /* restore kcontrols for widget */
@@ -273,18 +183,16 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
        if (ret < 0) {
                dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n",
                        swidget->widget->name);
-               /*
-                * widget use_count and core ref_count will both be decremented by
-                * sof_widget_free()
-                */
-               sof_widget_free(sdev, swidget);
-               return ret;
+               goto widget_free;
        }
 
        dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name);
 
        return 0;
 
+widget_free:
+       /* widget use_count and core ref_count will both be decremented by sof_widget_free() */
+       sof_widget_free(sdev, swidget);
 core_put:
        snd_sof_dsp_core_put(sdev, swidget->core);
 pipe_widget_free:
index 622d43707b2777fe1d69f272edcdf75024004746..19386184d8f3077211315acaa613c9b8b1ab4e6f 100644 (file)
@@ -40,6 +40,11 @@ struct snd_sof_widget;
 struct snd_sof_route;
 struct snd_sof_control;
 
+struct snd_sof_dai_config_data {
+       int dai_index;
+       int dai_data; /* contains DAI-specific information */
+};
+
 /**
  * struct sof_ipc_tplg_widget_ops - IPC-specific ops for topology widgets
  * @ipc_setup: Function pointer for setting up widget IPC params
@@ -69,6 +74,9 @@ struct sof_ipc_tplg_widget_ops {
  * @control_setup: Function pointer for setting up kcontrol IPC-specific data
  * @control_free: Function pointer for freeing kcontrol IPC-specific data
  * @pipeline_complete: Function pointer for pipeline complete IPC
+ * @widget_setup: Function pointer for setting up setup in the DSP
+ * @widget_free: Function pointer for freeing widget in the DSP
+ * @dai_config: Function pointer for sending DAI config IPC to the DSP
  */
 struct sof_ipc_tplg_ops {
        const struct sof_ipc_tplg_widget_ops *widget;
@@ -77,6 +85,10 @@ struct sof_ipc_tplg_ops {
        int (*control_setup)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol);
        int (*control_free)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol);
        int (*pipeline_complete)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
+       int (*widget_setup)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
+       int (*widget_free)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
+       int (*dai_config)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+                         unsigned int flags, struct snd_sof_dai_config_data *data);
 };
 
 /** struct snd_sof_tuple - Tuple info
@@ -276,7 +288,6 @@ struct snd_sof_dai {
 
        int number_configs;
        int current_config;
-       bool configured; /* DAI configured during BE hw_params */
        struct list_head list;  /* list in sdev dai list */
        void *private;
 };