Merge tag 'drm-intel-next-2014-10-03-no-ppgtt' of git://anongit.freedesktop.org/drm...
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_dp.c
index fdff1d4..64c8e04 100644 (file)
@@ -111,7 +111,7 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
 }
 
 static void intel_dp_link_down(struct intel_dp *intel_dp);
-static bool _edp_panel_vdd_on(struct intel_dp *intel_dp);
+static bool edp_panel_vdd_on(struct intel_dp *intel_dp);
 static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 
 int
@@ -225,7 +225,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
 }
 
 static uint32_t
-pack_aux(uint8_t *src, int src_bytes)
+pack_aux(const uint8_t *src, int src_bytes)
 {
        int     i;
        uint32_t v = 0;
@@ -290,32 +290,201 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                                              struct intel_dp *intel_dp,
                                              struct edp_power_seq *out);
 
+static void pps_lock(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
+
+       /*
+        * See vlv_power_sequencer_reset() why we need
+        * a power domain reference here.
+        */
+       power_domain = intel_display_port_power_domain(encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
+       mutex_lock(&dev_priv->pps_mutex);
+}
+
+static void pps_unlock(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
+
+       mutex_unlock(&dev_priv->pps_mutex);
+
+       power_domain = intel_display_port_power_domain(encoder);
+       intel_display_power_put(dev_priv, power_domain);
+}
+
 static enum pipe
 vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum port port = intel_dig_port->port;
-       enum pipe pipe;
+       struct intel_encoder *encoder;
+       unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B);
+       struct edp_power_seq power_seq;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (intel_dp->pps_pipe != INVALID_PIPE)
+               return intel_dp->pps_pipe;
+
+       /*
+        * We don't have power sequencer currently.
+        * Pick one that's not used by other ports.
+        */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               struct intel_dp *tmp;
+
+               if (encoder->type != INTEL_OUTPUT_EDP)
+                       continue;
+
+               tmp = enc_to_intel_dp(&encoder->base);
+
+               if (tmp->pps_pipe != INVALID_PIPE)
+                       pipes &= ~(1 << tmp->pps_pipe);
+       }
 
-       /* modeset should have pipe */
-       if (crtc)
-               return to_intel_crtc(crtc)->pipe;
+       /*
+        * Didn't find one. This should not happen since there
+        * are two power sequencers and up to two eDP ports.
+        */
+       if (WARN_ON(pipes == 0))
+               return PIPE_A;
+
+       intel_dp->pps_pipe = ffs(pipes) - 1;
+
+       DRM_DEBUG_KMS("picked pipe %c power sequencer for port %c\n",
+                     pipe_name(intel_dp->pps_pipe),
+                     port_name(intel_dig_port->port));
+
+       /* init power sequencer on this pipe and port */
+       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                     &power_seq);
+
+       return intel_dp->pps_pipe;
+}
+
+typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
+                              enum pipe pipe);
+
+static bool vlv_pipe_has_pp_on(struct drm_i915_private *dev_priv,
+                              enum pipe pipe)
+{
+       return I915_READ(VLV_PIPE_PP_STATUS(pipe)) & PP_ON;
+}
+
+static bool vlv_pipe_has_vdd_on(struct drm_i915_private *dev_priv,
+                               enum pipe pipe)
+{
+       return I915_READ(VLV_PIPE_PP_CONTROL(pipe)) & EDP_FORCE_VDD;
+}
+
+static bool vlv_pipe_any(struct drm_i915_private *dev_priv,
+                        enum pipe pipe)
+{
+       return true;
+}
+
+static enum pipe
+vlv_initial_pps_pipe(struct drm_i915_private *dev_priv,
+                    enum port port,
+                    vlv_pipe_check pipe_check)
+{
+       enum pipe pipe;
 
-       /* init time, try to find a pipe with this port selected */
        for (pipe = PIPE_A; pipe <= PIPE_B; pipe++) {
                u32 port_sel = I915_READ(VLV_PIPE_PP_ON_DELAYS(pipe)) &
                        PANEL_PORT_SELECT_MASK;
-               if (port_sel == PANEL_PORT_SELECT_DPB_VLV && port == PORT_B)
-                       return pipe;
-               if (port_sel == PANEL_PORT_SELECT_DPC_VLV && port == PORT_C)
-                       return pipe;
+
+               if (port_sel != PANEL_PORT_SELECT_VLV(port))
+                       continue;
+
+               if (!pipe_check(dev_priv, pipe))
+                       continue;
+
+               return pipe;
        }
 
-       /* shrug */
-       return PIPE_A;
+       return INVALID_PIPE;
+}
+
+static void
+vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct edp_power_seq power_seq;
+       enum port port = intel_dig_port->port;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       /* try to find a pipe with this port selected */
+       /* first pick one where the panel is on */
+       intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                 vlv_pipe_has_pp_on);
+       /* didn't find one? pick one where vdd is on */
+       if (intel_dp->pps_pipe == INVALID_PIPE)
+               intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                         vlv_pipe_has_vdd_on);
+       /* didn't find one? pick one with just the correct port */
+       if (intel_dp->pps_pipe == INVALID_PIPE)
+               intel_dp->pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
+                                                         vlv_pipe_any);
+
+       /* didn't find one? just let vlv_power_sequencer_pipe() pick one when needed */
+       if (intel_dp->pps_pipe == INVALID_PIPE) {
+               DRM_DEBUG_KMS("no initial power sequencer for port %c\n",
+                             port_name(port));
+               return;
+       }
+
+       DRM_DEBUG_KMS("initial power sequencer for port %c: pipe %c\n",
+                     port_name(port), pipe_name(intel_dp->pps_pipe));
+
+       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                     &power_seq);
+}
+
+void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_encoder *encoder;
+
+       if (WARN_ON(!IS_VALLEYVIEW(dev)))
+               return;
+
+       /*
+        * We can't grab pps_mutex here due to deadlock with power_domain
+        * mutex when power_domain functions are called while holding pps_mutex.
+        * That also means that in order to use pps_pipe the code needs to
+        * hold both a power domain reference and pps_mutex, and the power domain
+        * reference get/put must be done while _not_ holding pps_mutex.
+        * pps_{lock,unlock}() do these steps in the correct order, so one
+        * should use them always.
+        */
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               struct intel_dp *intel_dp;
+
+               if (encoder->type != INTEL_OUTPUT_EDP)
+                       continue;
+
+               intel_dp = enc_to_intel_dp(&encoder->base);
+               intel_dp->pps_pipe = INVALID_PIPE;
+       }
 }
 
 static u32 _pp_ctrl_reg(struct intel_dp *intel_dp)
@@ -349,12 +518,15 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 pp_div;
        u32 pp_ctrl_reg, pp_div_reg;
-       enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
 
        if (!is_edp(intel_dp) || code != SYS_RESTART)
                return 0;
 
+       pps_lock(intel_dp);
+
        if (IS_VALLEYVIEW(dev)) {
+               enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
+
                pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe);
                pp_div_reg  = VLV_PIPE_PP_DIVISOR(pipe);
                pp_div = I915_READ(pp_div_reg);
@@ -366,6 +538,8 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
                msleep(intel_dp->panel_power_cycle_delay);
        }
 
+       pps_unlock(intel_dp);
+
        return 0;
 }
 
@@ -374,6 +548,8 @@ static bool edp_have_panel_power(struct intel_dp *intel_dp)
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0;
 }
 
@@ -381,13 +557,10 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       enum intel_display_power_domain power_domain;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       return intel_display_power_enabled(dev_priv, power_domain) &&
-              (I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD) != 0;
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       return I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD;
 }
 
 static void
@@ -488,6 +661,16 @@ static uint32_t vlv_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
        return index ? 0 : 100;
 }
 
+static uint32_t skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
+{
+       /*
+        * SKL doesn't need us to program the AUX clock divider (Hardware will
+        * derive the clock from CDCLK automatically). We still implement the
+        * get_aux_clock_divider vfunc to plug-in into the existing code.
+        */
+       return index ? 0 : 1;
+}
+
 static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp,
                                      bool has_aux_irq,
                                      int send_bytes,
@@ -518,9 +701,24 @@ static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp,
               (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT);
 }
 
