Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion sound/soc/sof/intel/hda-dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ hda_link_dma_cleanup(struct snd_pcm_substream *substream,
if (!hlink)
return -EINVAL;

hda_stream = hstream_to_sof_hda_stream(hext_stream);
hda_stream->suspend_ignored = false;

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
Expand All @@ -157,7 +160,6 @@ hda_link_dma_cleanup(struct snd_pcm_substream *substream,
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;
Expand Down Expand Up @@ -280,6 +282,32 @@ static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
return hda_dai_hw_params_data(substream, params, dai, &data, flags);
}

static bool hda_dai_has_wov_fe(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dpcm *dpcm;
struct snd_sof_pcm *spcm;

if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
return false;

/*
* Only retain the BE for a connected WoV capture FE that is running
* or has already ignored its suspend trigger. An idle WoV FE may
* still be connected to the BE.
*/
for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) {
spcm = snd_sof_find_spcm_dai(sdev->component, dpcm->fe);
if (spcm && spcm->stream[SNDRV_PCM_STREAM_CAPTURE].d0i3_compatible &&
spcm->stream[SNDRV_PCM_STREAM_CAPTURE].dsp_max_burst_size_in_ms <= 1 &&
(dpcm->fe->dpcm[SNDRV_PCM_STREAM_CAPTURE].state == SND_SOC_DPCM_STATE_START ||
spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored))
return true;
}

return false;
}

/*
* In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
* (over IPC channel) and DMA state change (direct host register changes).
Expand All @@ -289,6 +317,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
{
const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
struct hdac_ext_stream *hext_stream;
struct sof_intel_hda_stream *hda_stream;
struct snd_sof_dev *sdev;
int ret;

Expand All @@ -305,6 +334,24 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
hext_stream = ops->get_hext_stream(sdev, dai, substream);
if (!hext_stream)
return -EINVAL;
hda_stream = hstream_to_sof_hda_stream(hext_stream);

if (cmd == SNDRV_PCM_TRIGGER_RESUME && hda_stream->suspend_ignored) {
hda_stream->suspend_ignored = false;
return 0;
}

/*
* Set the suspend_ignored flag for BE which is used with
* D0I3-compatible streams used for WoV to keep the firmware pipeline
* running.
*/
if (cmd == SNDRV_PCM_TRIGGER_SUSPEND &&
sdev->system_suspend_target == SOF_SUSPEND_S0IX &&
hda_dai_has_wov_fe(sdev, substream)) {
hda_stream->suspend_ignored = true;
return 0;
}

if (ops->pre_trigger) {
ret = ops->pre_trigger(sdev, dai, substream, cmd);
Expand Down
14 changes: 14 additions & 0 deletions sound/soc/sof/intel/hda-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,20 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
spcm->stream[substream->stream].d0i3_compatible)
flags |= SOF_HDA_STREAM_DMI_L1_COMPATIBLE;

/*
* Set the RESUME supported flag for WoV streams. The core will ignore
* the trigger but applications must not try to restart the WoV stream
* due to not supported RESUME.
* WoV streams can be indetified by:
* They are capture streams and
* They have the d0i3_compatible flag set and
* They don't use Deep Buffer
*/
if (direction == SNDRV_PCM_STREAM_CAPTURE &&
spcm->stream[substream->stream].d0i3_compatible &&
spcm->stream[substream->stream].dsp_max_burst_size_in_ms <= 1)
runtime->hw.info |= SNDRV_PCM_INFO_RESUME;
Comment thread
Copilot marked this conversation as resolved.

dsp_stream = hda_dsp_stream_get(sdev, direction, flags);
if (!dsp_stream) {
dev_err(sdev->dev, "error: no stream available\n");
Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ struct sof_intel_hda_stream {
struct hdac_ext_stream hext_stream;
struct sof_intel_stream sof_intel_stream;
int host_reserved; /* reserve host DMA channel */
bool suspend_ignored;
u32 flags;
struct completion ioc;
};
Expand Down
1 change: 0 additions & 1 deletion sound/soc/sof/ipc3-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,6 @@ const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
.trigger = sof_ipc3_pcm_trigger,
.dai_link_fixup = sof_ipc3_pcm_dai_link_fixup,
.reset_hw_params_during_stop = true,
.d0i3_supported_in_s0ix = true,
#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
.compress_ops = &sof_ipc3_compressed_ops,
#endif
Expand Down
23 changes: 17 additions & 6 deletions sound/soc/sof/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,18 +428,29 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
if (pcm_ops && pcm_ops->ipc_first_on_start)
ipc_first = true;
break;
case SNDRV_PCM_TRIGGER_RESUME:
if (spcm->stream[substream->stream].suspend_ignored) {
spcm->stream[substream->stream].suspend_ignored = false;
return 0;
}
spcm_err(spcm, substream->stream, "RESUME trigger is not supported\n");
return -EINVAL;
case SNDRV_PCM_TRIGGER_SUSPEND:
/*
* If DSP D0I3 is allowed during S0iX, set the suspend_ignored flag for
* D0I3-compatible streams to keep the firmware pipeline running
* Set the suspend_ignored flag for D0I3-compatible streams used
* for WoV to keep the firmware pipeline running.
* WoV streams can be indetified by:
* They are capture streams and
* They have the d0i3_compatible flag set and
* They don't use Deep Buffer
*/
if (pcm_ops && pcm_ops->d0i3_supported_in_s0ix &&
sdev->system_suspend_target == SOF_SUSPEND_S0IX &&
spcm->stream[substream->stream].d0i3_compatible) {
if (sdev->system_suspend_target == SOF_SUSPEND_S0IX &&
substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
spcm->stream[substream->stream].d0i3_compatible &&
spcm->stream[substream->stream].dsp_max_burst_size_in_ms <= 1) {
spcm->stream[substream->stream].suspend_ignored = true;
return 0;
}

/* On suspend the DMA must be stopped in DSPless mode */
if (sdev->dspless_mode_selected)
reset_hw_params = true;
Expand Down
3 changes: 2 additions & 1 deletion sound/soc/sof/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
* suspended, it is brought back to full power and then
* suspended again
*/
if (tplg_ops && tplg_ops->tear_down_all_pipelines && (old_state == SOF_DSP_PM_D0))
if (tplg_ops && tplg_ops->tear_down_all_pipelines && (old_state == SOF_DSP_PM_D0) &&
(target_state != SOF_DSP_PM_D0))
tplg_ops->tear_down_all_pipelines(sdev, false);

if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
Expand Down
2 changes: 0 additions & 2 deletions sound/soc/sof/sof-audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ struct snd_sof_dai_config_data {
* 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.
* @d0i3_supported_in_s0ix: Allow DSP D0I3 during S0iX
* @compress_ops: Pointer to ops for compressed streams
*/
struct sof_ipc_pcm_ops {
Expand All @@ -143,7 +142,6 @@ struct sof_ipc_pcm_ops {
bool reset_hw_params_during_stop;
bool ipc_first_on_start;
bool platform_stop_during_hw_free;
bool d0i3_supported_in_s0ix;
const struct snd_compress_ops *compress_ops;
};

Expand Down
Loading