Merge tag 'irq-core-2020-12-23' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / i915_irq.c
index e741cd7..6cdb052 100644 (file)
@@ -79,6 +79,8 @@ static inline void pmu_irq_stats(struct drm_i915_private *i915,
 }
 
 typedef bool (*long_pulse_detect_func)(enum hpd_pin pin, u32 val);
+typedef u32 (*hotplug_enables_func)(struct drm_i915_private *i915,
+                                   enum hpd_pin pin);
 
 static const u32 hpd_ilk[HPD_NUM_PINS] = {
        [HPD_PORT_A] = DE_DP_A_HOTPLUG,
@@ -89,7 +91,7 @@ static const u32 hpd_ivb[HPD_NUM_PINS] = {
 };
 
 static const u32 hpd_bdw[HPD_NUM_PINS] = {
-       [HPD_PORT_A] = GEN8_PORT_DP_A_HOTPLUG,
+       [HPD_PORT_A] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_A),
 };
 
 static const u32 hpd_ibx[HPD_NUM_PINS] = {
@@ -144,30 +146,37 @@ static const u32 hpd_status_i915[HPD_NUM_PINS] = {
 };
 
 static const u32 hpd_bxt[HPD_NUM_PINS] = {
-       [HPD_PORT_A] = BXT_DE_PORT_HP_DDIA,
-       [HPD_PORT_B] = BXT_DE_PORT_HP_DDIB,
-       [HPD_PORT_C] = BXT_DE_PORT_HP_DDIC,
+       [HPD_PORT_A] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_A),
+       [HPD_PORT_B] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_B),
+       [HPD_PORT_C] = GEN8_DE_PORT_HOTPLUG(HPD_PORT_C),
 };
 
 static const u32 hpd_gen11[HPD_NUM_PINS] = {
-       [HPD_PORT_TC1] = GEN11_TC_HOTPLUG(PORT_TC1) | GEN11_TBT_HOTPLUG(PORT_TC1),
-       [HPD_PORT_TC2] = GEN11_TC_HOTPLUG(PORT_TC2) | GEN11_TBT_HOTPLUG(PORT_TC2),
-       [HPD_PORT_TC3] = GEN11_TC_HOTPLUG(PORT_TC3) | GEN11_TBT_HOTPLUG(PORT_TC3),
-       [HPD_PORT_TC4] = GEN11_TC_HOTPLUG(PORT_TC4) | GEN11_TBT_HOTPLUG(PORT_TC4),
-       [HPD_PORT_TC5] = GEN11_TC_HOTPLUG(PORT_TC5) | GEN11_TBT_HOTPLUG(PORT_TC5),
-       [HPD_PORT_TC6] = GEN11_TC_HOTPLUG(PORT_TC6) | GEN11_TBT_HOTPLUG(PORT_TC6),
+       [HPD_PORT_TC1] = GEN11_TC_HOTPLUG(HPD_PORT_TC1) | GEN11_TBT_HOTPLUG(HPD_PORT_TC1),
+       [HPD_PORT_TC2] = GEN11_TC_HOTPLUG(HPD_PORT_TC2) | GEN11_TBT_HOTPLUG(HPD_PORT_TC2),
+       [HPD_PORT_TC3] = GEN11_TC_HOTPLUG(HPD_PORT_TC3) | GEN11_TBT_HOTPLUG(HPD_PORT_TC3),
+       [HPD_PORT_TC4] = GEN11_TC_HOTPLUG(HPD_PORT_TC4) | GEN11_TBT_HOTPLUG(HPD_PORT_TC4),
+       [HPD_PORT_TC5] = GEN11_TC_HOTPLUG(HPD_PORT_TC5) | GEN11_TBT_HOTPLUG(HPD_PORT_TC5),
+       [HPD_PORT_TC6] = GEN11_TC_HOTPLUG(HPD_PORT_TC6) | GEN11_TBT_HOTPLUG(HPD_PORT_TC6),
 };
 
 static const u32 hpd_icp[HPD_NUM_PINS] = {
-       [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(PORT_A),
-       [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(PORT_B),
-       [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(PORT_C),
-       [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(PORT_TC1),
-       [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(PORT_TC2),
-       [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(PORT_TC3),
-       [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(PORT_TC4),
-       [HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(PORT_TC5),
-       [HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(PORT_TC6),
+       [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A),
+       [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B),
+       [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_C),
+       [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC1),
+       [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC2),
+       [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC3),
+       [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC4),
+       [HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC5),
+       [HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(HPD_PORT_TC6),
+};
+
+static const u32 hpd_sde_dg1[HPD_NUM_PINS] = {
+       [HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_A),
+       [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_B),
+       [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_C),
+       [HPD_PORT_D] = SDE_DDI_HOTPLUG_ICP(HPD_PORT_D),
 };
 
 static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
@@ -194,11 +203,14 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
        else
                hpd->hpd = hpd_ilk;
 
-       if (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))
+       if ((INTEL_PCH_TYPE(dev_priv) < PCH_DG1) &&
+           (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv)))
                return;
 
-       if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) ||
-           HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
+       if (HAS_PCH_DG1(dev_priv))
+               hpd->pch_hpd = hpd_sde_dg1;
+       else if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) ||
+                HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
                hpd->pch_hpd = hpd_icp;
        else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv))
                hpd->pch_hpd = hpd_spt;
@@ -355,17 +367,14 @@ void ilk_update_display_irq(struct drm_i915_private *dev_priv,
        u32 new_val;
 
        lockdep_assert_held(&dev_priv->irq_lock);
-
        drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
 
-       if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
-               return;
-
        new_val = dev_priv->irq_mask;
        new_val &= ~interrupt_mask;
        new_val |= (~enabled_irq_mask & interrupt_mask);
 
-       if (new_val != dev_priv->irq_mask) {
+       if (new_val != dev_priv->irq_mask &&
+           !drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv))) {
                dev_priv->irq_mask = new_val;
                I915_WRITE(DEIMR, dev_priv->irq_mask);
                POSTING_READ(DEIMR);
@@ -700,8 +709,12 @@ u32 i915_get_vblank_counter(struct drm_crtc *crtc)
 u32 g4x_get_vblank_counter(struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
+       struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
        enum pipe pipe = to_intel_crtc(crtc)->pipe;
 
+       if (!vblank->max_vblank_count)
+               return 0;
+
        return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
 }
 
@@ -1049,17 +1062,17 @@ static bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
 {
        switch (pin) {
        case HPD_PORT_TC1:
-               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1);
+               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC1);
        case HPD_PORT_TC2:
-               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2);
+               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC2);
        case HPD_PORT_TC3:
-               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3);
+               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC3);
        case HPD_PORT_TC4:
-               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4);
+               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC4);
        case HPD_PORT_TC5:
