diff options
| author | Mark Brown <broonie@kernel.org> | 2023-03-22 21:44:46 +0300 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2023-03-22 21:44:46 +0300 |
| commit | f134bb6e284cefef18ab0273954c32f08d61fa1f (patch) | |
| tree | f279626cdfdf3389890de04aed0fe4845015aa58 | |
| parent | 59385ed41c37b609c70a1ebb46003e4cc6685ec0 (diff) | |
| parent | 51ce3e6effab4fd4e13a3f187f4e256259f6e5a4 (diff) | |
| download | linux-f134bb6e284cefef18ab0273954c32f08d61fa1f.tar.xz | |
ASoC: SOF: pcm/Intel: Handle IPC dependent sequencing
Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:
IPC3 and IPC4 firmwares handle and execute tasks at different
stages, like managing DMAs. In most cases these are aligned, but
we have few exceptions that needs to be handled differently.
This series introduces flags to handle the differing cases to make sure that
the correct sequencing is used regerless of the IPC version.
| -rw-r--r-- | sound/soc/sof/intel/hda-dai.c | 1 | ||||
| -rw-r--r-- | sound/soc/sof/ipc3-pcm.c | 1 | ||||
| -rw-r--r-- | sound/soc/sof/ipc4-pcm.c | 3 | ||||
| -rw-r--r-- | sound/soc/sof/pcm.c | 29 | ||||
| -rw-r--r-- | sound/soc/sof/sof-audio.h | 6 |
5 files changed, 31 insertions, 9 deletions
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 9637f0f44b01..46a17afdd1ea 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -305,7 +305,6 @@ static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct switch (cmd) { case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: ret = hda_link_dma_cleanup(substream, hext_stream, dai, codec_dai); if (ret < 0) { dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index b29d93e0d216..b7f1eb21ca26 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -382,4 +382,5 @@ const struct sof_ipc_pcm_ops ipc3_pcm_ops = { .hw_free = sof_ipc3_pcm_hw_free, .trigger = sof_ipc3_pcm_trigger, .dai_link_fixup = sof_ipc3_pcm_dai_link_fixup, + .reset_hw_params_during_stop = true, }; diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index db64200ba1e5..a2cd21256e44 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -835,5 +835,6 @@ const struct sof_ipc_pcm_ops ipc4_pcm_ops = { .dai_link_fixup = sof_ipc4_pcm_dai_link_fixup, .pcm_setup = sof_ipc4_pcm_setup, .pcm_free = sof_ipc4_pcm_free, - .delay = sof_ipc4_pcm_delay + .delay = sof_ipc4_pcm_delay, + .ipc_first_on_start = true }; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 445acb5c3a21..d9b4633bba7a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -301,6 +301,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component, ipc_first = true; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (pcm_ops && pcm_ops->ipc_first_on_start) + ipc_first = true; break; case SNDRV_PCM_TRIGGER_START: if (spcm->stream[substream->stream].suspend_ignored) { @@ -312,6 +314,9 @@ static int sof_pcm_trigger(struct snd_soc_component *component, spcm->stream[substream->stream].suspend_ignored = false; return 0; } + + if (pcm_ops && pcm_ops->ipc_first_on_start) + ipc_first = true; break; case SNDRV_PCM_TRIGGER_SUSPEND: if (sdev->system_suspend_target == SOF_SUSPEND_S0IX && @@ -328,26 +333,36 @@ static int sof_pcm_trigger(struct snd_soc_component *component, fallthrough; case SNDRV_PCM_TRIGGER_STOP: ipc_first = true; - reset_hw_params = true; + if (pcm_ops && pcm_ops->reset_hw_params_during_stop) + reset_hw_params = true; break; default: dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd); return -EINVAL; } - /* - * DMA and IPC sequence is different for start and stop. Need to send - * STOP IPC before stop DMA - */ if (!ipc_first) snd_sof_pcm_platform_trigger(sdev, substream, cmd); if (pcm_ops && pcm_ops->trigger) ret = pcm_ops->trigger(component, substream, cmd); - /* need to STOP DMA even if trigger IPC failed */ - if (ipc_first) + switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_START: + /* invoke platform trigger to start DMA only if pcm_ops is successful */ + if (ipc_first && !ret) + snd_sof_pcm_platform_trigger(sdev, substream, cmd); + break; + 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); + break; + default: + break; + } /* free PCM if reset_hw_params is set and the STOP IPC is successful */ if (!ret && reset_hw_params) diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index d220af5f08fb..6c64376858b3 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -104,6 +104,10 @@ struct snd_sof_dai_config_data { * @pcm_free: Function pointer for PCM free that can be used for freeing any * additional memory in the SOF PCM stream structure * @delay: Function pointer for pcm delay calculation + * @reset_hw_params_during_stop: Flag indicating whether the hw_params should be reset during the + * STOP pcm trigger + * @ipc_first_on_start: Send IPC before invoking platform trigger during + * START/PAUSE_RELEASE triggers */ struct sof_ipc_pcm_ops { int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream, @@ -117,6 +121,8 @@ struct sof_ipc_pcm_ops { void (*pcm_free)(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm); snd_pcm_sframes_t (*delay)(struct snd_soc_component *component, struct snd_pcm_substream *substream); + bool reset_hw_params_during_stop; + bool ipc_first_on_start; }; /** |
