aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2014-02-03 18:54:04 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-06 14:08:17 -0500
commit2b1461bbae34fc229cb5f58e5980aa32ee09ee77 (patch)
treee32c3a5953ae2f8b89549337738205797d4b89d3
parentc6a3cab88784e5d6d97ef57061b8fa75a4b67726 (diff)
ALSA: hda/hdmi - allow PIN_OUT to be dynamically enabled
(This is upstream 75fae117a5db "ALSA: hda/hdmi - allow PIN_OUT to be dynamically enabled", backported to stable 3.10 through 3.12. 3.13 and later can take the original patch.) Commit 384a48d71520 "ALSA: hda: HDMI: Support codecs with fewer cvts than pins" dynamically enabled each pin widget's PIN_OUT only when the pin was actively in use. This was required on certain NVIDIA CODECs for correct operation. Specifically, if multiple pin widgets each had their mux input select the same audio converter widget and each pin widget had PIN_OUT enabled, then only one of the pin widgets would actually receive the audio, and often not the one the user wanted! However, this apparently broke some Intel systems, and commit 6169b673618b "ALSA: hda - Always turn on pins for HDMI/DP" reverted the dynamic setting of PIN_OUT. This in turn broke the afore-mentioned NVIDIA CODECs. This change supports either dynamic or static handling of PIN_OUT, selected by a flag set up during CODEC initialization. This flag is enabled for all recent NVIDIA GPUs. Reported-by: Uosis <uosisl@gmail.com> Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--sound/pci/hda/patch_hdmi.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 4d8495f023ec..ba442d24257a 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -86,6 +86,9 @@ struct hdmi_spec {
86 unsigned int channels_max; /* max over all cvts */ 86 unsigned int channels_max; /* max over all cvts */
87 87
88 struct hdmi_eld temp_eld; 88 struct hdmi_eld temp_eld;
89
90 bool dyn_pin_out;
91
89 /* 92 /*
90 * Non-generic ATI/NVIDIA specific 93 * Non-generic ATI/NVIDIA specific
91 */ 94 */
@@ -450,15 +453,25 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
450 453
451static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) 454static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
452{ 455{
456 struct hdmi_spec *spec = codec->spec;
457 int pin_out;
458
453 /* Unmute */ 459 /* Unmute */
454 if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) 460 if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
455 snd_hda_codec_write(codec, pin_nid, 0, 461 snd_hda_codec_write(codec, pin_nid, 0,
456 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 462 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
457 /* Enable pin out: some machines with GM965 gets broken output when 463
458 * the pin is disabled or changed while using with HDMI 464 if (spec->dyn_pin_out)
459 */ 465 /* Disable pin out until stream is active */
466 pin_out = 0;
467 else
468 /* Enable pin out: some machines with GM965 gets broken output
469 * when the pin is disabled or changed while using with HDMI
470 */
471 pin_out = PIN_OUT;
472
460 snd_hda_codec_write(codec, pin_nid, 0, 473 snd_hda_codec_write(codec, pin_nid, 0,
461 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 474 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
462} 475}
463 476
464static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) 477static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
@@ -1473,6 +1486,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1473 struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); 1486 struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
1474 hda_nid_t pin_nid = per_pin->pin_nid; 1487 hda_nid_t pin_nid = per_pin->pin_nid;
1475 bool non_pcm; 1488 bool non_pcm;
1489 int pinctl;
1476 1490
1477 non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); 1491 non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
1478 per_pin->channels = substream->runtime->channels; 1492 per_pin->channels = substream->runtime->channels;
@@ -1482,6 +1496,14 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1482 1496
1483 hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); 1497 hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
1484 1498
1499 if (spec->dyn_pin_out) {
1500 pinctl = snd_hda_codec_read(codec, pin_nid, 0,
1501 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1502 snd_hda_codec_write(codec, pin_nid, 0,
1503 AC_VERB_SET_PIN_WIDGET_CONTROL,
1504 pinctl | PIN_OUT);
1505 }
1506
1485 return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); 1507 return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
1486} 1508}
1487 1509
@@ -1501,6 +1523,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
1501 int cvt_idx, pin_idx; 1523 int cvt_idx, pin_idx;
1502 struct hdmi_spec_per_cvt *per_cvt; 1524 struct hdmi_spec_per_cvt *per_cvt;
1503 struct hdmi_spec_per_pin *per_pin; 1525 struct hdmi_spec_per_pin *per_pin;
1526 int pinctl;
1504 1527
1505 if (hinfo->nid) { 1528 if (hinfo->nid) {
1506 cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); 1529 cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
@@ -1517,6 +1540,14 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
1517 return -EINVAL; 1540 return -EINVAL;
1518 per_pin = get_pin(spec, pin_idx); 1541 per_pin = get_pin(spec, pin_idx);
1519 1542
1543 if (spec->dyn_pin_out) {
1544 pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
1545 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1546 snd_hda_codec_write(codec, per_pin->pin_nid, 0,
1547 AC_VERB_SET_PIN_WIDGET_CONTROL,
1548 pinctl & ~PIN_OUT);
1549 }
1550
1520 snd_hda_spdif_ctls_unassign(codec, pin_idx); 1551 snd_hda_spdif_ctls_unassign(codec, pin_idx);
1521 per_pin->chmap_set = false; 1552 per_pin->chmap_set = false;
1522 memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); 1553 memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
@@ -2486,6 +2517,7 @@ static int patch_nvhdmi(struct hda_codec *codec)
2486 return err; 2517 return err;
2487 2518
2488 spec = codec->spec; 2519 spec = codec->spec;
2520 spec->dyn_pin_out = true;
2489 2521
2490 return 0; 2522 return 0;
2491} 2523}