diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 77 |
2 files changed, 35 insertions, 45 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d02de212e6ad..a72335e940f1 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 57bfc3e7b40a..944dfe199f6e 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) == 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,19 @@ 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) 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 +1433,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 +1447,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; } |