]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/i915/intel_dp.c
Merge branch 'char-misc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[~andy/linux] / drivers / gpu / drm / i915 / intel_dp.c
index 44fef5e1c4906d49547d79fc42296163eea71905..09b318b0227f3571402c479c06bb376c6aae7eda 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/i2c.h>
 #include <linux/slab.h>
+#include <linux/export.h>
 #include "drmP.h"
 #include "drm.h"
 #include "drm_crtc.h"
@@ -36,7 +37,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 +54,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 +96,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);
@@ -121,7 +142,7 @@ static void intel_dp_complete_link_train(struct intel_dp *intel_dp);
 static void intel_dp_link_down(struct intel_dp *intel_dp);
 
 void
-intel_edp_link_config (struct intel_encoder *intel_encoder,
+intel_edp_link_config(struct intel_encoder *intel_encoder,
                       int *lane_num, int *link_bw)
 {
        struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
@@ -175,9 +196,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 +223,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 +237,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 +311,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 +359,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 +367,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
@@ -337,7 +402,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                for (i = 0; i < send_bytes; i += 4)
                        I915_WRITE(ch_data + i,
                                   pack_aux(send + i, send_bytes - i));
-       
+
                /* Send the command and wait for it to complete */
                I915_WRITE(ch_ctl,
                           DP_AUX_CH_CTL_SEND_BUSY |
@@ -354,7 +419,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                                break;
                        udelay(100);
                }
-       
+
                /* Clear done status and any errors */
                I915_WRITE(ch_ctl,
                           status |
@@ -390,7 +455,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                      DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
        if (recv_bytes > recv_size)
                recv_bytes = recv_size;
-       
+
        for (i = 0; i < recv_bytes; i += 4)
                unpack_aux(I915_READ(ch_data + i),
                           recv + i, recv_bytes - i);
@@ -408,6 +473,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 +516,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 +560,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,24 +641,32 @@ 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;
        intel_dp->algo.aux_ch = intel_dp_i2c_aux_ch;
 
-       memset(&intel_dp->adapter, '\0', sizeof (intel_dp->adapter));
+       memset(&intel_dp->adapter, '\0', sizeof(intel_dp->adapter));
        intel_dp->adapter.owner = THIS_MODULE;
        intel_dp->adapter.class = I2C_CLASS_DDC;
-       strncpy (intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1);
+       strncpy(intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1);
        intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0';
        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 +674,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 +709,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 +802,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 +814,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 +830,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;
@@ -773,8 +846,12 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                intel_dp->DP |= DP_PORT_WIDTH_4;
                break;
        }
-       if (intel_dp->has_audio)
+       if (intel_dp->has_audio) {
+               DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
+                                pipe_name(intel_crtc->pipe));
                intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
+               intel_write_eld(encoder, adjusted_mode);
+       }
 
        memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
        intel_dp->link_configuration[0] = intel_dp->link_bw;
@@ -794,7 +871,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)
@@ -804,58 +881,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;
+       }
+}
+
+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;
 
-       /* Make sure sequencer is idle before allowing subsequent activity */
-       msleep(dev_priv->panel_t12);
+       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);
 
@@ -864,44 +1033,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
@@ -909,21 +1098,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)
@@ -986,43 +1186,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
@@ -1034,28 +1230,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;
 }
@@ -1364,7 +1559,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;
@@ -1383,7 +1578,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;
@@ -1458,7 +1653,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;
@@ -1499,7 +1694,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;
@@ -1529,7 +1724,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 {
@@ -1578,13 +1773,14 @@ 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
 intel_dp_get_dpcd(struct intel_dp *intel_dp)
 {
        if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd,
-                                          sizeof (intel_dp->dpcd)) &&
+                                          sizeof(intel_dp->dpcd)) &&
            (intel_dp->dpcd[DP_DPCD_REV] != 0)) {
                return true;
        }
@@ -1592,6 +1788,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:
@@ -1604,6 +1821,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;
 
@@ -1622,6 +1841,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));
@@ -1683,6 +1916,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.
  *
@@ -1715,7 +1973,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;
@@ -1736,28 +1994,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;
                }
@@ -1772,7 +2038,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);
 
@@ -1839,7 +2105,7 @@ done:
 }
 
 static void
-intel_dp_destroy (struct drm_connector *connector)
+intel_dp_destroy(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
 
@@ -1857,6 +2123,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);
 }
 
@@ -1896,7 +2166,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder)
 
 /* Return which DP Port should be selected for Transcoder DP control */
 int
-intel_trans_dp_port_sel (struct drm_crtc *crtc)
+intel_trans_dp_port_sel(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
@@ -1993,10 +2263,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;
 
@@ -2032,25 +2305,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 =
@@ -2065,18 +2373,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);
        }