-               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC5);
+               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC5);
        case HPD_PORT_TC6:
-               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC6);
+               return val & GEN11_HOTPLUG_CTL_LONG_DETECT(HPD_PORT_TC6);
        default:
                return false;
        }
@@ -1083,11 +1096,13 @@ static bool icp_ddi_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
 {
        switch (pin) {
        case HPD_PORT_A:
-               return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_A);
+               return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_A);
        case HPD_PORT_B:
-               return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_B);
+               return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_B);
        case HPD_PORT_C:
-               return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_C);
+               return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_C);
+       case HPD_PORT_D:
+               return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(HPD_PORT_D);
        default:
                return false;
        }
@@ -1097,17 +1112,17 @@ static bool icp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
 {
        switch (pin) {
        case HPD_PORT_TC1:
-               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1);
+               return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC1);
        case HPD_PORT_TC2:
-               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2);
+               return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC2);
        case HPD_PORT_TC3:
-               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3);
+               return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC3);
        case HPD_PORT_TC4:
-               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4);
+               return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC4);
        case HPD_PORT_TC5:
-               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC5);
+               return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC5);
        case HPD_PORT_TC6:
-               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC6);
+               return val & ICP_TC_HPD_LONG_DETECT(HPD_PORT_TC6);
        default:
                return false;
        }
@@ -1210,6 +1225,43 @@ static void intel_get_hpd_pins(struct drm_i915_private *dev_priv,
 
 }
 
+static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
+                                 const u32 hpd[HPD_NUM_PINS])
+{
+       struct intel_encoder *encoder;
+       u32 enabled_irqs = 0;
+
+       for_each_intel_encoder(&dev_priv->drm, encoder)
+               if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
+                       enabled_irqs |= hpd[encoder->hpd_pin];
+
+       return enabled_irqs;
+}
+
+static u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv,
+                                 const u32 hpd[HPD_NUM_PINS])
+{
+       struct intel_encoder *encoder;
+       u32 hotplug_irqs = 0;
+
+       for_each_intel_encoder(&dev_priv->drm, encoder)
+               hotplug_irqs |= hpd[encoder->hpd_pin];
+
+       return hotplug_irqs;
+}
+
+static u32 intel_hpd_hotplug_enables(struct drm_i915_private *i915,
+                                    hotplug_enables_func hotplug_enables)
+{
+       struct intel_encoder *encoder;
+       u32 hotplug = 0;
+
+       for_each_intel_encoder(&i915->drm, encoder)
+               hotplug |= hotplug_enables(i915, encoder->hpd_pin);
+
+       return hotplug;
+}
+
 static void gmbus_irq_handler(struct drm_i915_private *dev_priv)
 {
        wake_up_all(&dev_priv->gmbus_wait_queue);
@@ -1263,6 +1315,23 @@ display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
                             u32 crc4) {}
 #endif
 
+static void flip_done_handler(struct drm_i915_private *i915,
+                             enum pipe pipe)
+{
+       struct intel_crtc *crtc = intel_get_crtc_for_pipe(i915, pipe);
+       struct drm_crtc_state *crtc_state = crtc->base.state;
+       struct drm_pending_vblank_event *e = crtc_state->event;
+       struct drm_device *dev = &i915->drm;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev->event_lock, irqflags);
+
+       crtc_state->event = NULL;
+
+       drm_crtc_send_vblank_event(&crtc->base, e);
+
+       spin_unlock_irqrestore(&dev->event_lock, irqflags);
+}
 
 static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
                                     enum pipe pipe)
