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,
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
......
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