summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2010-07-23 00:18:19 +0400
committerEric Anholt <eric@anholt.net>2010-07-26 22:27:04 +0400
commit9934c132989d5c488d2e15188220ce240960ce96 (patch)
treed8ffde80fb3ac3ef19cdd671df1ec6741a95f7c4
parent4a655f043160eeae447efd3be297b6b4c397a640 (diff)
downloadlinux-9934c132989d5c488d2e15188220ce240960ce96.tar.xz
drm/i915: make sure eDP panel is turned on
When enabling the eDP port, we need to make sure the panel is turned on after training the link. If we don't, it likely won't come back after suspend or may not come up at all. For unknown reasons, unlocking the panel regs before initiating a power on sequence is necessary. There are known bugs in the PCH panel sequencing logic, apparently this is one possible workaround. Fixes https://bugs.freedesktop.org/show_bug.cgi?id=28739. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Tested-by: "Paulo J. S. Silva" <pjssilva@gmail.com> Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c53
1 files changed, 51 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1aac59e83bff..5d4266115311 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -717,6 +717,51 @@ 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;
+
+ pp = I915_READ(PCH_PP_CONTROL);
+ pp |= PANEL_UNLOCK_REGS | 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 | EDP_FORCE_VDD);
+ 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;
+
+ 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_on (struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -751,14 +796,18 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (mode != DRM_MODE_DPMS_ON) {
if (dp_reg & DP_PORT_EN) {
intel_dp_link_down(intel_encoder, dp_priv->DP);
- if (IS_eDP(intel_encoder))
+ if (IS_eDP(intel_encoder)) {
ironlake_edp_backlight_off(dev);
+ ironlake_edp_backlight_off(dev);
+ }
}
} else {
if (!(dp_reg & DP_PORT_EN)) {
intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration);
- if (IS_eDP(intel_encoder))
+ if (IS_eDP(intel_encoder)) {
+ ironlake_edp_panel_on(dev);
ironlake_edp_backlight_on(dev);
+ }
}
}
dp_priv->dpms_mode = mode;