Loading drivers/gpu/drm/i915/i915_dma.c +10 −2 Original line number Diff line number Diff line Loading @@ -1266,7 +1266,15 @@ static int i915_load_modeset_init(struct drm_device *dev) intel_modeset_gem_init(dev); if (HAS_PCH_SPLIT(dev)) { if (IS_IVYBRIDGE(dev)) { /* Share pre & uninstall handlers with ILK/SNB */ dev->driver->irq_handler = ivybridge_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; dev->driver->irq_postinstall = ivybridge_irq_postinstall; dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ivybridge_enable_vblank; dev->driver->disable_vblank = ivybridge_disable_vblank; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; dev->driver->irq_postinstall = ironlake_irq_postinstall; Loading Loading @@ -2011,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) { dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->driver->get_vblank_counter = gm45_get_vblank_counter; } Loading drivers/gpu/drm/i915/i915_drv.h +7 −0 Original line number Diff line number Diff line Loading @@ -1043,6 +1043,11 @@ extern void ironlake_irq_preinstall(struct drm_device *dev); extern int ironlake_irq_postinstall(struct drm_device *dev); extern void ironlake_irq_uninstall(struct drm_device *dev); extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS); extern void ivybridge_irq_preinstall(struct drm_device *dev); extern int ivybridge_irq_postinstall(struct drm_device *dev); extern void ivybridge_irq_uninstall(struct drm_device *dev); extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, Loading @@ -1051,6 +1056,8 @@ extern int i915_enable_vblank(struct drm_device *dev, int crtc); extern void i915_disable_vblank(struct drm_device *dev, int crtc); extern int ironlake_enable_vblank(struct drm_device *dev, int crtc); extern void ironlake_disable_vblank(struct drm_device *dev, int crtc); extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc); extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc); extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); extern int i915_vblank_swap(struct drm_device *dev, void *data, Loading drivers/gpu/drm/i915/i915_irq.c +165 −0 Original line number Diff line number Diff line Loading @@ -462,6 +462,94 @@ static void pch_irq_handler(struct drm_device *dev) DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); } irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; struct drm_i915_master_private *master_priv; atomic_inc(&dev_priv->irq_received); /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); POSTING_READ(DEIER); de_iir = I915_READ(DEIIR); gt_iir = I915_READ(GTIIR); pch_iir = I915_READ(SDEIIR); pm_iir = I915_READ(GEN6_PMIIR); if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0) goto done; ret = IRQ_HANDLED; if (dev->primary->master) { master_priv = dev->primary->master->driver_priv; if (master_priv->sarea_priv) master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); } if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) notify_ring(dev, &dev_priv->ring[RCS]); if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS]); if (gt_iir & GT_BLT_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[BCS]); if (de_iir & DE_GSE_IVB) intel_opregion_gse_intr(dev); if (de_iir & DE_PLANEA_FLIP_DONE_IVB) { intel_prepare_page_flip(dev, 0); intel_finish_page_flip_plane(dev, 0); } if (de_iir & DE_PLANEB_FLIP_DONE_IVB) { intel_prepare_page_flip(dev, 1); intel_finish_page_flip_plane(dev, 1); } if (de_iir & DE_PIPEA_VBLANK_IVB) drm_handle_vblank(dev, 0); if (de_iir & DE_PIPEB_VBLANK_IVB); drm_handle_vblank(dev, 1); /* check event from PCH */ if (de_iir & DE_PCH_EVENT_IVB) { if (pch_iir & SDE_HOTPLUG_MASK_CPT) queue_work(dev_priv->wq, &dev_priv->hotplug_work); pch_irq_handler(dev); } if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { unsigned long flags; spin_lock_irqsave(&dev_priv->rps_lock, flags); WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); I915_WRITE(GEN6_PMIMR, pm_iir); dev_priv->pm_iir |= pm_iir; spin_unlock_irqrestore(&dev_priv->rps_lock, flags); queue_work(dev_priv->wq, &dev_priv->rps_work); } /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(DEIIR, de_iir); I915_WRITE(GEN6_PMIIR, pm_iir); done: I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); return ret; } irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; Loading Loading @@ -1406,6 +1494,22 @@ int ironlake_enable_vblank(struct drm_device *dev, int pipe) return 0; } int ivybridge_enable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; if (!i915_pipe_enabled(dev, pipe)) return -EINVAL; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); ironlake_enable_display_irq(dev_priv, (pipe == 0) ? DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); return 0; } /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ Loading Loading @@ -1436,6 +1540,17 @@ void ironlake_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } void ivybridge_disable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); ironlake_disable_display_irq(dev_priv, (pipe == 0) ? DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } /* Set the vblank monitor pipe */ int i915_vblank_pipe_set(struct drm_device *dev, void *data, Loading Loading @@ -1713,6 +1828,56 @@ int ironlake_irq_postinstall(struct drm_device *dev) return 0; } int ivybridge_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB | DE_PLANEB_FLIP_DONE_IVB; u32 render_irqs; u32 hotplug_mask; DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue); if (HAS_BSD(dev)) DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue); if (HAS_BLT(dev)) DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue); dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; dev_priv->irq_mask = ~display_mask; /* should always can generate irq */ I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIMR, dev_priv->irq_mask); I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB | DE_PIPEB_VBLANK_IVB); POSTING_READ(DEIER); dev_priv->gt_irq_mask = ~0; I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT | GT_BLT_USER_INTERRUPT; I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); hotplug_mask = (SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT | SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT); dev_priv->pch_irq_mask = ~hotplug_mask; I915_WRITE(SDEIIR, I915_READ(SDEIIR)); I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); I915_WRITE(SDEIER, hotplug_mask); POSTING_READ(SDEIER); return 0; } void i915_driver_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; Loading drivers/gpu/drm/i915/i915_reg.h +13 −0 Original line number Diff line number Diff line Loading @@ -2778,6 +2778,19 @@ #define DE_PIPEA_VSYNC (1 << 3) #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) /* More Ivybridge lolz */ #define DE_ERR_DEBUG_IVB (1<<30) #define DE_GSE_IVB (1<<29) #define DE_PCH_EVENT_IVB (1<<28) #define DE_DP_A_HOTPLUG_IVB (1<<27) #define DE_AUX_CHANNEL_A_IVB (1<<26) #define DE_SPRITEB_FLIP_DONE_IVB (1<<9) #define DE_SPRITEA_FLIP_DONE_IVB (1<<4) #define DE_PLANEB_FLIP_DONE_IVB (1<<8) #define DE_PLANEA_FLIP_DONE_IVB (1<<3) #define DE_PIPEB_VBLANK_IVB (1<<5) #define DE_PIPEA_VBLANK_IVB (1<<0) #define DEISR 0x44000 #define DEIMR 0x44004 #define DEIIR 0x44008 Loading Loading
drivers/gpu/drm/i915/i915_dma.c +10 −2 Original line number Diff line number Diff line Loading @@ -1266,7 +1266,15 @@ static int i915_load_modeset_init(struct drm_device *dev) intel_modeset_gem_init(dev); if (HAS_PCH_SPLIT(dev)) { if (IS_IVYBRIDGE(dev)) { /* Share pre & uninstall handlers with ILK/SNB */ dev->driver->irq_handler = ivybridge_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; dev->driver->irq_postinstall = ivybridge_irq_postinstall; dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ivybridge_enable_vblank; dev->driver->disable_vblank = ivybridge_disable_vblank; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; dev->driver->irq_postinstall = ironlake_irq_postinstall; Loading Loading @@ -2011,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) { dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->driver->get_vblank_counter = gm45_get_vblank_counter; } Loading
drivers/gpu/drm/i915/i915_drv.h +7 −0 Original line number Diff line number Diff line Loading @@ -1043,6 +1043,11 @@ extern void ironlake_irq_preinstall(struct drm_device *dev); extern int ironlake_irq_postinstall(struct drm_device *dev); extern void ironlake_irq_uninstall(struct drm_device *dev); extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS); extern void ivybridge_irq_preinstall(struct drm_device *dev); extern int ivybridge_irq_postinstall(struct drm_device *dev); extern void ivybridge_irq_uninstall(struct drm_device *dev); extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, Loading @@ -1051,6 +1056,8 @@ extern int i915_enable_vblank(struct drm_device *dev, int crtc); extern void i915_disable_vblank(struct drm_device *dev, int crtc); extern int ironlake_enable_vblank(struct drm_device *dev, int crtc); extern void ironlake_disable_vblank(struct drm_device *dev, int crtc); extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc); extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc); extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); extern int i915_vblank_swap(struct drm_device *dev, void *data, Loading
drivers/gpu/drm/i915/i915_irq.c +165 −0 Original line number Diff line number Diff line Loading @@ -462,6 +462,94 @@ static void pch_irq_handler(struct drm_device *dev) DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); } irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; struct drm_i915_master_private *master_priv; atomic_inc(&dev_priv->irq_received); /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); POSTING_READ(DEIER); de_iir = I915_READ(DEIIR); gt_iir = I915_READ(GTIIR); pch_iir = I915_READ(SDEIIR); pm_iir = I915_READ(GEN6_PMIIR); if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0) goto done; ret = IRQ_HANDLED; if (dev->primary->master) { master_priv = dev->primary->master->driver_priv; if (master_priv->sarea_priv) master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); } if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) notify_ring(dev, &dev_priv->ring[RCS]); if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS]); if (gt_iir & GT_BLT_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[BCS]); if (de_iir & DE_GSE_IVB) intel_opregion_gse_intr(dev); if (de_iir & DE_PLANEA_FLIP_DONE_IVB) { intel_prepare_page_flip(dev, 0); intel_finish_page_flip_plane(dev, 0); } if (de_iir & DE_PLANEB_FLIP_DONE_IVB) { intel_prepare_page_flip(dev, 1); intel_finish_page_flip_plane(dev, 1); } if (de_iir & DE_PIPEA_VBLANK_IVB) drm_handle_vblank(dev, 0); if (de_iir & DE_PIPEB_VBLANK_IVB); drm_handle_vblank(dev, 1); /* check event from PCH */ if (de_iir & DE_PCH_EVENT_IVB) { if (pch_iir & SDE_HOTPLUG_MASK_CPT) queue_work(dev_priv->wq, &dev_priv->hotplug_work); pch_irq_handler(dev); } if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { unsigned long flags; spin_lock_irqsave(&dev_priv->rps_lock, flags); WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); I915_WRITE(GEN6_PMIMR, pm_iir); dev_priv->pm_iir |= pm_iir; spin_unlock_irqrestore(&dev_priv->rps_lock, flags); queue_work(dev_priv->wq, &dev_priv->rps_work); } /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(DEIIR, de_iir); I915_WRITE(GEN6_PMIIR, pm_iir); done: I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); return ret; } irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; Loading Loading @@ -1406,6 +1494,22 @@ int ironlake_enable_vblank(struct drm_device *dev, int pipe) return 0; } int ivybridge_enable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; if (!i915_pipe_enabled(dev, pipe)) return -EINVAL; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); ironlake_enable_display_irq(dev_priv, (pipe == 0) ? DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); return 0; } /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ Loading Loading @@ -1436,6 +1540,17 @@ void ironlake_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } void ivybridge_disable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); ironlake_disable_display_irq(dev_priv, (pipe == 0) ? DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } /* Set the vblank monitor pipe */ int i915_vblank_pipe_set(struct drm_device *dev, void *data, Loading Loading @@ -1713,6 +1828,56 @@ int ironlake_irq_postinstall(struct drm_device *dev) return 0; } int ivybridge_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB | DE_PLANEB_FLIP_DONE_IVB; u32 render_irqs; u32 hotplug_mask; DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue); if (HAS_BSD(dev)) DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue); if (HAS_BLT(dev)) DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue); dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; dev_priv->irq_mask = ~display_mask; /* should always can generate irq */ I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIMR, dev_priv->irq_mask); I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB | DE_PIPEB_VBLANK_IVB); POSTING_READ(DEIER); dev_priv->gt_irq_mask = ~0; I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT | GT_BLT_USER_INTERRUPT; I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); hotplug_mask = (SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT | SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT); dev_priv->pch_irq_mask = ~hotplug_mask; I915_WRITE(SDEIIR, I915_READ(SDEIIR)); I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); I915_WRITE(SDEIER, hotplug_mask); POSTING_READ(SDEIER); return 0; } void i915_driver_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; Loading
drivers/gpu/drm/i915/i915_reg.h +13 −0 Original line number Diff line number Diff line Loading @@ -2778,6 +2778,19 @@ #define DE_PIPEA_VSYNC (1 << 3) #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) /* More Ivybridge lolz */ #define DE_ERR_DEBUG_IVB (1<<30) #define DE_GSE_IVB (1<<29) #define DE_PCH_EVENT_IVB (1<<28) #define DE_DP_A_HOTPLUG_IVB (1<<27) #define DE_AUX_CHANNEL_A_IVB (1<<26) #define DE_SPRITEB_FLIP_DONE_IVB (1<<9) #define DE_SPRITEA_FLIP_DONE_IVB (1<<4) #define DE_PLANEB_FLIP_DONE_IVB (1<<8) #define DE_PLANEA_FLIP_DONE_IVB (1<<3) #define DE_PIPEB_VBLANK_IVB (1<<5) #define DE_PIPEA_VBLANK_IVB (1<<0) #define DEISR 0x44000 #define DEIMR 0x44004 #define DEIIR 0x44008 Loading