[PATCH 19/21] drm/i915: Asynchronous eDP panel power off

Keith Packard keithp at keithp.com
Thu Sep 29 18:09:51 PDT 2011


Using the same basic plan as the VDD force delayed power off, make
turning the panel power off asynchronous.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 drivers/gpu/drm/i915/intel_dp.c |   71 +++++++++++++++++++++++++++++----------
 1 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 08817b0..7120ba7 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -62,8 +62,9 @@ struct intel_dp {
 	int panel_power_up_delay;
 	int panel_power_down_delay;
 	struct drm_display_mode *panel_fixed_mode;  /* for eDP */
-	struct delayed_work panel_vdd_work;
+	struct delayed_work panel_work;
 	bool want_panel_vdd;
+	bool want_panel_power;
 	unsigned long panel_off_jiffies;
 };
 
@@ -906,7 +907,9 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
 	}
 }
 
-static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
+static void ironlake_edp_panel_off_sync(struct intel_dp *intel_dp);
+
+static void ironlake_edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -927,14 +930,15 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
 	}
 }
 
-static void ironlake_panel_vdd_work(struct work_struct *__work)
+static void ironlake_panel_work(struct work_struct *__work)
 {
 	struct intel_dp *intel_dp = container_of(to_delayed_work(__work),
-						 struct intel_dp, panel_vdd_work);
+						 struct intel_dp, panel_work);
 	struct drm_device *dev = intel_dp->base.base.dev;
 
 	mutex_lock(&dev->struct_mutex);
-	ironlake_panel_vdd_off_sync(intel_dp);
+	ironlake_edp_panel_vdd_off_sync(intel_dp);
+	ironlake_edp_panel_off_sync(intel_dp);
 	mutex_unlock(&dev->struct_mutex);
 }
 
@@ -943,20 +947,20 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
 	if (!is_edp(intel_dp))
 		return;
 
-	DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd);
+	DRM_DEBUG_KMS("Turn eDP VDD off %d\n", sync);
 	WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on");
 	
 	intel_dp->want_panel_vdd = false;
 
 	if (sync) {
-		ironlake_panel_vdd_off_sync(intel_dp);
+		ironlake_edp_panel_vdd_off_sync(intel_dp);
 	} else {
 		/*
 		 * Queue the timer to fire a long
 		 * time from now (relative to the power down delay)
 		 * to keep the panel power up across a sequence of operations
 		 */
-		schedule_delayed_work(&intel_dp->panel_vdd_work,
+		schedule_delayed_work(&intel_dp->panel_work,
 				      msecs_to_jiffies(intel_dp->panel_power_down_delay * 5));
 	}
 }
@@ -968,10 +972,16 @@ static void ironlake_edp_panel_on (struct intel_dp *intel_dp)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
 
-	if (ironlake_edp_have_panel_power(intel_dp))
+	DRM_DEBUG_KMS("Turn eDP panel on\n");
+	if (ironlake_edp_have_panel_power(intel_dp)) {
+		DRM_DEBUG_KMS("eDP panel already on\n");
 		return;
+	}
 
 	ironlake_wait_panel_off(intel_dp);
+
+	intel_dp->want_panel_power = true;
+
 	pp = I915_READ(PCH_PP_CONTROL);
 	pp &= ~PANEL_UNLOCK_MASK;
 	pp |= PANEL_UNLOCK_REGS;
@@ -995,14 +1005,16 @@ static void ironlake_edp_panel_on (struct intel_dp *intel_dp)
 	POSTING_READ(PCH_PP_CONTROL);
 }
 
-static void ironlake_edp_panel_off(struct drm_encoder *encoder)
+static void ironlake_edp_panel_off_sync(struct intel_dp *intel_dp)
 {
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-	struct drm_device *dev = encoder->dev;
+	struct drm_device *dev = intel_dp->base.base.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;
 
+	if (intel_dp->want_panel_power || !ironlake_edp_have_panel_power(intel_dp))
+		return;
+
 	pp = I915_READ(PCH_PP_CONTROL);
 	pp &= ~PANEL_UNLOCK_MASK;
 	pp |= PANEL_UNLOCK_REGS;
@@ -1026,6 +1038,28 @@ static void ironlake_edp_panel_off(struct drm_encoder *encoder)
 	intel_dp->panel_off_jiffies = jiffies;
 }
 
+static void ironlake_edp_panel_off(struct drm_encoder *encoder, bool sync)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+	DRM_DEBUG_KMS("Turn eDP panel off %d\n", sync);
+
+	intel_dp->want_panel_power = false;
+
+	if (sync)
+		ironlake_edp_panel_off_sync(intel_dp);
+	else {
+		/*
+		 * Queue the timer to fire a long
+		 * time from now (relative to the power down delay)
+		 * to keep the panel power up across a sequence of operations
+		 */
+		schedule_delayed_work(&intel_dp->panel_work,
+				      msecs_to_jiffies(intel_dp->panel_power_down_delay * 5));
+	}
+		
+}
+
 static void ironlake_edp_backlight_on (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1121,7 +1155,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
 
 	if (is_edp(intel_dp)) {
 		ironlake_edp_backlight_off(dev);
-		ironlake_edp_panel_off(encoder);
+		ironlake_edp_panel_off(encoder, false);
 		if (!is_pch_edp(intel_dp))
 			ironlake_edp_pll_on(encoder);
 		else
@@ -1165,7 +1199,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(encoder);
+			ironlake_edp_panel_off(encoder, true);
 		if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
 			ironlake_edp_pll_off(encoder);
 	} else {
@@ -2016,8 +2050,9 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 	i2c_del_adapter(&intel_dp->adapter);
 	drm_encoder_cleanup(encoder);
 	if (is_edp(intel_dp)) {
-		cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-		ironlake_panel_vdd_off_sync(intel_dp);
+		cancel_delayed_work_sync(&intel_dp->panel_work);
+		ironlake_edp_panel_vdd_off_sync(intel_dp);
+		ironlake_edp_panel_off_sync(intel_dp);
 	}
 	kfree(intel_dp);
 }
@@ -2157,8 +2192,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 
 	if (is_edp(intel_dp)) {
 		intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
-		INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
-				  ironlake_panel_vdd_work);
+		INIT_DELAYED_WORK(&intel_dp->panel_work,
+				  ironlake_panel_work);
 	}
 
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-- 
1.7.6.3



More information about the dri-devel mailing list