diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index b0f6e3e..33cfa40 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -86,7 +86,7 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp, * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions * before and after the installation. */ -static int drm_irq_install(drm_device_t * dev) +int drm_irq_install(drm_device_t * dev) { int ret; unsigned long sh_flags = 0; @@ -146,6 +146,7 @@ static int drm_irq_install(drm_device_t * dev) return 0; } +EXPORT_SYMBOL(drm_irq_install); /** * Uninstall the IRQ handler. diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index b0aa5df..4aef693 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -119,7 +119,6 @@ typedef struct drm_i915_private { spinlock_t user_irq_lock; int user_irq_refcount; int fence_irq_on; - uint32_t irq_enable_reg; int irq_enabled; #ifdef I915_HAVE_FENCE @@ -362,10 +361,24 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define I915REG_HWS_PGA 0x02080 #define I915REG_HWSTAM 0x02098 +#define I915REG_INT_STATUS_R 0x020ac #define I915REG_INT_IDENTITY_R 0x020a4 #define I915REG_INT_MASK_R 0x020a8 #define I915REG_INT_ENABLE_R 0x020a0 #define I915REG_INSTPM 0x020c0 +#define INT_CTX (1<<24) +#define INT_PF (1<<23) +#define INT_PIPE_CTL (1<<18) +#define INT_DISPLAY (1<<17) +#define INT_ERROR (1<<15) +#define INT_THERMAL (1<<14) +#define INT_SYNC_STATUS (1<<12) +#define INT_PIPEA_VBLANK (1<<7) +#define INT_PIPEA_EVENT (1<<6) +#define INT_PIPEB_VBLANK (1<<5) +#define INT_PIPEB_EVENT (1<<4) +#define INT_DEBUG (1<<2) +#define INT_USER (1<<1) #define I915REG_PIPEASTAT 0x70024 #define I915REG_PIPEBSTAT 0x71024 diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 7516b2c..b1486ca 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -246,6 +246,9 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); + drm_irq_install(dev); + DRM_DEBUG("Enabled IRQs\n"); + intel_modeset_init(dev); drm_initial_config(dev, false); @@ -256,6 +259,8 @@ int i915_driver_unload(drm_device_t *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + drm_irq_uninstall(dev); + if (dev_priv->status_page_dmah) { drm_pci_free(dev, dev_priv->status_page_dmah); dev_priv->status_page_dmah = NULL; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 2d4df76..604c6fc 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -31,10 +31,6 @@ #include "i915_drm.h" #include "i915_drv.h" -#define USER_INT_FLAG (1<<1) -#define VSYNC_PIPEB_FLAG (1<<5) -#define VSYNC_PIPEA_FLAG (1<<7) - #define MAX_NOPID ((u32)~0) /** @@ -278,47 +274,59 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u16 temp; + u16 irqstatus; u32 pipea_stats, pipeb_stats; + irqreturn_t ret = IRQ_NONE; pipea_stats = I915_READ(I915REG_PIPEASTAT); pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - - temp = I915_READ16(I915REG_INT_IDENTITY_R); - temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG); -#if 0 - DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); + /* Figure out which IRQs we care about actually happened */ + irqstatus = I915_READ16(I915REG_INT_IDENTITY_R); + irqstatus &= ~I915_READ16(I915REG_INT_MASK_R); + + if (!irqstatus) + goto out; + + ret = IRQ_HANDLED; + +#if 1 + DRM_DEBUG("%s iir=0x%08x\n", __FUNCTION__, irqstatus); + DRM_DEBUG("%s ier=0x%08x\n", __FUNCTION__, + I915_READ(I915REG_INT_ENABLE_R)); + DRM_DEBUG("%s imr=0x%08x\n", __FUNCTION__, + I915_READ(I915REG_INT_MASK_R)); + DRM_DEBUG("%s isr=0x%08x\n", __FUNCTION__, + I915_READ(I915REG_INT_STATUS_R)); #endif - if (temp == 0) - return IRQ_NONE; - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); - (void) I915_READ16(I915REG_INT_IDENTITY_R); - DRM_READMEMORYBARRIER(); + /* Clear interrupt status */ + I915_WRITE(I915REG_INT_IDENTITY_R, irqstatus); + (void)I915_READ(I915REG_INT_IDENTITY_R); + DRM_READMEMORYBARRIER(); /* FIXME: shouldn't be necessary */ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - if (temp & USER_INT_FLAG) { + if (irqstatus & INT_USER) { DRM_WAKEUP(&dev_priv->irq_queue); #ifdef I915_HAVE_FENCE i915_fence_handler(dev); #endif } - if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { + if (irqstatus & (INT_PIPEA_VBLANK | INT_PIPEB_VBLANK)) { int vblank_pipe = dev_priv->vblank_pipe; if ((vblank_pipe & (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { - if (temp & VSYNC_PIPEA_FLAG) + if (irqstatus & INT_PIPEA_VBLANK) atomic_inc(&dev->vbl_received); - if (temp & VSYNC_PIPEB_FLAG) + if (irqstatus & INT_PIPEB_VBLANK) atomic_inc(&dev->vbl_received2); - } else if (((temp & VSYNC_PIPEA_FLAG) && + } else if (((irqstatus & INT_PIPEA_VBLANK) && (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || - ((temp & VSYNC_PIPEB_FLAG) && + ((irqstatus & INT_PIPEB_VBLANK) && (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) atomic_inc(&dev->vbl_received); @@ -335,7 +343,11 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_VBLANK_CLEAR); } - return IRQ_HANDLED; + if (irqstatus & INT_DISPLAY) + DRM_DEBUG("display hotplug event occurred\n"); + +out: + return ret; } int i915_emit_irq(drm_device_t * dev) @@ -362,10 +374,11 @@ int i915_emit_irq(drm_device_t * dev) void i915_user_irq_on(drm_i915_private_t *dev_priv) { + DRM_DEBUG("user_irq_on\n"); spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ - dev_priv->irq_enable_reg |= USER_INT_FLAG; - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + u32 ints = I915_READ(I915REG_INT_ENABLE_R) | INT_USER; + I915_WRITE(I915REG_INT_ENABLE_R, ints); } spin_unlock(&dev_priv->user_irq_lock); @@ -375,8 +388,8 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv) { spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - // dev_priv->irq_enable_reg &= ~USER_INT_FLAG; - // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + //u32 ints = I915_READ(I915_REG_INT_ENABLE_R) & ~INT_USER; + //I915_WRITE(I915REG_INT_ENABLE_R, ints); } spin_unlock(&dev_priv->user_irq_lock); } @@ -512,14 +525,35 @@ int i915_irq_wait(DRM_IOCTL_ARGS) void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - - dev_priv->irq_enable_reg = USER_INT_FLAG; + u32 ints; + + /* Enable display hotplug interrupts... */ + ints = INT_DISPLAY; + + I915_WRITE(PORT_HOTPLUG_EN, SDVOB_HOTPLUG_INT_EN | + SDVOC_HOTPLUG_INT_EN | TV_HOTPLUG_INT_EN | + CRT_HOTPLUG_INT_EN); +#if 0 + /* and whichever vblank interrupts we need */ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) - dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; + ints |= INT_PIPEA_VBLANK; if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) - dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; + ints |= INT_PIPEB_VBLANK; +#else + I915_WRITE(I915REG_PIPEASTAT, I915_VBLANK_CLEAR); + I915_WRITE(I915REG_PIPEBSTAT, I915_VBLANK_CLEAR); +#endif + DRM_DEBUG("enabling interrupts 0x%08x\n", ints); + + I915_WRITE(I915REG_INT_ENABLE_R, ~0); + I915_WRITE(I915REG_INT_MASK_R, ~ints); + I915_WRITE(I915REG_INT_IDENTITY_R, ~0); - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + DRM_DEBUG("%s ier=0x%08x\n", __FUNCTION__, + I915_READ(I915REG_INT_ENABLE_R)); + DRM_DEBUG("%s imr=0x%08x\n", __FUNCTION__, + I915_READ(I915REG_INT_MASK_R)); + dev_priv->irq_enabled = 1; } @@ -566,9 +600,9 @@ int i915_vblank_pipe_get(DRM_IOCTL_ARGS) flag = I915_READ(I915REG_INT_ENABLE_R); pipe.pipe = 0; - if (flag & VSYNC_PIPEA_FLAG) + if (flag & INT_PIPEA_VBLANK) pipe.pipe |= DRM_I915_VBLANK_PIPE_A; - if (flag & VSYNC_PIPEB_FLAG) + if (flag & INT_PIPEB_VBLANK) pipe.pipe |= DRM_I915_VBLANK_PIPE_B; DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe, sizeof(pipe)); @@ -726,9 +760,9 @@ void i915_driver_irq_preinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - I915_WRITE16(I915REG_HWSTAM, 0xeffe); - I915_WRITE16(I915REG_INT_MASK_R, 0x0); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + I915_WRITE(I915REG_HWSTAM, 0xeffe); +// I915_WRITE(I915REG_INT_MASK_R, 0x0); +// I915_WRITE(I915REG_INT_ENABLE_R, 0x0); } void i915_driver_irq_postinstall(drm_device_t * dev) @@ -759,15 +793,17 @@ void i915_driver_irq_postinstall(drm_device_t * dev) void i915_driver_irq_uninstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u16 temp; + u32 irqstatus; if (!dev_priv) return; + DRM_DEBUG("disabling interrupts\n"); + dev_priv->irq_enabled = 0; - I915_WRITE16(I915REG_HWSTAM, 0xffff); - I915_WRITE16(I915REG_INT_MASK_R, 0xffff); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + I915_WRITE(I915REG_HWSTAM, ~0); + I915_WRITE(I915REG_INT_MASK_R, ~0); + I915_WRITE(I915REG_INT_ENABLE_R, 0x0); - temp = I915_READ16(I915REG_INT_IDENTITY_R); - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + irqstatus = I915_READ(I915REG_INT_IDENTITY_R); + I915_WRITE(I915REG_INT_IDENTITY_R, irqstatus); }