+static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp,
+                                     bool has_aux_irq,
+                                     int send_bytes,
+                                     uint32_t unused)
+{
+       return DP_AUX_CH_CTL_SEND_BUSY |
+              DP_AUX_CH_CTL_DONE |
+              (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
+              DP_AUX_CH_CTL_TIME_OUT_ERROR |
+              DP_AUX_CH_CTL_TIME_OUT_1600us |
+              DP_AUX_CH_CTL_RECEIVE_ERROR |
+              (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+              DP_AUX_CH_CTL_SYNC_PULSE_SKL(32);
+}
+
 static int
 intel_dp_aux_ch(struct intel_dp *intel_dp,
-               uint8_t *send, int send_bytes,
+               const uint8_t *send, int send_bytes,
                uint8_t *recv, int recv_size)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
@@ -535,7 +733,15 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        bool has_aux_irq = HAS_AUX_IRQ(dev);
        bool vdd;
 
-       vdd = _edp_panel_vdd_on(intel_dp);
+       pps_lock(intel_dp);
+
+       /*
+        * We will be called with VDD already enabled for dpcd/edid/oui reads.
+        * In such cases we want to leave VDD enabled and it's up to upper layers
+        * to turn it off. But for eg. i2c-dev access we need to turn it on/off
+        * ourselves.
+        */
+       vdd = edp_panel_vdd_on(intel_dp);
 
        /* dp aux is extremely sensitive to irq latency, hence request the
         * lowest possible wakeup latency and so prevent the cpu from going into
@@ -644,6 +850,8 @@ out:
        if (vdd)
                edp_panel_vdd_off(intel_dp, false);
 
+       pps_unlock(intel_dp);
+
        return ret;
 }
 
@@ -742,7 +950,16 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
                BUG();
        }
 
-       if (!HAS_DDI(dev))
+       /*
+        * The AUX_CTL register is usually DP_CTL + 0x10.
+        *
+        * On Haswell and Broadwell though:
+        *   - Both port A DDI_BUF_CTL and DDI_AUX_CTL are on the CPU
+        *   - Port B/C/D AUX channels are on the PCH, DDI_BUF_CTL on the CPU
+        *
+        * Skylake moves AUX_CTL back next to DDI_BUF_CTL, on the CPU.
+        */
+       if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
                intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
 
        intel_dp->aux.name = name;
@@ -828,20 +1045,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
        }
 }
 
-static void
-intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       enum transcoder transcoder = crtc->config.cpu_transcoder;
-
-       I915_WRITE(PIPE_DATA_M2(transcoder),
-               TU_SIZE(m_n->tu) | m_n->gmch_m);
-       I915_WRITE(PIPE_DATA_N2(transcoder), m_n->gmch_n);
-       I915_WRITE(PIPE_LINK_M2(transcoder), m_n->link_m);
-       I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n);
-}
-
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_config *pipe_config)
@@ -867,6 +1070,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                pipe_config->has_pch_encoder = true;
 
        pipe_config->has_dp_encoder = true;
+       pipe_config->has_drrs = false;
        pipe_config->has_audio = intel_dp->has_audio;
 
        if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
@@ -898,23 +1102,15 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                        bpp = dev_priv->vbt.edp_bpp;
                }
 
-               if (IS_BROADWELL(dev)) {
-                       /* Yes, it's an ugly hack. */
-                       min_lane_count = max_lane_count;
-                       DRM_DEBUG_KMS("forcing lane count to max (%u) on BDW\n",
-                                     min_lane_count);
-               } else if (dev_priv->vbt.edp_lanes) {
-                       min_lane_count = min(dev_priv->vbt.edp_lanes,
-                                            max_lane_count);
-                       DRM_DEBUG_KMS("using min %u lanes per VBT\n",
-                                     min_lane_count);
-               }
-
-               if (dev_priv->vbt.edp_rate) {
-                       min_clock = min(dev_priv->vbt.edp_rate >> 3, max_clock);
-                       DRM_DEBUG_KMS("using min %02x link bw per VBT\n",
-                                     bws[min_clock]);
-               }
+               /*
+                * Use the maximum clock and number of lanes the eDP panel
+                * advertizes being capable of. The panels are generally
+                * designed to support only a single clock and lane
+                * configuration, and typically these values correspond to the
+                * native resolution of the panel.
+                */
+               min_lane_count = max_lane_count;
+               min_clock = max_clock;
        }
 
        for (; bpp >= 6*3; bpp -= 2*3) {
@@ -970,13 +1166,14 @@ found:
 
        if (intel_connector->panel.downclock_mode != NULL &&
                intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) {
+                       pipe_config->has_drrs = true;
                        intel_link_compute_m_n(bpp, lane_count,
                                intel_connector->panel.downclock_mode->clock,
                                pipe_config->port_clock,
                                &pipe_config->dp_m2_n2);
        }
 
-       if (HAS_DDI(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw);
        else
                intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw);
@@ -1110,6 +1307,8 @@ static void wait_panel_status(struct intel_dp *intel_dp,
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 pp_stat_reg, pp_ctrl_reg;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        pp_stat_reg = _pp_stat_reg(intel_dp);
        pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
 
@@ -1173,13 +1372,20 @@ static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 control;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        control = I915_READ(_pp_ctrl_reg(intel_dp));
        control &= ~PANEL_UNLOCK_MASK;
        control |= PANEL_UNLOCK_REGS;
        return control;
 }
 
-static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
+/*
+ * Must be paired with edp_panel_vdd_off().
+ * Must hold pps_mutex around the whole on/off sequence.
+ * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
+ */
+static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
@@ -1190,6 +1396,8 @@ static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
        u32 pp_stat_reg, pp_ctrl_reg;
        bool need_to_disable = !intel_dp->want_panel_vdd;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        if (!is_edp(intel_dp))
                return false;
 
@@ -1227,62 +1435,76 @@ static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
        return need_to_disable;
 }
 
+/*
+ * Must be paired with intel_edp_panel_vdd_off() or
+ * intel_edp_panel_off().
+ * Nested calls to these functions are not allowed since
+ * we drop the lock. Caller must use some higher level
+ * locking to prevent nested calls from other threads.
+ */
 void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
 {
-       if (is_edp(intel_dp)) {
-               bool vdd = _edp_panel_vdd_on(intel_dp);
+       bool vdd;
 
-               WARN(!vdd, "eDP VDD already requested on\n");
-       }
+       if (!is_edp(intel_dp))
+               return;
+
+       pps_lock(intel_dp);
+       vdd = edp_panel_vdd_on(intel_dp);
+       pps_unlock(intel_dp);
+
+       WARN(!vdd, "eDP VDD already requested on\n");
 }
 
 static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_digital_port *intel_dig_port =
+               dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
+       enum intel_display_power_domain power_domain;
        u32 pp;
        u32 pp_stat_reg, pp_ctrl_reg;
 
-       WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+       lockdep_assert_held(&dev_priv->pps_mutex);
 
-       if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) {
-               struct intel_digital_port *intel_dig_port =
-                                               dp_to_dig_port(intel_dp);
-               struct intel_encoder *intel_encoder = &intel_dig_port->base;
-               enum intel_display_power_domain power_domain;
+       WARN_ON(intel_dp->want_panel_vdd);
 
-               DRM_DEBUG_KMS("Turning eDP VDD off\n");
+       if (!edp_have_panel_vdd(intel_dp))
+               return;
 
-               pp = ironlake_get_pp_control(intel_dp);
-               pp &= ~EDP_FORCE_VDD;
+       DRM_DEBUG_KMS("Turning eDP VDD off\n");
 
-               pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-               pp_stat_reg = _pp_stat_reg(intel_dp);
+       pp = ironlake_get_pp_control(intel_dp);
+       pp &= ~EDP_FORCE_VDD;
 
-               I915_WRITE(pp_ctrl_reg, pp);
-               POSTING_READ(pp_ctrl_reg);
+       pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+       pp_stat_reg = _pp_stat_reg(intel_dp);
+
+       I915_WRITE(pp_ctrl_reg, pp);
+       POSTING_READ(pp_ctrl_reg);
 
-               /* Make sure sequencer is idle before allowing subsequent activity */
-               DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
-               I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
+       /* Make sure sequencer is idle before allowing subsequent activity */
+       DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+       I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
 
-               if ((pp & POWER_TARGET_ON) == 0)
-                       intel_dp->last_power_cycle = jiffies;
+       if ((pp & POWER_TARGET_ON) == 0)
+               intel_dp->last_power_cycle = jiffies;
 
-               power_domain = intel_display_port_power_domain(intel_encoder);
-               intel_display_power_put(dev_priv, power_domain);
-       }
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_put(dev_priv, power_domain);
 }
 
 static void edp_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_to_dev(intel_dp);
 
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       edp_panel_vdd_off_sync(intel_dp);
-       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       pps_lock(intel_dp);
+       if (!intel_dp->want_panel_vdd)
+               edp_panel_vdd_off_sync(intel_dp);
+       pps_unlock(intel_dp);
 }
 
 static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp)
@@ -1298,8 +1520,18 @@ static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp)
        schedule_delayed_work(&intel_dp->panel_vdd_work, delay);
 }
 
