At Thu, 30 Jan 2014 11:52:16 -0700,
Stephen Warren wrote:
> 
> From: Stephen Warren <[email protected]>
> 
> 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 <[email protected]>
> Cc: <[email protected]> # v3.13
> Signed-off-by: Stephen Warren <[email protected]>

Thanks, pulled now.

> ---
> v3.12 or earlier stable require some manual back-porting effort, or
> perhaps just a variety of other commits to be backported. I'm
> investigating exactly which commits, and whether they're appropriate
> for stable.

OK, that's appreciated.


Takashi

> ---
>  sound/pci/hda/patch_hdmi.c | 40 ++++++++++++++++++++++++++++++++++++----
>  1 file changed, 36 insertions(+), 4 deletions(-)
> 
> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> index 64f0a5e73a25..5ef95034d041 100644
> --- a/sound/pci/hda/patch_hdmi.c
> +++ b/sound/pci/hda/patch_hdmi.c
> @@ -132,6 +132,9 @@ struct hdmi_spec {
>  
>       struct hdmi_eld temp_eld;
>       struct hdmi_ops ops;
> +
> +     bool dyn_pin_out;
> +
>       /*
>        * Non-generic VIA/NVIDIA specific
>        */
> @@ -500,15 +503,25 @@ static void hdmi_write_dip_byte(struct hda_codec 
> *codec, hda_nid_t pin_nid,
>  
>  static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
>  {
> +     struct hdmi_spec *spec = codec->spec;
> +     int pin_out;
> +
>       /* Unmute */
>       if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
>               snd_hda_codec_write(codec, pin_nid, 0,
>                               AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
> -     /* Enable pin out: some machines with GM965 gets broken output when
> -      * the pin is disabled or changed while using with HDMI
> -      */
> +
> +     if (spec->dyn_pin_out)
> +             /* Disable pin out until stream is active */
> +             pin_out = 0;
> +     else
> +             /* Enable pin out: some machines with GM965 gets broken output
> +              * when the pin is disabled or changed while using with HDMI
> +              */
> +             pin_out = PIN_OUT;
> +
>       snd_hda_codec_write(codec, pin_nid, 0,
> -                         AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
> +                         AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
>  }
>  
>  static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
> @@ -1735,6 +1748,7 @@ static int generic_hdmi_playback_pcm_prepare(struct 
> hda_pcm_stream *hinfo,
>       struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
>       hda_nid_t pin_nid = per_pin->pin_nid;
>       bool non_pcm;
> +     int pinctl;
>  
>       non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
>       mutex_lock(&per_pin->lock);
> @@ -1744,6 +1758,14 @@ static int generic_hdmi_playback_pcm_prepare(struct 
> hda_pcm_stream *hinfo,
>       hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
>       mutex_unlock(&per_pin->lock);
>  
> +     if (spec->dyn_pin_out) {
> +             pinctl = snd_hda_codec_read(codec, pin_nid, 0,
> +                                         AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
> +             snd_hda_codec_write(codec, pin_nid, 0,
> +                                 AC_VERB_SET_PIN_WIDGET_CONTROL,
> +                                 pinctl | PIN_OUT);
> +     }
> +
>       return spec->ops.setup_stream(codec, cvt_nid, pin_nid, stream_tag, 
> format);
>  }
>  
> @@ -1763,6 +1785,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
>       int cvt_idx, pin_idx;
>       struct hdmi_spec_per_cvt *per_cvt;
>       struct hdmi_spec_per_pin *per_pin;
> +     int pinctl;
>  
>       if (hinfo->nid) {
>               cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
> @@ -1779,6 +1802,14 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
>                       return -EINVAL;
>               per_pin = get_pin(spec, pin_idx);
>  
> +             if (spec->dyn_pin_out) {
> +                     pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
> +                                     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
> +                     snd_hda_codec_write(codec, per_pin->pin_nid, 0,
> +                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
> +                                         pinctl & ~PIN_OUT);
> +             }
> +
>               snd_hda_spdif_ctls_unassign(codec, pin_idx);
>  
>               mutex_lock(&per_pin->lock);
> @@ -2840,6 +2871,7 @@ static int patch_nvhdmi(struct hda_codec *codec)
>               return err;
>  
>       spec = codec->spec;
> +     spec->dyn_pin_out = true;
>  
>       spec->ops.chmap_cea_alloc_validate_get_type =
>               nvhdmi_chmap_cea_alloc_validate_get_type;
> -- 
> 1.8.1.5
> 
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to