Merge branch 'for-linus' into for-next
[cascardo/linux.git] / sound / pci / hda / patch_hdmi.c
index 5af372d..d2e57c7 100644 (file)
@@ -114,6 +114,9 @@ struct hdmi_ops {
        int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
                            hda_nid_t pin_nid, u32 stream_tag, int format);
 
+       void (*pin_cvt_fixup)(struct hda_codec *codec,
+                             struct hdmi_spec_per_pin *per_pin,
+                             hda_nid_t cvt_nid);
 };
 
 struct hdmi_pcm {
@@ -684,7 +687,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
        if (!channels)
                return;
 
-       if (is_haswell_plus(codec))
+       /* some HW (e.g. HSW+) needs reprogramming the amp at each time */
+       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);
@@ -864,9 +868,6 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
        struct hdmi_spec *spec = codec->spec;
        int err;
 
-       if (is_haswell_plus(codec))
-               haswell_verify_D0(codec, cvt_nid, pin_nid);
-
        err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format));
 
        if (err) {
@@ -884,7 +885,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
  * of the pin.
  */
 static int hdmi_choose_cvt(struct hda_codec *codec,
-                       int pin_idx, int *cvt_id, int *mux_id)
+                          int pin_idx, int *cvt_id)
 {
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_spec_per_pin *per_pin;
@@ -925,8 +926,6 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
 
        if (cvt_id)
                *cvt_id = cvt_idx;
-       if (mux_id)
-               *mux_id = mux_idx;
 
        return 0;
 }
@@ -1019,9 +1018,6 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
        int mux_idx;
        struct hdmi_spec *spec = codec->spec;
 
-       if (!is_haswell_plus(codec) && !is_valleyview_plus(codec))
-               return;
-
        /* On Intel platform, the mapping of converter nid to
         * mux index of the pins are always the same.
         * The pin nid may be 0, this means all pins will not
@@ -1032,6 +1028,17 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
                intel_not_share_assigned_cvt(codec, pin_nid, mux_idx);
 }
 
+/* skeleton caller of pin_cvt_fixup ops */
+static void pin_cvt_fixup(struct hda_codec *codec,
+                         struct hdmi_spec_per_pin *per_pin,
+                         hda_nid_t cvt_nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (spec->ops.pin_cvt_fixup)
+               spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid);
+}
+
 /* called in hdmi_pcm_open when no pin is assigned to the PCM
  * in dyn_pcm_assign mode.
  */
@@ -1049,7 +1056,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
        if (pcm_idx < 0)
                return -EINVAL;
 
-       err = hdmi_choose_cvt(codec, -1, &cvt_idx, NULL);
+       err = hdmi_choose_cvt(codec, -1, &cvt_idx);
        if (err)
                return err;
 
@@ -1057,7 +1064,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
        per_cvt->assigned = 1;
        hinfo->nid = per_cvt->cvt_nid;
 
-       intel_not_share_assigned_cvt_nid(codec, 0, per_cvt->cvt_nid);
+       pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid);
 
        set_bit(pcm_idx, &spec->pcm_in_use);
        /* todo: setup spdif ctls assign */
@@ -1089,7 +1096,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 {
        struct hdmi_spec *spec = codec->spec;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       int pin_idx, cvt_idx, pcm_idx, mux_idx = 0;
+       int pin_idx, cvt_idx, pcm_idx;
        struct hdmi_spec_per_pin *per_pin;
        struct hdmi_eld *eld;
        struct hdmi_spec_per_cvt *per_cvt = NULL;
@@ -1118,7 +1125,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                }
        }
 
-       err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx);
+       err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx);
        if (err < 0) {
                mutex_unlock(&spec->pcm_lock);
                return err;
@@ -1135,11 +1142,10 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 
        snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
                            AC_VERB_SET_CONNECT_SEL,
-                           mux_idx);
+                           per_pin->mux_idx);
 
        /* configure unused pins to choose other converters */
-       if (is_haswell_plus(codec) || is_valleyview_plus(codec))
-               intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx);
+       pin_cvt_fixup(codec, per_pin, 0);
 
        snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid);
 
@@ -1372,12 +1378,7 @@ static void update_eld(struct hda_codec *codec,
         *   and this can make HW reset converter selection on a pin.
         */
        if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
-               if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
-                       intel_verify_pin_cvt_connect(codec, per_pin);
-                       intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
-                                                    per_pin->mux_idx);
-               }
-
+               pin_cvt_fixup(codec, per_pin, 0);
                hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
        }
 
@@ -1396,7 +1397,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
        struct hda_codec *codec = per_pin->codec;
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_eld *eld = &spec->temp_eld;
-       struct hdmi_eld *pin_eld = &per_pin->sink_eld;
        hda_nid_t pin_nid = per_pin->pin_nid;
        /*
         * Always execute a GetPinSense verb here, even when called from
@@ -1413,15 +1413,15 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
        present = snd_hda_pin_sense(codec, pin_nid);
 
        mutex_lock(&per_pin->lock);
-       pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
-       if (pin_eld->monitor_present)
+       eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
+       if (eld->monitor_present)
                eld->eld_valid  = !!(present & AC_PINSENSE_ELDV);
        else
                eld->eld_valid = false;
 
        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);
+               codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
 
        if (eld->eld_valid) {
                if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer,
@@ -1441,7 +1441,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
        else
                update_eld(codec, per_pin, eld);
 
-       ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid;
+       ret = !repoll || !eld->monitor_present || eld->eld_valid;
 
        jack = snd_hda_jack_tbl_get(codec, pin_nid);
        if (jack)
@@ -1485,7 +1485,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
 
        mutex_lock(&per_pin->lock);
        eld->monitor_present = false;
-       size = snd_hdac_acomp_get_eld(&codec->bus->core, per_pin->pin_nid,
+       size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
                                      &eld->monitor_present, eld->eld_buffer,
                                      ELD_MAX_SIZE);
        if (size > 0) {
@@ -1712,7 +1712,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                 * skip pin setup and return 0 to make audio playback
                 * be ongoing
                 */
-               intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid);
+               pin_cvt_fixup(codec, NULL, cvt_nid);
                snd_hda_codec_setup_stream(codec, cvt_nid,
                                        stream_tag, 0, format);
                mutex_unlock(&spec->pcm_lock);
@@ -1725,23 +1725,21 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        }
        per_pin = get_pin(spec, pin_idx);
        pin_nid = per_pin->pin_nid;
-       if (is_haswell_plus(codec) || is_valleyview_plus(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);
-       }
+
+       /* 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.
+        */
+       pin_cvt_fixup(codec, per_pin, 0);
 
        /* Call sync_audio_rate to set the N/CTS/M manually if necessary */
        /* Todo: add DP1.2 MST audio support later */
        if (codec_has_acomp(codec))
-               snd_hdac_sync_audio_rate(&codec->bus->core, pin_nid, runtime->rate);
+               snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);
 
        non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
        mutex_lock(&per_pin->lock);
@@ -1838,6 +1836,18 @@ static const struct hda_pcm_ops generic_ops = {
        .cleanup = generic_hdmi_playback_pcm_cleanup,
 };
 
+static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
+{
+       struct hda_codec *codec = container_of(hdac, struct hda_codec, core);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+       if (!per_pin)
+               return 0;
+
+       return per_pin->sink_eld.info.spk_alloc;
+}
+
 static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
                                        unsigned char *chmap)
 {
@@ -1859,6 +1869,8 @@ static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
 
+       if (!per_pin)
+               return;
        mutex_lock(&per_pin->lock);
        per_pin->chmap_set = true;
        memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap));
@@ -2074,6 +2086,20 @@ static void hdmi_array_free(struct hdmi_spec *spec)
        snd_array_free(&spec->cvts);
 }
 
+static void generic_spec_free(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (spec) {
+               if (spec->i915_bound)
+                       snd_hdac_i915_exit(&codec->bus->core);
+               hdmi_array_free(spec);
+               kfree(spec);
+               codec->spec = NULL;
+       }
+       codec->dp_mst = false;
+}
+
 static void generic_hdmi_free(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
@@ -2098,10 +2124,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
                        spec->pcm_rec[pcm_idx].jack = NULL;
        }
 
-       if (spec->i915_bound)
-               snd_hdac_i915_exit(&codec->bus->core);
-       hdmi_array_free(spec);
-       kfree(spec);
+       generic_spec_free(codec);
 }
 
 #ifdef CONFIG_PM
@@ -2139,6 +2162,55 @@ static const struct hdmi_ops generic_standard_hdmi_ops = {
        .setup_stream                           = hdmi_setup_stream,
 };
 
