Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: hda - Update BCLK also at hotplug for i915 HSW/BDW

The recent bug report suggests that BCLK setup for i915 HSW/BDW needs
to be updated at each HDMI hotplug, not only at initialization and
resume. That is, we need to update HSW_EM4 and HSW_EM5 registers at
ELD notification, too. Otherwise the HDMI audio may be out of sync
and played in a wrong pitch.

However, the HDA codec driver has no access to the controller
registers, and currently the code managing these registers is in
hda_intel.c, i.e. local to the controller driver. For allowing the
explicit BCLK update from the codec driver, as in this patch, the
former haswell_set_bclk() in hda_intel.c is moved to hdac_i915.c and
exposed as snd_hdac_i915_set_bclk(). This is called from both the HDA
controller driver and intel_pin_eld_notify() in HDMI codec driver.

Along with this change, snd_hdac_get_display_clk() gets dropped as
it's no longer used.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91410
Cc: <stable@vger.kernel.org> # v4.5+
Signed-off-by: Takashi Iwai <tiwai@suse.de>

+57 -65
+2 -3
include/sound/hda_i915.h
··· 9 9 #ifdef CONFIG_SND_HDA_I915 10 10 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); 11 11 int snd_hdac_display_power(struct hdac_bus *bus, bool enable); 12 - int snd_hdac_get_display_clk(struct hdac_bus *bus); 12 + void snd_hdac_i915_set_bclk(struct hdac_bus *bus); 13 13 int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate); 14 14 int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, 15 15 bool *audio_enabled, char *buffer, int max_bytes); ··· 25 25 { 26 26 return 0; 27 27 } 28 - static inline int snd_hdac_get_display_clk(struct hdac_bus *bus) 28 + static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus) 29 29 { 30 - return 0; 31 30 } 32 31 static inline int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, 33 32 int rate)
+50 -10
sound/hda/hdac_i915.c
··· 20 20 #include <sound/core.h> 21 21 #include <sound/hdaudio.h> 22 22 #include <sound/hda_i915.h> 23 + #include <sound/hda_register.h> 23 24 24 25 static struct i915_audio_component *hdac_acomp; 25 26 ··· 98 97 } 99 98 EXPORT_SYMBOL_GPL(snd_hdac_display_power); 100 99 100 + #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ 101 + ((pci)->device == 0x0c0c) || \ 102 + ((pci)->device == 0x0d0c) || \ 103 + ((pci)->device == 0x160c)) 104 + 101 105 /** 102 - * snd_hdac_get_display_clk - Get CDCLK in kHz 106 + * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW 103 107 * @bus: HDA core bus 104 108 * 105 - * This function is supposed to be used only by a HD-audio controller 106 - * driver that needs the interaction with i915 graphics. 109 + * Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK 110 + * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) 111 + * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: 112 + * BCLK = CDCLK * M / N 113 + * The values will be lost when the display power well is disabled and need to 114 + * be restored to avoid abnormal playback speed. 107 115 * 108 - * This function queries CDCLK value in kHz from the graphics driver and 109 - * returns the value. A negative code is returned in error. 116 + * Call this function at initializing and changing power well, as well as 117 + * at ELD notifier for the hotplug. 110 118 */ 111 - int snd_hdac_get_display_clk(struct hdac_bus *bus) 119 + void snd_hdac_i915_set_bclk(struct hdac_bus *bus) 112 120 { 113 121 struct i915_audio_component *acomp = bus->audio_component; 122 + struct pci_dev *pci = to_pci_dev(bus->dev); 123 + int cdclk_freq; 124 + unsigned int bclk_m, bclk_n; 114 125 115 - if (!acomp || !acomp->ops) 116 - return -ENODEV; 126 + if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) 127 + return; /* only for i915 binding */ 128 + if (!CONTROLLER_IN_GPU(pci)) 129 + return; /* only HSW/BDW */ 117 130 118 - return acomp->ops->get_cdclk_freq(acomp->dev); 131 + cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); 132 + switch (cdclk_freq) { 133 + case 337500: 134 + bclk_m = 16; 135 + bclk_n = 225; 136 + break; 137 + 138 + case 450000: 139 + default: /* default CDCLK 450MHz */ 140 + bclk_m = 4; 141 + bclk_n = 75; 142 + break; 143 + 144 + case 540000: 145 + bclk_m = 4; 146 + bclk_n = 90; 147 + break; 148 + 149 + case 675000: 150 + bclk_m = 8; 151 + bclk_n = 225; 152 + break; 153 + } 154 + 155 + snd_hdac_chip_writew(bus, HSW_EM4, bclk_m); 156 + snd_hdac_chip_writew(bus, HSW_EM5, bclk_n); 119 157 } 120 - EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk); 158 + EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); 121 159 122 160 /* There is a fixed mapping between audio pin node and display port 123 161 * on current Intel platforms:
+4 -52
sound/pci/hda/hda_intel.c
··· 857 857 #define azx_del_card_list(chip) /* NOP */ 858 858 #endif /* CONFIG_PM */ 859 859 860 - /* Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK 861 - * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) 862 - * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: 863 - * BCLK = CDCLK * M / N 864 - * The values will be lost when the display power well is disabled and need to 865 - * be restored to avoid abnormal playback speed. 866 - */ 867 - static void haswell_set_bclk(struct hda_intel *hda) 868 - { 869 - struct azx *chip = &hda->chip; 870 - int cdclk_freq; 871 - unsigned int bclk_m, bclk_n; 872 - 873 - if (!hda->need_i915_power) 874 - return; 875 - 876 - cdclk_freq = snd_hdac_get_display_clk(azx_bus(chip)); 877 - switch (cdclk_freq) { 878 - case 337500: 879 - bclk_m = 16; 880 - bclk_n = 225; 881 - break; 882 - 883 - case 450000: 884 - default: /* default CDCLK 450MHz */ 885 - bclk_m = 4; 886 - bclk_n = 75; 887 - break; 888 - 889 - case 540000: 890 - bclk_m = 4; 891 - bclk_n = 90; 892 - break; 893 - 894 - case 675000: 895 - bclk_m = 8; 896 - bclk_n = 225; 897 - break; 898 - } 899 - 900 - azx_writew(chip, HSW_EM4, bclk_m); 901 - azx_writew(chip, HSW_EM5, bclk_n); 902 - } 903 - 904 860 #if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) 905 861 /* 906 862 * power management ··· 914 958 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL 915 959 && hda->need_i915_power) { 916 960 snd_hdac_display_power(azx_bus(chip), true); 917 - haswell_set_bclk(hda); 961 + snd_hdac_i915_set_bclk(azx_bus(chip)); 918 962 } 919 963 if (chip->msi) 920 964 if (pci_enable_msi(pci) < 0) ··· 1014 1058 bus = azx_bus(chip); 1015 1059 if (hda->need_i915_power) { 1016 1060 snd_hdac_display_power(bus, true); 1017 - haswell_set_bclk(hda); 1061 + snd_hdac_i915_set_bclk(bus); 1018 1062 } else { 1019 1063 /* toggle codec wakeup bit for STATESTS read */ 1020 1064 snd_hdac_set_codec_wakeup(bus, true); ··· 1752 1796 /* initialize chip */ 1753 1797 azx_init_pci(chip); 1754 1798 1755 - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { 1756 - struct hda_intel *hda; 1757 - 1758 - hda = container_of(chip, struct hda_intel, chip); 1759 - haswell_set_bclk(hda); 1760 - } 1799 + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) 1800 + snd_hdac_i915_set_bclk(bus); 1761 1801 1762 1802 hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0); 1763 1803
+1
sound/pci/hda/patch_hdmi.c
··· 2232 2232 if (atomic_read(&(codec)->core.in_pm)) 2233 2233 return; 2234 2234 2235 + snd_hdac_i915_set_bclk(&codec->bus->core); 2235 2236 check_presence_and_report(codec, pin_nid); 2236 2237 } 2237 2238