Add new interrupt handling functions for Ivy Bridge.
Signed-off-by: Jesse Barnes jbar...@virtuousgeek.org
---
drivers/gpu/drm/i915/i915_dma.c | 12 +++-
drivers/gpu/drm/i915/i915_drv.h |7 ++
drivers/gpu/drm/i915/i915_irq.c | 156 +++
drivers/gpu/drm/i915/i915_reg.h | 13 +++
4 files changed, 186 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index d124f0e..8e27bc4 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1253,7 +1253,15 @@ static int i915_load_modeset_init(struct drm_device *dev)
intel_modeset_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;
@@ -1998,7 +2006,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 = 0xff; /* 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 = 0x; /* full 32 bit counter */
dev-driver-get_vblank_counter = gm45_get_vblank_counter;
}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 4c06eb1..5f906f1 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1039,6 +1039,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,
@@ -1047,6 +1052,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,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d5dcb8f..a025002 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -448,6 +448,85 @@ 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))
+