+/* allocate codec->spec and assign/initialize generic parser ops */
+static int alloc_generic_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+
+       spec->ops = generic_standard_hdmi_ops;
+       mutex_init(&spec->pcm_lock);
+       snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
+
+       spec->chmap.ops.get_chmap = hdmi_get_chmap;
+       spec->chmap.ops.set_chmap = hdmi_set_chmap;
+       spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached;
+       spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc,
+
+       codec->spec = spec;
+       hdmi_array_init(spec, 4);
+
+       codec->patch_ops = generic_hdmi_patch_ops;
+
+       return 0;
+}
+
+/* generic HDMI parser */
+static int patch_generic_hdmi(struct hda_codec *codec)
+{
+       int err;
+
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+
+       err = hdmi_parse_codec(codec);
+       if (err < 0) {
+               generic_spec_free(codec);
+               return err;
+       }
+
+       generic_hdmi_init_per_pins(codec);
+       return 0;
+}
+
+/*
+ * Intel codec parsers and helpers
+ */
+
 static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
                                             hda_nid_t nid)
 {
@@ -2216,12 +2288,23 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 static void intel_pin_eld_notify(void *audio_ptr, int port)
 {
        struct hda_codec *codec = audio_ptr;
-       int pin_nid = port + 0x04;
+       int pin_nid;
 
        /* we assume only from port-B to port-D */
        if (port < 1 || port > 3)
                return;
 
+       switch (codec->core.vendor_id) {
+       case 0x80860054: /* ILK */
+       case 0x80862804: /* ILK */
+       case 0x80862882: /* VLV */
+               pin_nid = port + 0x03;
+               break;
+       default:
+               pin_nid = port + 0x04;
+               break;
+       }
+
        /* skip notification during system suspend (but not in runtime PM);
         * the state will be updated at resume
         */
@@ -2231,96 +2314,163 @@ static void intel_pin_eld_notify(void *audio_ptr, int port)
        if (atomic_read(&(codec)->core.in_pm))
                return;
 
+       snd_hdac_i915_set_bclk(&codec->bus->core);
        check_presence_and_report(codec, pin_nid);
 }
 
-static int patch_generic_hdmi(struct hda_codec *codec)
+/* register i915 component pin_eld_notify callback */
+static void register_i915_notifier(struct hda_codec *codec)
 {
-       struct hdmi_spec *spec;
+       struct hdmi_spec *spec = codec->spec;
 
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
+       spec->use_acomp_notifier = true;
+       spec->i915_audio_ops.audio_ptr = codec;
+       /* intel_audio_codec_enable() or intel_audio_codec_disable()
+        * will call pin_eld_notify with using audio_ptr pointer
+        * We need make sure audio_ptr is really setup
+        */
+       wmb();
+       spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
+       snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
+}
 
-       spec->ops = generic_standard_hdmi_ops;
-       mutex_init(&spec->pcm_lock);
-       snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
+/* 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, u32 stream_tag, int format)
+{
+       haswell_verify_D0(codec, cvt_nid, pin_nid);
+       return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
+}
 
-       spec->chmap.ops.get_chmap = hdmi_get_chmap;
-       spec->chmap.ops.set_chmap = hdmi_set_chmap;
-       spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached;
+/* pin_cvt_fixup ops override for HSW+ and VLV+ */
+static void i915_pin_cvt_fixup(struct hda_codec *codec,
+                              struct hdmi_spec_per_pin *per_pin,
+                              hda_nid_t cvt_nid)
+{
+       if (per_pin) {
+               intel_verify_pin_cvt_connect(codec, per_pin);
+               intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
+                                            per_pin->mux_idx);
+       } else {
+               intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid);
+       }
+}
 
-       codec->spec = spec;
-       hdmi_array_init(spec, 4);
+/* Intel Haswell and onwards; audio component with eld notifier */
+static int patch_i915_hsw_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err;
 
