diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 0ee0c44..7a6ffba 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -455,7 +455,7 @@ static void i915_hotplug_tv(struct drm_device *dev) { struct drm_output *output; struct intel_output *iout; - enum drm_output_status status; + enum drm_output_status status = output_status_disconnected; mutex_lock(&dev->mode_config.mutex); @@ -471,7 +471,6 @@ static void i915_hotplug_tv(struct drm_device *dev) if (iout == 0) goto unlock; - /* may need to I915_WRITE(TVDAC, 1<<31) to ack the interrupt */ status = output->funcs->detect(output); drm_hotplug_stage_two(dev, output, status == output_status_connected ? 1 : 0); @@ -631,7 +630,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; u32 iir; - u32 pipea_stats, pipeb_stats; + u32 pipea_stats = 0, pipeb_stats, tvdac; int hotplug = 0; int vblank = 0; @@ -672,11 +671,22 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } /* This is a global event, and not a pipe A event */ - if ((pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) || - (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS)) + if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) + hotplug = 1; + + if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS) { hotplug = 1; + /* Toggle hotplug detection to clear hotplug status */ + tvdac = I915_READ(TV_DAC); + I915_WRITE(TV_DAC, tvdac & ~TVDAC_STATE_CHG_EN); + I915_WRITE(TV_DAC, tvdac | TVDAC_STATE_CHG_EN); + DRM_INFO("received & acked TV interrupt\n"); + } I915_WRITE(I915REG_PIPEASTAT, pipea_stats); + + DRM_INFO("pipeastat: 0x%08x, tv_dac: 0x%08x\n", + I915_READ(I915REG_PIPEASTAT), I915_READ(TV_DAC)); } if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { @@ -729,7 +739,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) temp2 |= TV_HOTPLUG_INT_STATUS; } else { temp2 = I915_READ(PORT_HOTPLUG_STAT); - I915_WRITE(PORT_HOTPLUG_STAT, temp2); } i915_run_hotplug_tasklet(dev, temp2); @@ -952,19 +961,61 @@ void i915_disable_vblank(struct drm_device *dev, int plane) } } -void i915_enable_interrupt (struct drm_device *dev) +static void i915_enable_hotplug(struct drm_device *dev) { - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_output *o; + u32 hotplug_reg = 0; /* 945+ has hotplug reg */ - dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; + if (!dev->mode_config.num_output) + return; + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + hotplug_reg = I915_READ(PORT_HOTPLUG_EN); + + /* CRT */ + hotplug_reg |= CRT_HOTPLUG_INT_EN; + + /* SDVO */ + if (IS_I9XX(dev)) { + /* SDVOB */ + o = intel_sdvo_find(dev, 1); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + hotplug_reg |= SDVOB_HOTPLUG_INT_EN; + } + + /* SDVOC */ + o = intel_sdvo_find(dev, 0); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + hotplug_reg |= SDVOC_HOTPLUG_INT_EN; + } + + I915_WRITE(SDVOB, I915_READ(SDVOB) | SDVO_INTERRUPT_ENABLE); + I915_WRITE(SDVOC, I915_READ(SDVOC) | SDVO_INTERRUPT_ENABLE); + } else { + /* DVO ???? */ + } + + /* TV */ + if (IS_I9XX(dev) && !IS_I915G(dev)) { + hotplug_reg |= TV_HOTPLUG_INT_EN; + I915_WRITE(TV_DAC, I915_READ(TV_DAC) | TVDAC_STATE_CHG_EN); + } + + /* 945+ has sane hotplug hardware */ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - if (dev->mode_config.num_output) - dev_priv->irq_enable_reg |= I915_DISPLAY_PORT_INTERRUPT; + dev_priv->irq_enable_reg |= I915_DISPLAY_PORT_INTERRUPT; + + I915_WRITE(PORT_HOTPLUG_EN, hotplug_reg); + + DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN)); + DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT)); + + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); } else { - if (dev->mode_config.num_output) - dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; + dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; /* Enable global interrupts for hotplug - not a pipeA event */ I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | @@ -973,47 +1024,15 @@ void i915_enable_interrupt (struct drm_device *dev) I915_HOTPLUG_TV_CLEAR | I915_HOTPLUG_CLEAR); } +} - if (dev_priv->irq_enable_reg & (I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) { - u32 temp = 0; - - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - temp = I915_READ(PORT_HOTPLUG_EN); - - /* Activate the CRT */ - temp |= CRT_HOTPLUG_INT_EN; - } - - if (IS_I9XX(dev)) { - /* SDVOB */ - o = intel_sdvo_find(dev, 1); - if (o && intel_sdvo_supports_hotplug(o)) { - intel_sdvo_set_hotplug(o, 1); - temp |= SDVOB_HOTPLUG_INT_EN; - } - - /* SDVOC */ - o = intel_sdvo_find(dev, 0); - if (o && intel_sdvo_supports_hotplug(o)) { - intel_sdvo_set_hotplug(o, 1); - temp |= SDVOC_HOTPLUG_INT_EN; - } - - I915_WRITE(SDVOB, I915_READ(SDVOB) | SDVO_INTERRUPT_ENABLE); - I915_WRITE(SDVOC, I915_READ(SDVOC) | SDVO_INTERRUPT_ENABLE); - } else { - /* DVO ???? */ - } - - if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - I915_WRITE(PORT_HOTPLUG_EN, temp); +void i915_enable_interrupt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; - DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN)); - DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT)); + dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; - I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); - } - } + i915_enable_hotplug(dev); if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);