Commit 17df3f55652f7ea8fb1197b5c32e227b3da9f215

Authored by Takashi Iwai
1 parent 2195b063f6

ALSA: hda - Apply pin-enablement workaround to all Haswell HDMI codecs

This is a revised patch based on Mengdong Lin's fix patch, which is a
supplement to a previous patch [1611a9c9: ALSA: hda - Add fixup for
Haswell to enable all pin and convertor widgets].

Some Haswell BIOS will disable the 2nd and 3rd pin/covertor widgets
when the HD-A controller changes state from D3 to D0.  So when the
controller resumes after a system or runtime suspend, these widgets
are disabled and programming these widgets to D0 will cause H/W error
and codec will not respond.

In addition, we found out that some BIOS disables the pins at S3
although it shows up at boot.  This confuses the driver utterly, and
the hardware falls into the fatal communication error like the above.

So in this patch, we apply intel_haswell_enable_all_pins() not only as
a fixup to a certain device (with 8086:2010) but to all Haswell
machines.  The codec driver basically assumes that all pins are
exposed, so it's anyway better to see them from the beginning.  Even
if all pins and converters are shown by this call, there should be no
regression in practice: the pin default configurations are still kept,
thus the disabled pins are handled as disabled by the driver
properly.

Signed-off-by: Mengdong Lin <mengdong.lin@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

Showing 1 changed file with 22 additions and 32 deletions Side-by-side Diff

sound/pci/hda/patch_hdmi.c
... ... @@ -1832,12 +1832,10 @@
1832 1832 #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
1833 1833  
1834 1834 static void intel_haswell_enable_all_pins(struct hda_codec *codec,
1835   - const struct hda_fixup *fix, int action)
  1835 + bool update_tree)
1836 1836 {
1837 1837 unsigned int vendor_param;
1838 1838  
1839   - if (action != HDA_FIXUP_ACT_PRE_PROBE)
1840   - return;
1841 1839 vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
1842 1840 INTEL_GET_VENDOR_VERB, 0);
1843 1841 if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
... ... @@ -1849,8 +1847,8 @@
1849 1847 if (vendor_param == -1)
1850 1848 return;
1851 1849  
1852   - snd_hda_codec_update_widgets(codec);
1853   - return;
  1850 + if (update_tree)
  1851 + snd_hda_codec_update_widgets(codec);
1854 1852 }
1855 1853  
1856 1854 static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
1857 1855  
1858 1856  
... ... @@ -1868,31 +1866,21 @@
1868 1866 INTEL_SET_VENDOR_VERB, vendor_param);
1869 1867 }
1870 1868  
  1869 +/* Haswell needs to re-issue the vendor-specific verbs before turning to D0.
  1870 + * Otherwise you may get severe h/w communication errors.
  1871 + */
  1872 +static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
  1873 + unsigned int power_state)
  1874 +{
  1875 + if (power_state == AC_PWRST_D0) {
  1876 + intel_haswell_enable_all_pins(codec, false);
  1877 + intel_haswell_fixup_enable_dp12(codec);
  1878 + }
1871 1879  
  1880 + snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
  1881 + snd_hda_codec_set_power_to_all(codec, fg, power_state);
  1882 +}
1872 1883  
1873   -/* available models for fixup */
1874   -enum {
1875   - INTEL_HASWELL,
1876   -};
1877   -
1878   -static const struct hda_model_fixup hdmi_models[] = {
1879   - {.id = INTEL_HASWELL, .name = "Haswell"},
1880   - {}
1881   -};
1882   -
1883   -static const struct snd_pci_quirk hdmi_fixup_tbl[] = {
1884   - SND_PCI_QUIRK(0x8086, 0x2010, "Haswell", INTEL_HASWELL),
1885   - {} /* terminator */
1886   -};
1887   -
1888   -static const struct hda_fixup hdmi_fixups[] = {
1889   - [INTEL_HASWELL] = {
1890   - .type = HDA_FIXUP_FUNC,
1891   - .v.func = intel_haswell_enable_all_pins,
1892   - },
1893   -};
1894   -
1895   -
1896 1884 static int patch_generic_hdmi(struct hda_codec *codec)
1897 1885 {
1898 1886 struct hdmi_spec *spec;
1899 1887  
... ... @@ -1904,11 +1892,10 @@
1904 1892 codec->spec = spec;
1905 1893 hdmi_array_init(spec, 4);
1906 1894  
1907   - snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups);
1908   - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1909   -
1910   - if (codec->vendor_id == 0x80862807)
  1895 + if (codec->vendor_id == 0x80862807) {
  1896 + intel_haswell_enable_all_pins(codec, true);
1911 1897 intel_haswell_fixup_enable_dp12(codec);
  1898 + }
1912 1899  
1913 1900 if (hdmi_parse_codec(codec) < 0) {
1914 1901 codec->spec = NULL;
... ... @@ -1916,6 +1903,9 @@
1916 1903 return -EINVAL;
1917 1904 }
1918 1905 codec->patch_ops = generic_hdmi_patch_ops;
  1906 + if (codec->vendor_id == 0x80862807)
  1907 + codec->patch_ops.set_power_state = haswell_set_power_state;
  1908 +
1919 1909 generic_hdmi_init_per_pins(codec);
1920 1910  
1921 1911 init_channel_allocations();