Skip to content

Commit 816938b

Browse files
kv2019ibroonie
authored andcommitted
ASoC: SOF: Intel: hda: fix ordering bug in resume flow
When HDA controller is resumed from suspend, i915 HDMI/DP codec requires that following order of actions is kept: - i915 display power up and configuration of link params - hda link reset and setup Current SOF HDA code delegates display codec power control to the codec driver. This works most of the time, but in runtime PM sequences, the above constraint may be violated. On platforms where BIOS values for HDA link parameters do not match hardware reset defaults, this may lead to errors in HDA verb transactions after resume. Fix the issue by explicitly powering the display codec in the HDA controller resume/suspend calls, thus ensuring correct ordering. Special handling is needed for the D0i3 flow, where display power must be turned off even though DSP is left powered. Now that we have more invocations of the display power helper functions, the conditional checks surrounding each call have been moved inside hda_codec_i915_display_power(). The two special cases of display powering at initial probe are handled separately. The intent is to avoid powering the display whenever no display codecs are used. Note that early powering of display was removed in commit 687ae9e ("ASoC: intel: skl: Fix display power regression"). This change was also copied to the SOF driver. No failures have resulted as hardware default values for link parameters have worked out of the box. However with recent i915 driver changes like done in commit 87c1694 ("drm/i915: save AUD_FREQ_CNTRL state at audio domain suspend"), this does not hold anymore and errors are hit. Cc: Takashi Iwai <[email protected]> Signed-off-by: Kai Vehmanen <[email protected]> Reviewed-by: Ranjani Sridharan <[email protected]> Reviewed-by: Pierre-Louis Bossart <[email protected]> Reviewed-by: Takashi Iwai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 43bcb1c commit 816938b

File tree

3 files changed

+20
-5
lines changed

3 files changed

+20
-5
lines changed

sound/soc/sof/intel/hda-codec.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,10 @@ void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable)
174174
{
175175
struct hdac_bus *bus = sof_to_bus(sdev);
176176

177-
dev_dbg(bus->dev, "Turning i915 HDAC power %d\n", enable);
178-
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable);
177+
if (HDA_IDISP_CODEC(bus->codec_mask)) {
178+
dev_dbg(bus->dev, "Turning i915 HDAC power %d\n", enable);
179+
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable);
180+
}
179181
}
180182
EXPORT_SYMBOL_NS(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
181183

@@ -189,7 +191,8 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev)
189191
if (ret < 0)
190192
return ret;
191193

192-
hda_codec_i915_display_power(sdev, true);
194+
/* codec_mask not yet known, power up for probe */
195+
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
193196

194197
return 0;
195198
}
@@ -200,7 +203,8 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
200203
struct hdac_bus *bus = sof_to_bus(sdev);
201204
int ret;
202205

203-
hda_codec_i915_display_power(sdev, false);
206+
/* power down unconditionally */
207+
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
204208

205209
ret = snd_hdac_i915_exit(bus);
206210

sound/soc/sof/intel/hda-dsp.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
428428
return ret;
429429
}
430430

431+
/* display codec can powered off after link reset */
432+
hda_codec_i915_display_power(sdev, false);
433+
431434
return 0;
432435
}
433436

@@ -439,6 +442,9 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
439442
#endif
440443
int ret;
441444

445+
/* display codec must be powered before link reset */
446+
hda_codec_i915_display_power(sdev, true);
447+
442448
/*
443449
* clear TCSEL to clear playback on some HD Audio
444450
* codecs. PCI TCSEL is defined in the Intel manuals.
@@ -482,6 +488,8 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
482488
struct pci_dev *pci = to_pci_dev(sdev->dev);
483489

484490
if (sdev->s0_suspend) {
491+
hda_codec_i915_display_power(sdev, true);
492+
485493
/* restore L1SEN bit */
486494
if (hda->l1_support_changed)
487495
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
@@ -531,6 +539,9 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev)
531539
int ret;
532540

533541
if (sdev->s0_suspend) {
542+
/* we can't keep a wakeref to display driver at suspend */
543+
hda_codec_i915_display_power(sdev, false);
544+
534545
/* enable L1SEN to make sure the system can enter S0Ix */
535546
hda->l1_support_changed =
536547
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,

sound/soc/sof/intel/hda.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
381381
hda_codec_probe_bus(sdev, hda_codec_use_common_hdmi);
382382

383383
if (!HDA_IDISP_CODEC(bus->codec_mask))
384-
hda_codec_i915_display_power(sdev, false);
384+
hda_codec_i915_exit(sdev);
385385

386386
/*
387387
* we are done probing so decrement link counts

0 commit comments

Comments
 (0)