No subject
Mon Sep 19 15:12:57 PDT 2011
Power_Down_delay value, which is actually documented to be the 'T3
time sequence' value used 'during power up'. There aren't separate T1
and T2 values, but there is a combined T1+T2 value in the PP_ON_DELAYS
register, so I use that instead.
VBT doesn't provide any values for T1 or T2, so we'll always just use
the hardware value for that.
The panel power up delay is thus T1 + T2 + T3, which should be
sufficient in all cases.
The panel power down delay is T1 + T2 + T12, using T1+T2 as a proxy
for T11, which isn't available anywhere.
On the macbook air I'm testing with, this yields a power-up delay of
over 200ms and a power-down delay of over 600ms. It all works now, but
we're frobbing these power controls several times during mode setting,
making the whole process take an awfully long time.
Signed-off-by: Keith Packard <keithp at keithp.com>
---
drivers/gpu/drm/i915/i915_drv.h | 1 -
drivers/gpu/drm/i915/intel_dp.c | 56 ++++++++++++++++++++++++++++----------
2 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7916bd9..bcdf58b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -672,7 +672,6 @@ 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 41b1e05..f1d6105 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -59,6 +59,8 @@ struct intel_dp {
bool is_pch_edp;
uint8_t train_set[4];
uint8_t link_status[DP_LINK_STATUS_SIZE];
+ int panel_power_up_delay;
+ int panel_power_down_delay;
};
/**
@@ -848,10 +850,6 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
* active PP sequence before enabling AUX VDD.
*/
pp_status = I915_READ(PCH_PP_STATUS);
- if (!(pp_status & PP_ON)) {
- DRM_DEBUG_KMS("eDP VDD was not on\n");
- msleep(dev_priv->panel_t3);
- }
pp = I915_READ(PCH_PP_CONTROL);
pp &= ~PANEL_UNLOCK_MASK;
@@ -861,7 +859,10 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
POSTING_READ(PCH_PP_CONTROL);
DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n",
I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL));
- msleep(1000);
+ if (!(pp_status & PP_ON)) {
+ msleep(intel_dp->panel_power_up_delay);
+ DRM_DEBUG_KMS("eDP VDD was not on\n");
+ }
}
static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp)
@@ -881,10 +882,9 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp)
POSTING_READ(PCH_PP_CONTROL);
/* Make sure sequencer is idle before allowing subsequent activity */
- msleep(dev_priv->panel_t12);
DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n",
I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL));
- msleep(1000);
+ msleep(intel_dp->panel_power_down_delay);
}
/* Returns true if the panel was already on when called */
@@ -922,8 +922,10 @@ static bool ironlake_edp_panel_on (struct intel_dp *intel_dp)
return false;
}
-static void ironlake_edp_panel_off (struct drm_device *dev)
+static void ironlake_edp_panel_off(struct drm_encoder *encoder)
{
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
@@ -940,6 +942,7 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
pp &= ~POWER_TARGET_ON;
I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL);
+ msleep(intel_dp->panel_power_down_delay);
if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000))
DRM_ERROR("panel off wait timed out: 0x%08x\n",
@@ -1045,7 +1048,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
if (is_edp(intel_dp)) {
ironlake_edp_backlight_off(dev);
- ironlake_edp_panel_off(dev);
+ ironlake_edp_panel_off(encoder);
if (!is_pch_edp(intel_dp))
ironlake_edp_pll_on(encoder);
else
@@ -1088,7 +1091,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
intel_dp_sink_dpms(intel_dp, mode);
intel_dp_link_down(intel_dp);
if (is_edp(intel_dp))
- ironlake_edp_panel_off(dev);
+ ironlake_edp_panel_off(encoder);
if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
ironlake_edp_pll_off(encoder);
} else {
@@ -2115,16 +2118,39 @@ intel_dp_init(struct drm_device *dev, int output_reg)
/* Cache some DPCD data in the eDP case */
if (is_edp(intel_dp)) {
bool ret;
- u32 pp_on, pp_div;
+ u32 pp_on, pp_off, pp_div;
+ int current_t1_2;
+ int current_t3;
+ int current_t12;
+ int vbt_t3;
+ int vbt_t12;
pp_on = I915_READ(PCH_PP_ON_DELAYS);
+ pp_off = I915_READ(PCH_PP_OFF_DELAYS);
pp_div = I915_READ(PCH_PP_DIVISOR);
/* 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 */
+
+ current_t1_2 = (pp_on & 0x1fff0000) >> 16;
+ current_t1_2 = (current_t1_2 + 9) / 10; /* t1+t2 in 100us units */
+
+ current_t3 = (pp_off & 0x1fff0000) >> 16;
+ current_t3 = (current_t3 + 9) / 10; /* t3 in 100us units */
+
+ current_t12 = pp_div & 0xf;
+ current_t12 *= 100; /* t12 in 100ms units */
+
+ vbt_t3 = (dev_priv->edp.pps.t3 + 9) / 10;
+ vbt_t12 = (dev_priv->edp.pps.t12 + 9) / 10;
+ DRM_DEBUG_KMS("current t3 %d t12 %d\n",
+ current_t3, current_t12);
+ DRM_DEBUG_KMS("VBT t3 %d t12 %d\n",
+ vbt_t3, vbt_t12);
+
+ intel_dp->panel_power_up_delay = current_t1_2 + max(current_t3, vbt_t3);
+ intel_dp->panel_power_down_delay = current_t1_2 + max(current_t12, vbt_t12);
+ DRM_DEBUG_KMS("panel power up delay %d, power down delay %d\n",
+ intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay);
ironlake_edp_panel_vdd_on(intel_dp);
ret = intel_dp_get_dpcd(intel_dp);
--
1.7.6.3
More information about the dri-devel
mailing list