[Intel-gfx] [PATCH 07/20] drm/i915/dp: eDP power sequencing fixes

Jesse Barnes jbarnes at virtuousgeek.org
Fri Oct 8 01:01:12 CEST 2010


Enable the panel before adjusting eDP link params, make sure the panel
is idle after powering it on before proceeding with other activity,
delay backlight enable to avoid visible flicker.

Also avoid using VDD per hw team recommendation; it can conflict with
the builtin panel power sequencing logic and lead to panel power
sequencing failures.

Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_reg.h |    3 +
 drivers/gpu/drm/i915/intel_dp.c |   80 ++++++++++++++++----------------------
 2 files changed, 37 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index d02de21..a72335e 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1373,6 +1373,9 @@
 #define   PP_SEQUENCE_ON	(1 << 28)
 #define   PP_SEQUENCE_OFF	(2 << 28)
 #define   PP_SEQUENCE_MASK	0x30000000
+#define   PP_CYCLE_DELAY_ACTIVE	(1 << 27)
+#define   PP_SEQUENCE_STATE_ON_IDLE (1 << 3)
+#define   PP_SEQUENCE_STATE_MASK 0x0000000f
 #define PP_CONTROL	0x61204
 #define   POWER_TARGET_ON	(1 << 0)
 #define PP_ON_DELAYS	0x61208
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 57bfc3e..e5f183f 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -788,10 +788,11 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 }
 
 /* Returns true if the panel was already on when called */
-static bool ironlake_edp_panel_on (struct drm_device *dev)
+static bool ironlake_edp_panel_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;
+	u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
 
 	if (I915_READ(PCH_PP_STATUS) & PP_ON)
 		return true;
@@ -803,19 +804,20 @@ static bool ironlake_edp_panel_on (struct drm_device *dev)
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
 
-	pp |= POWER_TARGET_ON;
+	pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
 	I915_WRITE(PCH_PP_CONTROL, pp);
+	POSTING_READ(PCH_PP_CONTROL);
 
 	/* Ouch. We need to wait here for some panels, like Dell e6510
 	 * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
 	 */
 	msleep(300);
 
-	if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000))
+	if (wait_for(I915_READ(PCH_PP_STATUS) == idle_on_mask,
+		     5000))
 		DRM_ERROR("panel on wait timed out: 0x%08x\n",
 			  I915_READ(PCH_PP_STATUS));
 
-	pp &= ~(PANEL_UNLOCK_REGS);
 	pp |= PANEL_POWER_RESET; /* restore panel reset bit */
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
@@ -826,7 +828,8 @@ static bool ironlake_edp_panel_on (struct drm_device *dev)
 static void ironlake_edp_panel_off (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 pp;
+	u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
+		PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
 
 	pp = I915_READ(PCH_PP_CONTROL);
 
@@ -837,12 +840,12 @@ 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);
 
-	if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000))
+	if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000))
 		DRM_ERROR("panel off wait timed out: 0x%08x\n",
 			  I915_READ(PCH_PP_STATUS));
 
-	/* Make sure VDD is enabled so DP AUX will work */
 	pp |= PANEL_POWER_RESET; /* restore panel reset bit */
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
@@ -853,36 +856,19 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
 	msleep(300);
 }
 
-static void ironlake_edp_panel_vdd_on(struct drm_device *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);
-	msleep(300);
-}
-
-static void ironlake_edp_panel_vdd_off(struct drm_device *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);
-	msleep(300);
-}
-
 static void ironlake_edp_backlight_on (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pp;
 
 	DRM_DEBUG_KMS("\n");
+	/*
+	 * If we enable the backlight right away following a panel power
+	 * on, we may see slight flicker as the panel syncs with the eDP
+	 * link.  So delay a bit to make sure the image is solid before
+	 * allowing it to appear.
+	 */
+	msleep(300);
 	pp = I915_READ(PCH_PP_CONTROL);
 	pp |= EDP_BLC_ENABLE;
 	I915_WRITE(PCH_PP_CONTROL, pp);
@@ -932,10 +918,12 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
 	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
 	if (is_edp(intel_dp)) {
-		ironlake_edp_panel_off(dev);
 		ironlake_edp_backlight_off(dev);
-		ironlake_edp_panel_vdd_on(dev);
-		ironlake_edp_pll_on(encoder);
+		ironlake_edp_panel_on(intel_dp);
+		if (!is_pch_edp(intel_dp))
+			ironlake_edp_pll_on(encoder);
+		else
+			ironlake_edp_pll_off(encoder);
 	}
 	if (dp_reg & DP_PORT_EN)
 		intel_dp_link_down(intel_dp);
@@ -949,7 +937,7 @@ static void intel_dp_commit(struct drm_encoder *encoder)
 	intel_dp_start_link_train(intel_dp);
 
 	if (is_edp(intel_dp))
-		ironlake_edp_panel_on(dev);
+		ironlake_edp_panel_on(intel_dp);
 
 	intel_dp_complete_link_train(intel_dp);
 
@@ -966,19 +954,20 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
 	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
 	if (mode != DRM_MODE_DPMS_ON) {
-		if (is_edp(intel_dp)) {
+		if (is_edp(intel_dp))
 			ironlake_edp_backlight_off(dev);
-			ironlake_edp_panel_off(dev);
-		}
-		if (dp_reg & DP_PORT_EN)
+		if (dp_reg & DP_PORT_EN) {
 			intel_dp_link_down(intel_dp);
+		}
 		if (is_edp(intel_dp))
+			ironlake_edp_panel_off(dev);
+		if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
 			ironlake_edp_pll_off(encoder);
 	} else {
 		if (!(dp_reg & DP_PORT_EN)) {
-			intel_dp_start_link_train(intel_dp);
 			if (is_edp(intel_dp))
-				ironlake_edp_panel_on(dev);
+				ironlake_edp_panel_on(intel_dp);
+			intel_dp_start_link_train(intel_dp);
 			intel_dp_complete_link_train(intel_dp);
 			if (is_edp(intel_dp))
 				ironlake_edp_backlight_on(dev);
@@ -1445,9 +1434,10 @@ ironlake_dp_detect(struct drm_connector *connector)
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
 	enum drm_connector_status status;
 
-	/* Panel needs power for AUX to work */
+	/* Can't disconnect eDP */
 	if (is_edp(intel_dp))
-		ironlake_edp_panel_vdd_on(connector->dev);
+		return connector_status_connected;
+
 	status = connector_status_disconnected;
 	if (intel_dp_aux_native_read(intel_dp,
 				     0x000, intel_dp->dpcd,
@@ -1458,8 +1448,6 @@ ironlake_dp_detect(struct drm_connector *connector)
 	}
 	DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
 		      intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
-	if (is_edp(intel_dp))
-		ironlake_edp_panel_vdd_off(connector->dev);
 	return status;
 }
 
-- 
1.7.0.4




More information about the Intel-gfx mailing list