diff options
author | Alan Hourihane <alanh@tungstengraphics.com> | 2008-03-12 10:18:33 +0000 |
---|---|---|
committer | Alan Hourihane <alanh@tungstengraphics.com> | 2008-03-12 10:18:33 +0000 |
commit | b6dc381fabb199e70dc681e44e31452af8536313 (patch) | |
tree | 9b25b1a427cba3d3e35d4272e53a482038142242 /shared-core/i915_irq.c | |
parent | 7f04dd06e6003dd492ae5ddc876121a686f49157 (diff) | |
parent | 2a618e5a7f6d26fe85e7d931d0ef08d9f18b1b7c (diff) |
Merge branch 'master' of git+ssh://git.freedesktop.org/git/mesa/drm into modesetting-101
Conflicts:
shared-core/i915_dma.c
shared-core/i915_drv.h
shared-core/i915_irq.c
Diffstat (limited to 'shared-core/i915_irq.c')
-rw-r--r-- | shared-core/i915_irq.c | 163 |
1 files changed, 100 insertions, 63 deletions
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 558693f1..abd8a7d3 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -30,16 +30,8 @@ #include "drm.h" #include "i915_drm.h" #include "i915_drv.h" - #include "intel_drv.h" -#define USER_INT_FLAG (1<<1) -#define EVENT_PIPEB_FLAG (1<<4) -#define VSYNC_PIPEB_FLAG (1<<5) -#define EVENT_PIPEA_FLAG (1<<6) -#define VSYNC_PIPEA_FLAG (1<<7) -#define HOTPLUG_FLAG (1 << 17) - #define MAX_NOPID ((u32)~0) /** @@ -575,85 +567,90 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) struct drm_device *dev = (struct drm_device *) arg; struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - u32 temp = 0; + u32 iir; u32 pipea_stats, pipeb_stats; int hotplug = 0; + int vblank = 0; /* On i8xx/i915 hw the IIR and IER are 16bit on i9xx its 32bit */ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - temp = I915_READ(I915REG_INT_IDENTITY_R); + iir = I915_READ(I915REG_INT_IDENTITY_R); else - temp = I915_READ16(I915REG_INT_IDENTITY_R); + iir = I915_READ16(I915REG_INT_IDENTITY_R); - temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG); + iir &= (dev_priv->irq_enable_reg | I915_USER_INTERRUPT); - if (temp == 0) +#if 0 + DRM_DEBUG("flag=%08x\n", iir); +#endif + if (iir == 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)); return IRQ_NONE; - - pipea_stats = I915_READ(I915REG_PIPEASTAT); - pipeb_stats = I915_READ(I915REG_PIPEBSTAT); + } /* * Clear the PIPE(A|B)STAT regs before the IIR otherwise * we may get extra interrupts. */ - if (temp & VSYNC_PIPEA_FLAG) { - drm_handle_vblank(dev, i915_get_plane(dev, 0)); - - pipea_stats |= I915_VBLANK_INTERRUPT_ENABLE | - I915_VBLANK_CLEAR; - } - - if (temp & VSYNC_PIPEB_FLAG) { - drm_handle_vblank(dev, i915_get_plane(dev, 1)); - - pipeb_stats |= I915_VBLANK_INTERRUPT_ENABLE | - I915_VBLANK_CLEAR; - } + if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { + pipea_stats = I915_READ(I915REG_PIPEASTAT); + if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| + I915_VBLANK_INTERRUPT_STATUS)) + { + vblank++; + drm_handle_vblank(dev, i915_get_plane(dev, 0)); + } - /* This is a global event, and not a pipe A event */ - if (temp & EVENT_PIPEA_FLAG) { - if (pipea_stats & I915_HOTPLUG_CLEAR) + /* This is a global event, and not a pipe A event */ + if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) hotplug = 1; - pipea_stats |= I915_HOTPLUG_INTERRUPT_ENABLE | - I915_HOTPLUG_CLEAR; - + I915_WRITE(I915REG_PIPEASTAT, pipea_stats); } - I915_WRITE(I915REG_PIPEASTAT, pipea_stats); - (void) I915_READ(I915REG_PIPEASTAT); - I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); - (void) I915_READ(I915REG_PIPEBSTAT); + if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { + pipeb_stats = I915_READ(I915REG_PIPEBSTAT); + if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| + I915_VBLANK_INTERRUPT_STATUS)) + { + vblank++; + drm_handle_vblank(dev, i915_get_plane(dev, 1)); + } + I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); + } /* Clear the generated interrupt */ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - I915_WRITE(I915REG_INT_IDENTITY_R, temp); + I915_WRITE(I915REG_INT_IDENTITY_R, iir); (void) I915_READ(I915REG_INT_IDENTITY_R); } else { - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + I915_WRITE16(I915REG_INT_IDENTITY_R, iir); (void) I915_READ16(I915REG_INT_IDENTITY_R); } - if (dev->primary->master) { master_priv = dev->primary->master->driver_priv; master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); } - if (temp & USER_INT_FLAG) { + if (iir & I915_USER_INTERRUPT) { DRM_WAKEUP(&dev_priv->irq_queue); #ifdef I915_HAVE_FENCE i915_fence_handler(dev); #endif } - if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { + if (vblank) { if (dev_priv->swaps_pending > 0) drm_locked_tasklet(dev, i915_vblank_tasklet); } - if ((temp & HOTPLUG_FLAG) || hotplug) { + if ((iir & I915_DISPLAY_PORT_INTERRUPT) || hotplug) { u32 temp2 = 0; DRM_INFO("Hotplug event received\n"); @@ -697,7 +694,7 @@ void i915_user_irq_on(struct drm_device *dev) DRM_SPINLOCK(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ - dev_priv->irq_enable_reg |= USER_INT_FLAG; + dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); else @@ -713,7 +710,7 @@ void i915_user_irq_off(struct drm_device *dev) DRM_SPINLOCK(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - // dev_priv->irq_enable_reg &= ~USER_INT_FLAG; + // dev_priv->irq_enable_reg &= ~I915_USER_INTERRUPT; // if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) // I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); // else @@ -799,13 +796,17 @@ int i915_enable_vblank(struct drm_device *dev, int plane) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; int pipe = i915_get_pipe(dev, plane); - + u32 pipestat_reg = 0; + u32 pipestat; + switch (pipe) { case 0: - dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; + pipestat_reg = I915REG_PIPEASTAT; + dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: - dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; + pipestat_reg = I915REG_PIPEBSTAT; + dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", @@ -813,11 +814,31 @@ int i915_enable_vblank(struct drm_device *dev, int plane) break; } + if (pipestat_reg) + { + pipestat = I915_READ (pipestat_reg); + /* + * Older chips didn't have the start vblank interrupt, + * but + */ + if (IS_I965G (dev)) + pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE; + else + pipestat |= I915_VBLANK_INTERRUPT_ENABLE; + /* + * Clear any pending status + */ + pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | + I915_VBLANK_INTERRUPT_STATUS); + I915_WRITE(pipestat_reg, pipestat); + } + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); else I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + return 0; } @@ -825,13 +846,17 @@ void i915_disable_vblank(struct drm_device *dev, int plane) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; int pipe = i915_get_pipe(dev, plane); + u32 pipestat_reg = 0; + u32 pipestat; switch (pipe) { case 0: - dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG; + pipestat_reg = I915REG_PIPEASTAT; + dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: - dev_priv->irq_enable_reg &= ~VSYNC_PIPEB_FLAG; + pipestat_reg = I915REG_PIPEBSTAT; + dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", @@ -843,6 +868,19 @@ void i915_disable_vblank(struct drm_device *dev, int plane) I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); else I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + + if (pipestat_reg) + { + pipestat = I915_READ (pipestat_reg); + pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE | + I915_VBLANK_INTERRUPT_ENABLE); + /* + * Clear any pending status + */ + pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | + I915_VBLANK_INTERRUPT_STATUS); + I915_WRITE(pipestat_reg, pipestat); + } } void i915_enable_interrupt (struct drm_device *dev) @@ -850,20 +888,20 @@ void i915_enable_interrupt (struct drm_device *dev) struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; struct drm_output *o; - dev_priv->irq_enable_reg |= USER_INT_FLAG; + dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { if (dev->mode_config.num_output) - dev_priv->irq_enable_reg |= HOTPLUG_FLAG; + dev_priv->irq_enable_reg |= I915_DISPLAY_PORT_INTERRUPT; } else { if (dev->mode_config.num_output) - dev_priv->irq_enable_reg |= EVENT_PIPEA_FLAG | EVENT_PIPEB_FLAG; + 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); } - if (dev_priv->irq_enable_reg & (HOTPLUG_FLAG | EVENT_PIPEA_FLAG | EVENT_PIPEB_FLAG)) { + 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)) { @@ -953,9 +991,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, flag = I915_READ16(I915REG_INT_ENABLE_R); pipe->pipe = 0; - if (flag & VSYNC_PIPEA_FLAG) + if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) pipe->pipe |= DRM_I915_VBLANK_PIPE_A; - if (flag & VSYNC_PIPEB_FLAG) + if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) pipe->pipe |= DRM_I915_VBLANK_PIPE_B; return 0; @@ -1128,8 +1166,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - I915_WRITE(I915REG_PIPEASTAT, 0xffff); - I915_WRITE(I915REG_PIPEBSTAT, 0xffff); I915_WRITE16(I915REG_HWSTAM, 0xeffe); if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { I915_WRITE(I915REG_INT_MASK_R, 0x0); @@ -1185,9 +1221,10 @@ void i915_driver_irq_uninstall(struct drm_device * dev) dev_priv->irq_enabled = 0; - - I915_WRITE(I915REG_PIPEASTAT, 0xffff); - I915_WRITE(I915REG_PIPEBSTAT, 0xffff); + temp = I915_READ(I915REG_PIPEASTAT); + I915_WRITE(I915REG_PIPEASTAT, temp); + temp = I915_READ(I915REG_PIPEBSTAT); + I915_WRITE(I915REG_PIPEBSTAT, temp); if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { I915_WRITE(I915REG_HWSTAM, 0xffffffff); I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); |