diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 63 |
1 files changed, 35 insertions, 28 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ef9fce50530d..64c79a0cb570 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2028,7 +2028,13 @@ static void ironlake_irq_preinstall(struct drm_device *dev) /* south display irq */ I915_WRITE(SDEIMR, 0xffffffff); - I915_WRITE(SDEIER, 0x0); + /* + * 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. + */ + I915_WRITE(SDEIER, 0xffffffff); POSTING_READ(SDEIER); } @@ -2064,18 +2070,30 @@ static void valleyview_irq_preinstall(struct drm_device *dev) POSTING_READ(VLV_IER); } -/* - * Enable digital hotplug on the PCH, and configure the DP short pulse - * duration to 2ms (which is the minimum in the Display Port spec) - * - * This register is the same on all known PCH chips. - */ - -static void ibx_enable_hotplug(struct drm_device *dev) +static void ibx_hpd_irq_setup(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 hotplug; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *intel_encoder; + u32 mask = ~I915_READ(SDEIMR); + u32 hotplug; + + if (HAS_PCH_IBX(dev)) { + list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + mask |= hpd_ibx[intel_encoder->hpd_pin]; + } else { + list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + mask |= hpd_cpt[intel_encoder->hpd_pin]; + } + I915_WRITE(SDEIMR, ~mask); + + /* + * Enable digital hotplug on the PCH, and configure the DP short pulse + * duration to 2ms (which is the minimum in the Display Port spec) + * + * This register is the same on all known PCH chips. + */ hotplug = I915_READ(PCH_PORT_HOTPLUG); hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK); hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms; @@ -2087,27 +2105,14 @@ static void ibx_enable_hotplug(struct drm_device *dev) static void ibx_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_encoder *intel_encoder; - u32 mask = I915_READ(SDEIER); + u32 mask; - if (HAS_PCH_IBX(dev)) { - mask &= ~SDE_HOTPLUG_MASK; - list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) - mask |= hpd_ibx[intel_encoder->hpd_pin]; - mask |= SDE_GMBUS | SDE_AUX_MASK; - } else { - mask &= ~SDE_HOTPLUG_MASK_CPT; - list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) - mask |= hpd_cpt[intel_encoder->hpd_pin]; - mask |= SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; - } + if (HAS_PCH_IBX(dev)) + mask = SDE_GMBUS | SDE_AUX_MASK; + else + mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; I915_WRITE(SDEIIR, I915_READ(SDEIIR)); I915_WRITE(SDEIMR, ~mask); - I915_WRITE(SDEIER, mask); - POSTING_READ(SDEIER); - - ibx_enable_hotplug(dev); } static int ironlake_irq_postinstall(struct drm_device *dev) @@ -2977,6 +2982,7 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ivybridge_enable_vblank; dev->driver->disable_vblank = ivybridge_disable_vblank; + dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -2984,6 +2990,7 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ironlake_enable_vblank; dev->driver->disable_vblank = ironlake_disable_vblank; + dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; } else { if (INTEL_INFO(dev)->gen == 2) { dev->driver->irq_preinstall = i8xx_irq_preinstall; |