@@ -1862,27 +1931,10 @@ static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 
 static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 {
-       u32 ddi_hotplug_trigger, tc_hotplug_trigger;
+       u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_HOTPLUG_MASK_ICP;
+       u32 tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_MASK_ICP;
        u32 pin_mask = 0, long_mask = 0;
 
-       if (HAS_PCH_TGP(dev_priv)) {
-               ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
-               tc_hotplug_trigger = pch_iir & SDE_TC_MASK_TGP;
-       } else if (HAS_PCH_JSP(dev_priv)) {
-               ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
-               tc_hotplug_trigger = 0;
-       } else if (HAS_PCH_MCC(dev_priv)) {
-               ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
-               tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_ICP(PORT_TC1);
-       } else {
-               drm_WARN(&dev_priv->drm, !HAS_PCH_ICP(dev_priv),
-                        "Unrecognized PCH type 0x%x\n",
-                        INTEL_PCH_TYPE(dev_priv));
-
-               ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
-               tc_hotplug_trigger = pch_iir & SDE_TC_MASK_ICP;
-       }
-
        if (ddi_hotplug_trigger) {
                u32 dig_hotplug_reg;
 
@@ -2261,6 +2313,63 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
                drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n");
 }
 
+static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv,
+                                          u32 te_trigger)
+{
+       enum pipe pipe = INVALID_PIPE;
+       enum transcoder dsi_trans;
+       enum port port;
+       u32 val, tmp;
+
+       /*
+        * Incase of dual link, TE comes from DSI_1
+        * this is to check if dual link is enabled
+        */
+       val = I915_READ(TRANS_DDI_FUNC_CTL2(TRANSCODER_DSI_0));
+       val &= PORT_SYNC_MODE_ENABLE;
+
+       /*
+        * if dual link is enabled, then read DSI_0
+        * transcoder registers
+        */
+       port = ((te_trigger & DSI1_TE && val) || (te_trigger & DSI0_TE)) ?
+                                                 PORT_A : PORT_B;
+       dsi_trans = (port == PORT_A) ? TRANSCODER_DSI_0 : TRANSCODER_DSI_1;
+
+       /* Check if DSI configured in command mode */
+       val = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans));
+       val = val & OP_MODE_MASK;
+
+       if (val != CMD_MODE_NO_GATE && val != CMD_MODE_TE_GATE) {
+               drm_err(&dev_priv->drm, "DSI trancoder not configured in command mode\n");
+               return;
+       }
+
+       /* Get PIPE for handling VBLANK event */
+       val = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans));
+       switch (val & TRANS_DDI_EDP_INPUT_MASK) {
+       case TRANS_DDI_EDP_INPUT_A_ON:
+               pipe = PIPE_A;
+               break;
+       case TRANS_DDI_EDP_INPUT_B_ONOFF:
+               pipe = PIPE_B;
+               break;
+       case TRANS_DDI_EDP_INPUT_C_ONOFF:
+               pipe = PIPE_C;
+               break;
+       default:
+               drm_err(&dev_priv->drm, "Invalid PIPE\n");
+               return;
+       }
+
+       intel_handle_vblank(dev_priv, pipe);
+
+       /* clear TE in dsi IIR */
+       port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A;
+       tmp = I915_READ(DSI_INTR_IDENT_REG(port));
+       I915_WRITE(DSI_INTR_IDENT_REG(port), tmp);
+}
+
 static irqreturn_t
 gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 {
@@ -2295,7 +2404,6 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
        if (master_ctl & GEN8_DE_PORT_IRQ) {
                iir = I915_READ(GEN8_DE_PORT_IIR);
                if (iir) {
-                       u32 tmp_mask;
                        bool found = false;
 
                        I915_WRITE(GEN8_DE_PORT_IIR, iir);
@@ -2307,15 +2415,17 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                        }
 
                        if (IS_GEN9_LP(dev_priv)) {
-                               tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK;
-                               if (tmp_mask) {
-                                       bxt_hpd_irq_handler(dev_priv, tmp_mask);
+                               u32 hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK;
+
+                               if (hotplug_trigger) {
+                                       bxt_hpd_irq_handler(dev_priv, hotplug_trigger);
                                        found = true;
                                }
                        } else if (IS_BROADWELL(dev_priv)) {
-                               tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG;
-                               if (tmp_mask) {
-                                       ilk_hpd_irq_handler(dev_priv, tmp_mask);
+                               u32 hotplug_trigger = iir & BDW_DE_PORT_HOTPLUG_MASK;
+
+                               if (hotplug_trigger) {
+                                       ilk_hpd_irq_handler(dev_priv, hotplug_trigger);
                                        found = true;
                                }
                        }
@@ -2325,6 +2435,15 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                                found = true;
                        }
 
+                       if (INTEL_GEN(dev_priv) >= 11) {
+                               u32 te_trigger = iir & (DSI0_TE | DSI1_TE);
+
+                               if (te_trigger) {
+                                       gen11_dsi_te_interrupt_handler(dev_priv, te_trigger);
+                                       found = true;
+                               }
+                       }
+
                        if (!found)
                                drm_err(&dev_priv->drm,
                                        "Unexpected DE Port interrupt\n");
@@ -2353,6 +2472,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                if (iir & GEN8_PIPE_VBLANK)
                        intel_handle_vblank(dev_priv, pipe);
 
+               if (iir & GEN9_PIPE_PLANE1_FLIP_DONE)
+                       flip_done_handler(dev_priv, pipe);
+
                if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
                        hsw_pipe_crc_irq_handler(dev_priv, pipe);
 
@@ -2659,12 +2781,47 @@ int ilk_enable_vblank(struct drm_crtc *crtc)
        return 0;
 }
 
+static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc,
+                                  bool enable)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+       enum port port;
+       u32 tmp;
+
+       if (!(intel_crtc->mode_flags &
+           (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0)))
+               return false;
+
+       /* for dual link cases we consider TE from slave */
+       if (intel_crtc->mode_flags & I915_MODE_FLAG_DSI_USE_TE1)
+               port = PORT_B;
+       else
+               port = PORT_A;
+
+       tmp =  I915_READ(DSI_INTR_MASK_REG(port));
+       if (enable)
+               tmp &= ~DSI_TE_EVENT;
+       else
+               tmp |= DSI_TE_EVENT;
+
+       I915_WRITE(DSI_INTR_MASK_REG(port), tmp);
+
+       tmp = I915_READ(DSI_INTR_IDENT_REG(port));
+       I915_WRITE(DSI_INTR_IDENT_REG(port), tmp);
+
+       return true;
+}
+
 int bdw_enable_vblank(struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       enum pipe pipe = to_intel_crtc(crtc)->pipe;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum pipe pipe = intel_crtc->pipe;
        unsigned long irqflags;
 
+       if (gen11_dsi_configure_te(intel_crtc, true))
+               return 0;
+
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -2678,6 +2835,19 @@ int bdw_enable_vblank(struct drm_crtc *crtc)
        return 0;
 }
 
