drm/i915: Skip modifying PCH DREF if not changing clock sources
authorChris Wilson <chris@chris-wilson.co.uk>
Tue, 26 Mar 2013 23:33:04 +0000 (16:33 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 2 Apr 2013 18:25:34 +0000 (20:25 +0200)
Modifying the clock sources (via the DREF control on the PCH) is a slow
multi-stage process as we need to let the clocks stabilise between each
stage. If we are not actually changing the clock sources, then we can
return early.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
[danvet: Appease checkpatch by deleting a space after a ~]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_display.c

index 5e8b91f..0e172ce 100644 (file)
@@ -4701,7 +4701,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
-       u32 temp;
+       u32 val, final;
        bool has_lvds = false;
        bool has_cpu_edp = false;
        bool has_pch_edp = false;
@@ -4744,70 +4744,109 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
         * PCH B stepping, previous chipset stepping should be
         * ignoring this setting.
         */
-       temp = I915_READ(PCH_DREF_CONTROL);
+       val = I915_READ(PCH_DREF_CONTROL);
+
+       /* As we must carefully and slowly disable/enable each source in turn,
+        * compute the final state we want first and check if we need to
+        * make any changes at all.
+        */
+       final = val;
+       final &= ~DREF_NONSPREAD_SOURCE_MASK;
+       if (has_ck505)
+               final |= DREF_NONSPREAD_CK505_ENABLE;
+       else
+               final |= DREF_NONSPREAD_SOURCE_ENABLE;
+
+       final &= ~DREF_SSC_SOURCE_MASK;
+       final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+       final &= ~DREF_SSC1_ENABLE;
+
+       if (has_panel) {
+               final |= DREF_SSC_SOURCE_ENABLE;
+
+               if (intel_panel_use_ssc(dev_priv) && can_ssc)
+                       final |= DREF_SSC1_ENABLE;
+
+               if (has_cpu_edp) {
+                       if (intel_panel_use_ssc(dev_priv) && can_ssc)
+                               final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       else
+                               final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+               } else
+                       final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+       } else {
+               final |= DREF_SSC_SOURCE_DISABLE;
+               final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+       }
+
+       if (final == val)
+               return;
+
        /* Always enable nonspread source */
-       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+       val &= ~DREF_NONSPREAD_SOURCE_MASK;
 
        if (has_ck505)
-               temp |= DREF_NONSPREAD_CK505_ENABLE;
+               val |= DREF_NONSPREAD_CK505_ENABLE;
        else
-               temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+               val |= DREF_NONSPREAD_SOURCE_ENABLE;
 
        if (has_panel) {
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_ENABLE;
+               val &= ~DREF_SSC_SOURCE_MASK;
+               val |= DREF_SSC_SOURCE_ENABLE;
 
                /* SSC must be turned on before enabling the CPU output  */
                if (intel_panel_use_ssc(dev_priv) && can_ssc) {
                        DRM_DEBUG_KMS("Using SSC on panel\n");
-                       temp |= DREF_SSC1_ENABLE;
+                       val |= DREF_SSC1_ENABLE;
                } else
-                       temp &= ~DREF_SSC1_ENABLE;
+                       val &= ~DREF_SSC1_ENABLE;
 
                /* Get SSC going before enabling the outputs */
-               I915_WRITE(PCH_DREF_CONTROL, temp);
+               I915_WRITE(PCH_DREF_CONTROL, val);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
 
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+               val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
                /* Enable CPU source on CPU attached eDP */
                if (has_cpu_edp) {
                        if (intel_panel_use_ssc(dev_priv) && can_ssc) {
                                DRM_DEBUG_KMS("Using SSC on eDP\n");
-                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                               val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
                        }
                        else
-                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+                               val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
                } else
-                       temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+                       val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
 
-               I915_WRITE(PCH_DREF_CONTROL, temp);
+               I915_WRITE(PCH_DREF_CONTROL, val);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
        } else {
                DRM_DEBUG_KMS("Disabling SSC entirely\n");
 
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+               val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
                /* Turn off CPU output */
-               temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+               val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
 
-               I915_WRITE(PCH_DREF_CONTROL, temp);
+               I915_WRITE(PCH_DREF_CONTROL, val);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
 
                /* Turn off the SSC source */
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_DISABLE;
+               val &= ~DREF_SSC_SOURCE_MASK;
+               val |= DREF_SSC_SOURCE_DISABLE;
 
                /* Turn off SSC1 */
-               temp &= ~ DREF_SSC1_ENABLE;
+               val &= ~DREF_SSC1_ENABLE;
 
-               I915_WRITE(PCH_DREF_CONTROL, temp);
+               I915_WRITE(PCH_DREF_CONTROL, val);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
        }
+
+       BUG_ON(val != final);
 }
 
 /* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */