[alsa-devel] [PATCH] ALSA: hda/hdmi - allow PIN_OUT to be dynamically enabled

Takashi Iwai tiwai at suse.de
Fri Jan 31 07:44:26 CET 2014


At Thu, 30 Jan 2014 11:52:16 -0700,
Stephen Warren wrote:
> 
> From: Stephen Warren <swarren at nvidia.com>
> 
> 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 at gmail.com>
> Cc: <stable at vger.kernel.org> # v3.13
> Signed-off-by: Stephen Warren <swarren at nvidia.com>

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
> 


More information about the Alsa-devel mailing list