From 83f26ad2c909083fa638d2df1b1a25bcbf2d1be2 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 10 Apr 2013 12:26:07 +0200 Subject: [PATCH] ALSA: hda - fixup D3 pin and right channel mute on Haswell HDMI audio When graphics initializes the HDMI chip, sometimes this leads to pins going into D3 and right channel being muted. If the audio driver finishes initialization before the graphic driver does, this situation becomes permanent. This is a workaround that checks for this situation and corrects it on playback prepare. It has been verified working on at least one machine. BugLink: https://bugs.launchpad.net/bugs/1167270 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ede82156da0f..32930e668854 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1018,6 +1018,41 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) hdmi_non_intrinsic_event(codec, res); } +static void haswell_verify_pin_D0(struct hda_codec *codec, hda_nid_t nid) +{ + int pwr, lamp, ramp; + + pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); + pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT; + if (pwr != AC_PWRST_D0) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + msleep(40); + pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); + pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT; + snd_printd("Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr); + } + + lamp = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT); + ramp = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT); + if (lamp != ramp) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT | lamp); + + lamp = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT); + ramp = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT); + snd_printd("Haswell HDMI audio: Mute after set on pin 0x%x: [0x%x 0x%x]\n", nid, lamp, ramp); + } +} + /* * Callbacks */ @@ -1032,6 +1067,9 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, int pinctl; int new_pinctl = 0; + if (codec->vendor_id == 0x80862807) + haswell_verify_pin_D0(codec, pin_nid); + if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) { pinctl = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); -- 2.39.2