ASoC/SoundWire: clean up link DMA during stop for IPC4
Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>: Clean up the link DMA for playback during stop for IPC4 is required to reset the DMA read/write pointers when the stream is prepared and restarted after a call to snd_pcm_drain()/snd_pcm_drop(). The change is mainly on ASoC. We may go via ASoC tree with Vinod's Acked-by tag Ranjani Sridharan (4): ASoC: SOF: ipc4-topology: Do not set ALH node_id for aggregated DAIs ASoC: SOF: Intel: hda: Handle prepare without close for non-HDA DAI's soundwire: intel_ace2x: Send PDI stream number during prepare ASoC: SOF: Intel: hda: Always clean up link DMA during stop drivers/soundwire/intel_ace2x.c | 19 +++++----------- sound/soc/sof/intel/hda-dai-ops.c | 23 +++++++++---------- sound/soc/sof/intel/hda-dai.c | 37 +++++++++++++++++++++++++++---- sound/soc/sof/ipc4-topology.c | 15 +++++++++++-- 4 files changed, 62 insertions(+), 32 deletions(-) -- 2.43.0
This commit is contained in:
commit
d641c164f8
@ -376,11 +376,12 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
|
||||
static int intel_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
|
||||
struct sdw_intel *sdw = cdns_to_intel(cdns);
|
||||
struct sdw_cdns_dai_runtime *dai_runtime;
|
||||
struct snd_pcm_hw_params *hw_params;
|
||||
int ch, dir;
|
||||
int ret = 0;
|
||||
|
||||
dai_runtime = cdns->dai_runtime_array[dai->id];
|
||||
if (!dai_runtime) {
|
||||
@ -389,12 +390,8 @@ static int intel_prepare(struct snd_pcm_substream *substream,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
hw_params = &rtd->dpcm[substream->stream].hw_params;
|
||||
if (dai_runtime->suspended) {
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_pcm_hw_params *hw_params;
|
||||
|
||||
hw_params = &rtd->dpcm[substream->stream].hw_params;
|
||||
|
||||
dai_runtime->suspended = false;
|
||||
|
||||
/*
|
||||
@ -415,15 +412,11 @@ static int intel_prepare(struct snd_pcm_substream *substream,
|
||||
/* the SHIM will be configured in the callback functions */
|
||||
|
||||
sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);
|
||||
|
||||
/* Inform DSP about PDI stream number */
|
||||
ret = intel_params_stream(sdw, substream, dai,
|
||||
hw_params,
|
||||
sdw->instance,
|
||||
dai_runtime->pdi->intel_alh_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* Inform DSP about PDI stream number */
|
||||
return intel_params_stream(sdw, substream, dai, hw_params, sdw->instance,
|
||||
dai_runtime->pdi->intel_alh_id);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -346,20 +346,21 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
snd_hdac_ext_stream_start(hext_stream);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
snd_hdac_ext_stream_clear(hext_stream);
|
||||
|
||||
/*
|
||||
* Save the LLP registers in case the stream is
|
||||
* restarting due PAUSE_RELEASE, or START without a pcm
|
||||
* close/open since in this case the LLP register is not reset
|
||||
* to 0 and the delay calculation will return with invalid
|
||||
* results.
|
||||
* Save the LLP registers since in case of PAUSE the LLP
|
||||
* register are not reset to 0, the delay calculation will use
|
||||
* the saved offsets for compensating the delay calculation.
|
||||
*/
|
||||
hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
|
||||
hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
|
||||
snd_hdac_ext_stream_clear(hext_stream);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
hext_stream->pplcllpl = 0;
|
||||
hext_stream->pplcllpu = 0;
|
||||
snd_hdac_ext_stream_clear(hext_stream);
|
||||
break;
|
||||
default:
|
||||
dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
|
||||
@ -512,7 +513,6 @@ static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
|
||||
static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
|
||||
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
|
||||
|
||||
switch (cmd) {
|
||||
@ -527,9 +527,6 @@ static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (cmd == SNDRV_PCM_TRIGGER_STOP)
|
||||
return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
|
||||
|
||||
break;
|
||||
}
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
|
@ -302,6 +302,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
ret = hda_link_dma_cleanup(substream, hext_stream, dai);
|
||||
if (ret < 0) {
|
||||
@ -370,6 +371,13 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sdev = widget_to_sdev(w);
|
||||
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
|
||||
|
||||
/* nothing more to do if the link is already prepared */
|
||||
if (hext_stream && hext_stream->link_prepared)
|
||||
return 0;
|
||||
|
||||
/* use HDaudio stream handling */
|
||||
ret = hda_dai_hw_params_data(substream, params, cpu_dai, data, flags);
|
||||
if (ret < 0) {
|
||||
@ -377,7 +385,6 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdev = widget_to_sdev(w);
|
||||
if (sdev->dspless_mode_selected)
|
||||
return 0;
|
||||
|
||||
@ -482,6 +489,31 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ops = hda_dai_get_ops(substream, cpu_dai);
|
||||
if (!ops) {
|
||||
dev_err(cpu_dai->dev, "DAI widget ops not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sdev = widget_to_sdev(w);
|
||||
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
|
||||
|
||||
/* nothing more to do if the link is already prepared */
|
||||
if (hext_stream && hext_stream->link_prepared)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted
|
||||
* due to xruns or after a call to snd_pcm_drain/drop()
|
||||
*/
|
||||
ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
|
||||
0, 0, substream->stream);
|
||||
if (ret < 0) {
|
||||
dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
data.dai_index = (link_id << 8) | cpu_dai->id;
|
||||
data.dai_node_id = intel_alh_id;
|
||||
ret = non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
|
||||
@ -490,10 +522,7 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ops = hda_dai_get_ops(substream, cpu_dai);
|
||||
sdev = widget_to_sdev(w);
|
||||
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
|
||||
|
||||
if (!hext_stream)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -3129,9 +3129,20 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
|
||||
* group_id during copier's ipc_prepare op.
|
||||
*/
|
||||
if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
|
||||
struct sof_ipc4_alh_configuration_blob *blob;
|
||||
|
||||
blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
|
||||
ipc4_copier->dai_index = data->dai_node_id;
|
||||
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
|
||||
copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_node_id);
|
||||
|
||||
/*
|
||||
* no need to set the node_id for aggregated DAI's. These will be assigned
|
||||
* a group_id during widget ipc_prepare
|
||||
*/
|
||||
if (blob->alh_cfg.device_count == 1) {
|
||||
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
|
||||
copier_data->gtw_cfg.node_id |=
|
||||
SOF_IPC4_NODE_INDEX(data->dai_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user