+void skl_enable_flip_done(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&i915->irq_lock, irqflags);
+
+       bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE1_FLIP_DONE);
+
+       spin_unlock_irqrestore(&i915->irq_lock, irqflags);
+}
+
 /* Called from drm generic code, passed 'crtc' which
  * we use as a pipe index
  */
@@ -2730,14 +2900,31 @@ void ilk_disable_vblank(struct drm_crtc *crtc)
 void bdw_disable_vblank(struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       enum pipe pipe = to_intel_crtc(crtc)->pipe;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum pipe pipe = intel_crtc->pipe;
        unsigned long irqflags;
 
+       if (gen11_dsi_configure_te(intel_crtc, false))
+               return;
+
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
+void skl_disable_flip_done(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       enum pipe pipe = crtc->pipe;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&i915->irq_lock, irqflags);
+
+       bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE1_FLIP_DONE);
+
+       spin_unlock_irqrestore(&i915->irq_lock, irqflags);
+}
+
 static void ibx_irq_reset(struct drm_i915_private *dev_priv)
 {
        struct intel_uncore *uncore = &dev_priv->uncore;
@@ -2751,24 +2938,6 @@ static void ibx_irq_reset(struct drm_i915_private *dev_priv)
                I915_WRITE(SERR_INT, 0xffffffff);
 }
 
-/*
- * SDEIER is also touched by the interrupt handler to work around missed PCH
- * interrupts. Hence we can't update it after the interrupt handler is enabled -
- * instead we unconditionally enable all PCH interrupt sources here, but then
- * only unmask them as needed with SDEIMR.
- *
- * This function needs to be called before interrupts are enabled.
- */
-static void ibx_irq_pre_postinstall(struct drm_i915_private *dev_priv)
-{
-       if (HAS_PCH_NOP(dev_priv))
-               return;
-
-       drm_WARN_ON(&dev_priv->drm, I915_READ(SDEIER) != 0);
-       I915_WRITE(SDEIER, 0xffffffff);
-       POSTING_READ(SDEIER);
-}
-
 static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
 {
        struct intel_uncore *uncore = &dev_priv->uncore;
@@ -2825,6 +2994,8 @@ static void ilk_irq_reset(struct drm_i915_private *dev_priv)
        struct intel_uncore *uncore = &dev_priv->uncore;
 
        GEN3_IRQ_RESET(uncore, DE);
+       dev_priv->irq_mask = ~0u;
+
        if (IS_GEN(dev_priv, 7))
                intel_uncore_write(uncore, GEN7_ERR_INT, 0xffffffff);
 
@@ -2915,8 +3086,10 @@ static void gen11_display_irq_reset(struct drm_i915_private *dev_priv)
        if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
                GEN3_IRQ_RESET(uncore, SDE);
 
-       /* Wa_14010685332:icl,jsl,ehl,tgl,rkl */
-       if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) {
+       /* Wa_14010685332:cnp/cmp,tgp,adp */
+       if (INTEL_PCH_TYPE(dev_priv) == PCH_CNP ||
+           (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP &&
+            INTEL_PCH_TYPE(dev_priv) < PCH_DG1)) {
                intel_uncore_rmw(uncore, SOUTH_CHICKEN1,
                                 SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS);
                intel_uncore_rmw(uncore, SOUTH_CHICKEN1,
@@ -2948,6 +3121,9 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
        u32 extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
        enum pipe pipe;
 
+       if (INTEL_GEN(dev_priv) >= 9)
+               extra_ier |= GEN9_PIPE_PLANE1_FLIP_DONE;
+
        spin_lock_irq(&dev_priv->irq_lock);
 
        if (!intel_irqs_enabled(dev_priv)) {
@@ -3002,29 +3178,29 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv)
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
-static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
-                                 const u32 hpd[HPD_NUM_PINS])
-{
-       struct intel_encoder *encoder;
-       u32 enabled_irqs = 0;
-
-       for_each_intel_encoder(&dev_priv->drm, encoder)
-               if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
-                       enabled_irqs |= hpd[encoder->hpd_pin];
-
-       return enabled_irqs;
-}
-
-static u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv,
-                                 const u32 hpd[HPD_NUM_PINS])
+static u32 ibx_hotplug_enables(struct drm_i915_private *i915,
+                              enum hpd_pin pin)
 {
-       struct intel_encoder *encoder;
-       u32 hotplug_irqs = 0;
-
-       for_each_intel_encoder(&dev_priv->drm, encoder)
-               hotplug_irqs |= hpd[encoder->hpd_pin];
-
-       return hotplug_irqs;
+       switch (pin) {
+       case HPD_PORT_A:
+               /*
+                * When CPU and PCH are on the same package, port A
+                * HPD must be enabled in both north and south.
+                */
+               return HAS_PCH_LPT_LP(i915) ?
+                       PORTA_HOTPLUG_ENABLE : 0;
+       case HPD_PORT_B:
+               return PORTB_HOTPLUG_ENABLE |
+                       PORTB_PULSE_DURATION_2ms;
+       case HPD_PORT_C:
+               return PORTC_HOTPLUG_ENABLE |
+                       PORTC_PULSE_DURATION_2ms;
+       case HPD_PORT_D:
+               return PORTD_HOTPLUG_ENABLE |
+                       PORTD_PULSE_DURATION_2ms;
+       default:
+               return 0;
+       }
 }
 
 static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
@@ -3037,18 +3213,14 @@ static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
         * The pulse duration bits are reserved on LPT+.
         */
        hotplug = I915_READ(PCH_PORT_HOTPLUG);
-       hotplug &= ~(PORTB_PULSE_DURATION_MASK |
+       hotplug &= ~(PORTA_HOTPLUG_ENABLE |
+                    PORTB_HOTPLUG_ENABLE |
+                    PORTC_HOTPLUG_ENABLE |
+                    PORTD_HOTPLUG_ENABLE |
+                    PORTB_PULSE_DURATION_MASK |
                     PORTC_PULSE_DURATION_MASK |
                     PORTD_PULSE_DURATION_MASK);
-       hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
-       hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
-       hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
-       /*
-        * When CPU and PCH are on the same package, port A
-        * HPD must be enabled in both north and south.
-        */
-       if (HAS_PCH_LPT_LP(dev_priv))
-               hotplug |= PORTA_HOTPLUG_ENABLE;
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables);
        I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
 }
 
@@ -3064,28 +3236,65 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
        ibx_hpd_detection_setup(dev_priv);
 }
 
-static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv,
-                                       u32 enable_mask)
+static u32 icp_ddi_hotplug_enables(struct drm_i915_private *i915,
+                                  enum hpd_pin pin)
+{
+       switch (pin) {
+       case HPD_PORT_A:
+       case HPD_PORT_B:
+       case HPD_PORT_C:
+       case HPD_PORT_D:
+               return SHOTPLUG_CTL_DDI_HPD_ENABLE(pin);
+       default:
+               return 0;
+       }
+}
+
+static u32 icp_tc_hotplug_enables(struct drm_i915_private *i915,
+                                 enum hpd_pin pin)
+{
+       switch (pin) {
+       case HPD_PORT_TC1:
+       case HPD_PORT_TC2:
+       case HPD_PORT_TC3:
+       case HPD_PORT_TC4:
+       case HPD_PORT_TC5:
+       case HPD_PORT_TC6:
+               return ICP_TC_HPD_ENABLE(pin);
+       default:
+               return 0;
+       }
+}
+
+static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv)
 {
        u32 hotplug;
 
        hotplug = I915_READ(SHOTPLUG_CTL_DDI);
-       hotplug |= enable_mask;
+       hotplug &= ~(SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A) |
+                    SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B) |
+                    SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_C) |
+                    SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_D));
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables);
        I915_WRITE(SHOTPLUG_CTL_DDI, hotplug);
 }
 
-static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv,
-                                      u32 enable_mask)
+static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv)
 {
        u32 hotplug;
 
        hotplug = I915_READ(SHOTPLUG_CTL_TC);
-       hotplug |= enable_mask;
+       hotplug &= ~(ICP_TC_HPD_ENABLE(HPD_PORT_TC1) |
+                    ICP_TC_HPD_ENABLE(HPD_PORT_TC2) |
+                    ICP_TC_HPD_ENABLE(HPD_PORT_TC3) |
+                    ICP_TC_HPD_ENABLE(HPD_PORT_TC4) |
+                    ICP_TC_HPD_ENABLE(HPD_PORT_TC5) |
+                    ICP_TC_HPD_ENABLE(HPD_PORT_TC6));
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables);
        I915_WRITE(SHOTPLUG_CTL_TC, hotplug);
 }
 
-static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv,
-                             u32 ddi_enable_mask, u32 tc_enable_mask)
+static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv)
 {
        u32 hotplug_irqs, enabled_irqs;
 
@@ -3097,52 +3306,67 @@ static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv,
 
        ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
 
-       icp_ddi_hpd_detection_setup(dev_priv, ddi_enable_mask);
-       if (tc_enable_mask)
-               icp_tc_hpd_detection_setup(dev_priv, tc_enable_mask);
+       icp_ddi_hpd_detection_setup(dev_priv);
+       icp_tc_hpd_detection_setup(dev_priv);
 }
 
-/*
- * EHL doesn't need most of gen11_hpd_irq_setup, it's handling only the
- * equivalent of SDE.
- */
-static void mcc_hpd_irq_setup(struct drm_i915_private *dev_priv)
+static u32 gen11_hotplug_enables(struct drm_i915_private *i915,
+                                enum hpd_pin pin)
 {
-       icp_hpd_irq_setup(dev_priv,
-                         ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE(PORT_TC1));
+       switch (pin) {
+       case HPD_PORT_TC1:
+       case HPD_PORT_TC2:
+       case HPD_PORT_TC3:
+       case HPD_PORT_TC4:
+       case HPD_PORT_TC5:
+       case HPD_PORT_TC6:
+               return GEN11_HOTPLUG_CTL_ENABLE(pin);
+       default:
+               return 0;
+       }
 }
 
-/*
- * JSP behaves exactly the same as MCC above except that port C is mapped to
- * the DDI-C pins instead of the TC1 pins.  This means we should follow TGP's
- * masks & tables rather than ICP's masks & tables.
- */
-static void jsp_hpd_irq_setup(struct drm_i915_private *dev_priv)
+static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv)
 {
-       icp_hpd_irq_setup(dev_priv,
-                         TGP_DDI_HPD_ENABLE_MASK, 0);
+       u32 val;
+
+       val = I915_READ(SOUTH_CHICKEN1);
+       val |= (INVERT_DDIA_HPD |
+               INVERT_DDIB_HPD |
+               INVERT_DDIC_HPD |
+               INVERT_DDID_HPD);
+       I915_WRITE(SOUTH_CHICKEN1, val);
+
+       icp_hpd_irq_setup(dev_priv);
 }
 