+/*
+ * Must be paired with edp_panel_vdd_on().
+ * Must hold pps_mutex around the whole on/off sequence.
+ * Can be nested with intel_edp_panel_vdd_{on,off}() calls.
+ */
 static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
 {
+       struct drm_i915_private *dev_priv =
+               intel_dp_to_dev(intel_dp)->dev_private;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        if (!is_edp(intel_dp))
                return;
 
@@ -1313,6 +1545,22 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
                edp_panel_vdd_schedule_off(intel_dp);
 }
 
+/*
+ * Must be paired with intel_edp_panel_vdd_on().
+ * Nested calls to these functions are not allowed since
+ * we drop the lock. Caller must use some higher level
+ * locking to prevent nested calls from other threads.
+ */
+static void intel_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
+{
+       if (!is_edp(intel_dp))
+               return;
+
+       pps_lock(intel_dp);
+       edp_panel_vdd_off(intel_dp, sync);
+       pps_unlock(intel_dp);
+}
+
 void intel_edp_panel_on(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -1325,9 +1573,11 @@ void intel_edp_panel_on(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power on\n");
 
+       pps_lock(intel_dp);
+
        if (edp_have_panel_power(intel_dp)) {
                DRM_DEBUG_KMS("eDP power already on\n");
-               return;
+               goto out;
        }
 
        wait_panel_power_cycle(intel_dp);
@@ -1356,6 +1606,9 @@ void intel_edp_panel_on(struct intel_dp *intel_dp)
                I915_WRITE(pp_ctrl_reg, pp);
                POSTING_READ(pp_ctrl_reg);
        }
+
+ out:
+       pps_unlock(intel_dp);
 }
 
 void intel_edp_panel_off(struct intel_dp *intel_dp)
@@ -1373,6 +1626,8 @@ void intel_edp_panel_off(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power off\n");
 
+       pps_lock(intel_dp);
+
        WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
 
        pp = ironlake_get_pp_control(intel_dp);
@@ -1394,9 +1649,12 @@ void intel_edp_panel_off(struct intel_dp *intel_dp)
        /* We got a reference when we enabled the VDD. */
        power_domain = intel_display_port_power_domain(intel_encoder);
        intel_display_power_put(dev_priv, power_domain);
+
+       pps_unlock(intel_dp);
 }
 
-void intel_edp_backlight_on(struct intel_dp *intel_dp)
+/* Enable backlight in the panel power control. */
+static void _intel_edp_backlight_on(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -1404,13 +1662,6 @@ void intel_edp_backlight_on(struct intel_dp *intel_dp)
        u32 pp;
        u32 pp_ctrl_reg;
 
-       if (!is_edp(intel_dp))
-               return;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_panel_enable_backlight(intel_dp->attached_connector);
-
        /*
         * If we enable the backlight right away following a panel power
         * on, we may see slight flicker as the panel syncs with the eDP
@@ -1418,6 +1669,9 @@ void intel_edp_backlight_on(struct intel_dp *intel_dp)
         * allowing it to appear.
         */
        wait_backlight_on(intel_dp);
+
+       pps_lock(intel_dp);
+
        pp = ironlake_get_pp_control(intel_dp);
        pp |= EDP_BLC_ENABLE;
 
@@ -1425,9 +1679,24 @@ void intel_edp_backlight_on(struct intel_dp *intel_dp)
 
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
+
+       pps_unlock(intel_dp);
 }
 
-void intel_edp_backlight_off(struct intel_dp *intel_dp)
+/* Enable backlight PWM and backlight PP control. */
+void intel_edp_backlight_on(struct intel_dp *intel_dp)
+{
+       if (!is_edp(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("\n");
+
+       intel_panel_enable_backlight(intel_dp->attached_connector);
+       _intel_edp_backlight_on(intel_dp);
+}
+
+/* Disable backlight in the panel power control. */
+static void _intel_edp_backlight_off(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1437,7 +1706,8 @@ void intel_edp_backlight_off(struct intel_dp *intel_dp)
        if (!is_edp(intel_dp))
                return;
 
-       DRM_DEBUG_KMS("\n");
+       pps_lock(intel_dp);
+
        pp = ironlake_get_pp_control(intel_dp);
        pp &= ~EDP_BLC_ENABLE;
 
@@ -1445,13 +1715,51 @@ void intel_edp_backlight_off(struct intel_dp *intel_dp)
 
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
-       intel_dp->last_backlight_off = jiffies;
 
+       pps_unlock(intel_dp);
+
+       intel_dp->last_backlight_off = jiffies;
        edp_wait_backlight_off(intel_dp);
+}
+
+/* Disable backlight PP control and backlight PWM. */
+void intel_edp_backlight_off(struct intel_dp *intel_dp)
+{
+       if (!is_edp(intel_dp))
+               return;
+
+       DRM_DEBUG_KMS("\n");
 
+       _intel_edp_backlight_off(intel_dp);
        intel_panel_disable_backlight(intel_dp->attached_connector);
 }
 
+/*
+ * Hook for controlling the panel power control backlight through the bl_power
+ * sysfs attribute. Take care to handle multiple calls.
+ */
+static void intel_edp_backlight_power(struct intel_connector *connector,
+                                     bool enable)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(&connector->base);
+       bool is_enabled;
+
+       pps_lock(intel_dp);
+       is_enabled = ironlake_get_pp_control(intel_dp) & EDP_BLC_ENABLE;
+       pps_unlock(intel_dp);
+
+       if (is_enabled == enable)
+               return;
+
+       DRM_DEBUG_KMS("panel power control backlight %s\n",
+                     enable ? "enable" : "disable");
+
+       if (enable)
+               _intel_edp_backlight_on(intel_dp);
+       else
+               _intel_edp_backlight_off(intel_dp);
+}
+
 static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
@@ -1515,8 +1823,6 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
        if (mode != DRM_MODE_DPMS_ON) {
                ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
                                         DP_SET_POWER_D3);
-               if (ret != 1)
-                       DRM_DEBUG_DRIVER("failed to write sink power state\n");
        } else {
                /*
                 * When turning on, we need to retry for 1ms to give the sink
@@ -1530,6 +1836,10 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
                        msleep(1);
                }
        }
+
+       if (ret != 1)
+               DRM_DEBUG_KMS("failed to %s sink power state\n",
+                             mode == DRM_MODE_DPMS_ON ? "enable" : "disable");
 }
 
 static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
@@ -1543,7 +1853,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
        u32 tmp;
 
        power_domain = intel_display_port_power_domain(encoder);
-       if (!intel_display_power_enabled(dev_priv, power_domain))
+       if (!intel_display_power_is_enabled(dev_priv, power_domain))
                return false;
 
        tmp = I915_READ(intel_dp->output_reg);
@@ -1576,7 +1886,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
                        return true;
                }
 
-               for_each_pipe(i) {
+               for_each_pipe(dev_priv, i) {
                        trans_dp = I915_READ(TRANS_DP_CTL(i));
                        if ((trans_dp & TRANS_DP_PORT_SEL_MASK) == trans_sel) {
                                *pipe = i;
@@ -1719,10 +2029,8 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
        POSTING_READ(ctl_reg);
 }
 
-static void intel_edp_psr_setup(struct intel_dp *intel_dp)
+static void intel_edp_psr_setup_vsc(struct intel_dp *intel_dp)
 {
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct edp_vsc_psr psr_vsc;
 
        /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
@@ -1732,10 +2040,6 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
        psr_vsc.sdp_header.HB2 = 0x2;
        psr_vsc.sdp_header.HB3 = 0x8;
        intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
-
-       /* Avoid continuous PSR exit by masking memup and hpd */
-       I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-                  EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
 }
 
 static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
@@ -1745,8 +2049,17 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t aux_clock_divider;
        int precharge = 0x3;
-       int msg_size = 5;       /* Header(4) + Message(1) */
        bool only_standby = false;
+       static const uint8_t aux_msg[] = {
+               [0] = DP_AUX_NATIVE_WRITE << 4,
+               [1] = DP_SET_POWER >> 8,
+               [2] = DP_SET_POWER & 0xff,
+               [3] = 1 - 1,
+               [4] = DP_SET_POWER_D0,
+       };
+       int i;
+
+       BUILD_BUG_ON(sizeof(aux_msg) > 20);
 
        aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
 
@@ -1762,11 +2075,13 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
                                   DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
 
        /* Setup AUX registers */
