aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_runtime_pm.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2015-04-10 11:21:28 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-05-08 09:56:30 -0400
commit70722468872b0752abaff54d34ed16af0d95cb9f (patch)
tree4bae993705263b9fee73148ffc79db22bfe41a47 /drivers/gpu/drm/i915/intel_runtime_pm.c
parent2e523e98bb593950de2c749d4ceb45cc20313c1a (diff)
drm/i915: Work around DISPLAY_PHY_CONTROL register corruption on CHV
Sometimes (exactly when is a bit unclear) DISPLAY_PHY_CONTROL appears to get corrupted. The values I've managed to read from it seem to have some pattern but vary quite a lot. The corruption doesn't seem to just happen when the register is accessed, but can also happen spontaneosly during modeset. When this happens during a modeset things go south and the display doesn't light up. I've managed to hit the problemn when toggling HDMI on port D on and off. When things get corrupted the display doesn't light up, but as soon as I manually write the correct value to the register the display comes up. First I was suspicious that we ourselves accidentally overwrite it with garbage, but didn't catch anything with the reg_rw tracepoint. Also I sprinkled check all over the modeset path to see exactly when the corruption happens, and eg. the read back value was fine just before intel_dp_set_m(), and corrupted immediately after it. I also made my check function repair the register value whenever it was wrong, and with this approach the corruption repeated several times during the modeset operation, always seeming to trigger in the same exact calls to the check function, while other calls to the function never caught anything. So far I've not seen this problem occurring when carefully avoiding all read accesses to DISPLAY_PHY_CONTROL. Not sure if that's just pure luck or an actual workaround, but we can hope it works. So let's avoid reading the register and instead track the desired value of the register in dev_priv. v2: Read out the power well state to determine initial register value v3: Use DPIO_CHx names instead of raw numbers Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Deepak S <deepak.s@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c')
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c36
1 files changed, 31 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index bd7ad1d2d5f5..3d7352577bdc 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -949,8 +949,8 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
949 if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1)) 949 if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1))
950 DRM_ERROR("Display PHY %d is not power up\n", phy); 950 DRM_ERROR("Display PHY %d is not power up\n", phy);
951 951
952 I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) | 952 dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(phy);
953 PHY_COM_LANE_RESET_DEASSERT(phy)); 953 I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
954} 954}
955 955
956static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, 956static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
@@ -970,8 +970,8 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
970 assert_pll_disabled(dev_priv, PIPE_C); 970 assert_pll_disabled(dev_priv, PIPE_C);
971 } 971 }
972 972
973 I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) & 973 dev_priv->chv_phy_control &= ~PHY_COM_LANE_RESET_DEASSERT(phy);
974 ~PHY_COM_LANE_RESET_DEASSERT(phy)); 974 I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
975 975
976 vlv_set_power_well(dev_priv, power_well, false); 976 vlv_set_power_well(dev_priv, power_well, false);
977} 977}
@@ -1719,6 +1719,30 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
1719 mutex_unlock(&power_domains->lock); 1719 mutex_unlock(&power_domains->lock);
1720} 1720}
1721 1721
1722static void chv_phy_control_init(struct drm_i915_private *dev_priv)
1723{
1724 struct i915_power_well *cmn_bc =
1725 lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC);
1726 struct i915_power_well *cmn_d =
1727 lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D);
1728
1729 /*
1730 * DISPLAY_PHY_CONTROL can get corrupted if read. As a
1731 * workaround never ever read DISPLAY_PHY_CONTROL, and
1732 * instead maintain a shadow copy ourselves. Use the actual
1733 * power well state to reconstruct the expected initial
1734 * value.
1735 */
1736 dev_priv->chv_phy_control =
1737 PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY0, DPIO_CH0) |
1738 PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY0, DPIO_CH1) |
1739 PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY1, DPIO_CH0);
1740 if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc))
1741 dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY0);
1742 if (cmn_d->ops->is_enabled(dev_priv, cmn_d))
1743 dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY1);
1744}
1745
1722static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) 1746static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
1723{ 1747{
1724 struct i915_power_well *cmn = 1748 struct i915_power_well *cmn =
@@ -1761,7 +1785,9 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
1761 1785
1762 power_domains->initializing = true; 1786 power_domains->initializing = true;
1763 1787
1764 if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) { 1788 if (IS_CHERRYVIEW(dev)) {
1789 chv_phy_control_init(dev_priv);
1790 } else if (IS_VALLEYVIEW(dev)) {
1765 mutex_lock(&power_domains->lock); 1791 mutex_lock(&power_domains->lock);
1766 vlv_cmnlane_wa(dev_priv); 1792 vlv_cmnlane_wa(dev_priv);
1767 mutex_unlock(&power_domains->lock); 1793 mutex_unlock(&power_domains->lock);