-static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv)
+static void gen11_tc_hpd_detection_setup(struct drm_i915_private *dev_priv)
 {
        u32 hotplug;
 
        hotplug = I915_READ(GEN11_TC_HOTPLUG_CTL);
-       hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6);
+       hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6));
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables);
        I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug);
+}
+
+static void gen11_tbt_hpd_detection_setup(struct drm_i915_private *dev_priv)
+{
+       u32 hotplug;
 
        hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL);
-       hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) |
-                  GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6);
+       hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) |
+                    GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6));
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables);
        I915_WRITE(GEN11_TBT_HOTPLUG_CTL, hotplug);
 }
 
@@ -3160,14 +3384,39 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
        I915_WRITE(GEN11_DE_HPD_IMR, val);
        POSTING_READ(GEN11_DE_HPD_IMR);
 
-       gen11_hpd_detection_setup(dev_priv);
+       gen11_tc_hpd_detection_setup(dev_priv);
+       gen11_tbt_hpd_detection_setup(dev_priv);
 
-       if (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP)
-               icp_hpd_irq_setup(dev_priv,
-                                 TGP_DDI_HPD_ENABLE_MASK, TGP_TC_HPD_ENABLE_MASK);
-       else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
-               icp_hpd_irq_setup(dev_priv,
-                                 ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE_MASK);
+       if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
+               icp_hpd_irq_setup(dev_priv);
+}
+
+static u32 spt_hotplug_enables(struct drm_i915_private *i915,
+                              enum hpd_pin pin)
+{
+       switch (pin) {
+       case HPD_PORT_A:
+               return PORTA_HOTPLUG_ENABLE;
+       case HPD_PORT_B:
+               return PORTB_HOTPLUG_ENABLE;
+       case HPD_PORT_C:
+               return PORTC_HOTPLUG_ENABLE;
+       case HPD_PORT_D:
+               return PORTD_HOTPLUG_ENABLE;
+       default:
+               return 0;
+       }
+}
+
+static u32 spt_hotplug2_enables(struct drm_i915_private *i915,
+                               enum hpd_pin pin)
+{
+       switch (pin) {
+       case HPD_PORT_E:
+               return PORTE_HOTPLUG_ENABLE;
+       default:
+               return 0;
+       }
 }
 
 static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
@@ -3184,14 +3433,16 @@ static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
 
        /* Enable digital hotplug on the PCH */
        hotplug = I915_READ(PCH_PORT_HOTPLUG);
-       hotplug |= PORTA_HOTPLUG_ENABLE |
-                  PORTB_HOTPLUG_ENABLE |
-                  PORTC_HOTPLUG_ENABLE |
-                  PORTD_HOTPLUG_ENABLE;
+       hotplug &= ~(PORTA_HOTPLUG_ENABLE |
+                    PORTB_HOTPLUG_ENABLE |
+                    PORTC_HOTPLUG_ENABLE |
+                    PORTD_HOTPLUG_ENABLE);
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables);
        I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
 
        hotplug = I915_READ(PCH_PORT_HOTPLUG2);
-       hotplug |= PORTE_HOTPLUG_ENABLE;
+       hotplug &= ~PORTE_HOTPLUG_ENABLE;
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables);
        I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
 }
 
@@ -3210,6 +3461,18 @@ static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
        spt_hpd_detection_setup(dev_priv);
 }
 
+static u32 ilk_hotplug_enables(struct drm_i915_private *i915,
+                              enum hpd_pin pin)
+{
+       switch (pin) {
+       case HPD_PORT_A:
+               return DIGITAL_PORTA_HOTPLUG_ENABLE |
+                       DIGITAL_PORTA_PULSE_DURATION_2ms;
+       default:
+               return 0;
+       }
+}
+
 static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv)
 {
        u32 hotplug;
@@ -3220,9 +3483,9 @@ static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv)
         * The pulse duration bits are reserved on HSW+.
         */
        hotplug = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
-       hotplug &= ~DIGITAL_PORTA_PULSE_DURATION_MASK;
-       hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE |
-                  DIGITAL_PORTA_PULSE_DURATION_2ms;
+       hotplug &= ~(DIGITAL_PORTA_HOTPLUG_ENABLE |
+                    DIGITAL_PORTA_PULSE_DURATION_MASK);
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables);
        I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug);
 }
 
@@ -3243,41 +3506,45 @@ static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
        ibx_hpd_irq_setup(dev_priv);
 }
 
-static void __bxt_hpd_detection_setup(struct drm_i915_private *dev_priv,
-                                     u32 enabled_irqs)
+static u32 bxt_hotplug_enables(struct drm_i915_private *i915,
+                              enum hpd_pin pin)
 {
        u32 hotplug;
 
-       hotplug = I915_READ(PCH_PORT_HOTPLUG);
-       hotplug |= PORTA_HOTPLUG_ENABLE |
-                  PORTB_HOTPLUG_ENABLE |
-                  PORTC_HOTPLUG_ENABLE;
-
-       drm_dbg_kms(&dev_priv->drm,
-                   "Invert bit setting: hp_ctl:%x hp_port:%x\n",
-                   hotplug, enabled_irqs);
-       hotplug &= ~BXT_DDI_HPD_INVERT_MASK;
-
-       /*
-        * For BXT invert bit has to be set based on AOB design
-        * for HPD detection logic, update it based on VBT fields.
-        */
-       if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) &&
-           intel_bios_is_port_hpd_inverted(dev_priv, PORT_A))
-               hotplug |= BXT_DDIA_HPD_INVERT;
-       if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) &&
-           intel_bios_is_port_hpd_inverted(dev_priv, PORT_B))
-               hotplug |= BXT_DDIB_HPD_INVERT;
-       if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) &&
-           intel_bios_is_port_hpd_inverted(dev_priv, PORT_C))
-               hotplug |= BXT_DDIC_HPD_INVERT;
-
-       I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
+       switch (pin) {
+       case HPD_PORT_A:
+               hotplug = PORTA_HOTPLUG_ENABLE;
+               if (intel_bios_is_port_hpd_inverted(i915, PORT_A))
+                       hotplug |= BXT_DDIA_HPD_INVERT;
+               return hotplug;
+       case HPD_PORT_B:
+               hotplug = PORTB_HOTPLUG_ENABLE;
+               if (intel_bios_is_port_hpd_inverted(i915, PORT_B))
+                       hotplug |= BXT_DDIB_HPD_INVERT;
+               return hotplug;
+       case HPD_PORT_C:
+               hotplug = PORTC_HOTPLUG_ENABLE;
+               if (intel_bios_is_port_hpd_inverted(i915, PORT_C))
+                       hotplug |= BXT_DDIC_HPD_INVERT;
+               return hotplug;
+       default:
+               return 0;
+       }
 }
 
 static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv)
 {
-       __bxt_hpd_detection_setup(dev_priv, BXT_DE_PORT_HOTPLUG_MASK);
+       u32 hotplug;
+
+       hotplug = I915_READ(PCH_PORT_HOTPLUG);
+       hotplug &= ~(PORTA_HOTPLUG_ENABLE |
+                    PORTB_HOTPLUG_ENABLE |
+                    PORTC_HOTPLUG_ENABLE |
+                    BXT_DDIA_HPD_INVERT |
+                    BXT_DDIB_HPD_INVERT |
+                    BXT_DDIC_HPD_INVERT);
+       hotplug |= intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables);
+       I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
 }
 
 static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
@@ -3289,11 +3556,23 @@ static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
 
        bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
 
-       __bxt_hpd_detection_setup(dev_priv, enabled_irqs);
+       bxt_hpd_detection_setup(dev_priv);
 }
 
+/*
+ * SDEIER is also touched by the interrupt handler to work around missed PCH
+ * interrupts. Hence we can't update it after the interrupt handler is enabled -
+ * instead we unconditionally enable all PCH interrupt sources here, but then
+ * only unmask them as needed with SDEIMR.
+ *
+ * Note that we currently do this after installing the interrupt handler,
+ * but before we enable the master interrupt. That should be sufficient
+ * to avoid races with the irq handler, assuming we have MSI. Shared legacy
+ * interrupts could still race.
+ */
 static void ibx_irq_postinstall(struct drm_i915_private *dev_priv)
 {
+       struct intel_uncore *uncore = &dev_priv->uncore;
        u32 mask;
 
        if (HAS_PCH_NOP(dev_priv))
@@ -3306,14 +3585,7 @@ static void ibx_irq_postinstall(struct drm_i915_private *dev_priv)
        else
                mask = SDE_GMBUS_CPT;
 
-       gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR);
-       I915_WRITE(SDEIMR, ~mask);
-
-       if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
-           HAS_PCH_LPT(dev_priv))
-               ibx_hpd_detection_setup(dev_priv);
-       else
-               spt_hpd_detection_setup(dev_priv);
+       GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff);
 }
 
 static void ilk_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3331,7 +3603,7 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv)
                display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                                DE_AUX_CHANNEL_A | DE_PIPEB_CRC_DONE |
                                DE_PIPEA_CRC_DONE | DE_POISON);
-               extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
+               extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK |
                              DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
                              DE_DP_A_HOTPLUG);
        }
@@ -3341,29 +3613,17 @@ static void ilk_irq_postinstall(struct drm_i915_private *dev_priv)
                display_mask |= DE_EDP_PSR_INT_HSW;
        }
 
-       dev_priv->irq_mask = ~display_mask;
+       if (IS_IRONLAKE_M(dev_priv))
+               extra_mask |= DE_PCU_EVENT;
 
-       ibx_irq_pre_postinstall(dev_priv);
+       dev_priv->irq_mask = ~display_mask;
 
-       GEN3_IRQ_INIT(uncore, DE, dev_priv->irq_mask,
-                     display_mask | extra_mask);
+       ibx_irq_postinstall(dev_priv);
 
        gen5_gt_irq_postinstall(&dev_priv->gt);
 
-       ilk_hpd_detection_setup(dev_priv);
-
-       ibx_irq_postinstall(dev_priv);
-
-       if (IS_IRONLAKE_M(dev_priv)) {
-               /* Enable PCU event interrupts
-                *
-                * spinlocking not required here for correctness since interrupt
-                * setup is guaranteed to run in single-threaded context. But we
-                * need it to make the assert_spin_locked happy. */
-               spin_lock_irq(&dev_priv->irq_lock);
-               ilk_enable_display_irq(dev_priv, DE_PCU_EVENT);
-               spin_unlock_irq(&dev_priv->irq_lock);
-       }
+       GEN3_IRQ_INIT(uncore, DE, dev_priv->irq_mask,
+                     display_mask | extra_mask);
 }
 
 void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
@@ -3428,14 +3688,24 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
        if (IS_GEN9_LP(dev_priv))
                de_port_masked |= BXT_DE_PORT_GMBUS;
 
