drm/i915: detect & report PCH display error interrupts
authorJesse Barnes <jbarnes@virtuousgeek.org>
Tue, 4 Jan 2011 23:09:39 +0000 (15:09 -0800)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 11 Jan 2011 20:44:01 +0000 (20:44 +0000)
FDI and the transcoders can fail for various reasons, so detect those
conditions and report on them.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h

index c9adcdd6ad6a84296f9793ea451f5f55b55f9fd4..d431fc4fb84b971e93edfe713a0eff65016df6f9 100644 (file)
@@ -398,6 +398,50 @@ static void gen6_pm_irq_handler(struct drm_device *dev)
        I915_WRITE(GEN6_PMIIR, pm_iir);
 }
 
+static void pch_irq_handler(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 pch_iir;
+
+       pch_iir = I915_READ(SDEIIR);
+
+       if (pch_iir & SDE_AUDIO_POWER_MASK)
+               DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
+                                (pch_iir & SDE_AUDIO_POWER_MASK) >>
+                                SDE_AUDIO_POWER_SHIFT);
+
+       if (pch_iir & SDE_GMBUS)
+               DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
+
+       if (pch_iir & SDE_AUDIO_HDCP_MASK)
+               DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
+
+       if (pch_iir & SDE_AUDIO_TRANS_MASK)
+               DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n");
+
+       if (pch_iir & SDE_POISON)
+               DRM_ERROR("PCH poison interrupt\n");
+
+       if (pch_iir & SDE_FDI_MASK) {
+               u32 fdia, fdib;
+
+               fdia = I915_READ(FDI_RXA_IIR);
+               fdib = I915_READ(FDI_RXB_IIR);
+               DRM_DEBUG_DRIVER("PCH FDI RX interrupt; FDI RXA IIR: 0x%08x, FDI RXB IIR: 0x%08x\n", fdia, fdib);
+       }
+
+       if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
+               DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n");
+
+       if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
+               DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
+
+       if (pch_iir & SDE_TRANSB_FIFO_UNDER)
+               DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n");
+       if (pch_iir & SDE_TRANSA_FIFO_UNDER)
+               DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
+}
+
 static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -465,8 +509,11 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
                drm_handle_vblank(dev, 1);
 
        /* check event from PCH */
-       if ((de_iir & DE_PCH_EVENT) && (pch_iir & hotplug_mask))
-               queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+       if (de_iir & DE_PCH_EVENT) {
+               if (pch_iir & hotplug_mask)
+                       queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+               pch_irq_handler(dev);
+       }
 
        if (de_iir & DE_PCU_EVENT) {
                I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
@@ -1656,6 +1703,9 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        } else {
                hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
                               SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+               hotplug_mask |= SDE_AUX_MASK | SDE_FDI_MASK | SDE_TRANS_MASK;
+               I915_WRITE(FDI_RXA_IMR, 0);
+               I915_WRITE(FDI_RXB_IMR, 0);
        }
 
        dev_priv->pch_irq_mask = ~hotplug_mask;
index 33ddf3120f2f517626dc485a217d58f92a6fd4bc..40a407f41f61954fb5bd89cff03256b5283c3c35 100644 (file)
 /* PCH */
 
 /* south display engine interrupt */
+#define SDE_AUDIO_POWER_D      (1 << 27)
+#define SDE_AUDIO_POWER_C      (1 << 26)
+#define SDE_AUDIO_POWER_B      (1 << 25)
+#define SDE_AUDIO_POWER_SHIFT  (25)
+#define SDE_AUDIO_POWER_MASK   (7 << SDE_AUDIO_POWER_SHIFT)
+#define SDE_GMBUS              (1 << 24)
+#define SDE_AUDIO_HDCP_TRANSB  (1 << 23)
+#define SDE_AUDIO_HDCP_TRANSA  (1 << 22)
+#define SDE_AUDIO_HDCP_MASK    (3 << 22)
+#define SDE_AUDIO_TRANSB       (1 << 21)
+#define SDE_AUDIO_TRANSA       (1 << 20)
+#define SDE_AUDIO_TRANS_MASK   (3 << 20)
+#define SDE_POISON             (1 << 19)
+/* 18 reserved */
+#define SDE_FDI_RXB            (1 << 17)
+#define SDE_FDI_RXA            (1 << 16)
+#define SDE_FDI_MASK           (3 << 16)
+#define SDE_AUXD               (1 << 15)
+#define SDE_AUXC               (1 << 14)
+#define SDE_AUXB               (1 << 13)
+#define SDE_AUX_MASK           (7 << 13)
+/* 12 reserved */
 #define SDE_CRT_HOTPLUG         (1 << 11)
 #define SDE_PORTD_HOTPLUG       (1 << 10)
 #define SDE_PORTC_HOTPLUG       (1 << 9)
 #define SDE_PORTB_HOTPLUG       (1 << 8)
 #define SDE_SDVOB_HOTPLUG       (1 << 6)
 #define SDE_HOTPLUG_MASK       (0xf << 8)
+#define SDE_TRANSB_CRC_DONE    (1 << 5)
+#define SDE_TRANSB_CRC_ERR     (1 << 4)
+#define SDE_TRANSB_FIFO_UNDER  (1 << 3)
+#define SDE_TRANSA_CRC_DONE    (1 << 2)
+#define SDE_TRANSA_CRC_ERR     (1 << 1)
+#define SDE_TRANSA_FIFO_UNDER  (1 << 0)
+#define SDE_TRANS_MASK         (0x3f)
 /* CPT */
 #define SDE_CRT_HOTPLUG_CPT    (1 << 19)
 #define SDE_PORTD_HOTPLUG_CPT  (1 << 23)