Commit 5d613501 authored by Jesse Barnes's avatar Jesse Barnes Committed by Chris Wilson

drm/i915: use VDD AUX override to make panel power sequencing look better

Rather than power cycling the panel when there are no bits to display,
use the VDD AUX bit to power the panel up just enough for DP AUX
transactions to work.  This prevents a bit of unnecessary ugliness as
mode sets occur on the panel.
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 987a709e
...@@ -655,6 +655,7 @@ typedef struct drm_i915_private { ...@@ -655,6 +655,7 @@ typedef struct drm_i915_private {
unsigned int lvds_border_bits; unsigned int lvds_border_bits;
/* Panel fitter placement and size for Ironlake+ */ /* Panel fitter placement and size for Ironlake+ */
u32 pch_pf_pos, pch_pf_size; u32 pch_pf_pos, pch_pf_size;
int panel_t3, panel_t12;
struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *plane_to_crtc_mapping[2];
struct drm_crtc *pipe_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2];
......
...@@ -813,6 +813,40 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -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 */ /* Returns true if the panel was already on when called */
static bool ironlake_edp_panel_on (struct intel_dp *intel_dp) static bool ironlake_edp_panel_on (struct intel_dp *intel_dp)
{ {
...@@ -935,7 +969,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder) ...@@ -935,7 +969,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
ironlake_edp_backlight_off(dev); ironlake_edp_backlight_off(dev);
ironlake_edp_panel_on(intel_dp); ironlake_edp_panel_off(dev);
if (!is_pch_edp(intel_dp)) if (!is_pch_edp(intel_dp))
ironlake_edp_pll_on(encoder); ironlake_edp_pll_on(encoder);
else else
...@@ -949,10 +983,15 @@ static void intel_dp_commit(struct drm_encoder *encoder) ...@@ -949,10 +983,15 @@ static void intel_dp_commit(struct drm_encoder *encoder)
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev; 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); 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_on(intel_dp);
ironlake_edp_panel_vdd_off(intel_dp);
}
intel_dp_complete_link_train(intel_dp); intel_dp_complete_link_train(intel_dp);
...@@ -978,9 +1017,13 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -978,9 +1017,13 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
ironlake_edp_pll_off(encoder); ironlake_edp_pll_off(encoder);
} else { } else {
if (is_edp(intel_dp)) if (is_edp(intel_dp))
ironlake_edp_panel_on(intel_dp); ironlake_edp_panel_vdd_on(intel_dp);
if (!(dp_reg & DP_PORT_EN)) { if (!(dp_reg & DP_PORT_EN)) {
intel_dp_start_link_train(intel_dp); 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); intel_dp_complete_link_train(intel_dp);
} }
if (is_edp(intel_dp)) if (is_edp(intel_dp))
...@@ -1872,9 +1915,18 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1872,9 +1915,18 @@ intel_dp_init(struct drm_device *dev, int output_reg)
/* Cache some DPCD data in the eDP case */ /* Cache some DPCD data in the eDP case */
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
int ret; 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, ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV,
intel_dp->dpcd, intel_dp->dpcd,
sizeof(intel_dp->dpcd)); sizeof(intel_dp->dpcd));
...@@ -1885,8 +1937,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1885,8 +1937,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
} else { } else {
DRM_ERROR("failed to retrieve link info\n"); DRM_ERROR("failed to retrieve link info\n");
} }
if (!was_on) ironlake_edp_panel_vdd_off(intel_dp);
ironlake_edp_panel_off(dev);
} }
intel_encoder->hot_plug = intel_dp_hot_plug; intel_encoder->hot_plug = intel_dp_hot_plug;
......
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