summaryrefslogtreecommitdiff
path: root/sound/pci/hda/patch_hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_hdmi.c')
-rw-r--r--sound/pci/hda/patch_hdmi.c109
1 files changed, 72 insertions, 37 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 5ef9503..0cb5b89 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);