Commit f321ffc8 authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Mark Brown

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: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarRander Wang <rander.wang@intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarPéter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220421203201.1550328-7-pierre-louis.bossart@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 5ef85c9e
...@@ -176,40 +176,28 @@ static int hda_dai_widget_update(struct snd_soc_dapm_widget *w, ...@@ -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); return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
} }
static int hda_dai_hw_params(struct snd_pcm_substream *substream, static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params)
struct snd_soc_dai *dai)
{ {
struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_stream *hstream = substream->runtime->private_data;
struct hdac_bus *bus = hstream->bus;
struct hdac_ext_stream *hext_stream; struct hdac_ext_stream *hext_stream;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 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 snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct hda_pipe_params p_params = {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; struct hdac_ext_link *link;
int stream_tag;
int ret;
/* get stored dma data if resuming from system suspend */ /* 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) { if (!hext_stream) {
hext_stream = hda_link_stream_assign(bus, substream); hext_stream = hda_link_stream_assign(bus, substream);
if (!hext_stream) if (!hext_stream)
return -EBUSY; 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); link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link) if (!link)
return -EINVAL; return -EINVAL;
...@@ -232,23 +220,45 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream, ...@@ -232,23 +220,45 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream,
return hda_link_dma_params(hext_stream, &p_params); return hda_link_dma_params(hext_stream, &p_params);
} }
static int hda_dai_prepare(struct snd_pcm_substream *substream, static int hda_dai_hw_params_update(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct hdac_ext_stream *hext_stream = struct hdac_ext_stream *hext_stream;
snd_soc_dai_get_dma_data(dai, substream); struct snd_soc_dapm_widget *w;
struct snd_sof_dev *sdev = int stream_tag;
snd_soc_component_get_drvdata(dai->component);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
int stream = substream->stream;
if (hext_stream->link_prepared) hext_stream = snd_soc_dai_get_dma_data(dai, substream);
return 0; if (!hext_stream)
return -EINVAL;
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 */
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;
dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream); ret = hda_link_dma_hw_params(substream, params);
if (ret < 0)
return ret;
return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, return hda_dai_hw_params_update(substream, params, dai);
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) 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) ...@@ -269,31 +279,44 @@ static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
return ret; return ret;
} }
static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct hdac_ext_stream *hext_stream = struct hdac_ext_stream *hext_stream =
snd_soc_dai_get_dma_data(dai, substream); snd_soc_dai_get_dma_data(dai, substream);
struct snd_soc_pcm_runtime *rtd; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
struct snd_soc_dapm_widget *w; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct hdac_ext_link *link; int stream = substream->stream;
struct hdac_stream *hstream;
struct hdac_bus *bus;
int stream_tag;
int ret; int ret;
hstream = substream->runtime->private_data; if (hext_stream->link_prepared)
bus = hstream->bus; return 0;
rtd = asoc_substream_to_rtd(substream);
link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name); dev_dbg(sdev->dev, "%s: prepare stream dir %d\n", __func__, substream->stream);
if (!link)
return -EINVAL;
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) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
...@@ -303,13 +326,6 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, ...@@ -303,13 +326,6 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
snd_hdac_ext_link_stream_clear(hext_stream); 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) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(hext_stream)->stream_tag; stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag); snd_hdac_ext_link_clear_stream_id(link, stream_tag);
...@@ -320,9 +336,6 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, ...@@ -320,9 +336,6 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_hdac_ext_link_stream_clear(hext_stream); snd_hdac_ext_link_stream_clear(hext_stream);
ret = hda_dai_config_pause_push_ipc(w);
if (ret < 0)
return ret;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -330,40 +343,62 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, ...@@ -330,40 +343,62 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static int hda_dai_hw_free(struct snd_pcm_substream *substream, static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
{ {
unsigned int stream_tag;
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_ext_stream *hext_stream;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
int ret; int ret;
hstream = substream->runtime->private_data; ret = hda_link_dma_trigger(substream, cmd);
bus = hstream->bus; if (ret < 0)
rtd = asoc_substream_to_rtd(substream); return ret;
hext_stream = snd_soc_dai_get_dma_data(dai, substream);
if (!hext_stream) {
dev_dbg(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); w = snd_soc_dai_get_widget(dai, substream->stream);
/* free the link DMA channel in the FW and the DAI widget */ 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); ret = hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name); break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = hda_dai_config_pause_push_ipc(w);
if (ret < 0)
return ret;
break;
default:
break;
}
return 0;
}
static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
{
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 = hstream->bus;
struct hdac_ext_stream *hext_stream;
struct hdac_ext_link *link;
int stream_tag;
hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
if (!hext_stream) {
dev_dbg(cpu_dai->dev,
"%s: hext_stream is not assigned\n", __func__);
return -EINVAL;
}
link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link) if (!link)
return -EINVAL; return -EINVAL;
...@@ -372,21 +407,42 @@ static int hda_dai_hw_free(struct snd_pcm_substream *substream, ...@@ -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_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); snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
hext_stream->link_prepared = 0; hext_stream->link_prepared = 0;
/* free the host DMA channel reserved by hostless streams */ /* free the host DMA channel reserved by hostless streams */
hda_stream = hstream_to_sof_hda_stream(hext_stream);
hda_stream->host_reserved = 0; hda_stream->host_reserved = 0;
return 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 = { static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
.hw_params = hda_dai_hw_params, .hw_params = hda_dai_hw_params,
.hw_free = hda_dai_hw_free, .hw_free = hda_dai_hw_free,
.trigger = ipc3_hda_dai_trigger, .trigger = ipc3_hda_dai_trigger,
.prepare = hda_dai_prepare, .prepare = ipc3_hda_dai_prepare,
}; };
#endif #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