-       I915_WRITE(EDP_PSR_AUX_DATA1(dev), EDP_PSR_DPCD_COMMAND);
-       I915_WRITE(EDP_PSR_AUX_DATA2(dev), EDP_PSR_DPCD_NORMAL_OPERATION);
+       for (i = 0; i < sizeof(aux_msg); i += 4)
+               I915_WRITE(EDP_PSR_AUX_DATA1(dev) + i,
+                          pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
+
        I915_WRITE(EDP_PSR_AUX_CTL(dev),
                   DP_AUX_CH_CTL_TIME_OUT_400us |
-                  (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+                  (sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
                   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
                   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
 }
@@ -1855,10 +2170,7 @@ static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
        WARN_ON(dev_priv->psr.active);
        lockdep_assert_held(&dev_priv->psr.lock);
 
-       /* Enable PSR on the panel */
-       intel_edp_psr_enable_sink(intel_dp);
-
-       /* Enable PSR on the host */
+       /* Enable/Re-enable PSR on the host */
        intel_edp_psr_enable_source(intel_dp);
 
        dev_priv->psr.active = true;
@@ -1882,17 +2194,25 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp)
        mutex_lock(&dev_priv->psr.lock);
        if (dev_priv->psr.enabled) {
                DRM_DEBUG_KMS("PSR already in use\n");
-               mutex_unlock(&dev_priv->psr.lock);
-               return;
+               goto unlock;
        }
 
+       if (!intel_edp_psr_match_conditions(intel_dp))
+               goto unlock;
+
        dev_priv->psr.busy_frontbuffer_bits = 0;
 
-       /* Setup PSR once */
-       intel_edp_psr_setup(intel_dp);
+       intel_edp_psr_setup_vsc(intel_dp);
 
-       if (intel_edp_psr_match_conditions(intel_dp))
-               dev_priv->psr.enabled = intel_dp;
+       /* Avoid continuous PSR exit by masking memup and hpd */
+       I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+                  EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+
+       /* Enable PSR on the panel */
+       intel_edp_psr_enable_sink(intel_dp);
+
+       dev_priv->psr.enabled = intel_dp;
+unlock:
        mutex_unlock(&dev_priv->psr.lock);
 }
 
@@ -1933,6 +2253,17 @@ static void intel_edp_psr_work(struct work_struct *work)
                container_of(work, typeof(*dev_priv), psr.work.work);
        struct intel_dp *intel_dp = dev_priv->psr.enabled;
 
+       /* We have to make sure PSR is ready for re-enable
+        * otherwise it keeps disabled until next full enable/disable cycle.
+        * PSR might take some time to get fully disabled
+        * and be ready for re-enable.
+        */
+       if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
+                     EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
+               DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
+               return;
+       }
+
        mutex_lock(&dev_priv->psr.lock);
        intel_dp = dev_priv->psr.enabled;
 
@@ -2036,7 +2367,6 @@ void intel_edp_psr_init(struct drm_device *dev)
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       enum port port = dp_to_dig_port(intel_dp)->port;
        struct drm_device *dev = encoder->base.dev;
 
        /* Make sure the panel is off before trying to change the mode. But also
@@ -2046,21 +2376,19 @@ static void intel_disable_dp(struct intel_encoder *encoder)
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
        intel_edp_panel_off(intel_dp);
 
-       /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
-       if (!(port == PORT_A || IS_VALLEYVIEW(dev)))
+       /* disable the port before the pipe on g4x */
+       if (INTEL_INFO(dev)->gen < 5)
                intel_dp_link_down(intel_dp);
 }
 
-static void g4x_post_disable_dp(struct intel_encoder *encoder)
+static void ilk_post_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       if (port != PORT_A)
-               return;
-
        intel_dp_link_down(intel_dp);
-       ironlake_edp_pll_off(intel_dp);
+       if (port == PORT_A)
+               ironlake_edp_pll_off(intel_dp);
 }
 
 static void vlv_post_disable_dp(struct intel_encoder *encoder)
@@ -2106,6 +2434,104 @@ static void chv_post_disable_dp(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
+static void
+_intel_dp_set_link_train(struct intel_dp *intel_dp,
+                        uint32_t *DP,
+                        uint8_t dp_train_pat)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum port port = intel_dig_port->port;
+
+       if (HAS_DDI(dev)) {
+               uint32_t temp = I915_READ(DP_TP_CTL(port));
+
+               if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
+                       temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
+               else
+                       temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE;
+
+               temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
+
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       temp |= DP_TP_CTL_LINK_TRAIN_PAT3;
+                       break;
+               }
+               I915_WRITE(DP_TP_CTL(port), temp);
+
+       } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
+               *DP &= ~DP_LINK_TRAIN_MASK_CPT;
+
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       *DP |= DP_LINK_TRAIN_OFF_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       *DP |= DP_LINK_TRAIN_PAT_1_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       DRM_ERROR("DP training pattern 3 not supported\n");
+                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               }
+
+       } else {
+               if (IS_CHERRYVIEW(dev))
+                       *DP &= ~DP_LINK_TRAIN_MASK_CHV;
+               else
+                       *DP &= ~DP_LINK_TRAIN_MASK;
+
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       *DP |= DP_LINK_TRAIN_OFF;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       *DP |= DP_LINK_TRAIN_PAT_1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       *DP |= DP_LINK_TRAIN_PAT_2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       if (IS_CHERRYVIEW(dev)) {
+                               *DP |= DP_LINK_TRAIN_PAT_3_CHV;
+                       } else {
+                               DRM_ERROR("DP training pattern 3 not supported\n");
+                               *DP |= DP_LINK_TRAIN_PAT_2;
+                       }
+                       break;
+               }
+       }
+}
+
+static void intel_dp_enable_port(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       intel_dp->DP |= DP_PORT_EN;
+
+       /* enable with pattern 1 (as per spec) */
+       _intel_dp_set_link_train(intel_dp, &intel_dp->DP,
+                                DP_TRAINING_PATTERN_1);
+
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+       POSTING_READ(intel_dp->output_reg);
+}
+
 static void intel_enable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -2116,11 +2542,12 @@ static void intel_enable_dp(struct intel_encoder *encoder)
        if (WARN_ON(dp_reg & DP_PORT_EN))
                return;
 
+       intel_dp_enable_port(intel_dp);
        intel_edp_panel_vdd_on(intel_dp);
+       intel_edp_panel_on(intel_dp);
+       intel_edp_panel_vdd_off(intel_dp, true);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        intel_dp_start_link_train(intel_dp);
-       intel_edp_panel_on(intel_dp);
-       edp_panel_vdd_off(intel_dp, true);
        intel_dp_complete_link_train(intel_dp);
        intel_dp_stop_link_train(intel_dp);
 }
@@ -2129,29 +2556,101 @@ static void g4x_enable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
-       intel_enable_dp(encoder);
-       intel_edp_backlight_on(intel_dp);
-}
+       intel_enable_dp(encoder);
+       intel_edp_backlight_on(intel_dp);
+}
+
+static void vlv_enable_dp(struct intel_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+       intel_edp_backlight_on(intel_dp);
+}
+
+static void g4x_pre_enable_dp(struct intel_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+
+       intel_dp_prepare(encoder);
+
+       /* Only ilk+ has port A */
+       if (dport->port == PORT_A) {
+               ironlake_set_pll_cpu_edp(intel_dp);
+               ironlake_edp_pll_on(intel_dp);
+       }
+}
+
+static void vlv_steal_power_sequencer(struct drm_device *dev,
+                                     enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *encoder;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+                           base.head) {
+               struct intel_dp *intel_dp;
+               enum port port;
+
+               if (encoder->type != INTEL_OUTPUT_EDP)
+                       continue;
+
+               intel_dp = enc_to_intel_dp(&encoder->base);
+               port = dp_to_dig_port(intel_dp)->port;
+
+               if (intel_dp->pps_pipe != pipe)
+                       continue;
+
+               DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n",
+                             pipe_name(pipe), port_name(port));
+
+               /* make sure vdd is off before we steal it */
+               edp_panel_vdd_off_sync(intel_dp);
+
+               intel_dp->pps_pipe = INVALID_PIPE;
+       }
+}
+
+static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       struct edp_power_seq power_seq;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (intel_dp->pps_pipe == crtc->pipe)
+               return;
 
-static void vlv_enable_dp(struct intel_encoder *encoder)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       /*
+        * If another power sequencer was being used on this
+        * port previously make sure to turn off vdd there while
+        * we still have control of it.
+        */
+       if (intel_dp->pps_pipe != INVALID_PIPE)
+               edp_panel_vdd_off_sync(intel_dp);
 
-       intel_edp_backlight_on(intel_dp);
-}
+       /*
+        * We may be stealing the power
+        * sequencer from another port.
+        */
+       vlv_steal_power_sequencer(dev, crtc->pipe);
 
-static void g4x_pre_enable_dp(struct intel_encoder *encoder)
-{
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+       /* now it's all ours */
+       intel_dp->pps_pipe = crtc->pipe;
 
-       intel_dp_prepare(encoder);
+       DRM_DEBUG_KMS("initializing pipe %c power sequencer for port %c\n",
+                     pipe_name(intel_dp->pps_pipe), port_name(intel_dig_port->port));
 
-       /* Only ilk+ has port A */
-       if (dport->port == PORT_A) {
-               ironlake_set_pll_cpu_edp(intel_dp);
-               ironlake_edp_pll_on(intel_dp);
-       }
+       /* init power sequencer on this pipe and port */
+       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                     &power_seq);
 }
 
 static void vlv_pre_enable_dp(struct intel_encoder *encoder)
@@ -2163,7 +2662,6 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        enum dpio_channel port = vlv_dport_to_channel(dport);
        int pipe = intel_crtc->pipe;
-       struct edp_power_seq power_seq;
        u32 val;
 
        mutex_lock(&dev_priv->dpio_lock);
@@ -2182,10 +2680,9 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->dpio_lock);
 
        if (is_edp(intel_dp)) {
-               /* init power sequencer on this pipe and port */
-               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
-               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
-                                                             &power_seq);
+               pps_lock(intel_dp);
+               vlv_init_panel_power_sequencer(intel_dp);
+               pps_unlock(intel_dp);
        }
 
        intel_enable_dp(encoder);
@@ -2229,7 +2726,6 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
        struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct edp_power_seq power_seq;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(encoder->base.crtc);
        enum dpio_channel ch = vlv_dport_to_channel(dport);
@@ -2239,6 +2735,15 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
 
        mutex_lock(&dev_priv->dpio_lock);
 
+       /* allow hardware to manage TX FIFO reset source */
+       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch));
+       val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val);
+
+       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
+       val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
+
        /* Deassert soft data lane reset*/
        val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
        val |= CHV_PCS_REQ_SOFTRESET_EN;
@@ -2275,10 +2780,9 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->dpio_lock);
 
        if (is_edp(intel_dp)) {
-               /* init power sequencer on this pipe and port */
-               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
-               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
-                                                             &power_seq);
+               pps_lock(intel_dp);
+               vlv_init_panel_power_sequencer(intel_dp);
+               pps_unlock(intel_dp);
        }
 
        intel_enable_dp(encoder);
@@ -2297,6 +2801,8 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
        enum pipe pipe = intel_crtc->pipe;
        u32 val;
 
+       intel_dp_prepare(encoder);
+
        mutex_lock(&dev_priv->dpio_lock);
 
        /* program left/right clock distribution */
@@ -2394,14 +2900,16 @@ intel_dp_voltage_max(struct intel_dp *intel_dp)
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       if (IS_VALLEYVIEW(dev))
-               return DP_TRAIN_VOLTAGE_SWING_1200;
+       if (INTEL_INFO(dev)->gen >= 9)
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
+       else if (IS_VALLEYVIEW(dev))
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
        else if (IS_GEN7(dev) && port == PORT_A)
-               return DP_TRAIN_VOLTAGE_SWING_800;
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
        else if (HAS_PCH_CPT(dev) && port != PORT_A)
-               return DP_TRAIN_VOLTAGE_SWING_1200;
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
        else
-               return DP_TRAIN_VOLTAGE_SWING_800;
+               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
 }
 
 static uint8_t
@@ -2410,51 +2918,62 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        enum port port = dp_to_dig_port(intel_dp)->port;
 
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+       if (INTEL_INFO(dev)->gen >= 9) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
-                       return DP_TRAIN_PRE_EMPHASIS_9_5;
-               case DP_TRAIN_VOLTAGE_SWING_600:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_800:
-                       return DP_TRAIN_PRE_EMPHASIS_3_5;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_3;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
                default:
-                       return DP_TRAIN_PRE_EMPHASIS_0;
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
+               }
+       } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_3;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+               default:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
        } else if (IS_VALLEYVIEW(dev)) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
-                       return DP_TRAIN_PRE_EMPHASIS_9_5;
-               case DP_TRAIN_VOLTAGE_SWING_600:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_800:
-                       return DP_TRAIN_PRE_EMPHASIS_3_5;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_3;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                default:
-                       return DP_TRAIN_PRE_EMPHASIS_0;
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
        } else if (IS_GEN7(dev) && port == PORT_A) {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_600:
-               case DP_TRAIN_VOLTAGE_SWING_800:
-                       return DP_TRAIN_PRE_EMPHASIS_3_5;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
                default:
-                       return DP_TRAIN_PRE_EMPHASIS_0;
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
        } else {
                switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_600:
-                       return DP_TRAIN_PRE_EMPHASIS_6;
-               case DP_TRAIN_VOLTAGE_SWING_800:
-                       return DP_TRAIN_PRE_EMPHASIS_3_5;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_2;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+                       return DP_TRAIN_PRE_EMPH_LEVEL_1;
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                default:
-                       return DP_TRAIN_PRE_EMPHASIS_0;
+                       return DP_TRAIN_PRE_EMPH_LEVEL_0;
                }
        }
 }
@@ -2473,22 +2992,22 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
        int pipe = intel_crtc->pipe;
 
        switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
                preemph_reg_value = 0x0004000;
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        demph_reg_value = 0x2B405555;
                        uniqtranscale_reg_value = 0x552AB83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        demph_reg_value = 0x2B404040;
                        uniqtranscale_reg_value = 0x5548B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_800:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        demph_reg_value = 0x2B245555;
                        uniqtranscale_reg_value = 0x5560B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                        demph_reg_value = 0x2B405555;
                        uniqtranscale_reg_value = 0x5598DA3A;
                        break;
@@ -2496,18 +3015,18 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
                preemph_reg_value = 0x0002000;
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        demph_reg_value = 0x2B404040;
                        uniqtranscale_reg_value = 0x5552B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        demph_reg_value = 0x2B404848;
                        uniqtranscale_reg_value = 0x5580B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_800:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        demph_reg_value = 0x2B404040;
                        uniqtranscale_reg_value = 0x55ADDA3A;
                        break;
@@ -2515,14 +3034,14 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
                preemph_reg_value = 0x0000000;
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        demph_reg_value = 0x2B305555;
                        uniqtranscale_reg_value = 0x5570B83A;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        demph_reg_value = 0x2B2B4040;
                        uniqtranscale_reg_value = 0x55ADDA3A;
                        break;
@@ -2530,10 +3049,10 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_9_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
                preemph_reg_value = 0x0006000;
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        demph_reg_value = 0x1B405555;
                        uniqtranscale_reg_value = 0x55ADDA3A;
                        break;
@@ -2572,21 +3091,21 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
        int i;
 
        switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        deemph_reg_value = 128;
                        margin_reg_value = 52;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        deemph_reg_value = 128;
                        margin_reg_value = 77;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_800:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        deemph_reg_value = 128;
                        margin_reg_value = 102;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_1200:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                        deemph_reg_value = 128;
                        margin_reg_value = 154;
                        /* FIXME extra to set for 1200 */
@@ -2595,17 +3114,17 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        deemph_reg_value = 85;
                        margin_reg_value = 78;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        deemph_reg_value = 85;
                        margin_reg_value = 116;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_800:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                        deemph_reg_value = 85;
                        margin_reg_value = 154;
                        break;
@@ -2613,13 +3132,13 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        deemph_reg_value = 64;
                        margin_reg_value = 104;
                        break;
-               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                        deemph_reg_value = 64;
                        margin_reg_value = 154;
                        break;
@@ -2627,9 +3146,9 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
                        return 0;
                }
                break;
-       case DP_TRAIN_PRE_EMPHASIS_9_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
                switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-               case DP_TRAIN_VOLTAGE_SWING_400:
+               case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
                        deemph_reg_value = 43;
                        margin_reg_value = 154;
                        break;
@@ -2646,12 +3165,26 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
        /* Clear calc init */
        val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch));
        val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
+       val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
+       val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
        vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
 
        val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
        val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
+       val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
+       val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
        vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
 
+       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch));
+       val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
+       val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val);
+
+       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch));
+       val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
+       val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val);
+
        /* Program swing deemph */
        for (i = 0; i < 4; i++) {
                val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i));
@@ -2663,8 +3196,8 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
        /* Program swing margin */
        for (i = 0; i < 4; i++) {
                val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
-               val &= ~DPIO_SWING_MARGIN_MASK;
-               val |= margin_reg_value << DPIO_SWING_MARGIN_SHIFT;
+               val &= ~DPIO_SWING_MARGIN000_MASK;
+               val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT;
                vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
        }
 
