Commit de9c1b6b authored by Imre Deak's avatar Imre Deak

drm/i915: Sanity check PPS HW state

The wait for panel status helper will only function correctly if the
HW panel timings are programmed correctly. Returning prematurely from
this helper may lead to obscure bugs later, so sanity check the HW
timing registers.

v2:
- Check the T8, T9 fields too, we do program them (Ville)

CC: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1466096506-11937-1-git-send-email-imre.deak@intel.com
parent 54648618
...@@ -1772,6 +1772,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder) ...@@ -1772,6 +1772,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
#define IDLE_CYCLE_MASK (PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK) #define IDLE_CYCLE_MASK (PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
#define IDLE_CYCLE_VALUE (0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) #define IDLE_CYCLE_VALUE (0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE)
static void intel_pps_verify_state(struct drm_i915_private *dev_priv,
struct intel_dp *intel_dp);
static void wait_panel_status(struct intel_dp *intel_dp, static void wait_panel_status(struct intel_dp *intel_dp,
u32 mask, u32 mask,
u32 value) u32 value)
...@@ -1782,6 +1785,8 @@ static void wait_panel_status(struct intel_dp *intel_dp, ...@@ -1782,6 +1785,8 @@ static void wait_panel_status(struct intel_dp *intel_dp,
lockdep_assert_held(&dev_priv->pps_mutex); lockdep_assert_held(&dev_priv->pps_mutex);
intel_pps_verify_state(dev_priv, intel_dp);
pp_stat_reg = _pp_stat_reg(intel_dp); pp_stat_reg = _pp_stat_reg(intel_dp);
pp_ctrl_reg = _pp_ctrl_reg(intel_dp); pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
...@@ -4817,6 +4822,31 @@ intel_pps_readout_hw_state(struct drm_i915_private *dev_priv, ...@@ -4817,6 +4822,31 @@ intel_pps_readout_hw_state(struct drm_i915_private *dev_priv,
} }
} }
static void
intel_pps_dump_state(const char *state_name, const struct edp_power_seq *seq)
{
DRM_DEBUG_KMS("%s t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
state_name,
seq->t1_t3, seq->t8, seq->t9, seq->t10, seq->t11_t12);
}
static void
intel_pps_verify_state(struct drm_i915_private *dev_priv,
struct intel_dp *intel_dp)
{
struct edp_power_seq hw;
struct edp_power_seq *sw = &intel_dp->pps_delays;
intel_pps_readout_hw_state(dev_priv, intel_dp, &hw);
if (hw.t1_t3 != sw->t1_t3 || hw.t8 != sw->t8 || hw.t9 != sw->t9 ||
hw.t10 != sw->t10 || hw.t11_t12 != sw->t11_t12) {
DRM_ERROR("PPS state mismatch\n");
intel_pps_dump_state("sw", sw);
intel_pps_dump_state("hw", &hw);
}
}
static void static void
intel_dp_init_panel_power_sequencer(struct drm_device *dev, intel_dp_init_panel_power_sequencer(struct drm_device *dev,
struct intel_dp *intel_dp) struct intel_dp *intel_dp)
...@@ -4833,8 +4863,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, ...@@ -4833,8 +4863,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
intel_pps_readout_hw_state(dev_priv, intel_dp, &cur); intel_pps_readout_hw_state(dev_priv, intel_dp, &cur);
DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", intel_pps_dump_state("cur", &cur);
cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12);
vbt = dev_priv->vbt.edp.pps; vbt = dev_priv->vbt.edp.pps;
...@@ -4850,8 +4879,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, ...@@ -4850,8 +4879,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
* too. */ * too. */
spec.t11_t12 = (510 + 100) * 10; spec.t11_t12 = (510 + 100) * 10;
DRM_DEBUG_KMS("vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", intel_pps_dump_state("vbt", &vbt);
vbt.t1_t3, vbt.t8, vbt.t9, vbt.t10, vbt.t11_t12);
/* Use the max of the register settings and vbt. If both are /* Use the max of the register settings and vbt. If both are
* unset, fall back to the spec limits. */ * unset, fall back to the spec limits. */
...@@ -4879,6 +4907,16 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, ...@@ -4879,6 +4907,16 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
/*
* We override the HW backlight delays to 1 because we do manual waits
* on them. For T8, even BSpec recommends doing it. For T9, if we
* don't do this, we'll end up waiting for the backlight off delay
* twice: once when we do the manual sleep, and once when we disable
* the panel and wait for the PP_STATUS bit to become zero.
*/
final->t8 = 1;
final->t9 = 1;
} }
static void static void
...@@ -4896,17 +4934,9 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, ...@@ -4896,17 +4934,9 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
intel_pps_get_registers(dev_priv, intel_dp, &regs); intel_pps_get_registers(dev_priv, intel_dp, &regs);
/*
* And finally store the new values in the power sequencer. The
* backlight delays are set to 1 because we do manual waits on them. For
* T8, even BSpec recommends doing it. For T9, if we don't do this,
* we'll end up waiting for the backlight off delay twice: once when we
* do the manual sleep, and once when we disable the panel and wait for
* the PP_STATUS bit to become zero.
*/
pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
(1 << PANEL_LIGHT_ON_DELAY_SHIFT); (seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT);
pp_off = (1 << PANEL_LIGHT_OFF_DELAY_SHIFT) | pp_off = (seq->t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
(seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT);
/* Compute the divisor for the pp clock, simply match the Bspec /* Compute the divisor for the pp clock, simply match the Bspec
* formula. */ * formula. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment