diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 155 |
1 files changed, 94 insertions, 61 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1a24744f7a27..ef9fce50530d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -36,6 +36,59 @@ #include "i915_trace.h" #include "intel_drv.h" +static const u32 hpd_ibx[] = { + [HPD_CRT] = SDE_CRT_HOTPLUG, + [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG, + [HPD_PORT_B] = SDE_PORTB_HOTPLUG, + [HPD_PORT_C] = SDE_PORTC_HOTPLUG, + [HPD_PORT_D] = SDE_PORTD_HOTPLUG +}; + +static const u32 hpd_cpt[] = { + [HPD_CRT] = SDE_CRT_HOTPLUG_CPT, + [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, + [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT, + [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT +}; + +static const u32 hpd_mask_i915[] = { + [HPD_CRT] = CRT_HOTPLUG_INT_EN, + [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN, + [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN, + [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN, + [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN, + [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN +}; + +static const u32 hpd_status_gen4[] = { + [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, + [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, + [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, + [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, + [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, + [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS +}; + +static const u32 hpd_status_i965[] = { + [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, + [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965, + [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965, + [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, + [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, + [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS +}; + +static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ + [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, + [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, + [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915, + [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, + [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, + [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS +}; + + + /* For display hotplug interrupt */ static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) @@ -599,7 +652,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & dev_priv->hotplug_supported_mask) + if (hotplug_status & HOTPLUG_INT_STATUS_I915) queue_work(dev_priv->wq, &dev_priv->hotplug_work); @@ -2034,17 +2087,21 @@ 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; - u32 mask; - - if (HAS_PCH_IBX(dev)) - mask = SDE_HOTPLUG_MASK | - SDE_GMBUS | - SDE_AUX_MASK; - else - mask = SDE_HOTPLUG_MASK_CPT | - SDE_GMBUS_CPT | - SDE_AUX_MASK_CPT; - + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *intel_encoder; + u32 mask = I915_READ(SDEIER); + + 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; + } I915_WRITE(SDEIIR, I915_READ(SDEIIR)); I915_WRITE(SDEIMR, ~mask); I915_WRITE(SDEIER, mask); @@ -2466,26 +2523,16 @@ static int i915_irq_postinstall(struct drm_device *dev) static void i915_hpd_irq_setup(struct drm_device *dev) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 hotplug_en; - if (I915_HAS_HOTPLUG(dev)) { - hotplug_en = I915_READ(PORT_HOTPLUG_EN); - - if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) - hotplug_en |= PORTB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) - hotplug_en |= PORTC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) - hotplug_en |= PORTD_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) - hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) - hotplug_en |= SDVOB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { - hotplug_en |= CRT_HOTPLUG_INT_EN; - hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; - } + 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 *encoder; + u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); + + hotplug_en &= ~HOTPLUG_INT_EN_MASK; + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) + hotplug_en |= hpd_mask_i915[encoder->hpd_pin]; + hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; /* Ignore TV since it's buggy */ @@ -2576,7 +2623,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & dev_priv->hotplug_supported_mask) + if (hotplug_status & HOTPLUG_INT_STATUS_I915) queue_work(dev_priv->wq, &dev_priv->hotplug_work); @@ -2725,38 +2772,22 @@ static int i965_irq_postinstall(struct drm_device *dev) static void i965_hpd_irq_setup(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 *encoder; u32 hotplug_en; /* Note HDMI and DP share hotplug bits */ hotplug_en = 0; - if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) - hotplug_en |= PORTB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) - hotplug_en |= PORTC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) - hotplug_en |= PORTD_HOTPLUG_INT_EN; - if (IS_G4X(dev)) { - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X) - hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X) - hotplug_en |= SDVOB_HOTPLUG_INT_EN; - } else { - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965) - hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965) - hotplug_en |= SDVOB_HOTPLUG_INT_EN; - } - if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { - hotplug_en |= CRT_HOTPLUG_INT_EN; - - /* Programming the CRT detection parameters tends - to generate a spurious hotplug event about three - seconds later. So just do it once. - */ - if (IS_G4X(dev)) - hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; - hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; - } + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) + /* enable bits are the same for all generations */ + hotplug_en |= hpd_mask_i915[encoder->hpd_pin]; + /* Programming the CRT detection parameters tends + to generate a spurious hotplug event about three + seconds later. So just do it once. + */ + if (IS_G4X(dev)) + hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; + hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; /* Ignore TV since it's buggy */ @@ -2822,7 +2853,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & dev_priv->hotplug_supported_mask) + if (hotplug_status & (IS_G4X(dev) ? + HOTPLUG_INT_STATUS_G4X : + HOTPLUG_INT_STATUS_I965)) queue_work(dev_priv->wq, &dev_priv->hotplug_work); |