@@ -1672,6 +1672,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_mtrrfree;
}
+ dev_priv->display_irqs_enabled = true;
intel_irq_init(dev);
intel_uncore_sanitize(dev);
@@ -1469,6 +1469,8 @@ typedef struct drm_i915_private {
/* protects the irq masks */
spinlock_t irq_lock;
+ bool display_irqs_enabled;
+
/* To control wakeup latency, e.g. for irq-driven dp aux transfers. */
struct pm_qos_request pm_qos;
@@ -2071,6 +2073,9 @@ void
i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe,
u32 status_mask);
+void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv);
+void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv);
+
/* i915_gem.c */
int i915_gem_init_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -3035,36 +3035,113 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
return 0;
}
+static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv)
+{
+ u32 pipestat_mask;
+ u32 iir_mask;
+
+ pipestat_mask = PIPESTAT_INT_STATUS_MASK |
+ PIPE_FIFO_UNDERRUN_STATUS;
+
+ I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask);
+ I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask);
+ POSTING_READ(PIPESTAT(PIPE_A));
+
+ pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
+ PIPE_CRC_DONE_INTERRUPT_STATUS;
+
+ i915_enable_pipestat(dev_priv, PIPE_A, pipestat_mask |
+ PIPE_GMBUS_INTERRUPT_STATUS);
+ i915_enable_pipestat(dev_priv, PIPE_B, pipestat_mask);
+
+ iir_mask = I915_DISPLAY_PORT_INTERRUPT |
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ dev_priv->irq_mask &= ~iir_mask;
+
+ I915_WRITE(VLV_IIR, iir_mask);
+ I915_WRITE(VLV_IIR, iir_mask);
+ I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+ I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
+ POSTING_READ(VLV_IER);
+}
+
+static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv)
+{
+ u32 pipestat_mask;
+ u32 iir_mask;
+
+ iir_mask = I915_DISPLAY_PORT_INTERRUPT |
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+
+ dev_priv->irq_mask |= iir_mask;
+ I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
+ I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+ I915_WRITE(VLV_IIR, iir_mask);
+ I915_WRITE(VLV_IIR, iir_mask);
+ POSTING_READ(VLV_IIR);
+
+ pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
+ PIPE_CRC_DONE_INTERRUPT_STATUS;
+
+ i915_disable_pipestat(dev_priv, PIPE_A, pipestat_mask |
+ PIPE_GMBUS_INTERRUPT_STATUS);
+ i915_disable_pipestat(dev_priv, PIPE_B, pipestat_mask);
+
+ pipestat_mask = PIPESTAT_INT_STATUS_MASK |
+ PIPE_FIFO_UNDERRUN_STATUS;
+ I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask);
+ I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask);
+ POSTING_READ(PIPESTAT(PIPE_A));
+}
+
+void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
+{
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ if (dev_priv->display_irqs_enabled)
+ return;
+
+ dev_priv->display_irqs_enabled = true;
+
+ if (dev_priv->dev->irq_enabled)
+ valleyview_display_irqs_install(dev_priv);
+}
+
+void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
+{
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ if (!dev_priv->display_irqs_enabled)
+ return;
+
+ dev_priv->display_irqs_enabled = false;
+
+ if (dev_priv->dev->irq_enabled)
+ valleyview_display_irqs_uninstall(dev_priv);
+}
+
static int valleyview_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 enable_mask;
- u32 pipestat_enable = PLANE_FLIP_DONE_INT_STATUS_VLV |
- PIPE_CRC_DONE_INTERRUPT_STATUS;
unsigned long irqflags;
- enable_mask = I915_DISPLAY_PORT_INTERRUPT;
- enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
- I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
-
- dev_priv->irq_mask = ~enable_mask;
+ dev_priv->irq_mask = ~0;
I915_WRITE(PORT_HOTPLUG_EN, 0);
POSTING_READ(PORT_HOTPLUG_EN);
I915_WRITE(VLV_IMR, dev_priv->irq_mask);
- I915_WRITE(VLV_IER, enable_mask);
+ I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
I915_WRITE(VLV_IIR, 0xffffffff);
- I915_WRITE(PIPESTAT(0), 0xffff);
- I915_WRITE(PIPESTAT(1), 0xffff);
POSTING_READ(VLV_IER);
/* Interrupt setup is already guaranteed to be single-threaded, this is
* just to make the assert_spin_locked check happy. */
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- i915_enable_pipestat(dev_priv, PIPE_A, pipestat_enable);
- i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
- i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable);
+ if (dev_priv->display_irqs_enabled)
+ valleyview_display_irqs_install(dev_priv);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
I915_WRITE(VLV_IIR, 0xffffffff);
@@ -3195,6 +3272,7 @@ static void gen8_irq_uninstall(struct drm_device *dev)
static void valleyview_irq_uninstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
int pipe;
if (!dev_priv)
@@ -3208,8 +3286,14 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
I915_WRITE(HWSTAM, 0xffffffff);
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
- for_each_pipe(pipe)
- I915_WRITE(PIPESTAT(pipe), 0xffff);
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ if (dev_priv->display_irqs_enabled)
+ valleyview_display_irqs_uninstall(dev_priv);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ dev_priv->irq_mask = 0;
+
I915_WRITE(VLV_IIR, 0xffffffff);
I915_WRITE(VLV_IMR, 0xffffffff);
I915_WRITE(VLV_IER, 0x0);