@@ -2676,9 +3209,9 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp)
        }
 
        if (((train_set & DP_TRAIN_PRE_EMPHASIS_MASK)
-                       == DP_TRAIN_PRE_EMPHASIS_0) &&
+                       == DP_TRAIN_PRE_EMPH_LEVEL_0) &&
                ((train_set & DP_TRAIN_VOLTAGE_SWING_MASK)
-                       == DP_TRAIN_VOLTAGE_SWING_1200)) {
+                       == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)) {
 
                /*
                 * The document said it needs to set bit 27 for ch0 and bit 26
@@ -2757,32 +3290,32 @@ intel_gen4_signal_levels(uint8_t train_set)
        uint32_t        signal_levels = 0;
 
        switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
-       case DP_TRAIN_VOLTAGE_SWING_400:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
        default:
                signal_levels |= DP_VOLTAGE_0_4;
                break;
-       case DP_TRAIN_VOLTAGE_SWING_600:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
                signal_levels |= DP_VOLTAGE_0_6;
                break;
-       case DP_TRAIN_VOLTAGE_SWING_800:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
                signal_levels |= DP_VOLTAGE_0_8;
                break;
-       case DP_TRAIN_VOLTAGE_SWING_1200:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
                signal_levels |= DP_VOLTAGE_1_2;
                break;
        }
        switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
-       case DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_PRE_EMPH_LEVEL_0:
        default:
                signal_levels |= DP_PRE_EMPHASIS_0;
                break;
-       case DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_1:
                signal_levels |= DP_PRE_EMPHASIS_3_5;
                break;
-       case DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_PRE_EMPH_LEVEL_2:
                signal_levels |= DP_PRE_EMPHASIS_6;
                break;
-       case DP_TRAIN_PRE_EMPHASIS_9_5:
+       case DP_TRAIN_PRE_EMPH_LEVEL_3:
                signal_levels |= DP_PRE_EMPHASIS_9_5;
                break;
        }
@@ -2796,19 +3329,19 @@ intel_gen6_edp_signal_levels(uint8_t train_set)
        int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
                                         DP_TRAIN_PRE_EMPHASIS_MASK);
        switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_400MV_3_5DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
                return EDP_LINK_TRAIN_400_600MV_6DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B;
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
-       case DP_TRAIN_VOLTAGE_SWING_1200 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B;
        default:
                DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
@@ -2824,21 +3357,21 @@ intel_gen7_edp_signal_levels(uint8_t train_set)
        int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
                                         DP_TRAIN_PRE_EMPHASIS_MASK);
        switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_400MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_400MV_3_5DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
                return EDP_LINK_TRAIN_400MV_6DB_IVB;
 
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_600MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_600MV_3_5DB_IVB;
 
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
                return EDP_LINK_TRAIN_800MV_0DB_IVB;
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
                return EDP_LINK_TRAIN_800MV_3_5DB_IVB;
 
        default:
@@ -2855,30 +3388,30 @@ intel_hsw_signal_levels(uint8_t train_set)
        int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
                                         DP_TRAIN_PRE_EMPHASIS_MASK);
        switch (signal_levels) {
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
-               return DDI_BUF_EMP_400MV_0DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
-               return DDI_BUF_EMP_400MV_3_5DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
-               return DDI_BUF_EMP_400MV_6DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_9_5:
-               return DDI_BUF_EMP_400MV_9_5DB_HSW;
-
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
-               return DDI_BUF_EMP_600MV_0DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
-               return DDI_BUF_EMP_600MV_3_5DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_6:
-               return DDI_BUF_EMP_600MV_6DB_HSW;
-
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
-               return DDI_BUF_EMP_800MV_0DB_HSW;
-       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
-               return DDI_BUF_EMP_800MV_3_5DB_HSW;
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return DDI_BUF_TRANS_SELECT(0);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return DDI_BUF_TRANS_SELECT(1);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+               return DDI_BUF_TRANS_SELECT(2);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3:
+               return DDI_BUF_TRANS_SELECT(3);
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return DDI_BUF_TRANS_SELECT(4);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return DDI_BUF_TRANS_SELECT(5);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2:
+               return DDI_BUF_TRANS_SELECT(6);
+
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0:
+               return DDI_BUF_TRANS_SELECT(7);
+       case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1:
+               return DDI_BUF_TRANS_SELECT(8);
        default:
                DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
                              "0x%x\n", signal_levels);
-               return DDI_BUF_EMP_400MV_0DB_HSW;
+               return DDI_BUF_TRANS_SELECT(0);
        }
 }
 
@@ -2892,7 +3425,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
        uint32_t signal_levels, mask;
        uint8_t train_set = intel_dp->train_set[0];
 
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
                signal_levels = intel_hsw_signal_levels(train_set);
                mask = DDI_BUF_EMP_MASK;
        } else if (IS_CHERRYVIEW(dev)) {
@@ -2925,74 +3458,10 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum port port = intel_dig_port->port;
        uint8_t buf[sizeof(intel_dp->train_set) + 1];
        int ret, len;
 
-       if (HAS_DDI(dev)) {
-               uint32_t temp = I915_READ(DP_TP_CTL(port));
-
-               if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
-                       temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
-               else
-                       temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE;
-
-               temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
-               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
-
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT1;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT2;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       temp |= DP_TP_CTL_LINK_TRAIN_PAT3;
-                       break;
-               }
-               I915_WRITE(DP_TP_CTL(port), temp);
-
-       } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
-               *DP &= ~DP_LINK_TRAIN_MASK_CPT;
-
-               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       *DP |= DP_LINK_TRAIN_OFF_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       *DP |= DP_LINK_TRAIN_PAT_1_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       DRM_ERROR("DP training pattern 3 not supported\n");
-                       *DP |= DP_LINK_TRAIN_PAT_2_CPT;
-                       break;
-               }
-
-       } else {
-               *DP &= ~DP_LINK_TRAIN_MASK;
-
-               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
-               case DP_TRAINING_PATTERN_DISABLE:
-                       *DP |= DP_LINK_TRAIN_OFF;
-                       break;
-               case DP_TRAINING_PATTERN_1:
-                       *DP |= DP_LINK_TRAIN_PAT_1;
-                       break;
-               case DP_TRAINING_PATTERN_2:
-                       *DP |= DP_LINK_TRAIN_PAT_2;
-                       break;
-               case DP_TRAINING_PATTERN_3:
-                       DRM_ERROR("DP training pattern 3 not supported\n");
-                       *DP |= DP_LINK_TRAIN_PAT_2;
-                       break;
-               }
-       }
+       _intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
 
        I915_WRITE(intel_dp->output_reg, *DP);
        POSTING_READ(intel_dp->output_reg);
@@ -3276,7 +3745,10 @@ intel_dp_link_down(struct intel_dp *intel_dp)
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
        } else {
-               DP &= ~DP_LINK_TRAIN_MASK;
+               if (IS_CHERRYVIEW(dev))
+                       DP &= ~DP_LINK_TRAIN_MASK_CHV;
+               else
+                       DP &= ~DP_LINK_TRAIN_MASK;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
        }
        POSTING_READ(intel_dp->output_reg);
@@ -3322,15 +3794,11 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        struct drm_device *dev = dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3];
-
        if (intel_dp_dpcd_read_wake(&intel_dp->aux, 0x000, intel_dp->dpcd,
                                    sizeof(intel_dp->dpcd)) < 0)
                return false; /* aux transfer failed */
 
-       hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd),
-                          32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false);
-       DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump);
+       DRM_DEBUG_KMS("DPCD: %*ph\n", (int) sizeof(intel_dp->dpcd), intel_dp->dpcd);
 
        if (intel_dp->dpcd[DP_DPCD_REV] == 0)
                return false; /* DPCD not present */
@@ -3351,7 +3819,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
            intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED) {
                intel_dp->use_tps3 = true;
-               DRM_DEBUG_KMS("Displayport TPS3 supported");
+               DRM_DEBUG_KMS("Displayport TPS3 supported\n");
        } else
                intel_dp->use_tps3 = false;
 
@@ -3388,7 +3856,7 @@ intel_dp_probe_oui(struct intel_dp *intel_dp)
                DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
                              buf[0], buf[1], buf[2]);
 
-       edp_panel_vdd_off(intel_dp, false);
+       intel_edp_panel_vdd_off(intel_dp, false);
 }
 
 static bool
@@ -3402,7 +3870,7 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
                return false;
 
-       _edp_panel_vdd_on(intel_dp);
+       intel_edp_panel_vdd_on(intel_dp);
        if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_MSTM_CAP, buf, 1)) {
                if (buf[0] & DP_MST_CAP) {
                        DRM_DEBUG_KMS("Sink is MST capable\n");
@@ -3412,7 +3880,7 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
                        intel_dp->is_mst = false;
                }
        }
-       edp_panel_vdd_off(intel_dp, false);
+       intel_edp_panel_vdd_off(intel_dp, false);
 
        drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
        return intel_dp->is_mst;
@@ -3424,26 +3892,48 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(intel_dig_port->base.base.crtc);
-       u8 buf[1];
+       u8 buf;
+       int test_crc_count;
+       int attempts = 6;
 
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, buf) < 0)
-               return -EAGAIN;
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0)
+               return -EIO;
 
