@@ -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)
@@ -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;