[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