|
@@ -66,7 +66,6 @@ struct intel_dp {
|
|
|
struct drm_display_mode *panel_fixed_mode; /* for eDP */
|
|
|
struct delayed_work panel_vdd_work;
|
|
|
bool want_panel_vdd;
|
|
|
- unsigned long panel_off_jiffies;
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -906,32 +905,53 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void ironlake_wait_panel_off(struct intel_dp *intel_dp)
|
|
|
+#define IDLE_ON_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK)
|
|
|
+#define IDLE_ON_VALUE (PP_ON | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_ON_IDLE)
|
|
|
+
|
|
|
+#define IDLE_OFF_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK)
|
|
|
+#define IDLE_OFF_VALUE (0 | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE)
|
|
|
+
|
|
|
+#define IDLE_CYCLE_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
|
|
|
+#define IDLE_CYCLE_VALUE (0 | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE)
|
|
|
+
|
|
|
+static void ironlake_wait_panel_status(struct intel_dp *intel_dp,
|
|
|
+ u32 mask,
|
|
|
+ u32 value)
|
|
|
{
|
|
|
- unsigned long off_time;
|
|
|
- unsigned long delay;
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
|
|
|
- DRM_DEBUG_KMS("Wait for panel power off time\n");
|
|
|
+ DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n",
|
|
|
+ mask, value,
|
|
|
+ I915_READ(PCH_PP_STATUS),
|
|
|
+ I915_READ(PCH_PP_CONTROL));
|
|
|
|
|
|
- if (ironlake_edp_have_panel_power(intel_dp) ||
|
|
|
- ironlake_edp_have_panel_vdd(intel_dp))
|
|
|
- {
|
|
|
- DRM_DEBUG_KMS("Panel still on, no delay needed\n");
|
|
|
- return;
|
|
|
+ if (_wait_for((I915_READ(PCH_PP_STATUS) & mask) == value, 5000, 10)) {
|
|
|
+ DRM_ERROR("Panel status timeout: status %08x control %08x\n",
|
|
|
+ I915_READ(PCH_PP_STATUS),
|
|
|
+ I915_READ(PCH_PP_CONTROL));
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- off_time = intel_dp->panel_off_jiffies + msecs_to_jiffies(intel_dp->panel_power_down_delay);
|
|
|
- if (time_after(jiffies, off_time)) {
|
|
|
- DRM_DEBUG_KMS("Time already passed");
|
|
|
- return;
|
|
|
- }
|
|
|
- delay = jiffies_to_msecs(off_time - jiffies);
|
|
|
- if (delay > intel_dp->panel_power_down_delay)
|
|
|
- delay = intel_dp->panel_power_down_delay;
|
|
|
- DRM_DEBUG_KMS("Waiting an additional %ld ms\n", delay);
|
|
|
- msleep(delay);
|
|
|
+static void ironlake_wait_panel_on(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ DRM_DEBUG_KMS("Wait for panel power on\n");
|
|
|
+ ironlake_wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
|
|
|
}
|
|
|
|
|
|
+static void ironlake_wait_panel_off(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ DRM_DEBUG_KMS("Wait for panel power off time\n");
|
|
|
+ ironlake_wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
|
|
|
+}
|
|
|
+
|
|
|
+static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ DRM_DEBUG_KMS("Wait for panel power cycle\n");
|
|
|
+ ironlake_wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/* Read the current pp_control value, unlocking the register if it
|
|
|
* is locked
|
|
|
*/
|
|
@@ -959,12 +979,15 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
|
|
|
"eDP VDD already requested on\n");
|
|
|
|
|
|
intel_dp->want_panel_vdd = true;
|
|
|
+
|
|
|
if (ironlake_edp_have_panel_vdd(intel_dp)) {
|
|
|
DRM_DEBUG_KMS("eDP VDD already on\n");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- ironlake_wait_panel_off(intel_dp);
|
|
|
+ if (!ironlake_edp_have_panel_power(intel_dp))
|
|
|
+ ironlake_wait_panel_power_cycle(intel_dp);
|
|
|
+
|
|
|
pp = ironlake_get_pp_control(dev_priv);
|
|
|
pp |= EDP_FORCE_VDD;
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
@@ -996,7 +1019,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
|
|
|
/* Make sure sequencer is idle before allowing subsequent activity */
|
|
|
DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n",
|
|
|
I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL));
|
|
|
- intel_dp->panel_off_jiffies = jiffies;
|
|
|
+
|
|
|
+ msleep(intel_dp->panel_power_down_delay);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1034,21 +1058,25 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* Returns true if the panel was already on when called */
|
|
|
static void 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, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
|
|
|
+ u32 pp;
|
|
|
|
|
|
if (!is_edp(intel_dp))
|
|
|
return;
|
|
|
- if (ironlake_edp_have_panel_power(intel_dp))
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("Turn eDP power on\n");
|
|
|
+
|
|
|
+ if (ironlake_edp_have_panel_power(intel_dp)) {
|
|
|
+ DRM_DEBUG_KMS("eDP power already on\n");
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
- ironlake_wait_panel_off(intel_dp);
|
|
|
- pp = ironlake_get_pp_control(dev_priv);
|
|
|
+ ironlake_wait_panel_power_cycle(intel_dp);
|
|
|
|
|
|
+ pp = ironlake_get_pp_control(dev_priv);
|
|
|
if (IS_GEN5(dev)) {
|
|
|
/* ILK workaround: disable reset around power sequence */
|
|
|
pp &= ~PANEL_POWER_RESET;
|
|
@@ -1057,13 +1085,13 @@ static void ironlake_edp_panel_on(struct intel_dp *intel_dp)
|
|
|
}
|
|
|
|
|
|
pp |= POWER_TARGET_ON;
|
|
|
+ if (!IS_GEN5(dev))
|
|
|
+ pp |= PANEL_POWER_RESET;
|
|
|
+
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
POSTING_READ(PCH_PP_CONTROL);
|
|
|
|
|
|
- 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));
|
|
|
+ ironlake_wait_panel_on(intel_dp);
|
|
|
|
|
|
if (IS_GEN5(dev)) {
|
|
|
pp |= PANEL_POWER_RESET; /* restore panel reset bit */
|
|
@@ -1072,44 +1100,25 @@ static void ironlake_edp_panel_on(struct intel_dp *intel_dp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void ironlake_edp_panel_off(struct drm_encoder *encoder)
|
|
|
+static void ironlake_edp_panel_off(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;
|
|
|
+ u32 pp;
|
|
|
|
|
|
if (!is_edp(intel_dp))
|
|
|
return;
|
|
|
- pp = ironlake_get_pp_control(dev_priv);
|
|
|
|
|
|
- if (IS_GEN5(dev)) {
|
|
|
- /* ILK workaround: disable reset around power sequence */
|
|
|
- pp &= ~PANEL_POWER_RESET;
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
- }
|
|
|
-
|
|
|
- intel_dp->panel_off_jiffies = jiffies;
|
|
|
+ DRM_DEBUG_KMS("Turn eDP power off\n");
|
|
|
|
|
|
- if (IS_GEN5(dev)) {
|
|
|
- pp &= ~POWER_TARGET_ON;
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
- pp &= ~POWER_TARGET_ON;
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
- msleep(intel_dp->panel_power_cycle_delay);
|
|
|
+ WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n");
|
|
|
|
|
|
- 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));
|
|
|
+ pp = ironlake_get_pp_control(dev_priv);
|
|
|
+ pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
|
|
|
+ I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
+ POSTING_READ(PCH_PP_CONTROL);
|
|
|
|
|
|
- pp |= PANEL_POWER_RESET; /* restore panel reset bit */
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
- }
|
|
|
+ ironlake_wait_panel_off(intel_dp);
|
|
|
}
|
|
|
|
|
|
static void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
|
|
@@ -1223,7 +1232,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
|
|
|
*/
|
|
|
ironlake_edp_backlight_off(intel_dp);
|
|
|
intel_dp_link_down(intel_dp);
|
|
|
- ironlake_edp_panel_off(encoder);
|
|
|
+ ironlake_edp_panel_off(intel_dp);
|
|
|
}
|
|
|
|
|
|
static void intel_dp_commit(struct drm_encoder *encoder)
|
|
@@ -1237,7 +1246,6 @@ static void intel_dp_commit(struct drm_encoder *encoder)
|
|
|
intel_dp_start_link_train(intel_dp);
|
|
|
ironlake_edp_panel_on(intel_dp);
|
|
|
ironlake_edp_panel_vdd_off(intel_dp, true);
|
|
|
-
|
|
|
intel_dp_complete_link_train(intel_dp);
|
|
|
ironlake_edp_backlight_on(intel_dp);
|
|
|
|
|
@@ -1261,7 +1269,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
|
|
|
ironlake_edp_backlight_off(intel_dp);
|
|
|
intel_dp_sink_dpms(intel_dp, mode);
|
|
|
intel_dp_link_down(intel_dp);
|
|
|
- ironlake_edp_panel_off(encoder);
|
|
|
+ ironlake_edp_panel_off(intel_dp);
|
|
|
if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
|
|
|
ironlake_edp_pll_off(encoder);
|
|
|
ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
@@ -2398,11 +2406,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
|
|
|
intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
|
|
|
|
|
|
- intel_dp->panel_off_jiffies = jiffies - intel_dp->panel_power_down_delay;
|
|
|
-
|
|
|
ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
ret = intel_dp_get_dpcd(intel_dp);
|
|
|
ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
|
+
|
|
|
if (ret) {
|
|
|
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
|
|
|
dev_priv->no_aux_handshake =
|