drm/i915: Apply the PPS register unlock workaround more consistently
authorImre Deak <imre.deak@intel.com>
Wed, 10 Aug 2016 11:07:33 +0000 (14:07 +0300)
committerImre Deak <imre.deak@intel.com>
Wed, 10 Aug 2016 13:01:42 +0000 (16:01 +0300)
Atm, we apply this workaround somewhat inconsistently at the following
points: driver loading, LVDS init, eDP PPS init, system resume. As this
workaround also affects registers other than PPS (timing, PLL) a more
consistent way is to apply it early after the PPS HW context is known to
be lost: driver loading, system resume and on VLV/CHV/BXT when turning
on power domains.

This is needed by the next patch that removes saving/restoring of the
PP_CONTROL register.

This also removes the incorrect programming of the workaround on HSW+
PCH platforms which don't have the register locking mechanism.

v2: (Ville)
- Don't apply the workaround on BXT.
- Simplify platform checks using HAS_DDI().
v3:
- Move the call of intel_pps_unlock_regs_wa() to the more
  logical vlv_display_power_well_init() (also fixing CHV) (Ville).

Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470827254-21954-5-git-send-email-imre.deak@intel.com
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_runtime_pm.c

index 8cfc264ec9f690cd1bfd62a6d4821fd5ca84f648..0fcd1c0f67bb99ff1148530fe3433ea3f582b0d1 100644 (file)
@@ -1560,6 +1560,7 @@ static int i915_drm_resume(struct drm_device *dev)
        i915_gem_resume(dev);
 
        i915_restore_state(dev);
+       intel_pps_unlock_regs_wa(dev_priv);
        intel_opregion_setup(dev_priv);
 
        intel_init_pch_refclk(dev);
index dc0d1b61dae4f960c28f591c66bba8692de31268..c0509061f321fdf2056b3116590d001184694e64 100644 (file)
@@ -14729,6 +14729,30 @@ static bool intel_crt_present(struct drm_device *dev)
        return true;
 }
 
+void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv)
+{
+       int pps_num;
+       int pps_idx;
+
+       if (HAS_DDI(dev_priv))
+               return;
+       /*
+        * This w/a is needed at least on CPT/PPT, but to be sure apply it
+        * everywhere where registers can be write protected.
+        */
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               pps_num = 2;
+       else
+               pps_num = 1;
+
+       for (pps_idx = 0; pps_idx < pps_num; pps_idx++) {
+               u32 val = I915_READ(PP_CONTROL(pps_idx));
+
+               val = (val & ~PANEL_UNLOCK_MASK) | PANEL_UNLOCK_REGS;
+               I915_WRITE(PP_CONTROL(pps_idx), val);
+       }
+}
+
 static void intel_pps_init(struct drm_i915_private *dev_priv)
 {
        if (HAS_PCH_SPLIT(dev_priv) || IS_BROXTON(dev_priv))
@@ -14737,6 +14761,8 @@ static void intel_pps_init(struct drm_i915_private *dev_priv)
                dev_priv->pps_mmio_base = VLV_PPS_BASE;
        else
                dev_priv->pps_mmio_base = PPS_BASE;
+
+       intel_pps_unlock_regs_wa(dev_priv);
 }
 
 static void intel_setup_outputs(struct drm_device *dev)
index 2ef7b14cc36e2da3f5cf4cd3c50603d79aa61cc0..364db908c191b6d01e8c6d2fb1ae85db7f925a35 100644 (file)
@@ -1829,7 +1829,8 @@ static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
        lockdep_assert_held(&dev_priv->pps_mutex);
 
        control = I915_READ(_pp_ctrl_reg(intel_dp));
-       if (!IS_BROXTON(dev)) {
+       if (WARN_ON(!HAS_DDI(dev_priv) &&
+                   (control & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS)) {
                control &= ~PANEL_UNLOCK_MASK;
                control |= PANEL_UNLOCK_REGS;
        }
index b1fc67ed8bc2b91b6b120fa0b610be22ae9474ef..65c97a3eef1d6f783ba57154f13459073d8d507d 100644 (file)
@@ -1162,6 +1162,7 @@ void intel_mark_busy(struct drm_i915_private *dev_priv);
 void intel_mark_idle(struct drm_i915_private *dev_priv);
 void intel_crtc_restore_mode(struct drm_crtc *crtc);
 int intel_display_suspend(struct drm_device *dev);
+void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv);
 void intel_encoder_destroy(struct drm_encoder *encoder);
 int intel_connector_init(struct intel_connector *);
 struct intel_connector *intel_connector_alloc(void);
index e79fae4bbc1fc28057f74281b0d10eee89e436ce..668eabb0ba1bf6ca23414af333000c1c457b397d 100644 (file)
@@ -978,14 +978,6 @@ void intel_lvds_init(struct drm_device *dev)
        int pipe;
        u8 pin;
 
-       /*
-        * Unlock registers and just leave them unlocked. Do this before
-        * checking quirk lists to avoid bogus WARNINGs.
-        */
-       if (HAS_PCH_SPLIT(dev_priv) || INTEL_GEN(dev_priv) <= 4)
-               I915_WRITE(PP_CONTROL(0),
-                          I915_READ(PP_CONTROL(0)) | PANEL_UNLOCK_REGS);
-
        if (!intel_lvds_supported(dev))
                return;
 
index 1c603bbe5784fa7e21049e267eab52af25a60360..d659d6f5b8d3b8b30b95284ab5719b26b44ba4c9 100644 (file)
@@ -592,6 +592,8 @@ void bxt_disable_dc9(struct drm_i915_private *dev_priv)
        DRM_DEBUG_KMS("Disabling DC9\n");
 
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+       intel_pps_unlock_regs_wa(dev_priv);
 }
 
 static void assert_csr_loaded(struct drm_i915_private *dev_priv)
@@ -1121,6 +1123,8 @@ static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
        }
 
        i915_redisable_vga_power_on(&dev_priv->drm);
+
+       intel_pps_unlock_regs_wa(dev_priv);
 }
 
 static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv)