drm/i915: disable PCH ports if needed when disabling a CRTC
[linux-flexiantxendom0-natty.git] / drivers / gpu / drm / i915 / intel_display.c
index 841558b..88dc3fe 100644 (file)
@@ -1058,6 +1058,53 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
        }
 }
 
+static void disable_pch_dp(struct drm_i915_private *dev_priv,
+                          enum pipe pipe, int reg)
+{
+       u32 val = I915_READ(reg);
+       if (DP_PIPE_ENABLED(val, pipe))
+               I915_WRITE(reg, val & ~DP_PORT_EN);
+}
+
+static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
+                            enum pipe pipe, int reg)
+{
+       u32 val = I915_READ(reg);
+       if (HDMI_PIPE_ENABLED(val, pipe))
+               I915_WRITE(reg, val & ~PORT_ENABLE);
+}
+
+/* Disable any ports connected to this transcoder */
+static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
+                                   enum pipe pipe)
+{
+       u32 reg, val;
+
+       val = I915_READ(PCH_PP_CONTROL);
+       I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS);
+
+       disable_pch_dp(dev_priv, pipe, PCH_DP_B);
+       disable_pch_dp(dev_priv, pipe, PCH_DP_C);
+       disable_pch_dp(dev_priv, pipe, PCH_DP_D);
+
+       reg = PCH_ADPA;
+       val = I915_READ(reg);
+       if (ADPA_PIPE_ENABLED(val, pipe))
+               I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
+
+       reg = PCH_LVDS;
+       val = I915_READ(reg);
+       if (LVDS_PIPE_ENABLED(val, pipe)) {
+               I915_WRITE(reg, val & ~LVDS_PORT_EN);
+               POSTING_READ(reg);
+               udelay(100);
+       }
+
+       disable_pch_hdmi(dev_priv, pipe, HDMIB);
+       disable_pch_hdmi(dev_priv, pipe, HDMIC);
+       disable_pch_hdmi(dev_priv, pipe, HDMID);
+}
+
 static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
        struct drm_device *dev = crtc->dev;
@@ -2356,14 +2403,12 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(100);
 
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-               temp = I915_READ(PCH_LVDS);
-               if (temp & LVDS_PORT_EN) {
-                       I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
-                       POSTING_READ(PCH_LVDS);
-                       udelay(100);
-               }
-       }
+       /* This is a horrible layering violation; we should be doing this in
+        * the connector/encoder ->prepare instead, but we don't always have
+        * enough information there about the config to know whether it will
+        * actually be necessary or just cause undesired flicker.
+        */
+       intel_disable_pch_ports(dev_priv, pipe);
 
        /* disable PCH transcoder */
        reg = TRANSCONF(plane);