diff options
-rw-r--r-- | shared-core/i915_drv.h | 3 | ||||
-rw-r--r-- | shared-core/i915_irq.c | 60 |
2 files changed, 59 insertions, 4 deletions
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 64faac9b..e32c36f1 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -554,7 +554,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) #define I915_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) +#define I915_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) #define I915_HOTPLUG_CLEAR (1UL<<10) +#define I915_HOTPLUG_TV_CLEAR (1UL<<2) #define I915_VBLANK_CLEAR (1UL<<1) /* @@ -669,6 +671,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6) #define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) #define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) +#define I915_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) #define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ #define I915_VBLANK_INTERRUPT_STATUS (1UL<<1) #define I915_OVERLAY_UPDATED_STATUS (1UL<<0) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index abd8a7d3..8f136c8f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -424,11 +424,41 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) #define HOTPLUG_CMD_CRT_DIS 2 #define HOTPLUG_CMD_SDVOB 4 #define HOTPLUG_CMD_SDVOC 8 +#define HOTPLUG_CMD_TV 16 static struct drm_device *hotplug_dev; static int hotplug_cmd = 0; static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; +static void i915_hotplug_tv(struct drm_device *dev) +{ + struct drm_output *output; + struct intel_output *iout; + enum drm_output_status status; + + mutex_lock(&dev->mode_config.mutex); + + /* find the crt output */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + iout = output->driver_private; + if (iout->type == INTEL_OUTPUT_TVOUT) + break; + else + iout = 0; + } + + 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); + +unlock: + mutex_unlock(&dev->mode_config.mutex); +} + static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) { struct drm_output *output; @@ -493,8 +523,10 @@ static void i915_hotplug_work_func(struct work_struct *work) int crtDis; int sdvoB; int sdvoC; + int tv; spin_lock(&hotplug_lock); + tv = hotplug_cmd & HOTPLUG_CMD_TV; crt = hotplug_cmd & HOTPLUG_CMD_CRT; crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS; sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; @@ -502,6 +534,8 @@ static void i915_hotplug_work_func(struct work_struct *work) hotplug_cmd = 0; spin_unlock(&hotplug_lock); + if (tv) + i915_hotplug_tv(dev); if (crt) i915_hotplug_crt(dev, true); if (crtDis) @@ -527,6 +561,14 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) hotplug_dev = dev; + if (stat & TV_HOTPLUG_INT_STATUS) { + DRM_DEBUG("TV event\n"); + + spin_lock(&hotplug_lock); + hotplug_cmd |= HOTPLUG_CMD_TV; + spin_unlock(&hotplug_lock); + } + if (stat & CRT_HOTPLUG_INT_STATUS) { DRM_DEBUG("CRT event\n"); @@ -584,12 +626,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_DEBUG("flag=%08x\n", iir); #endif if (iir == 0) { +#if 0 DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", iir, I915_READ(I915REG_INT_MASK_R), I915_READ(I915REG_INT_ENABLE_R), I915_READ(I915REG_PIPEASTAT), I915_READ(I915REG_PIPEBSTAT)); +#endif return IRQ_NONE; } @@ -607,7 +651,8 @@ 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) + if ((pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) || + (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS)) hotplug = 1; I915_WRITE(I915REG_PIPEASTAT, pipea_stats); @@ -656,8 +701,11 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_INFO("Hotplug event received\n"); if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) { - temp2 |= SDVOB_HOTPLUG_INT_STATUS | - SDVOC_HOTPLUG_INT_STATUS; + if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) + temp2 |= SDVOB_HOTPLUG_INT_STATUS | + SDVOC_HOTPLUG_INT_STATUS; + if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS) + temp2 |= TV_HOTPLUG_INT_STATUS; } else { temp2 = I915_READ(PORT_HOTPLUG_STAT); @@ -898,7 +946,11 @@ void i915_enable_interrupt (struct drm_device *dev) 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) | I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR); + I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | + I915_HOTPLUG_INTERRUPT_ENABLE | + I915_HOTPLUG_TV_INTERRUPT_ENABLE | + I915_HOTPLUG_TV_CLEAR | + I915_HOTPLUG_CLEAR); } if (dev_priv->irq_enable_reg & (I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) { |