summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>2022-04-21 15:31:53 -0500
committerMark Brown <broonie@kernel.org>2022-04-25 13:58:29 +0100
commitf321ffc8d93639181af0512938e2b0630ca28051 (patch)
tree9f0a8a0ee9fc89545525b216c4e413c0802f91b2
parent5ef85c9e42e5fc549e934669fdca352b3da97ec4 (diff)
downloadlinux-stable-f321ffc8d93639181af0512938e2b0630ca28051.tar.gz
linux-stable-f321ffc8d93639181af0512938e2b0630ca28051.tar.bz2
linux-stable-f321ffc8d93639181af0512938e2b0630ca28051.zip
ASoC: SOF: Intel: hda-dai: split link DMA and dai operations
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>
-rw-r--r--sound/soc/sof/intel/hda-dai.c220
1 files changed, 138 insertions, 82 deletions
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 245009809894..d5ca5b1fefe6 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -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