-       if (!(buf[0] & DP_TEST_CRC_SUPPORTED))
+       if (!(buf & DP_TEST_CRC_SUPPORTED))
                return -ENOTTY;
 
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0)
+               return -EIO;
+
        if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
-                              DP_TEST_SINK_START) < 0)
-               return -EAGAIN;
+                               buf | DP_TEST_SINK_START) < 0)
+               return -EIO;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0)
+               return -EIO;
+       test_crc_count = buf & DP_TEST_COUNT_MASK;
 
-       /* Wait 2 vblanks to be sure we will have the correct CRC value */
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
+       do {
+               if (drm_dp_dpcd_readb(&intel_dp->aux,
+                                     DP_TEST_SINK_MISC, &buf) < 0)
+                       return -EIO;
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       } while (--attempts && (buf & DP_TEST_COUNT_MASK) == test_crc_count);
+
+       if (attempts == 0) {
+               DRM_ERROR("Panel is unable to calculate CRC after 6 vblanks\n");
+               return -EIO;
+       }
 
        if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0)
-               return -EAGAIN;
+               return -EIO;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0)
+               return -EIO;
+       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
+                              buf & ~DP_TEST_SINK_START) < 0)
+               return -EIO;
 
-       drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, 0);
        return 0;
 }
 
@@ -3643,21 +4133,25 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
        return connector_status_disconnected;
 }
 
+static enum drm_connector_status
+edp_detect(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       enum drm_connector_status status;
+
+       status = intel_panel_detect(dev);
+       if (status == connector_status_unknown)
+               status = connector_status_connected;
+
+       return status;
+}
+
 static enum drm_connector_status
 ironlake_dp_detect(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       enum drm_connector_status status;
-
-       /* Can't disconnect eDP, but you can close the lid... */
-       if (is_edp(intel_dp)) {
-               status = intel_panel_detect(dev);
-               if (status == connector_status_unknown)
-                       status = connector_status_connected;
-               return status;
-       }
 
        if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
                return connector_status_disconnected;
@@ -3733,9 +4227,9 @@ g4x_dp_detect(struct intel_dp *intel_dp)
 }
 
 static struct edid *
-intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
+intel_dp_get_edid(struct intel_dp *intel_dp)
 {
-       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
 
        /* use cached edid if we have one */
        if (intel_connector->edid) {
@@ -3744,27 +4238,55 @@ intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
                        return NULL;
 
                return drm_edid_duplicate(intel_connector->edid);
-       }
+       } else
+               return drm_get_edid(&intel_connector->base,
+                                   &intel_dp->aux.ddc);
+}
+
+static void
+intel_dp_set_edid(struct intel_dp *intel_dp)
+{
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
+       struct edid *edid;
 
-       return drm_get_edid(connector, adapter);
+       edid = intel_dp_get_edid(intel_dp);
+       intel_connector->detect_edid = edid;
+
+       if (intel_dp->force_audio != HDMI_AUDIO_AUTO)
+               intel_dp->has_audio = intel_dp->force_audio == HDMI_AUDIO_ON;
+       else
+               intel_dp->has_audio = drm_detect_monitor_audio(edid);
 }
 
-static int
-intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *adapter)
+static void
+intel_dp_unset_edid(struct intel_dp *intel_dp)
 {
-       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
 
-       /* use cached edid if we have one */
-       if (intel_connector->edid) {
-               /* invalid edid */
-               if (IS_ERR(intel_connector->edid))
-                       return 0;
+       kfree(intel_connector->detect_edid);
+       intel_connector->detect_edid = NULL;
 
-               return intel_connector_update_modes(connector,
-                                                   intel_connector->edid);
-       }
+       intel_dp->has_audio = false;
+}
+
+static enum intel_display_power_domain
+intel_dp_power_get(struct intel_dp *dp)
+{
+       struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
+       enum intel_display_power_domain power_domain;
+
+       power_domain = intel_display_port_power_domain(encoder);
+       intel_display_power_get(to_i915(encoder->base.dev), power_domain);
+
+       return power_domain;
+}
 
-       return intel_ddc_get_modes(connector, adapter);
+static void
+intel_dp_power_put(struct intel_dp *dp,
+                  enum intel_display_power_domain power_domain)
+{
+       struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
+       intel_display_power_put(to_i915(encoder->base.dev), power_domain);
 }
 
 static enum drm_connector_status
@@ -3774,33 +4296,30 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        enum drm_connector_status status;
        enum intel_display_power_domain power_domain;
-       struct edid *edid = NULL;
        bool ret;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
-
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
+       intel_dp_unset_edid(intel_dp);
 
        if (intel_dp->is_mst) {
                /* MST devices are disconnected from a monitor POV */
                if (intel_encoder->type != INTEL_OUTPUT_EDP)
                        intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
-               status = connector_status_disconnected;
-               goto out;
+               return connector_status_disconnected;
        }
 
-       intel_dp->has_audio = false;
+       power_domain = intel_dp_power_get(intel_dp);
 
-       if (HAS_PCH_SPLIT(dev))
+       /* Can't disconnect eDP, but you can close the lid... */
+       if (is_edp(intel_dp))
+               status = edp_detect(intel_dp);
+       else if (HAS_PCH_SPLIT(dev))
                status = ironlake_dp_detect(intel_dp);
        else
                status = g4x_dp_detect(intel_dp);
-
        if (status != connector_status_connected)
                goto out;
 
@@ -3816,82 +4335,78 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                goto out;
        }
 
-       if (intel_dp->force_audio != HDMI_AUDIO_AUTO) {
-               intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
-       } else {
-               edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
-               if (edid) {
-                       intel_dp->has_audio = drm_detect_monitor_audio(edid);
-                       kfree(edid);
-               }
-       }
+       intel_dp_set_edid(intel_dp);
 
        if (intel_encoder->type != INTEL_OUTPUT_EDP)
                intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
        status = connector_status_connected;
 
 out:
-       intel_display_power_put(dev_priv, power_domain);
+       intel_dp_power_put(intel_dp, power_domain);
        return status;
 }
 
-static int intel_dp_get_modes(struct drm_connector *connector)
+static void
+intel_dp_force(struct drm_connector *connector)
 {
        struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
        enum intel_display_power_domain power_domain;
-       int ret;
 
-       /* We should parse the EDID data and find out if it has an audio sink
-        */
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, connector->name);
+       intel_dp_unset_edid(intel_dp);
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
+       if (connector->status != connector_status_connected)
+               return;
 
