summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/sof/intel/hda-stream.c11
-rw-r--r--sound/soc/sof/ipc4-pcm.c3
-rw-r--r--sound/soc/sof/pcm.c23
-rw-r--r--sound/soc/sof/sof-audio.c22
-rw-r--r--sound/soc/sof/sof-audio.h6
5 files changed, 47 insertions, 18 deletions
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 79d818e6a0fa..8de422604ad5 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -337,7 +337,13 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
/* cmd must be for audio stream */
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!sdev->dspless_mode_selected)
+ break;
+ fallthrough;
case SNDRV_PCM_TRIGGER_START:
+ if (hstream->running)
+ break;
+
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
1 << hstream->index,
1 << hstream->index);
@@ -360,8 +366,11 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
hstream->running = true;
break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (!sdev->dspless_mode_selected)
+ break;
+ fallthrough;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
sd_offset,
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 6a4c91ea47ed..9e2b6c45080d 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -836,5 +836,6 @@ const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
.pcm_setup = sof_ipc4_pcm_setup,
.pcm_free = sof_ipc4_pcm_free,
.delay = sof_ipc4_pcm_delay,
- .ipc_first_on_start = true
+ .ipc_first_on_start = true,
+ .platform_stop_during_hw_free = true,
};
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 127b68caf9e1..567db32173a8 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -211,16 +211,22 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
dev_dbg(component->dev, "pcm: free stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
- /* free PCM in the DSP */
- if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) {
- ret = pcm_ops->hw_free(component, substream);
- if (ret < 0)
- err = ret;
+ if (spcm->prepared[substream->stream]) {
+ /* stop DMA first if needed */
+ if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
+ snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);
+
+ /* free PCM in the DSP */
+ if (pcm_ops && pcm_ops->hw_free) {
+ ret = pcm_ops->hw_free(component, substream);
+ if (ret < 0)
+ err = ret;
+ }
spcm->prepared[substream->stream] = false;
}
- /* stop DMA */
+ /* reset DMA */
ret = snd_sof_pcm_platform_hw_free(sdev, substream);
if (ret < 0) {
dev_err(component->dev, "error: platform hw free failed\n");
@@ -362,8 +368,9 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
- /* invoke platform trigger to stop DMA even if pcm_ops failed */
- snd_sof_pcm_platform_trigger(sdev, substream, cmd);
+ /* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */
+ if (!pcm_ops || (pcm_ops && !pcm_ops->platform_stop_during_hw_free))
+ snd_sof_pcm_platform_trigger(sdev, substream, cmd);
break;
default:
break;
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index 7651644fcd62..1cbda595c518 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -805,16 +805,22 @@ int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *subs
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
int ret;
- /* Send PCM_FREE IPC to reset pipeline */
- if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) {
- ret = pcm_ops->hw_free(sdev->component, substream);
- if (ret < 0)
- return ret;
- }
+ if (spcm->prepared[substream->stream]) {
+ /* stop DMA first if needed */
+ if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
+ snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);
+
+ /* Send PCM_FREE IPC to reset pipeline */
+ if (pcm_ops && pcm_ops->hw_free) {
+ ret = pcm_ops->hw_free(sdev->component, substream);
+ if (ret < 0)
+ return ret;
+ }
- spcm->prepared[substream->stream] = false;
+ spcm->prepared[substream->stream] = false;
+ }
- /* stop the DMA */
+ /* reset the DMA */
ret = snd_sof_pcm_platform_hw_free(sdev, substream);
if (ret < 0)
return ret;
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 6c64376858b3..a090a9eb4828 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -108,6 +108,11 @@ struct snd_sof_dai_config_data {
* STOP pcm trigger
* @ipc_first_on_start: Send IPC before invoking platform trigger during
* START/PAUSE_RELEASE triggers
+ * @platform_stop_during_hw_free: Invoke the platform trigger during hw_free. This is needed for
+ * IPC4 where a pipeline is only paused during stop/pause/suspend
+ * triggers. The FW keeps the host DMA running in this case and
+ * therefore the host must do the same and should stop the DMA during
+ * hw_free.
*/
struct sof_ipc_pcm_ops {
int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream,
@@ -123,6 +128,7 @@ struct sof_ipc_pcm_ops {
struct snd_pcm_substream *substream);
bool reset_hw_params_during_stop;
bool ipc_first_on_start;
+ bool platform_stop_during_hw_free;
};
/**