Commit 7a100d54 authored by Takashi Iwai's avatar Takashi Iwai Committed by Kamal Mostafa

ALSA: hda - Manage power well properly for resume

BugLink: http://bugs.launchpad.net/bugs/1621113

commit a52ff34e upstream.

For SKL and later Intel chips, we control the power well per codec
basis via link_power callback since the commit [03b135ce: ALSA:
hda - remove dependency on i915 power well for SKL].
However, there are a few exceptional cases where the gfx registers are
accessed from the audio driver: namely the wakeup override bit
toggling at (both system and runtime) resume.  This seems causing a
kernel warning when accessed during the power well down (and likely
resulting in the bogus register accesses).

This patch puts the proper power up / down sequence around the resume
code so that the wakeup bit is fiddled properly while the power is
up.  (The other callback, sync_audio_rate, is used only in the PCM
callback, so it's guaranteed in the power-on.)

Also, by this proper power up/down, the instantaneous flip of wakeup
bit in the resume callback that was introduced by the commit
[033ea349: ALSA: hda - Fix Skylake codec timeout] becomes
superfluous, as snd_hdac_display_power() already does it.  So we can
clean it up together.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96214
Fixes: 03b135ce ('ALSA: hda - remove dependency on i915 power well for SKL')
Cc: <stable@vger.kernel.org> # v4.2+
Tested-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
Signed-off-by: default avatarKamal Mostafa <kamal@canonical.com>
parent 15d4867b
...@@ -944,20 +944,23 @@ static int azx_resume(struct device *dev) ...@@ -944,20 +944,23 @@ static int azx_resume(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev); struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip; struct azx *chip;
struct hda_intel *hda; struct hda_intel *hda;
struct hdac_bus *bus;
if (!card) if (!card)
return 0; return 0;
chip = card->private_data; chip = card->private_data;
hda = container_of(chip, struct hda_intel, chip); hda = container_of(chip, struct hda_intel, chip);
bus = azx_bus(chip);
if (chip->disabled || hda->init_failed || !chip->running) if (chip->disabled || hda->init_failed || !chip->running)
return 0; return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
&& hda->need_i915_power) { snd_hdac_display_power(bus, true);
snd_hdac_display_power(azx_bus(chip), true); if (hda->need_i915_power)
haswell_set_bclk(hda); haswell_set_bclk(hda);
} }
if (chip->msi) if (chip->msi)
if (pci_enable_msi(pci) < 0) if (pci_enable_msi(pci) < 0)
chip->msi = 0; chip->msi = 0;
...@@ -967,6 +970,11 @@ static int azx_resume(struct device *dev) ...@@ -967,6 +970,11 @@ static int azx_resume(struct device *dev)
hda_intel_init_chip(chip, true); hda_intel_init_chip(chip, true);
/* power down again for link-controlled chips */
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
!hda->need_i915_power)
snd_hdac_display_power(bus, false);
snd_power_change_state(card, SNDRV_CTL_POWER_D0); snd_power_change_state(card, SNDRV_CTL_POWER_D0);
trace_azx_resume(chip); trace_azx_resume(chip);
...@@ -1046,6 +1054,7 @@ static int azx_runtime_resume(struct device *dev) ...@@ -1046,6 +1054,7 @@ static int azx_runtime_resume(struct device *dev)
chip = card->private_data; chip = card->private_data;
hda = container_of(chip, struct hda_intel, chip); hda = container_of(chip, struct hda_intel, chip);
bus = azx_bus(chip);
if (chip->disabled || hda->init_failed) if (chip->disabled || hda->init_failed)
return 0; return 0;
...@@ -1053,15 +1062,9 @@ static int azx_runtime_resume(struct device *dev) ...@@ -1053,15 +1062,9 @@ static int azx_runtime_resume(struct device *dev)
return 0; return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
bus = azx_bus(chip); snd_hdac_display_power(bus, true);
if (hda->need_i915_power) { if (hda->need_i915_power)
snd_hdac_display_power(bus, true);
haswell_set_bclk(hda); haswell_set_bclk(hda);
} else {
/* toggle codec wakeup bit for STATESTS read */
snd_hdac_set_codec_wakeup(bus, true);
snd_hdac_set_codec_wakeup(bus, false);
}
} }
/* Read STATESTS before controller reset */ /* Read STATESTS before controller reset */
...@@ -1081,6 +1084,11 @@ static int azx_runtime_resume(struct device *dev) ...@@ -1081,6 +1084,11 @@ static int azx_runtime_resume(struct device *dev)
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
~STATESTS_INT_MASK); ~STATESTS_INT_MASK);
/* power down again for link-controlled chips */
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
!hda->need_i915_power)
snd_hdac_display_power(bus, false);
trace_azx_runtime_resume(chip); trace_azx_runtime_resume(chip);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment