diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 175 |
1 files changed, 169 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4a02747ac658..46aaef5c1851 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -115,6 +115,13 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = { [HPD_PORT_C] = BXT_DE_PORT_HP_DDIC }; +static const u32 hpd_gen11[HPD_NUM_PINS] = { + [HPD_PORT_C] = GEN11_TC1_HOTPLUG | GEN11_TBT1_HOTPLUG, + [HPD_PORT_D] = GEN11_TC2_HOTPLUG | GEN11_TBT2_HOTPLUG, + [HPD_PORT_E] = GEN11_TC3_HOTPLUG | GEN11_TBT3_HOTPLUG, + [HPD_PORT_F] = GEN11_TC4_HOTPLUG | GEN11_TBT4_HOTPLUG +}; + /* IIR can theoretically queue up two events. Be paranoid. */ #define GEN8_IRQ_RESET_NDX(type, which) do { \ I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ @@ -1549,6 +1556,22 @@ static void gen8_gt_irq_handler(struct drm_i915_private *i915, } } +static bool gen11_port_hotplug_long_detect(enum port port, u32 val) +{ + switch (port) { + case PORT_C: + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1); + case PORT_D: + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2); + case PORT_E: + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3); + case PORT_F: + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4); + default: + return false; + } +} + static bool bxt_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { @@ -2598,6 +2621,40 @@ static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv, intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); } +static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir) +{ + u32 pin_mask = 0, long_mask = 0; + u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK; + u32 trigger_tbt = iir & GEN11_DE_TBT_HOTPLUG_MASK; + + if (trigger_tc) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = I915_READ(GEN11_TC_HOTPLUG_CTL); + I915_WRITE(GEN11_TC_HOTPLUG_CTL, dig_hotplug_reg); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tc, + dig_hotplug_reg, hpd_gen11, + gen11_port_hotplug_long_detect); + } + + if (trigger_tbt) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = I915_READ(GEN11_TBT_HOTPLUG_CTL); + I915_WRITE(GEN11_TBT_HOTPLUG_CTL, dig_hotplug_reg); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tbt, + dig_hotplug_reg, hpd_gen11, + gen11_port_hotplug_long_detect); + } + + if (pin_mask) + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); + else + DRM_ERROR("Unexpected DE HPD interrupt 0x%08x\n", iir); +} + static irqreturn_t gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) { @@ -2633,6 +2690,17 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) DRM_ERROR("The master control interrupt lied (DE MISC)!\n"); } + if (INTEL_GEN(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) { + iir = I915_READ(GEN11_DE_HPD_IIR); + if (iir) { + I915_WRITE(GEN11_DE_HPD_IIR, iir); + ret = IRQ_HANDLED; + gen11_hpd_irq_handler(dev_priv, iir); + } else { + DRM_ERROR("The master control interrupt lied, (DE HPD)!\n"); + } + } + if (master_ctl & GEN8_DE_PORT_IRQ) { iir = I915_READ(GEN8_DE_PORT_IIR); if (iir) { @@ -2648,7 +2716,11 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) GEN9_AUX_CHANNEL_C | GEN9_AUX_CHANNEL_D; - if (IS_CNL_WITH_PORT_F(dev_priv)) + if (INTEL_GEN(dev_priv) >= 11) + tmp_mask |= ICL_AUX_CHANNEL_E; + + if (IS_CNL_WITH_PORT_F(dev_priv) || + INTEL_GEN(dev_priv) >= 11) tmp_mask |= CNL_AUX_CHANNEL_F; if (iir & tmp_mask) { @@ -2950,11 +3022,44 @@ gen11_gt_irq_handler(struct drm_i915_private * const i915, spin_unlock(&i915->irq_lock); } +static void +gen11_gu_misc_irq_ack(struct drm_i915_private *dev_priv, const u32 master_ctl, + u32 *iir) +{ + void __iomem * const regs = dev_priv->regs; + + if (!(master_ctl & GEN11_GU_MISC_IRQ)) + return; + + *iir = raw_reg_read(regs, GEN11_GU_MISC_IIR); + if (likely(*iir)) + raw_reg_write(regs, GEN11_GU_MISC_IIR, *iir); +} + +static void +gen11_gu_misc_irq_handler(struct drm_i915_private *dev_priv, + const u32 master_ctl, const u32 iir) +{ + if (!(master_ctl & GEN11_GU_MISC_IRQ)) + return; + + if (unlikely(!iir)) { + DRM_ERROR("GU_MISC iir blank!\n"); + return; + } + + if (iir & GEN11_GU_MISC_GSE) + intel_opregion_asle_intr(dev_priv); + else + DRM_ERROR("Unexpected GU_MISC interrupt 0x%x\n", iir); +} + static irqreturn_t gen11_irq_handler(int irq, void *arg) { struct drm_i915_private * const i915 = to_i915(arg); void __iomem * const regs = i915->regs; u32 master_ctl; + u32 gu_misc_iir; if (!intel_irqs_enabled(i915)) return IRQ_NONE; @@ -2983,9 +3088,13 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg) enable_rpm_wakeref_asserts(i915); } + gen11_gu_misc_irq_ack(i915, master_ctl, &gu_misc_iir); + /* Acknowledge and enable interrupts. */ raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ | master_ctl); + gen11_gu_misc_irq_handler(i915, master_ctl, gu_misc_iir); + return IRQ_HANDLED; } @@ -3472,6 +3581,8 @@ static void gen11_irq_reset(struct drm_device *dev) GEN3_IRQ_RESET(GEN8_DE_PORT_); GEN3_IRQ_RESET(GEN8_DE_MISC_); + GEN3_IRQ_RESET(GEN11_DE_HPD_); + GEN3_IRQ_RESET(GEN11_GU_MISC_); GEN3_IRQ_RESET(GEN8_PCU_); } @@ -3589,6 +3700,41 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv) ibx_hpd_detection_setup(dev_priv); } +static void gen11_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); + I915_WRITE(GEN11_TC_HOTPLUG_CTL, 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); + I915_WRITE(GEN11_TBT_HOTPLUG_CTL, hotplug); +} + +static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + u32 val; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_gen11); + hotplug_irqs = GEN11_DE_TC_HOTPLUG_MASK | GEN11_DE_TBT_HOTPLUG_MASK; + + val = I915_READ(GEN11_DE_HPD_IMR); + val &= ~hotplug_irqs; + I915_WRITE(GEN11_DE_HPD_IMR, val); + POSTING_READ(GEN11_DE_HPD_IMR); + + gen11_hpd_detection_setup(dev_priv); +} + static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) { u32 val, hotplug; @@ -3915,9 +4061,12 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) uint32_t de_pipe_enables; u32 de_port_masked = GEN8_AUX_CHANNEL_A; u32 de_port_enables; - u32 de_misc_masked = GEN8_DE_MISC_GSE | GEN8_DE_EDP_PSR; + u32 de_misc_masked = GEN8_DE_EDP_PSR; enum pipe pipe; + if (INTEL_GEN(dev_priv) <= 10) + de_misc_masked |= GEN8_DE_MISC_GSE; + if (INTEL_GEN(dev_priv) >= 9) { de_pipe_masked |= GEN9_DE_PIPE_IRQ_FAULT_ERRORS; de_port_masked |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C | @@ -3928,7 +4077,10 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) de_pipe_masked |= GEN8_DE_PIPE_IRQ_FAULT_ERRORS; } - if (IS_CNL_WITH_PORT_F(dev_priv)) + if (INTEL_GEN(dev_priv) >= 11) + de_port_masked |= ICL_AUX_CHANNEL_E; + + if (IS_CNL_WITH_PORT_F(dev_priv) || INTEL_GEN(dev_priv) >= 11) de_port_masked |= CNL_AUX_CHANNEL_F; de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | @@ -3956,10 +4108,18 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) GEN3_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables); GEN3_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); - if (IS_GEN9_LP(dev_priv)) + if (INTEL_GEN(dev_priv) >= 11) { + u32 de_hpd_masked = 0; + u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | + GEN11_DE_TBT_HOTPLUG_MASK; + + GEN3_IRQ_INIT(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)) + } else if (IS_BROADWELL(dev_priv)) { ilk_hpd_detection_setup(dev_priv); + } } static int gen8_irq_postinstall(struct drm_device *dev) @@ -4011,10 +4171,13 @@ static void gen11_gt_irq_postinstall(struct drm_i915_private *dev_priv) static int gen11_irq_postinstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 gu_misc_masked = GEN11_GU_MISC_GSE; gen11_gt_irq_postinstall(dev_priv); gen8_de_irq_postinstall(dev_priv); + GEN3_IRQ_INIT(GEN11_GU_MISC_, ~gu_misc_masked, gu_misc_masked); + I915_WRITE(GEN11_DISPLAY_INT_CTL, GEN11_DISPLAY_IRQ_ENABLE); I915_WRITE(GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ); @@ -4478,7 +4641,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) dev->driver->irq_uninstall = gen11_irq_reset; dev->driver->enable_vblank = gen8_enable_vblank; dev->driver->disable_vblank = gen8_disable_vblank; - dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup; + dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup; } else if (INTEL_GEN(dev_priv) >= 8) { dev->driver->irq_handler = gen8_irq_handler; dev->driver->irq_preinstall = gen8_irq_reset; |