drm/i915: only enable hotplug for detected outputs
authorJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 11 Dec 2009 19:07:17 +0000 (11:07 -0800)
committerEric Anholt <eric@anholt.net>
Wed, 16 Dec 2009 22:00:05 +0000 (14:00 -0800)
This patch changes around our hotplug enable code a bit to only enable
it for ports we actually detect and initialize.  This prevents problems
with stuck or spurious interrupts on outputs that aren't actually wired
up, and is generally more correct.

Fixes FDO bug #23183.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c

index 28d99b8..e3e5d50 100644 (file)
@@ -1249,6 +1249,8 @@ static int i915_load_modeset_init(struct drm_device *dev,
        if (ret)
                goto destroy_ringbuffer;
 
+       intel_modeset_init(dev);
+
        ret = drm_irq_install(dev);
        if (ret)
                goto destroy_ringbuffer;
@@ -1263,8 +1265,6 @@ static int i915_load_modeset_init(struct drm_device *dev,
 
        I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
 
-       intel_modeset_init(dev);
-
        drm_helper_initial_config(dev);
 
        return 0;
index 85f4c5d..1733eea 100644 (file)
@@ -1084,6 +1084,10 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
        (void) I915_READ(IER);
 }
 
+/*
+ * Must be called after intel_modeset_init or hotplug interrupts won't be
+ * enabled correctly.
+ */
 int i915_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -1106,19 +1110,23 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        if (I915_HAS_HOTPLUG(dev)) {
                u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
 
-               /* Leave other bits alone */
-               hotplug_en |= HOTPLUG_EN_MASK;
+               /* Note HDMI and DP share bits */
+               if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
+                       hotplug_en |= HDMIB_HOTPLUG_INT_EN;
+               if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
+                       hotplug_en |= HDMIC_HOTPLUG_INT_EN;
+               if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
+                       hotplug_en |= HDMID_HOTPLUG_INT_EN;
+               if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
+                       hotplug_en |= SDVOC_HOTPLUG_INT_EN;
+               if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
+                       hotplug_en |= SDVOB_HOTPLUG_INT_EN;
+               if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS)
+                       hotplug_en |= CRT_HOTPLUG_INT_EN;
+               /* Ignore TV since it's buggy */
+
                I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
 
-               dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS |
-                       TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS |
-                       SDVOB_HOTPLUG_INT_STATUS;
-               if (IS_G4X(dev)) {
-                       dev_priv->hotplug_supported_mask |=
-                               HDMIB_HOTPLUG_INT_STATUS |
-                               HDMIC_HOTPLUG_INT_STATUS |
-                               HDMID_HOTPLUG_INT_STATUS;
-               }
                /* Enable in IER... */
                enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
                /* and unmask in IMR */
index 974b3cf..f79b133 100644 (file)
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV       (1 << 2)
 #define CRT_HOTPLUG_MASK                       (0x3fc) /* Bits 9-2 */
 #define CRT_FORCE_HOTPLUG_MASK                 0xfffffe1f
-#define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \
-                        HDMIC_HOTPLUG_INT_EN |   \
-                        HDMID_HOTPLUG_INT_EN |   \
-                        SDVOB_HOTPLUG_INT_EN |   \
-                        SDVOC_HOTPLUG_INT_EN |   \
-                        CRT_HOTPLUG_INT_EN)
-
 
 #define PORT_HOTPLUG_STAT      0x61114
 #define   HDMIB_HOTPLUG_INT_STATUS             (1 << 29)
index 9f3d3e5..ddefc87 100644 (file)
@@ -548,4 +548,6 @@ void intel_crt_init(struct drm_device *dev)
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
        drm_sysfs_connector_add(connector);
+
+       dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
 }
index ef9c613..c21dede 100644 (file)
@@ -4400,29 +4400,43 @@ static void intel_setup_outputs(struct drm_device *dev)
                bool found = false;
 
                if (I915_READ(SDVOB) & SDVO_DETECTED) {
+                       DRM_DEBUG_KMS("probing SDVOB\n");
                        found = intel_sdvo_init(dev, SDVOB);
-                       if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
+                       if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
+                               DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
                                intel_hdmi_init(dev, SDVOB);
+                       }
 
-                       if (!found && SUPPORTS_INTEGRATED_DP(dev))
+                       if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
+                               DRM_DEBUG_KMS("probing DP_B\n");
                                intel_dp_init(dev, DP_B);
+                       }
                }
 
                /* Before G4X SDVOC doesn't have its own detect register */
 
-               if (I915_READ(SDVOB) & SDVO_DETECTED)
+               if (I915_READ(SDVOB) & SDVO_DETECTED) {
+                       DRM_DEBUG_KMS("probing SDVOC\n");
                        found = intel_sdvo_init(dev, SDVOC);
+               }
 
                if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
 
-                       if (SUPPORTS_INTEGRATED_HDMI(dev))
+                       if (SUPPORTS_INTEGRATED_HDMI(dev)) {
+                               DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
                                intel_hdmi_init(dev, SDVOC);
-                       if (SUPPORTS_INTEGRATED_DP(dev))
+                       }
+                       if (SUPPORTS_INTEGRATED_DP(dev)) {
+                               DRM_DEBUG_KMS("probing DP_C\n");
                                intel_dp_init(dev, DP_C);
+                       }
                }
 
-               if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
+               if (SUPPORTS_INTEGRATED_DP(dev) &&
+                   (I915_READ(DP_D) & DP_DETECTED)) {
+                       DRM_DEBUG_KMS("probing DP_D\n");
                        intel_dp_init(dev, DP_D);
+               }
        } else if (IS_I8XX(dev))
                intel_dvo_init(dev);
 
index 4e7aa8b..1349d9f 100644 (file)
@@ -1402,14 +1402,20 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                        break;
                case DP_B:
                case PCH_DP_B:
+                       dev_priv->hotplug_supported_mask |=
+                               HDMIB_HOTPLUG_INT_STATUS;
                        name = "DPDDC-B";
                        break;
                case DP_C:
                case PCH_DP_C:
+                       dev_priv->hotplug_supported_mask |=
+                               HDMIC_HOTPLUG_INT_STATUS;
                        name = "DPDDC-C";
                        break;
                case DP_D:
                case PCH_DP_D:
+                       dev_priv->hotplug_supported_mask |=
+                               HDMID_HOTPLUG_INT_STATUS;
                        name = "DPDDC-D";
                        break;
        }
index f04dbbe..0643194 100644 (file)
@@ -303,21 +303,26 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
        if (sdvox_reg == SDVOB) {
                intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
                intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
+               dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == SDVOC) {
                intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
                intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+               dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMIB) {
                intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
                intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
                                                                "HDMIB");
+               dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMIC) {
                intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
                intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
                                                                "HDMIC");
+               dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMID) {
                intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
                intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
                                                                "HDMID");
+               dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
        }
        if (!intel_output->ddc_bus)
                goto err_connector;
index 24a3dc9..de5144c 100644 (file)
@@ -2662,6 +2662,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
 
 bool intel_sdvo_init(struct drm_device *dev, int output_device)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_connector *connector;
        struct intel_output *intel_output;
        struct intel_sdvo_priv *sdvo_priv;
@@ -2708,10 +2709,12 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
                intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
                sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
                                                "SDVOB/VGA DDC BUS");
+               dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
        } else {
                intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
                sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
                                                "SDVOC/VGA DDC BUS");
+               dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
        }
 
        if (intel_output->ddc_bus == NULL)
index 552ec11..1d5b9b7 100644 (file)
@@ -1840,6 +1840,8 @@ intel_tv_init(struct drm_device *dev)
        drm_connector_attach_property(connector,
                                   dev->mode_config.tv_bottom_margin_property,
                                   tv_priv->margin[TV_MARGIN_BOTTOM]);
+
+       dev_priv->hotplug_supported_mask |= TV_HOTPLUG_INT_STATUS;
 out:
        drm_sysfs_connector_add(connector);
 }