aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-09-02 06:33:02 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-26 20:18:14 -0400
commitdc780f7fc64b6ca11854cd5ac724b85fa1853495 (patch)
treef60823edae9767246927bdf99cec4802805f2cb1 /sound
parentc18c0f9da9d97ea6710804971b981456a40cd01a (diff)
ALSA: hda - Re-setup HDMI pin and audio infoframe on stream switches
commit b054087dbacee30a9dddaef2c9a96312146be04e upstream. When the transcoder:port mapping on Haswell HDMI/DP audio is changed during the stream playback, the sound gets lost. Typically this problem is seen when the user switches the graphics mode from eDP+DP to DP-only configuration, where CRTC 1 is used for DP in the former while CRTC 0 is used for the latter. The graphics controller notifies the change via the normal ELD update procedure, so we get the intrinsic event. For enabling the sound again, the HDMI audio driver needs to reset the pin and set up the audio infoframe again. This patch achieves it by: - keep the current status of channels and info frame setup in per_pin struct, - check the reconnection in the intrinsic event handler, - reset the pin and the re-invoke hdmi_setup_audio_infoframe() accordingly. The hdmi_setup_audio_infoframe() function has been changed, too, so that it can be invoked without passing the substream instance. The patch is mostly based on the work by Mengdong Lin. Cc: Mengdong Lin <mengdong.lin@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_hdmi.c41
1 files changed, 31 insertions, 10 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 5bc419452198..83c1ad54ae75 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -67,6 +67,8 @@ struct hdmi_spec_per_pin {
67 struct delayed_work work; 67 struct delayed_work work;
68 struct snd_kcontrol *eld_ctl; 68 struct snd_kcontrol *eld_ctl;
69 int repoll_count; 69 int repoll_count;
70 bool setup; /* the stream has been set up by prepare callback */
71 int channels; /* current number of channels */
70 bool non_pcm; 72 bool non_pcm;
71 bool chmap_set; /* channel-map override by ALSA API? */ 73 bool chmap_set; /* channel-map override by ALSA API? */
72 unsigned char chmap[8]; /* ALSA API channel-map */ 74 unsigned char chmap[8]; /* ALSA API channel-map */
@@ -868,18 +870,19 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
868 return true; 870 return true;
869} 871}
870 872
871static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, 873static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
872 bool non_pcm, 874 struct hdmi_spec_per_pin *per_pin,
873 struct snd_pcm_substream *substream) 875 bool non_pcm)
874{ 876{
875 struct hdmi_spec *spec = codec->spec;
876 struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
877 hda_nid_t pin_nid = per_pin->pin_nid; 877 hda_nid_t pin_nid = per_pin->pin_nid;
878 int channels = substream->runtime->channels; 878 int channels = per_pin->channels;
879 struct hdmi_eld *eld; 879 struct hdmi_eld *eld;
880 int ca; 880 int ca;
881 union audio_infoframe ai; 881 union audio_infoframe ai;
882 882
883 if (!channels)
884 return;
885
883 eld = &per_pin->sink_eld; 886 eld = &per_pin->sink_eld;
884 if (!eld->monitor_present) 887 if (!eld->monitor_present)
885 return; 888 return;
@@ -1263,6 +1266,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
1263 eld_changed = true; 1266 eld_changed = true;
1264 } 1267 }
1265 if (update_eld) { 1268 if (update_eld) {
1269 bool old_eld_valid = pin_eld->eld_valid;
1266 pin_eld->eld_valid = eld->eld_valid; 1270 pin_eld->eld_valid = eld->eld_valid;
1267 eld_changed = pin_eld->eld_size != eld->eld_size || 1271 eld_changed = pin_eld->eld_size != eld->eld_size ||
1268 memcmp(pin_eld->eld_buffer, eld->eld_buffer, 1272 memcmp(pin_eld->eld_buffer, eld->eld_buffer,
@@ -1272,6 +1276,18 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
1272 eld->eld_size); 1276 eld->eld_size);
1273 pin_eld->eld_size = eld->eld_size; 1277 pin_eld->eld_size = eld->eld_size;
1274 pin_eld->info = eld->info; 1278 pin_eld->info = eld->info;
1279
1280 /* Haswell-specific workaround: re-setup when the transcoder is
1281 * changed during the stream playback
1282 */
1283 if (codec->vendor_id == 0x80862807 &&
1284 eld->eld_valid && !old_eld_valid && per_pin->setup) {
1285 snd_hda_codec_write(codec, pin_nid, 0,
1286 AC_VERB_SET_AMP_GAIN_MUTE,
1287 AMP_OUT_UNMUTE);
1288 hdmi_setup_audio_infoframe(codec, per_pin,
1289 per_pin->non_pcm);
1290 }
1275 } 1291 }
1276 mutex_unlock(&pin_eld->lock); 1292 mutex_unlock(&pin_eld->lock);
1277 1293
@@ -1444,14 +1460,17 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1444 hda_nid_t cvt_nid = hinfo->nid; 1460 hda_nid_t cvt_nid = hinfo->nid;
1445 struct hdmi_spec *spec = codec->spec; 1461 struct hdmi_spec *spec = codec->spec;
1446 int pin_idx = hinfo_to_pin_index(spec, hinfo); 1462 int pin_idx = hinfo_to_pin_index(spec, hinfo);
1447 hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid; 1463 struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
1464 hda_nid_t pin_nid = per_pin->pin_nid;
1448 bool non_pcm; 1465 bool non_pcm;
1449 1466
1450 non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); 1467 non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
1468 per_pin->channels = substream->runtime->channels;
1469 per_pin->setup = true;
1451 1470
1452 hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); 1471 hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
1453 1472
1454 hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream); 1473 hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
1455 1474
1456 return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); 1475 return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
1457} 1476}
@@ -1491,6 +1510,9 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
1491 snd_hda_spdif_ctls_unassign(codec, pin_idx); 1510 snd_hda_spdif_ctls_unassign(codec, pin_idx);
1492 per_pin->chmap_set = false; 1511 per_pin->chmap_set = false;
1493 memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); 1512 memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
1513
1514 per_pin->setup = false;
1515 per_pin->channels = 0;
1494 } 1516 }
1495 1517
1496 return 0; 1518 return 0;
@@ -1626,8 +1648,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1626 per_pin->chmap_set = true; 1648 per_pin->chmap_set = true;
1627 memcpy(per_pin->chmap, chmap, sizeof(chmap)); 1649 memcpy(per_pin->chmap, chmap, sizeof(chmap));
1628 if (prepared) 1650 if (prepared)
1629 hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm, 1651 hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
1630 substream);
1631 1652
1632 return 0; 1653 return 0;
1633} 1654}