+       if (INTEL_GEN(dev_priv) >= 11) {
+               enum port port;
+
+               if (intel_bios_is_dsi_present(dev_priv, &port))
+                       de_port_masked |= DSI0_TE | DSI1_TE;
+       }
+
        de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
                                           GEN8_PIPE_FIFO_UNDERRUN;
 
+       if (INTEL_GEN(dev_priv) >= 9)
+               de_pipe_enables |= GEN9_PIPE_PLANE1_FLIP_DONE;
+
        de_port_enables = de_port_masked;
        if (IS_GEN9_LP(dev_priv))
                de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK;
        else if (IS_BROADWELL(dev_priv))
-               de_port_enables |= GEN8_PORT_DP_A_HOTPLUG;
+               de_port_enables |= BDW_DE_PORT_HOTPLUG_MASK;
 
        if (INTEL_GEN(dev_priv) >= 12) {
                enum transcoder trans;
@@ -3473,51 +3743,26 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
 
                GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked,
                              de_hpd_enables);
-               gen11_hpd_detection_setup(dev_priv);
-       } else if (IS_GEN9_LP(dev_priv)) {
-               bxt_hpd_detection_setup(dev_priv);
-       } else if (IS_BROADWELL(dev_priv)) {
-               ilk_hpd_detection_setup(dev_priv);
        }
 }
 
 static void gen8_irq_postinstall(struct drm_i915_private *dev_priv)
 {
        if (HAS_PCH_SPLIT(dev_priv))
-               ibx_irq_pre_postinstall(dev_priv);
+               ibx_irq_postinstall(dev_priv);
 
        gen8_gt_irq_postinstall(&dev_priv->gt);
        gen8_de_irq_postinstall(dev_priv);
 
-       if (HAS_PCH_SPLIT(dev_priv))
-               ibx_irq_postinstall(dev_priv);
-
        gen8_master_intr_enable(dev_priv->uncore.regs);
 }
 
 static void icp_irq_postinstall(struct drm_i915_private *dev_priv)
 {
+       struct intel_uncore *uncore = &dev_priv->uncore;
        u32 mask = SDE_GMBUS_ICP;
 
-       drm_WARN_ON(&dev_priv->drm, I915_READ(SDEIER) != 0);
-       I915_WRITE(SDEIER, 0xffffffff);
-       POSTING_READ(SDEIER);
-
-       gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR);
-       I915_WRITE(SDEIMR, ~mask);
-
-       if (HAS_PCH_TGP(dev_priv)) {
-               icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
-               icp_tc_hpd_detection_setup(dev_priv, TGP_TC_HPD_ENABLE_MASK);
-       } else if (HAS_PCH_JSP(dev_priv)) {
-               icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
-       } else if (HAS_PCH_MCC(dev_priv)) {
-               icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
-               icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE(PORT_TC1));
-       } else {
-               icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
-               icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE_MASK);
-       }
+       GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff);
 }
 
 static void gen11_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3564,6 +3809,7 @@ static void i8xx_irq_reset(struct drm_i915_private *dev_priv)
        i9xx_pipestat_irq_reset(dev_priv);
 
        GEN2_IRQ_RESET(uncore);
+       dev_priv->irq_mask = ~0u;
 }
 
 static void i8xx_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3735,6 +3981,7 @@ static void i915_irq_reset(struct drm_i915_private *dev_priv)
        i9xx_pipestat_irq_reset(dev_priv);
 
        GEN3_IRQ_RESET(uncore, GEN2_);
+       dev_priv->irq_mask = ~0u;
 }
 
 static void i915_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3843,6 +4090,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv)
        i9xx_pipestat_irq_reset(dev_priv);
 
        GEN3_IRQ_RESET(uncore, GEN2_);
+       dev_priv->irq_mask = ~0u;
 }
 
 static void i965_irq_postinstall(struct drm_i915_private *dev_priv)
@@ -3992,10 +4240,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        struct drm_device *dev = &dev_priv->drm;
        int i;
 
-       intel_hpd_init_pins(dev_priv);
-
-       intel_hpd_init_work(dev_priv);
-
        INIT_WORK(&dev_priv->l3_parity.error_work, ivb_parity_work);
        for (i = 0; i < MAX_L3_SLICES; ++i)
                dev_priv->l3_parity.remap_info[i] = NULL;
@@ -4004,6 +4248,13 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        if (HAS_GT_UC(dev_priv) && INTEL_GEN(dev_priv) < 11)
                dev_priv->gt.pm_guc_events = GUC_INTR_GUC2HOST << 16;
 
+       if (!HAS_DISPLAY(dev_priv))
+               return;
+
+       intel_hpd_init_pins(dev_priv);
+
+       intel_hpd_init_work(dev_priv);
+
        dev->vblank_disable_immediate = true;
 
        /* Most platforms treat the display irq block as an always-on
@@ -4029,10 +4280,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
                if (I915_HAS_HOTPLUG(dev_priv))
                        dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
        } else {
-               if (HAS_PCH_JSP(dev_priv))
-                       dev_priv->display.hpd_irq_setup = jsp_hpd_irq_setup;
-               else if (HAS_PCH_MCC(dev_priv))
-                       dev_priv->display.hpd_irq_setup = mcc_hpd_irq_setup;
+               if (HAS_PCH_DG1(dev_priv))
+                       dev_priv->display.hpd_irq_setup = dg1_hpd_irq_setup;
                else if (INTEL_GEN(dev_priv) >= 11)
                        dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup;
                else if (IS_GEN9_LP(dev_priv))