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>
This commit is contained in:
Pierre-Louis Bossart 2022-04-21 15:31:53 -05:00 committed by Mark Brown
parent 5ef85c9e42
commit f321ffc8d9
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0

View 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;
struct snd_soc_dapm_widget *w;
int stream_tag;
hext_stream = snd_soc_dai_get_dma_data(dai, substream);
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;
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 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;
if (hext_stream->link_prepared)
return 0;
dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream);
return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params,
dai);
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);
dev_dbg(sdev->dev, "%s: prepare stream dir %d\n", __func__, substream->stream);
ret = hda_link_dma_prepare(substream);
if (ret < 0)
return ret;
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(dai->dev, "In %s cmd=%d\n", __func__, cmd);
w = snd_soc_dai_get_widget(dai, substream->stream);
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,9 +336,6 @@ 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);
ret = hda_dai_config_pause_push_ipc(w);
if (ret < 0)
return ret;
break;
default:
return -EINVAL;
@ -330,40 +343,62 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
return 0;
}
static int hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
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;
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);
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:
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(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