ASoC: SOF: Intel: hda-dai: split link DMA and dai operations
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Thu, 21 Apr 2022 20:31:53 +0000 (15:31 -0500)
committerMark Brown <broonie@kernel.org>
Mon, 25 Apr 2022 12:58:29 +0000 (13:58 +0100)
The link DMA state management is handled completely on the host side,
while the DAI operations require an IPC. Split the first part in
dedicated helpers.

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

index 2450098..d5ca5b1 100644 (file)
@@ -176,40 +176,28 @@ static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
        return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
 }
 
-static int hda_dai_hw_params(struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *params,
-                            struct snd_soc_dai *dai)
+static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params)
 {
        struct hdac_stream *hstream = substream->runtime->private_data;
-       struct hdac_bus *bus = hstream->bus;
        struct hdac_ext_stream *hext_stream;
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
        struct hda_pipe_params p_params = {0};
-       struct snd_soc_dapm_widget *w;
+       struct hdac_bus *bus = hstream->bus;
        struct hdac_ext_link *link;
-       int stream_tag;
-       int ret;
 
        /* get stored dma data if resuming from system suspend */
-       hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+       hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
        if (!hext_stream) {
                hext_stream = hda_link_stream_assign(bus, substream);
                if (!hext_stream)
                        return -EBUSY;
 
-               snd_soc_dai_set_dma_data(dai, substream, (void *)hext_stream);
+               snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
        }
 
-       stream_tag = hdac_stream(hext_stream)->stream_tag;
-
-       w = snd_soc_dai_get_widget(dai, substream->stream);
-
-       /* set up the DAI widget and send the DAI_CONFIG with the new tag */
-       ret = hda_dai_widget_update(w, stream_tag - 1, true);
-       if (ret < 0)
-               return ret;
-
        link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
        if (!link)
                return -EINVAL;
@@ -232,23 +220,45 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream,
        return hda_link_dma_params(hext_stream, &p_params);
 }
 
-static int hda_dai_prepare(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
+static int hda_dai_hw_params_update(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *dai)
 {
-       struct hdac_ext_stream *hext_stream =
-                               snd_soc_dai_get_dma_data(dai, substream);
-       struct snd_sof_dev *sdev =
-                               snd_soc_component_get_drvdata(dai->component);
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       int stream = substream->stream;
+       struct hdac_ext_stream *hext_stream;
+       struct snd_soc_dapm_widget *w;
+       int stream_tag;
 
-       if (hext_stream->link_prepared)
-               return 0;
+       hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+       if (!hext_stream)
+               return -EINVAL;
+
+       stream_tag = hdac_stream(hext_stream)->stream_tag;
 
-       dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream);
+       w = snd_soc_dai_get_widget(dai, substream->stream);
 
-       return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params,
-                                 dai);
+       /* set up the DAI widget and send the DAI_CONFIG with the new tag */
+       return hda_dai_widget_update(w, stream_tag - 1, true);
+}
+
+static int hda_dai_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       int ret;
+
+       ret = hda_link_dma_hw_params(substream, params);
+       if (ret < 0)
+               return ret;
+
+       return hda_dai_hw_params_update(substream, params, dai);
+}
+
+static int hda_link_dma_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       int stream = substream->stream;
+
+       return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params);
 }
 
 static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
@@ -269,31 +279,44 @@ static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
        return ret;
 }
 
-static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
-                               int cmd, struct snd_soc_dai *dai)
+static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
 {
        struct hdac_ext_stream *hext_stream =
                                snd_soc_dai_get_dma_data(dai, substream);
-       struct snd_soc_pcm_runtime *rtd;
-       struct snd_soc_dapm_widget *w;
-       struct hdac_ext_link *link;
-       struct hdac_stream *hstream;
-       struct hdac_bus *bus;
-       int stream_tag;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       int stream = substream->stream;
        int ret;
 
-       hstream = substream->runtime->private_data;
-       bus = hstream->bus;
-       rtd = asoc_substream_to_rtd(substream);
+       if (hext_stream->link_prepared)
+               return 0;
 
-       link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
-       if (!link)
-               return -EINVAL;
+       dev_dbg(sdev->dev, "%s: prepare stream dir %d\n", __func__, substream->stream);
 
-       dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
+       ret = hda_link_dma_prepare(substream);
+       if (ret < 0)
+               return ret;
 
-       w = snd_soc_dai_get_widget(dai, substream->stream);
+       return hda_dai_hw_params_update(substream, &rtd->dpcm[stream].hw_params, dai);
+}
+
+static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct hdac_stream *hstream = substream->runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
+       struct hdac_ext_link *link;
+       struct hdac_bus *bus = hstream->bus;
+       int stream_tag;
+
+       link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
+       if (!link)
+               return -EINVAL;
 