-       ret = intel_dp_get_edid_modes(connector, &intel_dp->aux.ddc);
-       intel_display_power_put(dev_priv, power_domain);
-       if (ret)
-               return ret;
+       power_domain = intel_dp_power_get(intel_dp);
+
+       intel_dp_set_edid(intel_dp);
+
+       intel_dp_power_put(intel_dp, power_domain);
+
+       if (intel_encoder->type != INTEL_OUTPUT_EDP)
+               intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
+}
+
+static int intel_dp_get_modes(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct edid *edid;
+
+       edid = intel_connector->detect_edid;
+       if (edid) {
+               int ret = intel_connector_update_modes(connector, edid);
+               if (ret)
+                       return ret;
+       }
 
        /* if eDP has no EDID, fall back to fixed mode */
-       if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
+       if (is_edp(intel_attached_dp(connector)) &&
+           intel_connector->panel.fixed_mode) {
                struct drm_display_mode *mode;
-               mode = drm_mode_duplicate(dev,
+
+               mode = drm_mode_duplicate(connector->dev,
                                          intel_connector->panel.fixed_mode);
                if (mode) {
                        drm_mode_probed_add(connector, mode);
                        return 1;
                }
        }
+
        return 0;
 }
 
 static bool
 intel_dp_detect_audio(struct drm_connector *connector)
 {
-       struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       enum intel_display_power_domain power_domain;
-       struct edid *edid;
        bool has_audio = false;
+       struct edid *edid;
 
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
-
-       edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
-       if (edid) {
+       edid = to_intel_connector(connector)->detect_edid;
+       if (edid)
                has_audio = drm_detect_monitor_audio(edid);
-               kfree(edid);
-       }
-
-       intel_display_power_put(dev_priv, power_domain);
 
        return has_audio;
 }
@@ -3989,6 +4504,8 @@ intel_dp_connector_destroy(struct drm_connector *connector)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
 
+       kfree(intel_connector->detect_edid);
+
        if (!IS_ERR_OR_NULL(intel_connector->edid))
                kfree(intel_connector->edid);
 
@@ -4005,16 +4522,20 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 {
        struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
        struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
        drm_dp_aux_unregister(&intel_dp->aux);
        intel_dp_mst_encoder_cleanup(intel_dig_port);
        drm_encoder_cleanup(encoder);
        if (is_edp(intel_dp)) {
                cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-               drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+               /*
+                * vdd might still be enabled do to the delayed vdd off.
+                * Make sure vdd is actually turned off here.
+                */
+               pps_lock(intel_dp);
                edp_panel_vdd_off_sync(intel_dp);
-               drm_modeset_unlock(&dev->mode_config.connection_mutex);
+               pps_unlock(intel_dp);
+
                if (intel_dp->edp_notifier.notifier_call) {
                        unregister_reboot_notifier(&intel_dp->edp_notifier);
                        intel_dp->edp_notifier.notifier_call = NULL;
@@ -4030,7 +4551,13 @@ static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
        if (!is_edp(intel_dp))
                return;
 
+       /*
+        * vdd might still be enabled do to the delayed vdd off.
+        * Make sure vdd is actually turned off here.
+        */
+       pps_lock(intel_dp);
        edp_panel_vdd_off_sync(intel_dp);
+       pps_unlock(intel_dp);
 }
 
 static void intel_dp_encoder_reset(struct drm_encoder *encoder)
@@ -4041,6 +4568,7 @@ static void intel_dp_encoder_reset(struct drm_encoder *encoder)
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .dpms = intel_connector_dpms,
        .detect = intel_dp_detect,
+       .force = intel_dp_force,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_dp_set_property,
        .destroy = intel_dp_connector_destroy,
@@ -4076,7 +4604,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
        if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
                intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
 
-       DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port,
+       DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
+                     port_name(intel_dig_port->port),
                      long_hpd ? "long" : "short");
 
        power_domain = intel_display_port_power_domain(intel_encoder);
@@ -4216,6 +4745,8 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
        u32 pp_on, pp_off, pp_div, pp;
        int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg;
 
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
        if (HAS_PCH_SPLIT(dev)) {
                pp_ctrl_reg = PCH_PP_CONTROL;
                pp_on_reg = PCH_PP_ON_DELAYS;
@@ -4315,6 +4846,9 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
        u32 pp_on, pp_off, pp_div, port_sel = 0;
        int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev);
        int pp_on_reg, pp_off_reg, pp_div_reg;
+       enum port port = dp_to_dig_port(intel_dp)->port;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
 
        if (HAS_PCH_SPLIT(dev)) {
                pp_on_reg = PCH_PP_ON_DELAYS;
@@ -4349,12 +4883,9 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
        /* Haswell doesn't have any port selection bits for the panel
         * power sequencer any more. */
        if (IS_VALLEYVIEW(dev)) {
-               if (dp_to_dig_port(intel_dp)->port == PORT_B)
-                       port_sel = PANEL_PORT_SELECT_DPB_VLV;
-               else
-                       port_sel = PANEL_PORT_SELECT_DPC_VLV;
+               port_sel = PANEL_PORT_SELECT_VLV(port);
        } else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
-               if (dp_to_dig_port(intel_dp)->port == PORT_A)
+               if (port == PORT_A)
                        port_sel = PANEL_PORT_SELECT_DPA;
                else
                        port_sel = PANEL_PORT_SELECT_DPD;
@@ -4438,7 +4969,7 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                val = I915_READ(reg);
                if (index > DRRS_HIGH_RR) {
                        val |= PIPECONF_EDP_RR_MODE_SWITCH;
-                       intel_dp_set_m2_n2(intel_crtc, &config->dp_m2_n2);
+                       intel_dp_set_m_n(intel_crtc);
                } else {
                        val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
                }
@@ -4478,7 +5009,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
        }
 
        if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
-               DRM_INFO("VBT doesn't support DRRS\n");
+               DRM_DEBUG_KMS("VBT doesn't support DRRS\n");
                return NULL;
        }
 
@@ -4486,7 +5017,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
                                        (dev, fixed_mode, connector);
 
        if (!downclock_mode) {
-               DRM_INFO("DRRS not supported\n");
+               DRM_DEBUG_KMS("DRRS not supported\n");
                return NULL;
        }
 
@@ -4497,7 +5028,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
        intel_dp->drrs_state.type = dev_priv->vbt.drrs_type;
 
        intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR;
-       DRM_INFO("seamless DRRS supported for eDP panel.\n");
+       DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
        return downclock_mode;
 }
 
@@ -4512,8 +5043,11 @@ void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder)
                return;
 
        intel_dp = enc_to_intel_dp(&intel_encoder->base);
+
+       pps_lock(intel_dp);
+
        if (!edp_have_panel_vdd(intel_dp))
-               return;
+               goto out;
        /*
         * The VDD bit needs a power domain reference, so if the bit is
         * already enabled when we boot or resume, grab this reference and
@@ -4525,6 +5059,8 @@ void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder)
        intel_display_power_get(dev_priv, power_domain);
 
        edp_panel_vdd_schedule_off(intel_dp);
+ out:
+       pps_unlock(intel_dp);
 }
 
 static bool intel_edp_init_connector(struct intel_dp *intel_dp,
@@ -4552,7 +5088,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        /* Cache DPCD and EDID for edp. */
        intel_edp_panel_vdd_on(intel_dp);
        has_dpcd = intel_dp_get_dpcd(intel_dp);
-       edp_panel_vdd_off(intel_dp, false);
+       intel_edp_panel_vdd_off(intel_dp, false);
 
        if (has_dpcd) {
                if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
@@ -4566,7 +5102,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        }
 
        /* We now know it's not a ghost, init power sequence regs. */
+       pps_lock(intel_dp);
        intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq);
+       pps_unlock(intel_dp);
 
        mutex_lock(&dev->mode_config.mutex);
        edid = drm_get_edid(connector, &intel_dp->aux.ddc);
@@ -4610,6 +5148,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        }
 
        intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
+       intel_connector->panel.backlight_power = intel_edp_backlight_power;
        intel_panel_setup_backlight(connector);
 
        return true;
@@ -4628,8 +5167,12 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        struct edp_power_seq power_seq = { 0 };
        int type;
 
+       intel_dp->pps_pipe = INVALID_PIPE;
+
        /* intel_dp vfuncs */
-       if (IS_VALLEYVIEW(dev))
+       if (INTEL_INFO(dev)->gen >= 9)
+               intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
+       else if (IS_VALLEYVIEW(dev))
                intel_dp->get_aux_clock_divider = vlv_get_aux_clock_divider;
        else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
@@ -4638,7 +5181,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        else
                intel_dp->get_aux_clock_divider = i9xx_get_aux_clock_divider;
 
-       intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl;
+       if (INTEL_INFO(dev)->gen >= 9)
+               intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
+       else
+               intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl;
 
        /* Preserve the current hw state. */
        intel_dp->DP = I915_READ(intel_dp->output_reg);
@@ -4698,8 +5244,15 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        }
 
        if (is_edp(intel_dp)) {
-               intel_dp_init_panel_power_timestamps(intel_dp);
-               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+               pps_lock(intel_dp);
+               if (IS_VALLEYVIEW(dev)) {
+                       vlv_initial_power_sequencer_setup(intel_dp);
+               } else {
+                       intel_dp_init_panel_power_timestamps(intel_dp);
+                       intel_dp_init_panel_power_sequencer(dev, intel_dp,
+                                                           &power_seq);
+               }
+               pps_unlock(intel_dp);
        }
 
        intel_dp_aux_init(intel_dp, intel_connector);
@@ -4707,7 +5260,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        /* init MST on ports that can support it */
        if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                if (port == PORT_B || port == PORT_C || port == PORT_D) {
-                       intel_dp_mst_encoder_init(intel_dig_port, intel_connector->base.base.id);
+                       intel_dp_mst_encoder_init(intel_dig_port,
+                                                 intel_connector->base.base.id);
                }
        }
 
@@ -4715,9 +5269,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                drm_dp_aux_unregister(&intel_dp->aux);
                if (is_edp(intel_dp)) {
                        cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-                       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+                       /*
+                        * vdd might still be enabled do to the delayed vdd off.
+                        * Make sure vdd is actually turned off here.
+                        */
+                       pps_lock(intel_dp);
                        edp_panel_vdd_off_sync(intel_dp);
-                       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+                       pps_unlock(intel_dp);
                }
                drm_connector_unregister(connector);
                drm_connector_cleanup(connector);
@@ -4781,7 +5339,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
        } else {
                intel_encoder->pre_enable = g4x_pre_enable_dp;
                intel_encoder->enable = g4x_enable_dp;
-               intel_encoder->post_disable = g4x_post_disable_dp;
+               if (INTEL_INFO(dev)->gen >= 5)
+                       intel_encoder->post_disable = ilk_post_disable_dp;
        }
 
        intel_dig_port->port = port;