[alsa-devel] [PATCH v2 1/1] ALSA: hda - bug fix for invalid connection list of Haswell HDMI codec pin
From: Mengdong Lin mengdong.lin@intel.com
Haswell HDMI codec pins may report invalid connection list entries, which will cause failure to play audio via HDMI.
So this patch - allow generic hdmi patch to pick up and apply fixups for different codecs. - add fixup for Haswell to workaround this hardware issue: enable DP1.2 mode and override the connection list entries with proper value.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com Signed-off-by: Xingchao Wang xingchao.wang@intel.com
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 71555cc..42fdf14 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -38,6 +38,7 @@ #include <sound/tlv.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" #include "hda_jack.h"
static bool static_hdmi_pcm; @@ -79,6 +80,7 @@ struct hdmi_spec_per_pin { };
struct hdmi_spec { + struct hda_gen_spec gen; int num_cvts; struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
@@ -1687,6 +1689,54 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { .unsol_event = hdmi_unsol_event, };
+static void intel_haswell_fixup_connect_list(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + unsigned int vendor_param; + hda_nid_t list[3] = {0x2, 0x3, 0x4}; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0); + if (vendor_param == -1 || vendor_param & 0x02) + return; + + /* enable DP1.2 mode */ + vendor_param |= 0x02; + snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param); + + vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0); + if (vendor_param == -1 || !(vendor_param & 0x02)) + return; + + snd_hda_override_conn_list(codec, 0x06, 3, list); + hdmi_read_pin_conn(codec, 1); +} + + +/* available models for fixup */ +enum { + INTEL_HASWELL, +}; + +static const struct hda_model_fixup hdmi_models[] = { + {.id = INTEL_HASWELL, .name = "Haswell"}, + {} +}; + +static const struct snd_pci_quirk hdmi_fixup_tbl[] = { + SND_PCI_QUIRK(0x8086, 0x2010, "Haswell", INTEL_HASWELL), + {} /* terminator */ +}; + +static const struct hda_fixup hdmi_fixups[] = { + [INTEL_HASWELL] = { + .type = HDA_FIXUP_FUNC, + .v.func = intel_haswell_fixup_connect_list, + }, +}; + static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -1696,6 +1746,11 @@ static int patch_generic_hdmi(struct hda_codec *codec) return -ENOMEM;
codec->spec = spec; + snd_hda_gen_init(&spec->gen); + + snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; kfree(spec);
At Fri, 14 Dec 2012 16:53:50 -0500, mengdong.lin@intel.com wrote:
From: Mengdong Lin mengdong.lin@intel.com
Haswell HDMI codec pins may report invalid connection list entries, which will cause failure to play audio via HDMI.
So this patch
- allow generic hdmi patch to pick up and apply fixups for different codecs.
- add fixup for Haswell to workaround this hardware issue: enable DP1.2 mode and override the connection list entries with proper value.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com Signed-off-by: Xingchao Wang xingchao.wang@intel.com
Applied now. Thanks.
Takashi
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 71555cc..42fdf14 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -38,6 +38,7 @@ #include <sound/tlv.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" #include "hda_jack.h"
static bool static_hdmi_pcm; @@ -79,6 +80,7 @@ struct hdmi_spec_per_pin { };
struct hdmi_spec {
- struct hda_gen_spec gen; int num_cvts; struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
@@ -1687,6 +1689,54 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { .unsol_event = hdmi_unsol_event, };
+static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
+{
- unsigned int vendor_param;
- hda_nid_t list[3] = {0x2, 0x3, 0x4};
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
- vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
- if (vendor_param == -1 || vendor_param & 0x02)
return;
- /* enable DP1.2 mode */
- vendor_param |= 0x02;
- snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param);
- vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
- if (vendor_param == -1 || !(vendor_param & 0x02))
return;
- snd_hda_override_conn_list(codec, 0x06, 3, list);
- hdmi_read_pin_conn(codec, 1);
+}
+/* available models for fixup */ +enum {
- INTEL_HASWELL,
+};
+static const struct hda_model_fixup hdmi_models[] = {
- {.id = INTEL_HASWELL, .name = "Haswell"},
- {}
+};
+static const struct snd_pci_quirk hdmi_fixup_tbl[] = {
- SND_PCI_QUIRK(0x8086, 0x2010, "Haswell", INTEL_HASWELL),
- {} /* terminator */
+};
+static const struct hda_fixup hdmi_fixups[] = {
- [INTEL_HASWELL] = {
.type = HDA_FIXUP_FUNC,
.v.func = intel_haswell_fixup_connect_list,
- },
+};
static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -1696,6 +1746,11 @@ static int patch_generic_hdmi(struct hda_codec *codec) return -ENOMEM;
codec->spec = spec;
- snd_hda_gen_init(&spec->gen);
- snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; kfree(spec);
-- 1.7.9.5
At Fri, 14 Dec 2012 11:01:14 +0100, Takashi Iwai wrote:
At Fri, 14 Dec 2012 16:53:50 -0500, mengdong.lin@intel.com wrote:
From: Mengdong Lin mengdong.lin@intel.com
Haswell HDMI codec pins may report invalid connection list entries, which will cause failure to play audio via HDMI.
So this patch
- allow generic hdmi patch to pick up and apply fixups for different codecs.
- add fixup for Haswell to workaround this hardware issue: enable DP1.2 mode and override the connection list entries with proper value.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com Signed-off-by: Xingchao Wang xingchao.wang@intel.com
Applied now. Thanks.
Thinking this again, does the problem exist with Haswell codec in general, or only on certain machines? Since the fixup 8086:2010 is applied only for either PCI SSID or codec SSID, this won't be applied for the codec vendor ID.
If the bug is for all machines with the specific codec, better to add an explicit code like
static int patch_generic_hdmi(struct hda_codec *codec) { ....
if (codec->vendor_id == 0x80862807) intel_haswell_fixup_connect_list(codec);
if (hdmi_parse_codec(codec) < 0) { ....
thanks,
Takashi
Takashi
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 71555cc..42fdf14 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -38,6 +38,7 @@ #include <sound/tlv.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" #include "hda_jack.h"
static bool static_hdmi_pcm; @@ -79,6 +80,7 @@ struct hdmi_spec_per_pin { };
struct hdmi_spec {
- struct hda_gen_spec gen; int num_cvts; struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
@@ -1687,6 +1689,54 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { .unsol_event = hdmi_unsol_event, };
+static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
+{
- unsigned int vendor_param;
- hda_nid_t list[3] = {0x2, 0x3, 0x4};
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
- vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
- if (vendor_param == -1 || vendor_param & 0x02)
return;
- /* enable DP1.2 mode */
- vendor_param |= 0x02;
- snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param);
- vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
- if (vendor_param == -1 || !(vendor_param & 0x02))
return;
- snd_hda_override_conn_list(codec, 0x06, 3, list);
- hdmi_read_pin_conn(codec, 1);
+}
+/* available models for fixup */ +enum {
- INTEL_HASWELL,
+};
+static const struct hda_model_fixup hdmi_models[] = {
- {.id = INTEL_HASWELL, .name = "Haswell"},
- {}
+};
+static const struct snd_pci_quirk hdmi_fixup_tbl[] = {
- SND_PCI_QUIRK(0x8086, 0x2010, "Haswell", INTEL_HASWELL),
- {} /* terminator */
+};
+static const struct hda_fixup hdmi_fixups[] = {
- [INTEL_HASWELL] = {
.type = HDA_FIXUP_FUNC,
.v.func = intel_haswell_fixup_connect_list,
- },
+};
static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -1696,6 +1746,11 @@ static int patch_generic_hdmi(struct hda_codec *codec) return -ENOMEM;
codec->spec = spec;
- snd_hda_gen_init(&spec->gen);
- snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; kfree(spec);
-- 1.7.9.5
participants (2)
-
mengdong.lin@intel.com
-
Takashi Iwai