DRM/i915: Convert HPD interrupts to make use of HPD pin assignment in encoders (v2)
authorEgbert Eich <eich@suse.de>
Thu, 28 Feb 2013 09:17:12 +0000 (04:17 -0500)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 26 Mar 2013 20:52:19 +0000 (21:52 +0100)
This allows to enable HPD interrupts for individual pins to only receive
hotplug events from lines which are connected and working.

v2: Restructured initailization of const arrays following a suggstion
    by Chris Wilson <chris@chris-wilson.co.uk>

Signed-off-by: Egbert Eich <eich@suse.de>
Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v1)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h

index 1a24744f7a27e8948a187b532823dde764eb0471..ef9fce50530d804b73f63ab3b682b9f70b57cfe6 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+static const u32 hpd_ibx[] = {
+       [HPD_CRT] = SDE_CRT_HOTPLUG,
+       [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
+       [HPD_PORT_B] = SDE_PORTB_HOTPLUG,
+       [HPD_PORT_C] = SDE_PORTC_HOTPLUG,
+       [HPD_PORT_D] = SDE_PORTD_HOTPLUG
+};
+
+static const u32 hpd_cpt[] = {
+       [HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
+       [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
+       [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
+       [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
+};
+
+static const u32 hpd_mask_i915[] = {
+       [HPD_CRT] = CRT_HOTPLUG_INT_EN,
+       [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
+       [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
+       [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN,
+       [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN,
+       [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
+};
+
+static const u32 hpd_status_gen4[] = {
+       [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+       [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
+       [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
+       [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+       [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+       [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+static const u32 hpd_status_i965[] = {
+        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965,
+        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965,
+        [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+        [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
+       [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
+       [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
+       [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
+       [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
+       [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
+       [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
+};
+
+
+
 /* For display hotplug interrupt */
 static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -599,7 +652,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                         hotplug_status);
-                       if (hotplug_status & dev_priv->hotplug_supported_mask)
+                       if (hotplug_status & HOTPLUG_INT_STATUS_I915)
                                queue_work(dev_priv->wq,
                                           &dev_priv->hotplug_work);
 
@@ -2034,17 +2087,21 @@ static void ibx_enable_hotplug(struct drm_device *dev)
 static void ibx_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 mask;
-
-       if (HAS_PCH_IBX(dev))
-               mask = SDE_HOTPLUG_MASK |
-                      SDE_GMBUS |
-                      SDE_AUX_MASK;
-       else
-               mask = SDE_HOTPLUG_MASK_CPT |
-                      SDE_GMBUS_CPT |
-                      SDE_AUX_MASK_CPT;
-
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *intel_encoder;
+       u32 mask = I915_READ(SDEIER);
+
+       if (HAS_PCH_IBX(dev)) {
+               mask &= ~SDE_HOTPLUG_MASK;
+               list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+                       mask |= hpd_ibx[intel_encoder->hpd_pin];
+               mask |= SDE_GMBUS | SDE_AUX_MASK;
+       } else {
+               mask &= ~SDE_HOTPLUG_MASK_CPT;
+               list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
+                       mask |= hpd_cpt[intel_encoder->hpd_pin];
+               mask |= SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
+       }
        I915_WRITE(SDEIIR, I915_READ(SDEIIR));
        I915_WRITE(SDEIMR, ~mask);
        I915_WRITE(SDEIER, mask);
@@ -2466,26 +2523,16 @@ static int i915_irq_postinstall(struct drm_device *dev)
 
 static void i915_hpd_irq_setup(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 hotplug_en;
-
        if (I915_HAS_HOTPLUG(dev)) {
-               hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-
-               if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
-                       hotplug_en |= PORTB_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
-                       hotplug_en |= PORTC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
-                       hotplug_en |= PORTD_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
-                       hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
-                       hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
-                       hotplug_en |= CRT_HOTPLUG_INT_EN;
-                       hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-               }
+               drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+               struct drm_mode_config *mode_config = &dev->mode_config;
+               struct intel_encoder *encoder;
+               u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+
+               hotplug_en &= ~HOTPLUG_INT_EN_MASK;
+               list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+                       hotplug_en |= hpd_mask_i915[encoder->hpd_pin];
+               hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
 
                /* Ignore TV since it's buggy */
 
@@ -2576,7 +2623,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                  hotplug_status);
-                       if (hotplug_status & dev_priv->hotplug_supported_mask)
+                       if (hotplug_status & HOTPLUG_INT_STATUS_I915)
                                queue_work(dev_priv->wq,
                                           &dev_priv->hotplug_work);
 
@@ -2725,38 +2772,22 @@ static int i965_irq_postinstall(struct drm_device *dev)
 static void i965_hpd_irq_setup(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
        u32 hotplug_en;
 
        /* Note HDMI and DP share hotplug bits */
        hotplug_en = 0;
-       if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTB_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTC_HOTPLUG_INT_EN;
-       if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS)
-               hotplug_en |= PORTD_HOTPLUG_INT_EN;
-       if (IS_G4X(dev)) {
-               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)
-                       hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X)
-                       hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-       } else {
-               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965)
-                       hotplug_en |= SDVOC_HOTPLUG_INT_EN;
-               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965)
-                       hotplug_en |= SDVOB_HOTPLUG_INT_EN;
-       }
-       if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
-               hotplug_en |= CRT_HOTPLUG_INT_EN;
-
-               /* Programming the CRT detection parameters tends
-                  to generate a spurious hotplug event about three
-                  seconds later.  So just do it once.
-                  */
-               if (IS_G4X(dev))
-                       hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
-               hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-       }
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+               /* enable bits are the same for all generations */
+               hotplug_en |= hpd_mask_i915[encoder->hpd_pin];
+       /* Programming the CRT detection parameters tends
+          to generate a spurious hotplug event about three
+          seconds later.  So just do it once.
+       */
+       if (IS_G4X(dev))
+               hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
+       hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
 
        /* Ignore TV since it's buggy */
 
@@ -2822,7 +2853,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
                        DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
                                  hotplug_status);
-                       if (hotplug_status & dev_priv->hotplug_supported_mask)
+                       if (hotplug_status & (IS_G4X(dev) ?
+                                             HOTPLUG_INT_STATUS_G4X :
+                                             HOTPLUG_INT_STATUS_I965))
                                queue_work(dev_priv->wq,
                                           &dev_priv->hotplug_work);
 
index 5e995ec0951d3e0d775c2aaa7a620c9f2181b99c..97033077d00174276389c89e7c93f8393d8e5528 100644 (file)
 #define   SDVOC_HOTPLUG_INT_EN                 (1 << 25)
 #define   TV_HOTPLUG_INT_EN                    (1 << 18)
 #define   CRT_HOTPLUG_INT_EN                   (1 << 9)
+#define HOTPLUG_INT_EN_MASK                    (PORTB_HOTPLUG_INT_EN | \
+                                                PORTC_HOTPLUG_INT_EN | \
+                                                PORTD_HOTPLUG_INT_EN | \
+                                                SDVOC_HOTPLUG_INT_EN | \
+                                                SDVOB_HOTPLUG_INT_EN | \
+                                                CRT_HOTPLUG_INT_EN)
 #define   CRT_HOTPLUG_FORCE_DETECT             (1 << 3)
 #define CRT_HOTPLUG_ACTIVATION_PERIOD_32       (0 << 8)
 /* must use period 64 on GM45 according to docs */
 #define   SDVOB_HOTPLUG_INT_STATUS_I965                (3 << 2)
 #define   SDVOC_HOTPLUG_INT_STATUS_I915                (1 << 7)
 #define   SDVOB_HOTPLUG_INT_STATUS_I915                (1 << 6)
+#define   HOTPLUG_INT_STATUS_G4X               (CRT_HOTPLUG_INT_STATUS | \
+                                                SDVOB_HOTPLUG_INT_STATUS_G4X | \
+                                                SDVOC_HOTPLUG_INT_STATUS_G4X | \
+                                                PORTB_HOTPLUG_INT_STATUS | \
+                                                PORTC_HOTPLUG_INT_STATUS | \
+                                                PORTD_HOTPLUG_INT_STATUS)
+
+#define HOTPLUG_INT_STATUS_I965                        (CRT_HOTPLUG_INT_STATUS | \
+                                                SDVOB_HOTPLUG_INT_STATUS_I965 | \
+                                                SDVOC_HOTPLUG_INT_STATUS_I965 | \
+                                                PORTB_HOTPLUG_INT_STATUS | \
+                                                PORTC_HOTPLUG_INT_STATUS | \
+                                                PORTD_HOTPLUG_INT_STATUS)
+
+#define HOTPLUG_INT_STATUS_I915                        (CRT_HOTPLUG_INT_STATUS | \
+                                                SDVOB_HOTPLUG_INT_STATUS_I915 | \
+                                                SDVOC_HOTPLUG_INT_STATUS_I915 | \
+                                                PORTB_HOTPLUG_INT_STATUS | \
+                                                PORTC_HOTPLUG_INT_STATUS | \
+                                                PORTD_HOTPLUG_INT_STATUS)
 
 /* SDVO and HDMI port control.
  * The same register may be used for SDVO or HDMI */
 #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_HOTPLUG_MASK        (SDE_CRT_HOTPLUG | \
+                                SDE_SDVOB_HOTPLUG |    \
+                                SDE_PORTB_HOTPLUG |    \
+                                SDE_PORTC_HOTPLUG |    \
+                                SDE_PORTD_HOTPLUG)
 #define SDE_TRANSB_CRC_DONE    (1 << 5)
 #define SDE_TRANSB_CRC_ERR     (1 << 4)
 #define SDE_TRANSB_FIFO_UNDER  (1 << 3)