summaryrefslogtreecommitdiff
path: root/sound/hda/codecs/hdmi/intelhdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/hda/codecs/hdmi/intelhdmi.c')
-rw-r--r--sound/hda/codecs/hdmi/intelhdmi.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/sound/hda/codecs/hdmi/intelhdmi.c b/sound/hda/codecs/hdmi/intelhdmi.c
index 6a7882544ab7..73141046d502 100644
--- a/sound/hda/codecs/hdmi/intelhdmi.c
+++ b/sound/hda/codecs/hdmi/intelhdmi.c
@@ -418,6 +418,28 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
}
+/*
+ * prepare ops override for HSW+
+ *
+ * Disable keep-alive before the converter format and audio infoframe are
+ * reprogrammed by the PCM prepare sequence. Changing the audio format (e.g.
+ * the channel count when switching to multichannel PCM) while a keep-alive
+ * stream is active is not safe, so release keep-alive here, early in the
+ * sequence. It is re-enabled once the new stream has been set up, in
+ * i915_hsw_setup_stream().
+ */
+static void i915_hsw_prepare(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin->silent_stream) {
+ silent_stream_set_kae(codec, per_pin, false);
+ /* wait for pending transfers in codec to clear */
+ usleep_range(100, 200);
+ }
+}
+
/* setup_stream ops override for HSW+ */
static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
hda_nid_t pin_nid, int dev_id, u32 stream_tag,
@@ -435,15 +457,16 @@ static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
haswell_verify_D0(codec, cvt_nid, pin_nid);
- if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
- silent_stream_set_kae(codec, per_pin, false);
- /* wait for pending transfers in codec to clear */
- usleep_range(100, 200);
- }
-
res = snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
stream_tag, format);
+ /*
+ * Keep-alive was disabled in i915_hsw_prepare(), re-enable it now.
+ * The pin lookup above resolves to the same per_pin that prepare
+ * used (pin_nid comes from that per_pin), so this stays balanced; a
+ * NULL per_pin only occurs on a lookup failure that also implies no
+ * active keep-alive stream to restore.
+ */
if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
usleep_range(100, 200);
silent_stream_set_kae(codec, per_pin, true);
@@ -607,6 +630,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
codec->depop_delay = 0;
codec->auto_runtime_pm = 1;
+ spec->ops.prepare = i915_hsw_prepare;
spec->ops.setup_stream = i915_hsw_setup_stream;
spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
spec->ops.silent_stream = i915_set_silent_stream;