diff options
author | Takashi Iwai <tiwai@suse.de> | 2016-08-04 16:38:36 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2016-08-10 09:05:17 -0400 |
commit | a52ff34e5ec61749c62c6618b76a9d6dbecee450 (patch) | |
tree | 1690217f584b284eb714a7509c3a7f0f9d3bba68 /sound/pci/hda | |
parent | 41f5e3bdbf706a9e98194bf0c4b62a875c02f170 (diff) |
ALSA: hda - Manage power well properly for resume
For SKL and later Intel chips, we control the power well per codec
basis via link_power callback since the commit [03b135cebc47: 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
[033ea349a7cd: 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: 03b135cebc47 ('ALSA: hda - remove dependency on i915 power well for SKL')
Cc: <stable@vger.kernel.org> # v4.2+
Tested-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_intel.c | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 89dacf9b4e6c..160c7f713722 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -906,20 +906,23 @@ static int azx_resume(struct device *dev) | |||
906 | struct snd_card *card = dev_get_drvdata(dev); | 906 | struct snd_card *card = dev_get_drvdata(dev); |
907 | struct azx *chip; | 907 | struct azx *chip; |
908 | struct hda_intel *hda; | 908 | struct hda_intel *hda; |
909 | struct hdac_bus *bus; | ||
909 | 910 | ||
910 | if (!card) | 911 | if (!card) |
911 | return 0; | 912 | return 0; |
912 | 913 | ||
913 | chip = card->private_data; | 914 | chip = card->private_data; |
914 | hda = container_of(chip, struct hda_intel, chip); | 915 | hda = container_of(chip, struct hda_intel, chip); |
916 | bus = azx_bus(chip); | ||
915 | if (chip->disabled || hda->init_failed || !chip->running) | 917 | if (chip->disabled || hda->init_failed || !chip->running) |
916 | return 0; | 918 | return 0; |
917 | 919 | ||
918 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL | 920 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
919 | && hda->need_i915_power) { | 921 | snd_hdac_display_power(bus, true); |
920 | snd_hdac_display_power(azx_bus(chip), true); | 922 | if (hda->need_i915_power) |
921 | snd_hdac_i915_set_bclk(azx_bus(chip)); | 923 | snd_hdac_i915_set_bclk(bus); |
922 | } | 924 | } |
925 | |||
923 | if (chip->msi) | 926 | if (chip->msi) |
924 | if (pci_enable_msi(pci) < 0) | 927 | if (pci_enable_msi(pci) < 0) |
925 | chip->msi = 0; | 928 | chip->msi = 0; |
@@ -929,6 +932,11 @@ static int azx_resume(struct device *dev) | |||
929 | 932 | ||
930 | hda_intel_init_chip(chip, true); | 933 | hda_intel_init_chip(chip, true); |
931 | 934 | ||
935 | /* power down again for link-controlled chips */ | ||
936 | if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && | ||
937 | !hda->need_i915_power) | ||
938 | snd_hdac_display_power(bus, false); | ||
939 | |||
932 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 940 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
933 | 941 | ||
934 | trace_azx_resume(chip); | 942 | trace_azx_resume(chip); |
@@ -1008,6 +1016,7 @@ static int azx_runtime_resume(struct device *dev) | |||
1008 | 1016 | ||
1009 | chip = card->private_data; | 1017 | chip = card->private_data; |
1010 | hda = container_of(chip, struct hda_intel, chip); | 1018 | hda = container_of(chip, struct hda_intel, chip); |
1019 | bus = azx_bus(chip); | ||
1011 | if (chip->disabled || hda->init_failed) | 1020 | if (chip->disabled || hda->init_failed) |
1012 | return 0; | 1021 | return 0; |
1013 | 1022 | ||
@@ -1015,15 +1024,9 @@ static int azx_runtime_resume(struct device *dev) | |||
1015 | return 0; | 1024 | return 0; |
1016 | 1025 | ||
1017 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | 1026 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
1018 | bus = azx_bus(chip); | 1027 | snd_hdac_display_power(bus, true); |
1019 | if (hda->need_i915_power) { | 1028 | if (hda->need_i915_power) |
1020 | snd_hdac_display_power(bus, true); | ||
1021 | snd_hdac_i915_set_bclk(bus); | 1029 | snd_hdac_i915_set_bclk(bus); |
1022 | } else { | ||
1023 | /* toggle codec wakeup bit for STATESTS read */ | ||
1024 | snd_hdac_set_codec_wakeup(bus, true); | ||
1025 | snd_hdac_set_codec_wakeup(bus, false); | ||
1026 | } | ||
1027 | } | 1030 | } |
1028 | 1031 | ||
1029 | /* Read STATESTS before controller reset */ | 1032 | /* Read STATESTS before controller reset */ |
@@ -1043,6 +1046,11 @@ static int azx_runtime_resume(struct device *dev) | |||
1043 | azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & | 1046 | azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & |
1044 | ~STATESTS_INT_MASK); | 1047 | ~STATESTS_INT_MASK); |
1045 | 1048 | ||
1049 | /* power down again for link-controlled chips */ | ||
1050 | if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && | ||
1051 | !hda->need_i915_power) | ||
1052 | snd_hdac_display_power(bus, false); | ||
1053 | |||
1046 | trace_azx_runtime_resume(chip); | 1054 | trace_azx_runtime_resume(chip); |
1047 | return 0; | 1055 | return 0; |
1048 | } | 1056 | } |