|
@@ -36,7 +36,7 @@
|
|
|
#include "i915_drv.h"
|
|
|
#include "drm_dp_helper.h"
|
|
|
|
|
|
-
|
|
|
+#define DP_RECEIVER_CAP_SIZE 0xf
|
|
|
#define DP_LINK_STATUS_SIZE 6
|
|
|
#define DP_LINK_CHECK_TIMEOUT (10 * 1000)
|
|
|
|
|
@@ -53,12 +53,21 @@ struct intel_dp {
|
|
|
int dpms_mode;
|
|
|
uint8_t link_bw;
|
|
|
uint8_t lane_count;
|
|
|
- uint8_t dpcd[8];
|
|
|
+ uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
|
|
|
struct i2c_adapter adapter;
|
|
|
struct i2c_algo_dp_aux_data algo;
|
|
|
bool is_pch_edp;
|
|
|
uint8_t train_set[4];
|
|
|
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
|
|
+ int panel_power_up_delay;
|
|
|
+ int panel_power_down_delay;
|
|
|
+ int panel_power_cycle_delay;
|
|
|
+ int backlight_on_delay;
|
|
|
+ int backlight_off_delay;
|
|
|
+ struct drm_display_mode *panel_fixed_mode; /* for eDP */
|
|
|
+ struct delayed_work panel_vdd_work;
|
|
|
+ bool want_panel_vdd;
|
|
|
+ unsigned long panel_off_jiffies;
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -86,6 +95,17 @@ static bool is_pch_edp(struct intel_dp *intel_dp)
|
|
|
return intel_dp->is_pch_edp;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * is_cpu_edp - is the port on the CPU and attached to an eDP panel?
|
|
|
+ * @intel_dp: DP struct
|
|
|
+ *
|
|
|
+ * Returns true if the given DP struct corresponds to a CPU eDP port.
|
|
|
+ */
|
|
|
+static bool is_cpu_edp(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ return is_edp(intel_dp) && !is_pch_edp(intel_dp);
|
|
|
+}
|
|
|
+
|
|
|
static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
|
|
|
{
|
|
|
return container_of(encoder, struct intel_dp, base.base);
|
|
@@ -175,9 +195,25 @@ intel_dp_link_clock(uint8_t link_bw)
|
|
|
return 162000;
|
|
|
}
|
|
|
|
|
|
-/* I think this is a fiction */
|
|
|
+/*
|
|
|
+ * The units on the numbers in the next two are... bizarre. Examples will
|
|
|
+ * make it clearer; this one parallels an example in the eDP spec.
|
|
|
+ *
|
|
|
+ * intel_dp_max_data_rate for one lane of 2.7GHz evaluates as:
|
|
|
+ *
|
|
|
+ * 270000 * 1 * 8 / 10 == 216000
|
|
|
+ *
|
|
|
+ * The actual data capacity of that configuration is 2.16Gbit/s, so the
|
|
|
+ * units are decakilobits. ->clock in a drm_display_mode is in kilohertz -
|
|
|
+ * or equivalently, kilopixels per second - so for 1680x1050R it'd be
|
|
|
+ * 119000. At 18bpp that's 2142000 kilobits per second.
|
|
|
+ *
|
|
|
+ * Thus the strange-looking division by 10 in intel_dp_link_required, to
|
|
|
+ * get the result in decakilobits instead of kilobits.
|
|
|
+ */
|
|
|
+
|
|
|
static int
|
|
|
-intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pixel_clock)
|
|
|
+intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock)
|
|
|
{
|
|
|
struct drm_crtc *crtc = intel_dp->base.base.crtc;
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
@@ -186,7 +222,7 @@ intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pi
|
|
|
if (intel_crtc)
|
|
|
bpp = intel_crtc->bpp;
|
|
|
|
|
|
- return (pixel_clock * bpp + 7) / 8;
|
|
|
+ return (pixel_clock * bpp + 9) / 10;
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -200,24 +236,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
|
|
|
struct drm_display_mode *mode)
|
|
|
{
|
|
|
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
|
|
- struct drm_device *dev = connector->dev;
|
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
|
|
|
int max_lanes = intel_dp_max_lane_count(intel_dp);
|
|
|
|
|
|
- if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
|
|
|
- if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
|
|
|
+ if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
|
|
|
+ if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay)
|
|
|
return MODE_PANEL;
|
|
|
|
|
|
- if (mode->vdisplay > dev_priv->panel_fixed_mode->vdisplay)
|
|
|
+ if (mode->vdisplay > intel_dp->panel_fixed_mode->vdisplay)
|
|
|
return MODE_PANEL;
|
|
|
}
|
|
|
|
|
|
- /* only refuse the mode on non eDP since we have seen some weird eDP panels
|
|
|
- which are outside spec tolerances but somehow work by magic */
|
|
|
- if (!is_edp(intel_dp) &&
|
|
|
- (intel_dp_link_required(connector->dev, intel_dp, mode->clock)
|
|
|
- > intel_dp_max_data_rate(max_link_clock, max_lanes)))
|
|
|
+ if (intel_dp_link_required(intel_dp, mode->clock)
|
|
|
+ > intel_dp_max_data_rate(max_link_clock, max_lanes))
|
|
|
return MODE_CLOCK_HIGH;
|
|
|
|
|
|
if (mode->clock < 10000)
|
|
@@ -279,6 +310,38 @@ intel_hrawclk(struct drm_device *dev)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+
|
|
|
+ return (I915_READ(PCH_PP_STATUS) & PP_ON) != 0;
|
|
|
+}
|
|
|
+
|
|
|
+static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+
|
|
|
+ return (I915_READ(PCH_PP_CONTROL) & EDP_FORCE_VDD) != 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+intel_dp_check_edp(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+
|
|
|
+ if (!is_edp(intel_dp))
|
|
|
+ return;
|
|
|
+ if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) {
|
|
|
+ WARN(1, "eDP powered off while attempting aux channel communication.\n");
|
|
|
+ DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n",
|
|
|
+ I915_READ(PCH_PP_STATUS),
|
|
|
+ I915_READ(PCH_PP_CONTROL));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|
|
uint8_t *send, int send_bytes,
|
|
@@ -295,6 +358,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|
|
uint32_t aux_clock_divider;
|
|
|
int try, precharge;
|
|
|
|
|
|
+ intel_dp_check_edp(intel_dp);
|
|
|
/* The clock divider is based off the hrawclk,
|
|
|
* and would like to run at 2MHz. So, take the
|
|
|
* hrawclk value and divide by 2 and use that
|
|
@@ -302,7 +366,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|
|
* Note that PCH attached eDP panels should use a 125MHz input
|
|
|
* clock divider.
|
|
|
*/
|
|
|
- if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
|
|
|
+ if (is_cpu_edp(intel_dp)) {
|
|
|
if (IS_GEN6(dev))
|
|
|
aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
|
|
|
else
|
|
@@ -408,6 +472,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
|
|
|
int msg_bytes;
|
|
|
uint8_t ack;
|
|
|
|
|
|
+ intel_dp_check_edp(intel_dp);
|
|
|
if (send_bytes > 16)
|
|
|
return -1;
|
|
|
msg[0] = AUX_NATIVE_WRITE << 4;
|
|
@@ -450,6 +515,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
|
|
|
uint8_t ack;
|
|
|
int ret;
|
|
|
|
|
|
+ intel_dp_check_edp(intel_dp);
|
|
|
msg[0] = AUX_NATIVE_READ << 4;
|
|
|
msg[1] = address >> 8;
|
|
|
msg[2] = address & 0xff;
|
|
@@ -493,6 +559,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
|
|
|
int reply_bytes;
|
|
|
int ret;
|
|
|
|
|
|
+ intel_dp_check_edp(intel_dp);
|
|
|
/* Set up the command byte */
|
|
|
if (mode & MODE_I2C_READ)
|
|
|
msg[0] = AUX_I2C_READ << 4;
|
|
@@ -573,10 +640,15 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
|
|
|
return -EREMOTEIO;
|
|
|
}
|
|
|
|
|
|
+static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp);
|
|
|
+static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
|
|
|
+
|
|
|
static int
|
|
|
intel_dp_i2c_init(struct intel_dp *intel_dp,
|
|
|
struct intel_connector *intel_connector, const char *name)
|
|
|
{
|
|
|
+ int ret;
|
|
|
+
|
|
|
DRM_DEBUG_KMS("i2c_init %s\n", name);
|
|
|
intel_dp->algo.running = false;
|
|
|
intel_dp->algo.address = 0;
|
|
@@ -590,7 +662,10 @@ intel_dp_i2c_init(struct intel_dp *intel_dp,
|
|
|
intel_dp->adapter.algo_data = &intel_dp->algo;
|
|
|
intel_dp->adapter.dev.parent = &intel_connector->base.kdev;
|
|
|
|
|
|
- return i2c_dp_aux_add_bus(&intel_dp->adapter);
|
|
|
+ ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
+ ret = i2c_dp_aux_add_bus(&intel_dp->adapter);
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static bool
|
|
@@ -598,29 +673,28 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
struct drm_display_mode *adjusted_mode)
|
|
|
{
|
|
|
struct drm_device *dev = encoder->dev;
|
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
|
|
int lane_count, clock;
|
|
|
int max_lane_count = intel_dp_max_lane_count(intel_dp);
|
|
|
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
|
|
|
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
|
|
|
|
|
|
- if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
|
|
|
- intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
|
|
|
+ if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
|
|
|
+ intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode);
|
|
|
intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
|
|
|
mode, adjusted_mode);
|
|
|
/*
|
|
|
* the mode->clock is used to calculate the Data&Link M/N
|
|
|
* of the pipe. For the eDP the fixed clock should be used.
|
|
|
*/
|
|
|
- mode->clock = dev_priv->panel_fixed_mode->clock;
|
|
|
+ mode->clock = intel_dp->panel_fixed_mode->clock;
|
|
|
}
|
|
|
|
|
|
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
|
|
|
for (clock = 0; clock <= max_clock; clock++) {
|
|
|
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
|
|
|
|
|
|
- if (intel_dp_link_required(encoder->dev, intel_dp, mode->clock)
|
|
|
+ if (intel_dp_link_required(intel_dp, mode->clock)
|
|
|
<= link_avail) {
|
|
|
intel_dp->link_bw = bws[clock];
|
|
|
intel_dp->lane_count = lane_count;
|
|
@@ -634,19 +708,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (is_edp(intel_dp)) {
|
|
|
- /* okay we failed just pick the highest */
|
|
|
- intel_dp->lane_count = max_lane_count;
|
|
|
- intel_dp->link_bw = bws[max_clock];
|
|
|
- adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
|
|
|
- DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
|
|
|
- "count %d clock %d\n",
|
|
|
- intel_dp->link_bw, intel_dp->lane_count,
|
|
|
- adjusted_mode->clock);
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -740,6 +801,9 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void ironlake_edp_pll_on(struct drm_encoder *encoder);
|
|
|
+static void ironlake_edp_pll_off(struct drm_encoder *encoder);
|
|
|
+
|
|
|
static void
|
|
|
intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
struct drm_display_mode *adjusted_mode)
|
|
@@ -749,6 +813,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
struct drm_crtc *crtc = intel_dp->base.base.crtc;
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
|
+ /* Turn on the eDP PLL if needed */
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
+ if (!is_pch_edp(intel_dp))
|
|
|
+ ironlake_edp_pll_on(encoder);
|
|
|
+ else
|
|
|
+ ironlake_edp_pll_off(encoder);
|
|
|
+ }
|
|
|
+
|
|
|
intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
|
|
|
intel_dp->DP |= intel_dp->color_range;
|
|
|
|
|
@@ -757,7 +829,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
|
|
intel_dp->DP |= DP_SYNC_VS_HIGH;
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
|
|
|
intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
|
|
|
else
|
|
|
intel_dp->DP |= DP_LINK_TRAIN_OFF;
|
|
@@ -798,7 +870,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev))
|
|
|
intel_dp->DP |= DP_PIPEB_SELECT;
|
|
|
|
|
|
- if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
|
|
|
+ if (is_cpu_edp(intel_dp)) {
|
|
|
/* don't miss out required setting for eDP */
|
|
|
intel_dp->DP |= DP_PLL_ENABLE;
|
|
|
if (adjusted_mode->clock < 200000)
|
|
@@ -808,58 +880,150 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void ironlake_wait_panel_off(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ unsigned long off_time;
|
|
|
+ unsigned long delay;
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("Wait for panel power off time\n");
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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_edp_panel_vdd_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;
|
|
|
|
|
|
- /*
|
|
|
- * If the panel wasn't on, make sure there's not a currently
|
|
|
- * active PP sequence before enabling AUX VDD.
|
|
|
- */
|
|
|
- if (!(I915_READ(PCH_PP_STATUS) & PP_ON))
|
|
|
- msleep(dev_priv->panel_t3);
|
|
|
+ if (!is_edp(intel_dp))
|
|
|
+ return;
|
|
|
+ DRM_DEBUG_KMS("Turn eDP VDD on\n");
|
|
|
|
|
|
+ WARN(intel_dp->want_panel_vdd,
|
|
|
+ "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);
|
|
|
pp = I915_READ(PCH_PP_CONTROL);
|
|
|
+ pp &= ~PANEL_UNLOCK_MASK;
|
|
|
+ pp |= PANEL_UNLOCK_REGS;
|
|
|
pp |= EDP_FORCE_VDD;
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
POSTING_READ(PCH_PP_CONTROL);
|
|
|
+ DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n",
|
|
|
+ I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the panel wasn't on, delay before accessing aux channel
|
|
|
+ */
|
|
|
+ if (!ironlake_edp_have_panel_power(intel_dp)) {
|
|
|
+ DRM_DEBUG_KMS("eDP was not running\n");
|
|
|
+ msleep(intel_dp->panel_power_up_delay);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp)
|
|
|
+static void ironlake_panel_vdd_off_sync(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;
|
|
|
|
|
|
- pp = I915_READ(PCH_PP_CONTROL);
|
|
|
- pp &= ~EDP_FORCE_VDD;
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
+ if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
|
|
|
+ pp = I915_READ(PCH_PP_CONTROL);
|
|
|
+ pp &= ~PANEL_UNLOCK_MASK;
|
|
|
+ pp |= PANEL_UNLOCK_REGS;
|
|
|
+ pp &= ~EDP_FORCE_VDD;
|
|
|
+ I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
+ POSTING_READ(PCH_PP_CONTROL);
|
|
|
+
|
|
|
+ /* 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;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- /* Make sure sequencer is idle before allowing subsequent activity */
|
|
|
- msleep(dev_priv->panel_t12);
|
|
|
+static void ironlake_panel_vdd_work(struct work_struct *__work)
|
|
|
+{
|
|
|
+ struct intel_dp *intel_dp = container_of(to_delayed_work(__work),
|
|
|
+ struct intel_dp, panel_vdd_work);
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
+
|
|
|
+ mutex_lock(&dev->struct_mutex);
|
|
|
+ ironlake_panel_vdd_off_sync(intel_dp);
|
|
|
+ mutex_unlock(&dev->struct_mutex);
|
|
|
+}
|
|
|
+
|
|
|
+static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
|
|
|
+{
|
|
|
+ if (!is_edp(intel_dp))
|
|
|
+ return;
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd);
|
|
|
+ WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on");
|
|
|
+
|
|
|
+ intel_dp->want_panel_vdd = false;
|
|
|
+
|
|
|
+ if (sync) {
|
|
|
+ ironlake_panel_vdd_off_sync(intel_dp);
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * Queue the timer to fire a long
|
|
|
+ * time from now (relative to the power down delay)
|
|
|
+ * to keep the panel power up across a sequence of operations
|
|
|
+ */
|
|
|
+ schedule_delayed_work(&intel_dp->panel_vdd_work,
|
|
|
+ msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Returns true if the panel was already on when called */
|
|
|
-static bool ironlake_edp_panel_on(struct intel_dp *intel_dp)
|
|
|
+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;
|
|
|
|
|
|
- if (I915_READ(PCH_PP_STATUS) & PP_ON)
|
|
|
- return true;
|
|
|
+ if (!is_edp(intel_dp))
|
|
|
+ return;
|
|
|
+ if (ironlake_edp_have_panel_power(intel_dp))
|
|
|
+ return;
|
|
|
|
|
|
+ ironlake_wait_panel_off(intel_dp);
|
|
|
pp = I915_READ(PCH_PP_CONTROL);
|
|
|
+ pp &= ~PANEL_UNLOCK_MASK;
|
|
|
+ pp |= PANEL_UNLOCK_REGS;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
|
|
|
- /* ILK workaround: disable reset around power sequence */
|
|
|
- pp &= ~PANEL_POWER_RESET;
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
-
|
|
|
- pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
|
|
|
+ pp |= POWER_TARGET_ON;
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
POSTING_READ(PCH_PP_CONTROL);
|
|
|
|
|
@@ -868,44 +1032,64 @@ static bool ironlake_edp_panel_on(struct intel_dp *intel_dp)
|
|
|
DRM_ERROR("panel on wait timed out: 0x%08x\n",
|
|
|
I915_READ(PCH_PP_STATUS));
|
|
|
|
|
|
- pp |= PANEL_POWER_RESET; /* restore panel reset bit */
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
-
|
|
|
- return false;
|
|
|
+ if (IS_GEN5(dev)) {
|
|
|
+ pp |= PANEL_POWER_RESET; /* restore panel reset bit */
|
|
|
+ I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
+ POSTING_READ(PCH_PP_CONTROL);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static void ironlake_edp_panel_off(struct drm_device *dev)
|
|
|
+static void ironlake_edp_panel_off(struct drm_encoder *encoder)
|
|
|
{
|
|
|
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
|
|
+ struct drm_device *dev = encoder->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;
|
|
|
|
|
|
+ if (!is_edp(intel_dp))
|
|
|
+ return;
|
|
|
pp = I915_READ(PCH_PP_CONTROL);
|
|
|
+ pp &= ~PANEL_UNLOCK_MASK;
|
|
|
+ pp |= PANEL_UNLOCK_REGS;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
|
|
|
- /* 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;
|
|
|
|
|
|
- pp &= ~POWER_TARGET_ON;
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
+ 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);
|
|
|
|
|
|
- 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));
|
|
|
+ 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 |= PANEL_POWER_RESET; /* restore panel reset bit */
|
|
|
- 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);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static void ironlake_edp_backlight_on(struct drm_device *dev)
|
|
|
+static void ironlake_edp_backlight_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;
|
|
|
|
|
|
+ if (!is_edp(intel_dp))
|
|
|
+ return;
|
|
|
+
|
|
|
DRM_DEBUG_KMS("\n");
|
|
|
/*
|
|
|
* If we enable the backlight right away following a panel power
|
|
@@ -913,21 +1097,32 @@ static void ironlake_edp_backlight_on(struct drm_device *dev)
|
|
|
* link. So delay a bit to make sure the image is solid before
|
|
|
* allowing it to appear.
|
|
|
*/
|
|
|
- msleep(300);
|
|
|
+ msleep(intel_dp->backlight_on_delay);
|
|
|
pp = I915_READ(PCH_PP_CONTROL);
|
|
|
+ pp &= ~PANEL_UNLOCK_MASK;
|
|
|
+ pp |= PANEL_UNLOCK_REGS;
|
|
|
pp |= EDP_BLC_ENABLE;
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
+ POSTING_READ(PCH_PP_CONTROL);
|
|
|
}
|
|
|
|
|
|
-static void ironlake_edp_backlight_off(struct drm_device *dev)
|
|
|
+static void ironlake_edp_backlight_off(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;
|
|
|
|
|
|
+ if (!is_edp(intel_dp))
|
|
|
+ return;
|
|
|
+
|
|
|
DRM_DEBUG_KMS("\n");
|
|
|
pp = I915_READ(PCH_PP_CONTROL);
|
|
|
+ pp &= ~PANEL_UNLOCK_MASK;
|
|
|
+ pp |= PANEL_UNLOCK_REGS;
|
|
|
pp &= ~EDP_BLC_ENABLE;
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
+ POSTING_READ(PCH_PP_CONTROL);
|
|
|
+ msleep(intel_dp->backlight_off_delay);
|
|
|
}
|
|
|
|
|
|
static void ironlake_edp_pll_on(struct drm_encoder *encoder)
|
|
@@ -990,43 +1185,39 @@ static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
|
|
|
static void intel_dp_prepare(struct drm_encoder *encoder)
|
|
|
{
|
|
|
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
|
|
- struct drm_device *dev = encoder->dev;
|
|
|
|
|
|
/* Wake up the sink first */
|
|
|
+ ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
|
|
|
|
- if (is_edp(intel_dp)) {
|
|
|
- ironlake_edp_backlight_off(dev);
|
|
|
- ironlake_edp_panel_off(dev);
|
|
|
- if (!is_pch_edp(intel_dp))
|
|
|
- ironlake_edp_pll_on(encoder);
|
|
|
- else
|
|
|
- ironlake_edp_pll_off(encoder);
|
|
|
- }
|
|
|
+ /* Make sure the panel is off before trying to
|
|
|
+ * change the mode
|
|
|
+ */
|
|
|
+ ironlake_edp_backlight_off(intel_dp);
|
|
|
intel_dp_link_down(intel_dp);
|
|
|
+ ironlake_edp_panel_off(encoder);
|
|
|
}
|
|
|
|
|
|
static void intel_dp_commit(struct drm_encoder *encoder)
|
|
|
{
|
|
|
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
|
|
struct drm_device *dev = encoder->dev;
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
|
|
|
|
|
|
- if (is_edp(intel_dp))
|
|
|
- ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
-
|
|
|
+ ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
+ intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
|
|
|
intel_dp_start_link_train(intel_dp);
|
|
|
-
|
|
|
- if (is_edp(intel_dp)) {
|
|
|
- ironlake_edp_panel_on(intel_dp);
|
|
|
- ironlake_edp_panel_vdd_off(intel_dp);
|
|
|
- }
|
|
|
+ ironlake_edp_panel_on(intel_dp);
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, true);
|
|
|
|
|
|
intel_dp_complete_link_train(intel_dp);
|
|
|
-
|
|
|
- if (is_edp(intel_dp))
|
|
|
- ironlake_edp_backlight_on(dev);
|
|
|
+ ironlake_edp_backlight_on(intel_dp);
|
|
|
|
|
|
intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
|
|
|
+
|
|
|
+ if (HAS_PCH_CPT(dev))
|
|
|
+ intel_cpt_verify_modeset(dev, intel_crtc->pipe);
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -1038,28 +1229,27 @@ 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) {
|
|
|
+ ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
if (is_edp(intel_dp))
|
|
|
- ironlake_edp_backlight_off(dev);
|
|
|
+ ironlake_edp_backlight_off(intel_dp);
|
|
|
intel_dp_sink_dpms(intel_dp, mode);
|
|
|
intel_dp_link_down(intel_dp);
|
|
|
- if (is_edp(intel_dp))
|
|
|
- ironlake_edp_panel_off(dev);
|
|
|
+ ironlake_edp_panel_off(encoder);
|
|
|
if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
|
|
|
ironlake_edp_pll_off(encoder);
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
|
} else {
|
|
|
- if (is_edp(intel_dp))
|
|
|
- ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
+ ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
intel_dp_sink_dpms(intel_dp, mode);
|
|
|
if (!(dp_reg & DP_PORT_EN)) {
|
|
|
intel_dp_start_link_train(intel_dp);
|
|
|
- if (is_edp(intel_dp)) {
|
|
|
- ironlake_edp_panel_on(intel_dp);
|
|
|
- ironlake_edp_panel_vdd_off(intel_dp);
|
|
|
- }
|
|
|
+ ironlake_edp_panel_on(intel_dp);
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, true);
|
|
|
intel_dp_complete_link_train(intel_dp);
|
|
|
- }
|
|
|
- if (is_edp(intel_dp))
|
|
|
- ironlake_edp_backlight_on(dev);
|
|
|
+ ironlake_edp_backlight_on(intel_dp);
|
|
|
+ } else
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
|
+ ironlake_edp_backlight_on(intel_dp);
|
|
|
}
|
|
|
intel_dp->dpms_mode = mode;
|
|
|
}
|
|
@@ -1368,7 +1558,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
|
|
DP_LINK_CONFIGURATION_SIZE);
|
|
|
|
|
|
DP |= DP_PORT_EN;
|
|
|
- if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
|
|
|
DP &= ~DP_LINK_TRAIN_MASK_CPT;
|
|
|
else
|
|
|
DP &= ~DP_LINK_TRAIN_MASK;
|
|
@@ -1387,7 +1577,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
|
|
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
|
|
|
}
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
|
|
|
reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
|
|
|
else
|
|
|
reg = DP | DP_LINK_TRAIN_PAT_1;
|
|
@@ -1462,7 +1652,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
|
|
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
|
|
|
}
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
|
|
|
reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
|
|
|
else
|
|
|
reg = DP | DP_LINK_TRAIN_PAT_2;
|
|
@@ -1503,7 +1693,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
|
|
++tries;
|
|
|
}
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
|
|
|
reg = DP | DP_LINK_TRAIN_OFF_CPT;
|
|
|
else
|
|
|
reg = DP | DP_LINK_TRAIN_OFF;
|
|
@@ -1533,7 +1723,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
|
|
udelay(100);
|
|
|
}
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) {
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) {
|
|
|
DP &= ~DP_LINK_TRAIN_MASK_CPT;
|
|
|
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
|
|
|
} else {
|
|
@@ -1582,6 +1772,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
|
|
|
|
|
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
|
|
|
POSTING_READ(intel_dp->output_reg);
|
|
|
+ msleep(intel_dp->panel_power_down_delay);
|
|
|
}
|
|
|
|
|
|
static bool
|
|
@@ -1596,6 +1787,27 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+static bool
|
|
|
+intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = intel_dp_aux_native_read_retry(intel_dp,
|
|
|
+ DP_DEVICE_SERVICE_IRQ_VECTOR,
|
|
|
+ sink_irq_vector, 1);
|
|
|
+ if (!ret)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+intel_dp_handle_test_request(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ /* NAK by default */
|
|
|
+ intel_dp_aux_native_write_1(intel_dp, DP_TEST_RESPONSE, DP_TEST_ACK);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* According to DP spec
|
|
|
* 5.1.2:
|
|
@@ -1608,6 +1820,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
|
|
static void
|
|
|
intel_dp_check_link_status(struct intel_dp *intel_dp)
|
|
|
{
|
|
|
+ u8 sink_irq_vector;
|
|
|
+
|
|
|
if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON)
|
|
|
return;
|
|
|
|
|
@@ -1626,6 +1840,20 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ /* Try to read the source of the interrupt */
|
|
|
+ if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
|
|
|
+ intel_dp_get_sink_irq(intel_dp, &sink_irq_vector)) {
|
|
|
+ /* Clear interrupt source */
|
|
|
+ intel_dp_aux_native_write_1(intel_dp,
|
|
|
+ DP_DEVICE_SERVICE_IRQ_VECTOR,
|
|
|
+ sink_irq_vector);
|
|
|
+
|
|
|
+ if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST)
|
|
|
+ intel_dp_handle_test_request(intel_dp);
|
|
|
+ if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ))
|
|
|
+ DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
|
|
|
+ }
|
|
|
+
|
|
|
if (!intel_channel_eq_ok(intel_dp)) {
|
|
|
DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
|
|
|
drm_get_encoder_name(&intel_dp->base.base));
|
|
@@ -1687,6 +1915,31 @@ g4x_dp_detect(struct intel_dp *intel_dp)
|
|
|
return intel_dp_detect_dpcd(intel_dp);
|
|
|
}
|
|
|
|
|
|
+static struct edid *
|
|
|
+intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
|
|
|
+{
|
|
|
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
|
|
|
+ struct edid *edid;
|
|
|
+
|
|
|
+ ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
+ edid = drm_get_edid(connector, adapter);
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
|
+ return edid;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *adapter)
|
|
|
+{
|
|
|
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ironlake_edp_panel_vdd_on(intel_dp);
|
|
|
+ ret = intel_ddc_get_modes(connector, adapter);
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
|
|
|
*
|
|
@@ -1719,7 +1972,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
|
|
|
if (intel_dp->force_audio) {
|
|
|
intel_dp->has_audio = intel_dp->force_audio > 0;
|
|
|
} else {
|
|
|
- edid = drm_get_edid(connector, &intel_dp->adapter);
|
|
|
+ edid = intel_dp_get_edid(connector, &intel_dp->adapter);
|
|
|
if (edid) {
|
|
|
intel_dp->has_audio = drm_detect_monitor_audio(edid);
|
|
|
connector->display_info.raw_edid = NULL;
|
|
@@ -1740,28 +1993,36 @@ static int intel_dp_get_modes(struct drm_connector *connector)
|
|
|
/* We should parse the EDID data and find out if it has an audio sink
|
|
|
*/
|
|
|
|
|
|
- ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
|
|
|
+ ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter);
|
|
|
if (ret) {
|
|
|
- if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) {
|
|
|
+ if (is_edp(intel_dp) && !intel_dp->panel_fixed_mode) {
|
|
|
struct drm_display_mode *newmode;
|
|
|
list_for_each_entry(newmode, &connector->probed_modes,
|
|
|
head) {
|
|
|
- if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
|
|
|
- dev_priv->panel_fixed_mode =
|
|
|
+ if ((newmode->type & DRM_MODE_TYPE_PREFERRED)) {
|
|
|
+ intel_dp->panel_fixed_mode =
|
|
|
drm_mode_duplicate(dev, newmode);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
/* if eDP has no EDID, try to use fixed panel mode from VBT */
|
|
|
if (is_edp(intel_dp)) {
|
|
|
- if (dev_priv->panel_fixed_mode != NULL) {
|
|
|
+ /* initialize panel mode from VBT if available for eDP */
|
|
|
+ if (intel_dp->panel_fixed_mode == NULL && dev_priv->lfp_lvds_vbt_mode != NULL) {
|
|
|
+ intel_dp->panel_fixed_mode =
|
|
|
+ drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
|
|
|
+ if (intel_dp->panel_fixed_mode) {
|
|
|
+ intel_dp->panel_fixed_mode->type |=
|
|
|
+ DRM_MODE_TYPE_PREFERRED;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (intel_dp->panel_fixed_mode) {
|
|
|
struct drm_display_mode *mode;
|
|
|
- mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
|
|
|
+ mode = drm_mode_duplicate(dev, intel_dp->panel_fixed_mode);
|
|
|
drm_mode_probed_add(connector, mode);
|
|
|
return 1;
|
|
|
}
|
|
@@ -1776,7 +2037,7 @@ intel_dp_detect_audio(struct drm_connector *connector)
|
|
|
struct edid *edid;
|
|
|
bool has_audio = false;
|
|
|
|
|
|
- edid = drm_get_edid(connector, &intel_dp->adapter);
|
|
|
+ edid = intel_dp_get_edid(connector, &intel_dp->adapter);
|
|
|
if (edid) {
|
|
|
has_audio = drm_detect_monitor_audio(edid);
|
|
|
|
|
@@ -1861,6 +2122,10 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
|
|
|
|
|
|
i2c_del_adapter(&intel_dp->adapter);
|
|
|
drm_encoder_cleanup(encoder);
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
+ cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
|
|
|
+ ironlake_panel_vdd_off_sync(intel_dp);
|
|
|
+ }
|
|
|
kfree(intel_dp);
|
|
|
}
|
|
|
|
|
@@ -1997,10 +2262,13 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
else if (output_reg == DP_D || output_reg == PCH_DP_D)
|
|
|
intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
|
|
|
|
|
|
- if (is_edp(intel_dp))
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
|
|
|
+ INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
|
|
|
+ ironlake_panel_vdd_work);
|
|
|
+ }
|
|
|
|
|
|
- intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
|
|
+ intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
|
|
connector->interlace_allowed = true;
|
|
|
connector->doublescan_allowed = 0;
|
|
|
|
|
@@ -2036,25 +2304,60 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- intel_dp_i2c_init(intel_dp, intel_connector, name);
|
|
|
-
|
|
|
/* Cache some DPCD data in the eDP case */
|
|
|
if (is_edp(intel_dp)) {
|
|
|
bool ret;
|
|
|
- u32 pp_on, pp_div;
|
|
|
+ struct edp_power_seq cur, vbt;
|
|
|
+ u32 pp_on, pp_off, pp_div;
|
|
|
|
|
|
pp_on = I915_READ(PCH_PP_ON_DELAYS);
|
|
|
+ pp_off = I915_READ(PCH_PP_OFF_DELAYS);
|
|
|
pp_div = I915_READ(PCH_PP_DIVISOR);
|
|
|
|
|
|
- /* Get T3 & T12 values (note: VESA not bspec terminology) */
|
|
|
- dev_priv->panel_t3 = (pp_on & 0x1fff0000) >> 16;
|
|
|
- dev_priv->panel_t3 /= 10; /* t3 in 100us units */
|
|
|
- dev_priv->panel_t12 = pp_div & 0xf;
|
|
|
- dev_priv->panel_t12 *= 100; /* t12 in 100ms units */
|
|
|
+ /* Pull timing values out of registers */
|
|
|
+ cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >>
|
|
|
+ PANEL_POWER_UP_DELAY_SHIFT;
|
|
|
+
|
|
|
+ cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >>
|
|
|
+ PANEL_LIGHT_ON_DELAY_SHIFT;
|
|
|
+
|
|
|
+ cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >>
|
|
|
+ PANEL_LIGHT_OFF_DELAY_SHIFT;
|
|
|
+
|
|
|
+ cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >>
|
|
|
+ PANEL_POWER_DOWN_DELAY_SHIFT;
|
|
|
+
|
|
|
+ cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >>
|
|
|
+ PANEL_POWER_CYCLE_DELAY_SHIFT) * 1000;
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
|
|
|
+ cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12);
|
|
|
+
|
|
|
+ vbt = dev_priv->edp.pps;
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
|
|
|
+ vbt.t1_t3, vbt.t8, vbt.t9, vbt.t10, vbt.t11_t12);
|
|
|
+
|
|
|
+#define get_delay(field) ((max(cur.field, vbt.field) + 9) / 10)
|
|
|
+
|
|
|
+ intel_dp->panel_power_up_delay = get_delay(t1_t3);
|
|
|
+ intel_dp->backlight_on_delay = get_delay(t8);
|
|
|
+ intel_dp->backlight_off_delay = get_delay(t9);
|
|
|
+ intel_dp->panel_power_down_delay = get_delay(t10);
|
|
|
+ intel_dp->panel_power_cycle_delay = get_delay(t11_t12);
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
|
|
|
+ intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
|
|
|
+ intel_dp->panel_power_cycle_delay);
|
|
|
+
|
|
|
+ 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);
|
|
|
+ ironlake_edp_panel_vdd_off(intel_dp, false);
|
|
|
if (ret) {
|
|
|
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
|
|
|
dev_priv->no_aux_handshake =
|
|
@@ -2069,18 +2372,11 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ intel_dp_i2c_init(intel_dp, intel_connector, name);
|
|
|
+
|
|
|
intel_encoder->hot_plug = intel_dp_hot_plug;
|
|
|
|
|
|
if (is_edp(intel_dp)) {
|
|
|
- /* initialize panel mode from VBT if available for eDP */
|
|
|
- if (dev_priv->lfp_lvds_vbt_mode) {
|
|
|
- dev_priv->panel_fixed_mode =
|
|
|
- drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
|
|
|
- if (dev_priv->panel_fixed_mode) {
|
|
|
- dev_priv->panel_fixed_mode->type |=
|
|
|
- DRM_MODE_TYPE_PREFERRED;
|
|
|
- }
|
|
|
- }
|
|
|
dev_priv->int_edp_connector = connector;
|
|
|
intel_panel_setup_backlight(dev);
|
|
|
}
|