-#ifdef CONFIG_SND_HDA_I915
-       /* Try to bind with i915 for Intel HSW+ codecs (if not done yet) */
-       if ((codec->core.vendor_id >> 16) == 0x8086 &&
-           is_haswell_plus(codec)) {
-#if 0
-               /* on-demand binding leads to an unbalanced refcount when
-                * both i915 and hda drivers are probed concurrently;
-                * disabled temporarily for now
-                */
-               if (!codec->bus->core.audio_component)
-                       if (!snd_hdac_i915_init(&codec->bus->core))
-                               spec->i915_bound = true;
-#endif
-               /* use i915 audio component notifier for hotplug */
-               if (codec->bus->core.audio_component)
-                       spec->use_acomp_notifier = true;
+       /* HSW+ requires i915 binding */
+       if (!codec->bus->core.audio_component) {
+               codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
+               return -ENODEV;
        }
-#endif
 
-       if (is_haswell_plus(codec)) {
-               intel_haswell_enable_all_pins(codec, true);
-               intel_haswell_fixup_enable_dp12(codec);
-       }
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
 
-       /* For Valleyview/Cherryview, only the display codec is in the display
-        * power well and can use link_power ops to request/release the power.
-        * For Haswell/Broadwell, the controller is also in the power well and
+       intel_haswell_enable_all_pins(codec, true);
+       intel_haswell_fixup_enable_dp12(codec);
+
+       /* For Haswell/Broadwell, the controller is also in the power well and
         * can cover the codec power request, and so need not set this flag.
-        * For previous platforms, there is no such power well feature.
         */
-       if (is_valleyview_plus(codec) || is_skylake(codec) ||
-                       is_broxton(codec))
+       if (!is_haswell(codec) && !is_broadwell(codec))
                codec->core.link_power_control = 1;
 
-       if (hdmi_parse_codec(codec) < 0) {
-               if (spec->i915_bound)
-                       snd_hdac_i915_exit(&codec->bus->core);
-               codec->spec = NULL;
-               kfree(spec);
-               return -EINVAL;
+       codec->patch_ops.set_power_state = haswell_set_power_state;
+       codec->dp_mst = true;
+       codec->depop_delay = 0;
+       codec->auto_runtime_pm = 1;
+
+       spec->ops.setup_stream = i915_hsw_setup_stream;
+       spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+
+       err = hdmi_parse_codec(codec);
+       if (err < 0) {
+               generic_spec_free(codec);
+               return err;
        }
-       codec->patch_ops = generic_hdmi_patch_ops;
-       if (is_haswell_plus(codec)) {
-               codec->patch_ops.set_power_state = haswell_set_power_state;
-               codec->dp_mst = true;
+
+       generic_hdmi_init_per_pins(codec);
+       register_i915_notifier(codec);
+       return 0;
+}
+
+/* Intel Baytrail and Braswell; with eld notifier */
+static int patch_i915_byt_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err;
+
+       /* requires i915 binding */
+       if (!codec->bus->core.audio_component) {
+               codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
+               return -ENODEV;
        }
 
-       /* Enable runtime pm for HDMI audio codec of HSW/BDW/SKL/BYT/BSW */
-       if (is_haswell_plus(codec) || is_valleyview_plus(codec))
-               codec->auto_runtime_pm = 1;
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
 
-       generic_hdmi_init_per_pins(codec);
+       /* For Valleyview/Cherryview, only the display codec is in the display
+        * power well and can use link_power ops to request/release the power.
+        */
+       codec->core.link_power_control = 1;
 
+       codec->depop_delay = 0;
+       codec->auto_runtime_pm = 1;
 
-       if (codec_has_acomp(codec)) {
-               codec->depop_delay = 0;
-               spec->i915_audio_ops.audio_ptr = codec;
-               /* intel_audio_codec_enable() or intel_audio_codec_disable()
-                * will call pin_eld_notify with using audio_ptr pointer
-                * We need make sure audio_ptr is really setup
-                */
-               wmb();
-               spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
-               snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
+       spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+
+       err = hdmi_parse_codec(codec);
+       if (err < 0) {
+               generic_spec_free(codec);
+               return err;
        }
 
-       WARN_ON(spec->dyn_pcm_assign && !codec_has_acomp(codec));
+       generic_hdmi_init_per_pins(codec);
+       register_i915_notifier(codec);
+       return 0;
+}
+
+/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
+static int patch_i915_cpt_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err;
+
+       /* no i915 component should have been bound before this */
+       if (WARN_ON(codec->bus->core.audio_component))
+               return -EBUSY;
+
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+
+       /* Try to bind with i915 now */
+       err = snd_hdac_i915_init(&codec->bus->core);
+       if (err < 0)
+               goto error;
+       spec->i915_bound = true;
+
+       err = hdmi_parse_codec(codec);
+       if (err < 0)
+               goto error;
+
+       generic_hdmi_init_per_pins(codec);
+       register_i915_notifier(codec);
        return 0;
+
+ error:
+       generic_spec_free(codec);
+       return err;
 }
 
 /*
@@ -3491,21 +3641,21 @@ HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",    patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",   patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",    patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI",   patch_i915_cpt_hdmi),
 HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI",   patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI",    patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI",  patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI",   patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI",        patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",  patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI",   patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI",        patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",    patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",  patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",    patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",    patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",   patch_i915_hsw_hdmi),
 HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",        patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",        patch_i915_byt_hdmi),
+HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",   patch_i915_byt_hdmi),
 HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI",  patch_generic_hdmi),
 /* special ID for generic HDMI */
 HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),