+       dev_dbg(cpu_dai->dev, "%s: cmd=%d\n", __func__, cmd);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -303,13 +326,6 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_STOP:
                snd_hdac_ext_link_stream_clear(hext_stream);
 
-               /*
-                * free DAI widget during stop/suspend to keep widget use_count's balanced.
-                */
-               ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
-               if (ret < 0)
-                       return ret;
-
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        stream_tag = hdac_stream(hext_stream)->stream_tag;
                        snd_hdac_ext_link_clear_stream_id(link, stream_tag);
@@ -320,50 +336,69 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                snd_hdac_ext_link_stream_clear(hext_stream);
 
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
+                               int cmd, struct snd_soc_dai *dai)
+{
+       struct snd_soc_dapm_widget *w;
+       int ret;
+
+       ret = hda_link_dma_trigger(substream, cmd);
+       if (ret < 0)
+               return ret;
+
+       w = snd_soc_dai_get_widget(dai, substream->stream);
+
+       dev_dbg(dai->dev, "%s: cmd=%d\n", __func__, cmd);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+               /*
+                * free DAI widget during stop/suspend to keep widget use_count's balanced.
+                */
+               ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
+               if (ret < 0)
+                       return ret;
+
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                ret = hda_dai_config_pause_push_ipc(w);
                if (ret < 0)
                        return ret;
                break;
+
        default:
-               return -EINVAL;
+               break;
        }
        return 0;
 }
 
-static int hda_dai_hw_free(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
+static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
 {
-       unsigned int stream_tag;
+       struct hdac_stream *hstream = substream->runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
        struct sof_intel_hda_stream *hda_stream;
-       struct hdac_bus *bus;
-       struct hdac_ext_link *link;
-       struct hdac_stream *hstream;
-       struct snd_soc_pcm_runtime *rtd;
+       struct hdac_bus *bus = hstream->bus;
        struct hdac_ext_stream *hext_stream;
-       struct snd_soc_dapm_widget *w;
-       int ret;
-
-       hstream = substream->runtime->private_data;
-       bus = hstream->bus;
-       rtd = asoc_substream_to_rtd(substream);
-       hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+       struct hdac_ext_link *link;
+       int stream_tag;
 
+       hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
        if (!hext_stream) {
-               dev_dbg(dai->dev,
+               dev_dbg(cpu_dai->dev,
                        "%s: hext_stream is not assigned\n", __func__);
                return -EINVAL;
        }
 
-       hda_stream = hstream_to_sof_hda_stream(hext_stream);
-
-       w = snd_soc_dai_get_widget(dai, substream->stream);
-
-       /* free the link DMA channel in the FW and the DAI widget */
-       ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
-       if (ret < 0)
-               return ret;
-
-       link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
+       link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
        if (!link)
                return -EINVAL;
 
@@ -372,21 +407,42 @@ static int hda_dai_hw_free(struct snd_pcm_substream *substream,
                snd_hdac_ext_link_clear_stream_id(link, stream_tag);
        }
 
-       snd_soc_dai_set_dma_data(dai, substream, NULL);
+       snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
        snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
        hext_stream->link_prepared = 0;
 
        /* free the host DMA channel reserved by hostless streams */
+       hda_stream = hstream_to_sof_hda_stream(hext_stream);
        hda_stream->host_reserved = 0;
 
        return 0;
 }
 
+static int hda_dai_hw_free(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
+{
+       struct snd_soc_dapm_widget *w;
+       int ret;
+
+       ret = hda_link_dma_hw_free(substream);
+       if (ret < 0)
+               return ret;
+
+       w = snd_soc_dai_get_widget(dai, substream->stream);
+
+       /* free the link DMA channel in the FW and the DAI widget */
+       ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
        .hw_params = hda_dai_hw_params,
        .hw_free = hda_dai_hw_free,
        .trigger = ipc3_hda_dai_trigger,
-       .prepare = hda_dai_prepare,
+       .prepare = ipc3_hda_dai_prepare,
 };
 
 #endif