diff mbox

drm/i915: be sure panel is powered up in eDP configs

Message ID 20100714154056.208b30c9@virtuousgeek.org
State Deferred, archived
Headers show

Commit Message

Jesse Barnes July 14, 2010, 10:40 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 42c6024..b191f02 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2805,6 +2805,7 @@ 
 
 #define PCH_PP_STATUS		0xc7200
 #define PCH_PP_CONTROL		0xc7204
+#define  PANEL_UNLOCK_REGS	(0xabcd << 16)
 #define  EDP_FORCE_VDD		(1 << 3)
 #define  EDP_BLC_ENABLE		(1 << 2)
 #define  PANEL_POWER_RESET	(1 << 1)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index b4f0282..a20dd7b 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -744,6 +744,32 @@  intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 	}
 }
 
+static void ironlake_edp_panel_on(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned long timeout = jiffies + msecs_to_jiffies(5000);
+	u32 pp, pp_status;
+
+	pp_status = I915_READ(PCH_PP_STATUS);
+	if (pp_status & PP_ON)
+		return;
+
+	DRM_DEBUG_KMS("\n");
+	pp = I915_READ(PCH_PP_CONTROL);
+	pp |= POWER_TARGET_ON;
+	I915_WRITE(PCH_PP_CONTROL, pp);
+	do {
+		pp_status = I915_READ(PCH_PP_STATUS);
+	} while (((pp_status & PP_ON) == 0) && !time_after(jiffies, timeout));
+
+	if (time_after(jiffies, timeout))
+		DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status);
+
+	pp |= PANEL_UNLOCK_REGS;
+	pp &= ~EDP_FORCE_VDD;
+	I915_WRITE(PCH_PP_CONTROL, pp);
+}
+
 static void ironlake_edp_backlight_on (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -755,6 +781,28 @@  static void ironlake_edp_backlight_on (struct drm_device *dev)
 	I915_WRITE(PCH_PP_CONTROL, pp);
 }
 
+static void ironlake_edp_panel_off(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned long timeout = jiffies + msecs_to_jiffies(5000);
+	u32 pp, pp_status;
+
+	DRM_DEBUG_KMS("\n");
+	pp = I915_READ(PCH_PP_CONTROL);
+	pp &= ~POWER_TARGET_ON;
+	I915_WRITE(PCH_PP_CONTROL, pp);
+	do {
+		pp_status = I915_READ(PCH_PP_STATUS);
+	} while ((pp_status & PP_ON) && !time_after(jiffies, timeout));
+
+	if (time_after(jiffies, timeout))
+		DRM_DEBUG_KMS("panel off wait timed out\n");
+
+	/* Make sure VDD is enabled so DP AUX will work */
+	pp |= EDP_FORCE_VDD;
+	I915_WRITE(PCH_PP_CONTROL, pp);
+}
+
 static void ironlake_edp_backlight_off (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -776,16 +824,24 @@  intel_dp_dpms(struct drm_encoder *encoder, int mode)
 	uint32_t dp_reg = I915_READ(dp_priv->output_reg);
 
 	if (mode != DRM_MODE_DPMS_ON) {
+		if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
+			ironlake_edp_backlight_off(dev);
+			ironlake_edp_panel_off(dev);
+		}
 		if (dp_reg & DP_PORT_EN) {
 			intel_dp_link_down(intel_encoder, dp_priv->DP);
-			if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv))
-				ironlake_edp_backlight_off(dev);
 		}
 	} else {
+		/* Turn off the panel so we can modify DP_A etc */
+		if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv))
+			ironlake_edp_panel_off(dev);
 		if (!(dp_reg & DP_PORT_EN)) {
 			intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration);
-			if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv))
-				ironlake_edp_backlight_on(dev);
+		}
+		if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
+			if (I915_READ(dp_priv->output_reg) & DP_PORT_EN)
+				ironlake_edp_panel_on(dev);
+			ironlake_edp_backlight_on(dev);
 		}
 	}
 	dp_priv->dpms_mode = mode;