diff options
Diffstat (limited to 'sound/pci/hda/patch_hdmi.c')
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 109 |
1 files changed, 72 insertions, 37 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5ef95034d04..0cb5b89cd0c 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -68,6 +68,7 @@ struct hdmi_spec_per_pin { hda_nid_t pin_nid; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; + int mux_idx; hda_nid_t cvt_nid; struct hda_codec *codec; @@ -353,40 +354,43 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { #define get_pcm_rec(spec, idx) \ ((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx)) -static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid) +static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid) { + struct hdmi_spec *spec = codec->spec; int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) if (get_pin(spec, pin_idx)->pin_nid == pin_nid) return pin_idx; - snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid); + codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid); return -EINVAL; } -static int hinfo_to_pin_index(struct hdmi_spec *spec, +static int hinfo_to_pin_index(struct hda_codec *codec, struct hda_pcm_stream *hinfo) { + struct hdmi_spec *spec = codec->spec; int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) if (get_pcm_rec(spec, pin_idx)->stream == hinfo) return pin_idx; - snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo); + codec_warn(codec, "HDMI: hinfo %p not registered\n", hinfo); return -EINVAL; } -static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid) +static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid) { + struct hdmi_spec *spec = codec->spec; int cvt_idx; for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid) return cvt_idx; - snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid); + codec_warn(codec, "HDMI: cvt nid %d not registered\n", cvt_nid); return -EINVAL; } @@ -706,7 +710,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, for (i = 0; i < 8; i++) { channel = spec->ops.pin_get_slot_channel(codec, pin_nid, i); - printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", + codec_dbg(codec, "HDMI: ASP channel %d => slot %d\n", channel, i); } #endif @@ -755,8 +759,7 @@ static void hdmi_std_setup_channel_mapping(struct hda_codec *codec, int channel = (slotsetup & 0xf0) >> 4; err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot, channel); if (err) { - snd_printdd(KERN_NOTICE - "HDMI: channel mapping failed\n"); + codec_dbg(codec, "HDMI: channel mapping failed\n"); break; } } @@ -967,12 +970,12 @@ static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) int size; size = snd_hdmi_get_eld_size(codec, pin_nid); - printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); + codec_dbg(codec, "HDMI: ELD buf size is %d\n", size); for (i = 0; i < 8; i++) { size = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, i); - printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); + codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size); } #endif } @@ -994,12 +997,12 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) hdmi_write_dip_byte(codec, pin_nid, 0x0); hdmi_get_dip_index(codec, pin_nid, &pi, &bi); if (pi != i) - snd_printd(KERN_INFO "dip index %d: %d != %d\n", + codec_dbg(codec, "dip index %d: %d != %d\n", bi, pi, i); if (bi == 0) /* byte index wrapped around */ break; } - snd_printd(KERN_INFO + codec_dbg(codec, "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", i, size, j); } @@ -1062,6 +1065,7 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, { union audio_infoframe ai; + memset(&ai, 0, sizeof(ai)); if (conn_type == 0) { /* HDMI */ struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; @@ -1080,7 +1084,7 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, dp_ai->CC02_CT47 = active_channels - 1; dp_ai->CA = ca; } else { - snd_printd("HDMI: unknown connection type at pin %d\n", + codec_dbg(codec, "HDMI: unknown connection type at pin %d\n", pin_nid); return; } @@ -1092,8 +1096,8 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, */ if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, sizeof(ai))) { - snd_printdd("hdmi_pin_setup_infoframe: " - "pin=%d channels=%d ca=0x%02x\n", + codec_dbg(codec, + "hdmi_pin_setup_infoframe: pin=%d channels=%d ca=0x%02x\n", pin_nid, active_channels, ca); hdmi_stop_infoframe_trans(codec, pin_nid); @@ -1161,7 +1165,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll); static void jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack) { struct hdmi_spec *spec = codec->spec; - int pin_idx = pin_nid_to_pin_index(spec, jack->nid); + int pin_idx = pin_nid_to_pin_index(codec, jack->nid); if (pin_idx < 0) return; @@ -1180,7 +1184,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) return; jack->jack_dirty = 1; - _snd_printd(SND_PR_VERBOSE, + codec_dbg(codec, "HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n", codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA), !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); @@ -1195,7 +1199,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); - printk(KERN_INFO + codec_info(codec, "HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", codec->addr, tag, @@ -1217,7 +1221,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) { - snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); + codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag); return; } @@ -1244,7 +1248,7 @@ static void haswell_verify_D0(struct hda_codec *codec, msleep(40); pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT; - snd_printd("Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr); + codec_dbg(codec, "Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr); } } @@ -1274,8 +1278,8 @@ static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, else new_pinctl |= AC_PINCTL_EPT_NATIVE; - snd_printdd("hdmi_pin_hbr_setup: " - "NID=0x%x, %spinctl=0x%x\n", + codec_dbg(codec, + "hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n", pin_nid, pinctl == new_pinctl ? "" : "new-", new_pinctl); @@ -1302,7 +1306,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format)); if (err) { - snd_printdd("hdmi_setup_stream: HBR is not supported\n"); + codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n"); return err; } @@ -1341,6 +1345,8 @@ static int hdmi_choose_cvt(struct hda_codec *codec, if (cvt_idx == spec->num_cvts) return -ENODEV; + per_pin->mux_idx = mux_idx; + if (cvt_id) *cvt_id = cvt_idx; if (mux_id) @@ -1349,6 +1355,22 @@ static int hdmi_choose_cvt(struct hda_codec *codec, return 0; } +/* Assure the pin select the right convetor */ +static void intel_verify_pin_cvt_connect(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + hda_nid_t pin_nid = per_pin->pin_nid; + int mux_idx, curr; + + mux_idx = per_pin->mux_idx; + curr = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + if (curr != mux_idx) + snd_hda_codec_write_cache(codec, pin_nid, 0, + AC_VERB_SET_CONNECT_SEL, + mux_idx); +} + /* Intel HDMI workaround to fix audio routing issue: * For some Intel display codecs, pins share the same connection list. * So a conveter can be selected by multiple pins and playback on any of these @@ -1389,7 +1411,8 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec, for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { per_cvt = get_cvt(spec, cvt_idx); if (!per_cvt->assigned) { - snd_printdd("choose cvt %d for pin nid %d\n", + codec_dbg(codec, + "choose cvt %d for pin nid %d\n", cvt_idx, nid); snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, @@ -1416,7 +1439,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, int err; /* Validate hinfo */ - pin_idx = hinfo_to_pin_index(spec, hinfo); + pin_idx = hinfo_to_pin_index(codec, hinfo); if (snd_BUG_ON(pin_idx < 0)) return -EINVAL; per_pin = get_pin(spec, pin_idx); @@ -1482,9 +1505,8 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) hda_nid_t pin_nid = per_pin->pin_nid; if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { - snd_printk(KERN_WARNING - "HDMI: pin %d wcaps %#x " - "does not support connection list\n", + codec_warn(codec, + "HDMI: pin %d wcaps %#x does not support connection list\n", pin_nid, get_wcaps(codec, pin_nid)); return -EINVAL; } @@ -1527,7 +1549,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) else eld->eld_valid = false; - _snd_printd(SND_PR_VERBOSE, + codec_dbg(codec, "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid); @@ -1690,7 +1712,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (!nid || nodes < 0) { - snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n"); + codec_warn(codec, "HDMI: failed to get afg sub nodes\n"); return -EINVAL; } @@ -1744,12 +1766,25 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, { hda_nid_t cvt_nid = hinfo->nid; struct hdmi_spec *spec = codec->spec; - int pin_idx = hinfo_to_pin_index(spec, hinfo); + int pin_idx = hinfo_to_pin_index(codec, 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; + if (is_haswell_plus(codec) || is_valleyview(codec)) { + /* Verify pin:cvt selections to avoid silent audio after S3. + * After S3, the audio driver restores pin:cvt selections + * but this can happen before gfx is ready and such selection + * is overlooked by HW. Thus multiple pins can share a same + * default convertor and mute control will affect each other, + * which can cause a resumed audio playback become silent + * after S3. + */ + intel_verify_pin_cvt_connect(codec, per_pin); + intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx); + } + non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); per_pin->channels = substream->runtime->channels; @@ -1788,7 +1823,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, int pinctl; if (hinfo->nid) { - cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); + cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid); if (snd_BUG_ON(cvt_idx < 0)) return -EINVAL; per_cvt = get_cvt(spec, cvt_idx); @@ -1797,7 +1832,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, per_cvt->assigned = 0; hinfo->nid = 0; - pin_idx = hinfo_to_pin_index(spec, hinfo); + pin_idx = hinfo_to_pin_index(codec, hinfo); if (snd_BUG_ON(pin_idx < 0)) return -EINVAL; per_pin = get_pin(spec, pin_idx); @@ -2211,7 +2246,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec, return; /* override pins connection list */ - snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid); + codec_dbg(codec, "hdmi: haswell: override pin connection 0x%x\n", nid); snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids); } @@ -3132,8 +3167,8 @@ static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, else hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE; - snd_printdd("atihdmi_pin_hbr_setup: " - "NID=0x%x, %shbr-ctl=0x%x\n", + codec_dbg(codec, + "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n", pin_nid, hbr_ctl == hbr_ctl_new ? "" : "new-", hbr_ctl_new); |