diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 65 |
2 files changed, 59 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 33b5134fc017..a39f8d254502 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -655,6 +655,7 @@ typedef struct drm_i915_private { unsigned int lvds_border_bits; /* Panel fitter placement and size for Ironlake+ */ u32 pch_pf_pos, pch_pf_size; + int panel_t3, panel_t12; struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2]; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ad6925ea2b51..ac261155b2f7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -813,6 +813,40 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } } +static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp; + + /* + * If the panel wasn't on, make sure there's not a currently + * active PP sequence before enabling AUX VDD. + */ + if (!(I915_READ(PCH_PP_STATUS) & PP_ON)) + msleep(dev_priv->panel_t3); + + pp = I915_READ(PCH_PP_CONTROL); + pp |= EDP_FORCE_VDD; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); +} + +static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp; + + pp = I915_READ(PCH_PP_CONTROL); + pp &= ~EDP_FORCE_VDD; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + + /* Make sure sequencer is idle before allowing subsequent activity */ + msleep(dev_priv->panel_t12); +} + /* Returns true if the panel was already on when called */ static bool ironlake_edp_panel_on (struct intel_dp *intel_dp) { @@ -935,7 +969,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder) if (is_edp(intel_dp)) { ironlake_edp_backlight_off(dev); - ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_off(dev); if (!is_pch_edp(intel_dp)) ironlake_edp_pll_on(encoder); else @@ -949,10 +983,15 @@ static void intel_dp_commit(struct drm_encoder *encoder) struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = encoder->dev; + if (is_edp(intel_dp)) + ironlake_edp_panel_vdd_on(intel_dp); + intel_dp_start_link_train(intel_dp); - if (is_edp(intel_dp)) + if (is_edp(intel_dp)) { ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp); + } intel_dp_complete_link_train(intel_dp); @@ -978,9 +1017,13 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ironlake_edp_pll_off(encoder); } else { if (is_edp(intel_dp)) - ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_on(intel_dp); if (!(dp_reg & DP_PORT_EN)) { intel_dp_start_link_train(intel_dp); + if (is_edp(intel_dp)) { + ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp); + } intel_dp_complete_link_train(intel_dp); } if (is_edp(intel_dp)) @@ -1872,9 +1915,18 @@ intel_dp_init(struct drm_device *dev, int output_reg) /* Cache some DPCD data in the eDP case */ if (is_edp(intel_dp)) { int ret; - bool was_on; + u32 pp_on, pp_div; + + pp_on = I915_READ(PCH_PP_ON_DELAYS); + pp_div = I915_READ(PCH_PP_DIVISOR); - was_on = ironlake_edp_panel_on(intel_dp); + /* Get T3 & T12 values (note: VESA not bspec terminology) */ + dev_priv->panel_t3 = (pp_on & 0x1fff0000) >> 16; + dev_priv->panel_t3 /= 10; /* t3 in 100us units */ + dev_priv->panel_t12 = pp_div & 0xf; + dev_priv->panel_t12 *= 100; /* t12 in 100ms units */ + + ironlake_edp_panel_vdd_on(intel_dp); ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV, intel_dp->dpcd, sizeof(intel_dp->dpcd)); @@ -1885,8 +1937,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) } else { DRM_ERROR("failed to retrieve link info\n"); } - if (!was_on) - ironlake_edp_panel_off(dev); + ironlake_edp_panel_vdd_off(intel_dp); } intel_encoder->hot_plug = intel_dp_hot_plug; |