drm/i915: only enable hotplug for detected outputs
authorJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 11 Dec 2009 19:07:17 +0000 (11:07 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 9 Feb 2010 12:50:52 +0000 (04:50 -0800)
commit b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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 bc2db7d16d187e0939d00956b1c62032aaf1010d..eaa1893b6e9b977c3ae8a63c618fb9a1dd7ebd5b 100644 (file)
@@ -1252,6 +1252,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;
@@ -1266,8 +1268,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 2d468e9fb9e81d170fcf2908324b16053ed0c157..63f28adf65093fa95f383830c6a59173a67f76c8 100644 (file)
@@ -1044,6 +1044,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;
@@ -1066,19 +1070,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 54e5907723d7bfc3f6415aee11f66d9a7d991a42..fd537f4af52c193540023d0bc2b94290d57344d6 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 |   \
-                        TV_HOTPLUG_INT_EN |      \
-                        CRT_HOTPLUG_INT_EN)
-
 
 #define PORT_HOTPLUG_STAT      0x61114
 #define   HDMIB_HOTPLUG_INT_STATUS             (1 << 29)
index e5051446c48e12ff14f5d504fbc3bdef72c8b2b8..6d3730f327cf6365a39d780d1e26cc040aeea77b 100644 (file)
@@ -576,4 +576,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 121b92e0eec7fedd66b2421458b04f3dc896318f..601415dc17bf40a4fb6554beee7eef621fae0326 100644 (file)
@@ -4068,29 +4068,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 92a3d7b0d009a6862d3278ce8927b1912f3221ea..d487771d5434a6418f6ffe41bcf063405bb0380b 100644 (file)
@@ -1290,14 +1290,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 c33451aec1bd647a601c7f256fd805598fb42d01..85760bf7ffa510e7750bdb9620f6bd8293188e93 100644 (file)
@@ -254,21 +254,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 29e21d32f9cedd296c0e4708a3abb4c802a06604..3f5aaf14e6a3b5393c2334b0ce89e99e90a45119 100644 (file)
@@ -2743,6 +2743,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;
@@ -2789,10 +2790,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 5b28b4e7ebe79ebfc7cc47608bd9501d9c0d0baf..ce026f002ea5f0674db27cba57570bee2d9f98b3 100644 (file)
@@ -1801,6 +1801,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);
 }