]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - drivers/gpu/drm/i915/intel_dp.c
drm/i915: force link training when requested by Sink
[mirror_ubuntu-zesty-kernel.git] / drivers / gpu / drm / i915 / intel_dp.c
index 0a2e33fbf20dd2902817d85c10aa6b402d40e869..e35a0b8284e500f7ab628514305025b32022d4a2 100644 (file)
@@ -130,6 +130,11 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp);
 static void vlv_steal_power_sequencer(struct drm_device *dev,
                                      enum pipe pipe);
 
+static unsigned int intel_dp_unused_lane_mask(int lane_count)
+{
+       return ~((1 << lane_count) - 1) & 0xf;
+}
+
 static int
 intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 {
@@ -253,40 +258,6 @@ static void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
                dst[i] = src >> ((3-i) * 8);
 }
 
-/* hrawclock is 1/4 the FSB frequency */
-static int
-intel_hrawclk(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t clkcfg;
-
-       /* There is no CLKCFG reg in Valleyview. VLV hrawclk is 200 MHz */
-       if (IS_VALLEYVIEW(dev))
-               return 200;
-
-       clkcfg = I915_READ(CLKCFG);
-       switch (clkcfg & CLKCFG_FSB_MASK) {
-       case CLKCFG_FSB_400:
-               return 100;
-       case CLKCFG_FSB_533:
-               return 133;
-       case CLKCFG_FSB_667:
-               return 166;
-       case CLKCFG_FSB_800:
-               return 200;
-       case CLKCFG_FSB_1067:
-               return 266;
-       case CLKCFG_FSB_1333:
-               return 333;
-       /* these two are just a guess; one of them might be right */
-       case CLKCFG_FSB_1600:
-       case CLKCFG_FSB_1600_ALT:
-               return 400;
-       default:
-               return 133;
-       }
-}
-
 static void
 intel_dp_init_panel_power_sequencer(struct drm_device *dev,
                                    struct intel_dp *intel_dp);
@@ -333,7 +304,9 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe = intel_dp->pps_pipe;
-       bool pll_enabled;
+       bool pll_enabled, release_cl_override = false;
+       enum dpio_phy phy = DPIO_PHY(pipe);
+       enum dpio_channel ch = vlv_pipe_to_channel(pipe);
        uint32_t DP;
 
        if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN,
@@ -363,9 +336,13 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
         * The DPLL for the pipe must be enabled for this to work.
         * So enable temporarily it if it's not already enabled.
         */
-       if (!pll_enabled)
+       if (!pll_enabled) {
+               release_cl_override = IS_CHERRYVIEW(dev) &&
+                       !chv_phy_powergate_ch(dev_priv, phy, ch, true);
+
                vlv_force_pll_on(dev, pipe, IS_CHERRYVIEW(dev) ?
                                 &chv_dpll[0].dpll : &vlv_dpll[0].dpll);
+       }
 
        /*
         * Similar magic as in intel_dp_enable_port().
@@ -382,8 +359,12 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
        I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
        POSTING_READ(intel_dp->output_reg);
 
-       if (!pll_enabled)
+       if (!pll_enabled) {
                vlv_force_pll_off(dev, pipe);
+
+               if (release_cl_override)
+                       chv_phy_powergate_ch(dev_priv, phy, ch, false);
+       }
 }
 
 static enum pipe
@@ -593,8 +574,6 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
                                                 edp_notifier);
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp_div;
-       u32 pp_ctrl_reg, pp_div_reg;
 
        if (!is_edp(intel_dp) || code != SYS_RESTART)
                return 0;
@@ -603,6 +582,8 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
 
        if (IS_VALLEYVIEW(dev)) {
                enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
+               u32 pp_ctrl_reg, pp_div_reg;
+               u32 pp_div;
 
                pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe);
                pp_div_reg  = VLV_PIPE_PP_DIVISOR(pipe);
@@ -769,7 +750,7 @@ static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp,
        else
                precharge = 5;
 
-       if (IS_BROADWELL(dev) && intel_dp->aux_ch_ctl_reg == DPA_AUX_CH_CTL)
+       if (IS_BROADWELL(dev) && intel_dig_port->port == PORT_A)
                timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
        else
                timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
@@ -809,7 +790,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
-       uint32_t ch_data = ch_ctl + 4;
        uint32_t aux_clock_divider;
        int i, ret, recv_bytes;
        uint32_t status;
@@ -875,7 +855,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                for (try = 0; try < 5; try++) {
                        /* Load the send data into the aux channel data registers */
                        for (i = 0; i < send_bytes; i += 4)
-                               I915_WRITE(ch_data + i,
+                               I915_WRITE(intel_dp->aux_ch_data_reg[i >> 2],
                                           intel_dp_pack_aux(send + i,
                                                             send_bytes - i));
 
@@ -939,7 +919,7 @@ done:
                recv_bytes = recv_size;
 
        for (i = 0; i < recv_bytes; i += 4)
-               intel_dp_unpack_aux(I915_READ(ch_data + i),
+               intel_dp_unpack_aux(I915_READ(intel_dp->aux_ch_data_reg[i >> 2]),
                                    recv + i, recv_bytes - i);
 
        ret = recv_bytes;
@@ -974,6 +954,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        switch (msg->request & ~DP_AUX_I2C_MOT) {
        case DP_AUX_NATIVE_WRITE:
        case DP_AUX_I2C_WRITE:
+       case DP_AUX_I2C_WRITE_STATUS_UPDATE:
                txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
                rxsize = 2; /* 0 or 1 data bytes */
 
@@ -1026,96 +1007,206 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        return ret;
 }
 
-static void
-intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
+static uint32_t g4x_aux_ctl_reg(struct drm_i915_private *dev_priv,
+                               enum port port)
 {
-       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 port port = intel_dig_port->port;
-       struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port];
-       const char *name = NULL;
-       uint32_t porte_aux_ctl_reg = DPA_AUX_CH_CTL;
-       int ret;
+       switch (port) {
+       case PORT_B:
+       case PORT_C:
+       case PORT_D:
+               return DP_AUX_CH_CTL(port);
+       default:
+               MISSING_CASE(port);
+               return DP_AUX_CH_CTL(PORT_B);
+       }
+}
 
-       /* On SKL we don't have Aux for port E so we rely on VBT to set
-        * a proper alternate aux channel.
-        */
-       if (IS_SKYLAKE(dev) && port == PORT_E) {
-               switch (info->alternate_aux_channel) {
-               case DP_AUX_B:
-                       porte_aux_ctl_reg = DPB_AUX_CH_CTL;
-                       break;
-               case DP_AUX_C:
-                       porte_aux_ctl_reg = DPC_AUX_CH_CTL;
-                       break;
-               case DP_AUX_D:
-                       porte_aux_ctl_reg = DPD_AUX_CH_CTL;
-                       break;
-               case DP_AUX_A:
-               default:
-                       porte_aux_ctl_reg = DPA_AUX_CH_CTL;
-               }
+static uint32_t g4x_aux_data_reg(struct drm_i915_private *dev_priv,
+                                enum port port, int index)
+{
+       switch (port) {
+       case PORT_B:
+       case PORT_C:
+       case PORT_D:
+               return DP_AUX_CH_DATA(port, index);
+       default:
+               MISSING_CASE(port);
+               return DP_AUX_CH_DATA(PORT_B, index);
        }
+}
 
+static uint32_t ilk_aux_ctl_reg(struct drm_i915_private *dev_priv,
+                               enum port port)
+{
        switch (port) {
        case PORT_A:
-               intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
-               name = "DPDDC-A";
-               break;
+               return DP_AUX_CH_CTL(port);
        case PORT_B:
-               intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL;
-               name = "DPDDC-B";
-               break;
        case PORT_C:
-               intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL;
-               name = "DPDDC-C";
-               break;
        case PORT_D:
-               intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
-               name = "DPDDC-D";
-               break;
-       case PORT_E:
-               intel_dp->aux_ch_ctl_reg = porte_aux_ctl_reg;
-               name = "DPDDC-E";
-               break;
+               return PCH_DP_AUX_CH_CTL(port);
        default:
-               BUG();
+               MISSING_CASE(port);
+               return DP_AUX_CH_CTL(PORT_A);
        }
+}
 
-       /*
-        * 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) && port != PORT_E)
-               intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
+static uint32_t ilk_aux_data_reg(struct drm_i915_private *dev_priv,
+                                enum port port, int index)
+{
+       switch (port) {
+       case PORT_A:
+               return DP_AUX_CH_DATA(port, index);
+       case PORT_B:
+       case PORT_C:
+       case PORT_D:
+               return PCH_DP_AUX_CH_DATA(port, index);
+       default:
+               MISSING_CASE(port);
+               return DP_AUX_CH_DATA(PORT_A, index);
+       }
+}
+
+/*
+ * On SKL we don't have Aux for port E so we rely
+ * on VBT to set a proper alternate aux channel.
+ */
+static enum port skl_porte_aux_port(struct drm_i915_private *dev_priv)
+{
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[PORT_E];
+
+       switch (info->alternate_aux_channel) {
+       case DP_AUX_A:
+               return PORT_A;
+       case DP_AUX_B:
+               return PORT_B;
+       case DP_AUX_C:
+               return PORT_C;
+       case DP_AUX_D:
+               return PORT_D;
+       default:
+               MISSING_CASE(info->alternate_aux_channel);
+               return PORT_A;
+       }
+}
+
+static uint32_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv,
+                               enum port port)
+{
+       if (port == PORT_E)
+               port = skl_porte_aux_port(dev_priv);
+
+       switch (port) {
+       case PORT_A:
+       case PORT_B:
+       case PORT_C:
+       case PORT_D:
+               return DP_AUX_CH_CTL(port);
+       default:
+               MISSING_CASE(port);
+               return DP_AUX_CH_CTL(PORT_A);
+       }
+}
+
+static uint32_t skl_aux_data_reg(struct drm_i915_private *dev_priv,
+                                enum port port, int index)
+{
+       if (port == PORT_E)
+               port = skl_porte_aux_port(dev_priv);
+
+       switch (port) {
+       case PORT_A:
+       case PORT_B:
+       case PORT_C:
+       case PORT_D:
+               return DP_AUX_CH_DATA(port, index);
+       default:
+               MISSING_CASE(port);
+               return DP_AUX_CH_DATA(PORT_A, index);
+       }
+}
+
+static uint32_t intel_aux_ctl_reg(struct drm_i915_private *dev_priv,
+                                 enum port port)
+{
+       if (INTEL_INFO(dev_priv)->gen >= 9)
+               return skl_aux_ctl_reg(dev_priv, port);
+       else if (HAS_PCH_SPLIT(dev_priv))
+               return ilk_aux_ctl_reg(dev_priv, port);
+       else
+               return g4x_aux_ctl_reg(dev_priv, port);
+}
+
+static uint32_t intel_aux_data_reg(struct drm_i915_private *dev_priv,
+                                  enum port port, int index)
+{
+       if (INTEL_INFO(dev_priv)->gen >= 9)
+               return skl_aux_data_reg(dev_priv, port, index);
+       else if (HAS_PCH_SPLIT(dev_priv))
+               return ilk_aux_data_reg(dev_priv, port, index);
+       else
+               return g4x_aux_data_reg(dev_priv, port, index);
+}
+
+static void intel_aux_reg_init(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
+       enum port port = dp_to_dig_port(intel_dp)->port;
+       int i;
+
+       intel_dp->aux_ch_ctl_reg = intel_aux_ctl_reg(dev_priv, port);
+       for (i = 0; i < ARRAY_SIZE(intel_dp->aux_ch_data_reg); i++)
+               intel_dp->aux_ch_data_reg[i] = intel_aux_data_reg(dev_priv, port, i);
+}
+
+static void
+intel_dp_aux_fini(struct intel_dp *intel_dp)
+{
+       drm_dp_aux_unregister(&intel_dp->aux);
+       kfree(intel_dp->aux.name);
+}
+
+static int
+intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum port port = intel_dig_port->port;
+       int ret;
+
+       intel_aux_reg_init(intel_dp);
+
+       intel_dp->aux.name = kasprintf(GFP_KERNEL, "DPDDC-%c", port_name(port));
+       if (!intel_dp->aux.name)
+               return -ENOMEM;
 
-       intel_dp->aux.name = name;
        intel_dp->aux.dev = dev->dev;
        intel_dp->aux.transfer = intel_dp_aux_transfer;
 
-       DRM_DEBUG_KMS("registering %s bus for %s\n", name,
+       DRM_DEBUG_KMS("registering %s bus for %s\n",
+                     intel_dp->aux.name,
                      connector->base.kdev->kobj.name);
 
        ret = drm_dp_aux_register(&intel_dp->aux);
        if (ret < 0) {
                DRM_ERROR("drm_dp_aux_register() for %s failed (%d)\n",
-                         name, ret);
-               return;
+                         intel_dp->aux.name, ret);
+               kfree(intel_dp->aux.name);
+               return ret;
        }
 
        ret = sysfs_create_link(&connector->base.kdev->kobj,
                                &intel_dp->aux.ddc.dev.kobj,
                                intel_dp->aux.ddc.dev.kobj.name);
        if (ret < 0) {
-               DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret);
-               drm_dp_aux_unregister(&intel_dp->aux);
+               DRM_ERROR("sysfs_create_link() for %s failed (%d)\n",
+                         intel_dp->aux.name, ret);
+               intel_dp_aux_fini(intel_dp);
+               return ret;
        }
+
+       return 0;
 }
 
 static void
@@ -1207,10 +1298,13 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
        return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
 }
 
-static bool intel_dp_source_supports_hbr2(struct drm_device *dev)
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
 {
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = dig_port->base.base.dev;
+
        /* WaDisableHBR2:skl */
-       if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
+       if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
                return false;
 
        if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
@@ -1221,14 +1315,16 @@ static bool intel_dp_source_supports_hbr2(struct drm_device *dev)
 }
 
 static int
-intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
 {
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = dig_port->base.base.dev;
        int size;
 
        if (IS_BROXTON(dev)) {
                *source_rates = bxt_rates;
                size = ARRAY_SIZE(bxt_rates);
-       } else if (IS_SKYLAKE(dev)) {
+       } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                *source_rates = skl_rates;
                size = ARRAY_SIZE(skl_rates);
        } else {
@@ -1237,7 +1333,7 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
        }
 
        /* This depends on the fact that 5.4 is last value in the array */
-       if (!intel_dp_source_supports_hbr2(dev))
+       if (!intel_dp_source_supports_hbr2(intel_dp))
                size--;
 
        return size;
@@ -1302,12 +1398,11 @@ static int intersect_rates(const int *source_rates, int source_len,
 static int intel_dp_common_rates(struct intel_dp *intel_dp,
                                 int *common_rates)
 {
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
        const int *source_rates, *sink_rates;
        int source_len, sink_len;
 
        sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-       source_len = intel_dp_source_rates(dev, &source_rates);
+       source_len = intel_dp_source_rates(intel_dp, &source_rates);
 
        return intersect_rates(source_rates, source_len,
                               sink_rates, sink_len,
@@ -1332,7 +1427,6 @@ static void snprintf_int_array(char *str, size_t len,
 
 static void intel_dp_print_rates(struct intel_dp *intel_dp)
 {
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
        const int *source_rates, *sink_rates;
        int source_len, sink_len, common_len;
        int common_rates[DP_MAX_SUPPORTED_RATES];
@@ -1341,7 +1435,7 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
        if ((drm_debug & DRM_UT_KMS) == 0)
                return;
 
-       source_len = intel_dp_source_rates(dev, &source_rates);
+       source_len = intel_dp_source_rates(intel_dp, &source_rates);
        snprintf_int_array(str, sizeof(str), source_rates, source_len);
        DRM_DEBUG_KMS("source rates: %s\n", str);
 
@@ -1383,6 +1477,19 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
        return rate_to_index(rate, intel_dp->sink_rates);
 }
 
+void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
+                          uint8_t *link_bw, uint8_t *rate_select)
+{
+       if (intel_dp->num_sink_rates) {
+               *link_bw = 0;
+               *rate_select =
+                       intel_dp_rate_select(intel_dp, port_clock);
+       } else {
+               *link_bw = drm_dp_link_rate_to_bw_code(port_clock);
+               *rate_select = 0;
+       }
+}
+
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_state *pipe_config)
@@ -1404,6 +1511,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        int link_avail, link_clock;
        int common_rates[DP_MAX_SUPPORTED_RATES] = {};
        int common_len;
+       uint8_t link_bw, rate_select;
 
        common_len = intel_dp_common_rates(intel_dp, common_rates);
 
@@ -1430,7 +1538,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                                return ret;
                }
 
-               if (!HAS_PCH_SPLIT(dev))
+               if (HAS_GMCH_DISPLAY(dev))
                        intel_gmch_panel_fitting(intel_crtc, pipe_config,
                                                 intel_connector->panel.fitting_mode);
                else
@@ -1499,32 +1607,23 @@ found:
                 * CEA-861-E - 5.1 Default Encoding Parameters
                 * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry
                 */
-               if (bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1)
-                       intel_dp->color_range = DP_COLOR_RANGE_16_235;
-               else
-                       intel_dp->color_range = 0;
-       }
-
-       if (intel_dp->color_range)
-               pipe_config->limited_color_range = true;
-
-       intel_dp->lane_count = lane_count;
-
-       if (intel_dp->num_sink_rates) {
-               intel_dp->link_bw = 0;
-               intel_dp->rate_select =
-                       intel_dp_rate_select(intel_dp, common_rates[clock]);
+               pipe_config->limited_color_range =
+                       bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1;
        } else {
-               intel_dp->link_bw =
-                       drm_dp_link_rate_to_bw_code(common_rates[clock]);
-               intel_dp->rate_select = 0;
+               pipe_config->limited_color_range =
+                       intel_dp->limited_color_range;
        }
 
+       pipe_config->lane_count = lane_count;
+
        pipe_config->pipe_bpp = bpp;
        pipe_config->port_clock = common_rates[clock];
 
-       DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
-                     intel_dp->link_bw, intel_dp->lane_count,
+       intel_dp_compute_rate(intel_dp, pipe_config->port_clock,
+                             &link_bw, &rate_select);
+
+       DRM_DEBUG_KMS("DP link bw %02x rate select %02x lane count %d clock %d bpp %d\n",
+                     link_bw, rate_select, pipe_config->lane_count,
                      pipe_config->port_clock, bpp);
        DRM_DEBUG_KMS("DP link bw required %i available %i\n",
                      mode_rate, link_avail);
@@ -1543,7 +1642,7 @@ found:
                                &pipe_config->dp_m2_n2);
        }
 
-       if (IS_SKYLAKE(dev) && is_edp(intel_dp))
+       if ((IS_SKYLAKE(dev)  || IS_KABYLAKE(dev)) && is_edp(intel_dp))
                skl_edp_set_pll_config(pipe_config);
        else if (IS_BROXTON(dev))
                /* handled in ddi */;
@@ -1555,35 +1654,11 @@ found:
        return true;
 }
 
-static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp)
+void intel_dp_set_link_params(struct intel_dp *intel_dp,
+                             const struct intel_crtc_state *pipe_config)
 {
-       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-       struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 dpa_ctl;
-
-       DRM_DEBUG_KMS("eDP PLL enable for clock %d\n",
-                     crtc->config->port_clock);
-       dpa_ctl = I915_READ(DP_A);
-       dpa_ctl &= ~DP_PLL_FREQ_MASK;
-
-       if (crtc->config->port_clock == 162000) {
-               /* For a long time we've carried around a ILK-DevA w/a for the
-                * 160MHz clock. If we're really unlucky, it's still required.
-                */
-               DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n");
-               dpa_ctl |= DP_PLL_FREQ_160MHZ;
-               intel_dp->DP |= DP_PLL_FREQ_160MHZ;
-       } else {
-               dpa_ctl |= DP_PLL_FREQ_270MHZ;
-               intel_dp->DP |= DP_PLL_FREQ_270MHZ;
-       }
-
-       I915_WRITE(DP_A, dpa_ctl);
-
-       POSTING_READ(DP_A);
-       udelay(500);
+       intel_dp->link_rate = pipe_config->port_clock;
+       intel_dp->lane_count = pipe_config->lane_count;
 }
 
 static void intel_dp_prepare(struct intel_encoder *encoder)
@@ -1593,7 +1668,9 @@ static void intel_dp_prepare(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 intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+       const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+
+       intel_dp_set_link_params(intel_dp, crtc->config);
 
        /*
         * There are four kinds of DP registers:
@@ -1619,10 +1696,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
 
        /* Handle DP bits in common between all three register formats */
        intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
-       intel_dp->DP |= DP_PORT_WIDTH(intel_dp->lane_count);
-
-       if (crtc->config->has_audio)
-               intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
+       intel_dp->DP |= DP_PORT_WIDTH(crtc->config->lane_count);
 
        /* Split out the IBX/CPU vs CPT settings */
 
@@ -1649,8 +1723,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
                        trans_dp &= ~TRANS_DP_ENH_FRAMING;
                I915_WRITE(TRANS_DP_CTL(crtc->pipe), trans_dp);
        } else {
-               if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev))
-                       intel_dp->DP |= intel_dp->color_range;
+               if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
+                   crtc->config->limited_color_range)
+                       intel_dp->DP |= DP_COLOR_RANGE_16_235;
 
                if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                        intel_dp->DP |= DP_SYNC_HS_HIGH;
@@ -2149,27 +2224,61 @@ static void intel_edp_backlight_power(struct intel_connector *connector,
                _intel_edp_backlight_off(intel_dp);
 }
 
+static const char *state_string(bool enabled)
+{
+       return enabled ? "on" : "off";
+}
+
+static void assert_dp_port(struct intel_dp *intel_dp, bool state)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+       bool cur_state = I915_READ(intel_dp->output_reg) & DP_PORT_EN;
+
+       I915_STATE_WARN(cur_state != state,
+                       "DP port %c state assertion failure (expected %s, current %s)\n",
+                       port_name(dig_port->port),
+                       state_string(state), state_string(cur_state));
+}
+#define assert_dp_port_disabled(d) assert_dp_port((d), false)
+
+static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
+{
+       bool cur_state = I915_READ(DP_A) & DP_PLL_ENABLE;
+
+       I915_STATE_WARN(cur_state != state,
+                       "eDP PLL state assertion failure (expected %s, current %s)\n",
+                       state_string(state), state_string(cur_state));
+}
+#define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
+#define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
+
 static void ironlake_edp_pll_on(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 = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 dpa_ctl;
+       struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       assert_pipe_disabled(dev_priv,
-                            to_intel_crtc(crtc)->pipe);
+       assert_pipe_disabled(dev_priv, crtc->pipe);
+       assert_dp_port_disabled(intel_dp);
+       assert_edp_pll_disabled(dev_priv);
+
+       DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n",
+                     crtc->config->port_clock);
+
+       intel_dp->DP &= ~DP_PLL_FREQ_MASK;
+
+       if (crtc->config->port_clock == 162000)
+               intel_dp->DP |= DP_PLL_FREQ_162MHZ;
+       else
+               intel_dp->DP |= DP_PLL_FREQ_270MHZ;
+
+       I915_WRITE(DP_A, intel_dp->DP);
+       POSTING_READ(DP_A);
+       udelay(500);
 
-       DRM_DEBUG_KMS("\n");
-       dpa_ctl = I915_READ(DP_A);
-       WARN(dpa_ctl & DP_PLL_ENABLE, "dp pll on, should be off\n");
-       WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
-
-       /* We don't adjust intel_dp->DP while tearing down the link, to
-        * facilitate link retraining (e.g. after hotplug). Hence clear all
-        * enable bits here to ensure that we don't enable too much. */
-       intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
        intel_dp->DP |= DP_PLL_ENABLE;
+
        I915_WRITE(DP_A, intel_dp->DP);
        POSTING_READ(DP_A);
        udelay(200);
@@ -2178,24 +2287,18 @@ static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
 static void ironlake_edp_pll_off(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 = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 dpa_ctl;
+       struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-       assert_pipe_disabled(dev_priv,
-                            to_intel_crtc(crtc)->pipe);
+       assert_pipe_disabled(dev_priv, crtc->pipe);
+       assert_dp_port_disabled(intel_dp);
+       assert_edp_pll_enabled(dev_priv);
 
-       dpa_ctl = I915_READ(DP_A);
-       WARN((dpa_ctl & DP_PLL_ENABLE) == 0,
-            "dp pll off, should be on\n");
-       WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
+       DRM_DEBUG_KMS("disabling eDP PLL\n");
 
-       /* We can't rely on the value tracked for the DP register in
-        * intel_dp->DP because link_down must not change that (otherwise link
-        * re-training will fail. */
-       dpa_ctl &= ~DP_PLL_ENABLE;
-       I915_WRITE(DP_A, dpa_ctl);
+       intel_dp->DP &= ~DP_PLL_ENABLE;
+
+       I915_WRITE(DP_A, intel_dp->DP);
        POSTING_READ(DP_A);
        udelay(200);
 }
@@ -2290,13 +2393,14 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
        pipe_config->has_audio = tmp & DP_AUDIO_OUTPUT_ENABLE && port != PORT_A;
 
        if (HAS_PCH_CPT(dev) && port != PORT_A) {
-               tmp = I915_READ(TRANS_DP_CTL(crtc->pipe));
-               if (tmp & TRANS_DP_HSYNC_ACTIVE_HIGH)
+               u32 trans_dp = I915_READ(TRANS_DP_CTL(crtc->pipe));
+
+               if (trans_dp & TRANS_DP_HSYNC_ACTIVE_HIGH)
                        flags |= DRM_MODE_FLAG_PHSYNC;
                else
                        flags |= DRM_MODE_FLAG_NHSYNC;
 
-               if (tmp & TRANS_DP_VSYNC_ACTIVE_HIGH)
+               if (trans_dp & TRANS_DP_VSYNC_ACTIVE_HIGH)
                        flags |= DRM_MODE_FLAG_PVSYNC;
                else
                        flags |= DRM_MODE_FLAG_NVSYNC;
@@ -2320,10 +2424,13 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
 
        pipe_config->has_dp_encoder = true;
 
+       pipe_config->lane_count =
+               ((tmp & DP_PORT_WIDTH_MASK) >> DP_PORT_WIDTH_SHIFT) + 1;
+
        intel_dp_get_m_n(crtc, pipe_config);
 
        if (port == PORT_A) {
-               if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ)
+               if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_162MHZ)
                        pipe_config->port_clock = 162000;
                else
                        pipe_config->port_clock = 270000;
@@ -2388,6 +2495,8 @@ static void ilk_post_disable_dp(struct intel_encoder *encoder)
        enum port port = dp_to_dig_port(intel_dp)->port;
 
        intel_dp_link_down(intel_dp);
+
+       /* Only ilk+ has port A */
        if (port == PORT_A)
                ironlake_edp_pll_off(intel_dp);
 }
@@ -2399,38 +2508,62 @@ static void vlv_post_disable_dp(struct intel_encoder *encoder)
        intel_dp_link_down(intel_dp);
 }
 
-static void chv_post_disable_dp(struct intel_encoder *encoder)
+static void chv_data_lane_soft_reset(struct intel_encoder *encoder,
+                                    bool reset)
 {
-       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       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 intel_crtc *intel_crtc =
-               to_intel_crtc(encoder->base.crtc);
-       enum dpio_channel ch = vlv_dport_to_channel(dport);
-       enum pipe pipe = intel_crtc->pipe;
-       u32 val;
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum dpio_channel ch = vlv_dport_to_channel(enc_to_dig_port(&encoder->base));
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       enum pipe pipe = crtc->pipe;
+       uint32_t val;
 
-       intel_dp_link_down(intel_dp);
+       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
+       if (reset)
+               val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
+       else
+               val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
 
-       mutex_lock(&dev_priv->sb_lock);
+       if (crtc->config->lane_count > 2) {
+               val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
+               if (reset)
+                       val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
+               else
+                       val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
+               vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
+       }
 
-       /* Propagate soft reset to data lane reset */
        val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
        val |= CHV_PCS_REQ_SOFTRESET_EN;
+       if (reset)
+               val &= ~DPIO_PCS_CLK_SOFT_RESET;
+       else
+               val |= DPIO_PCS_CLK_SOFT_RESET;
        vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
 
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
-       val |= CHV_PCS_REQ_SOFTRESET_EN;
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
+       if (crtc->config->lane_count > 2) {
+               val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
+               val |= CHV_PCS_REQ_SOFTRESET_EN;
+               if (reset)
+                       val &= ~DPIO_PCS_CLK_SOFT_RESET;
+               else
+                       val |= DPIO_PCS_CLK_SOFT_RESET;
+               vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
+       }
+}
 
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
-       val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
+static void chv_post_disable_dp(struct intel_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       intel_dp_link_down(intel_dp);
+
+       mutex_lock(&dev_priv->sb_lock);
 
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
-       val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
+       /* Assert data lane reset */
+       chv_data_lane_soft_reset(encoder, true);
 
        mutex_unlock(&dev_priv->sb_lock);
 }
@@ -2523,6 +2656,8 @@ 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;
+       struct intel_crtc *crtc =
+               to_intel_crtc(dp_to_dig_port(intel_dp)->base.base.crtc);
 
        /* enable with pattern 1 (as per spec) */
        _intel_dp_set_link_train(intel_dp, &intel_dp->DP,
@@ -2538,6 +2673,8 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp)
         * fail when the power sequencer is freshly used for this port.
         */
        intel_dp->DP |= DP_PORT_EN;
+       if (crtc->config->has_audio)
+               intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
 
        I915_WRITE(intel_dp->output_reg, intel_dp->DP);
        POSTING_READ(intel_dp->output_reg);
@@ -2550,7 +2687,8 @@ static void intel_enable_dp(struct intel_encoder *encoder)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
        uint32_t dp_reg = I915_READ(intel_dp->output_reg);
-       unsigned int lane_mask = 0x0;
+       enum port port = dp_to_dig_port(intel_dp)->port;
+       enum pipe pipe = crtc->pipe;
 
        if (WARN_ON(dp_reg & DP_PORT_EN))
                return;
@@ -2562,24 +2700,40 @@ static void intel_enable_dp(struct intel_encoder *encoder)
 
        intel_dp_enable_port(intel_dp);
 
+       if (port == PORT_A && IS_GEN5(dev_priv)) {
+               /*
+                * Underrun reporting for the other pipe was disabled in
+                * g4x_pre_enable_dp(). The eDP PLL and port have now been
+                * enabled, so it's now safe to re-enable underrun reporting.
+                */
+               intel_wait_for_vblank_if_active(dev_priv->dev, !pipe);
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, !pipe, true);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, !pipe, true);
+       }
+
        edp_panel_vdd_on(intel_dp);
        edp_panel_on(intel_dp);
        edp_panel_vdd_off(intel_dp, true);
 
        pps_unlock(intel_dp);
 
-       if (IS_VALLEYVIEW(dev))
+       if (IS_VALLEYVIEW(dev)) {
+               unsigned int lane_mask = 0x0;
+
+               if (IS_CHERRYVIEW(dev))
+                       lane_mask = intel_dp_unused_lane_mask(crtc->config->lane_count);
+
                vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp),
                                    lane_mask);
+       }
 
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        intel_dp_start_link_train(intel_dp);
-       intel_dp_complete_link_train(intel_dp);
        intel_dp_stop_link_train(intel_dp);
 
        if (crtc->config->has_audio) {
                DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
-                                pipe_name(crtc->pipe));
+                                pipe_name(pipe));
                intel_audio_codec_enable(encoder);
        }
 }
@@ -2602,16 +2756,29 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
 {
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-       struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+       enum port port = dp_to_dig_port(intel_dp)->port;
+       enum pipe pipe = to_intel_crtc(encoder->base.crtc)->pipe;
 
        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);
+       if (port == PORT_A && IS_GEN5(dev_priv)) {
+               /*
+                * We get FIFO underruns on the other pipe when
+                * enabling the CPU eDP PLL, and when enabling CPU
+                * eDP port. We could potentially avoid the PLL
+                * underrun with a vblank wait just prior to enabling
+                * the PLL, but that doesn't appear to help the port
+                * enable case. Just sweep it all under the rug.
+                */
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, !pipe, false);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, !pipe, false);
        }
+
+       /* Only ilk+ has port A */
+       if (port == PORT_A)
+               ironlake_edp_pll_on(intel_dp);
 }
 
 static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
@@ -2797,31 +2964,19 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
        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;
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
-
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
-       val |= CHV_PCS_REQ_SOFTRESET_EN;
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
-
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
-       val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
-
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
-       val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
+       if (intel_crtc->config->lane_count > 2) {
+               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);
+       }
 
        /* Program Tx lane latency optimal setting*/
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < intel_crtc->config->lane_count; i++) {
                /* Set the upar bit */
-               data = (i == 1) ? 0x0 : 0x1;
+               if (intel_crtc->config->lane_count == 1)
+                       data = 0x0;
+               else
+                       data = (i == 1) ? 0x0 : 0x1;
                vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i),
                                data << DPIO_UPAR_SHIFT);
        }
@@ -2842,9 +2997,11 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
        val |= DPIO_TX2_STAGGER_MASK(0x1f);
        vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val);
 
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
-       val |= DPIO_TX2_STAGGER_MASK(0x1f);
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
+       if (intel_crtc->config->lane_count > 2) {
+               val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
+               val |= DPIO_TX2_STAGGER_MASK(0x1f);
+               vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
+       }
 
        vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch),
                       DPIO_LANESTAGGER_STRAP(stagger) |
@@ -2853,16 +3010,27 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
                       DPIO_TX1_STAGGER_MULT(6) |
                       DPIO_TX2_STAGGER_MULT(0));
 
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch),
-                      DPIO_LANESTAGGER_STRAP(stagger) |
-                      DPIO_LANESTAGGER_STRAP_OVRD |
-                      DPIO_TX1_STAGGER_MASK(0x1f) |
-                      DPIO_TX1_STAGGER_MULT(7) |
-                      DPIO_TX2_STAGGER_MULT(5));
+       if (intel_crtc->config->lane_count > 2) {
+               vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch),
+                              DPIO_LANESTAGGER_STRAP(stagger) |
+                              DPIO_LANESTAGGER_STRAP_OVRD |
+                              DPIO_TX1_STAGGER_MASK(0x1f) |
+                              DPIO_TX1_STAGGER_MULT(7) |
+                              DPIO_TX2_STAGGER_MULT(5));
+       }
+
+       /* Deassert data lane reset */
+       chv_data_lane_soft_reset(encoder, false);
 
        mutex_unlock(&dev_priv->sb_lock);
 
        intel_enable_dp(encoder);
+
+       /* Second common lane will stay alive on its own now */
+       if (dport->release_cl2_override) {
+               chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, false);
+               dport->release_cl2_override = false;
+       }
 }
 
 static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
@@ -2874,12 +3042,27 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
                to_intel_crtc(encoder->base.crtc);
        enum dpio_channel ch = vlv_dport_to_channel(dport);
        enum pipe pipe = intel_crtc->pipe;
+       unsigned int lane_mask =
+               intel_dp_unused_lane_mask(intel_crtc->config->lane_count);
        u32 val;
 
        intel_dp_prepare(encoder);
 
+       /*
+        * Must trick the second common lane into life.
+        * Otherwise we can't even access the PLL.
+        */
+       if (ch == DPIO_CH0 && pipe == PIPE_B)
+               dport->release_cl2_override =
+                       !chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, true);
+
+       chv_phy_powergate_lanes(encoder, true, lane_mask);
+
        mutex_lock(&dev_priv->sb_lock);
 
+       /* Assert data lane reset */
+       chv_data_lane_soft_reset(encoder, true);
+
        /* program left/right clock distribution */
        if (pipe != PIPE_B) {
                val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
@@ -2908,13 +3091,15 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
                val |= CHV_PCS_USEDCLKCHANNEL;
        vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val);
 
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch));
-       val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE;
-       if (pipe != PIPE_B)
-               val &= ~CHV_PCS_USEDCLKCHANNEL;
-       else
-               val |= CHV_PCS_USEDCLKCHANNEL;
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val);
+       if (intel_crtc->config->lane_count > 2) {
+               val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch));
+               val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE;
+               if (pipe != PIPE_B)
+                       val &= ~CHV_PCS_USEDCLKCHANNEL;
+               else
+                       val |= CHV_PCS_USEDCLKCHANNEL;
+               vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val);
+       }
 
        /*
         * This a a bit weird since generally CL
@@ -2931,6 +3116,39 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->sb_lock);
 }
 
+static void chv_dp_post_pll_disable(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       enum pipe pipe = to_intel_crtc(encoder->base.crtc)->pipe;
+       u32 val;
+
+       mutex_lock(&dev_priv->sb_lock);
+
+       /* disable left/right clock distribution */
+       if (pipe != PIPE_B) {
+               val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
+               val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK);
+               vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val);
+       } else {
+               val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1);
+               val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK);
+               vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val);
+       }
+
+       mutex_unlock(&dev_priv->sb_lock);
+
+       /*
+        * Leave the power down bit cleared for at least one
+        * lane so that chv_powergate_phy_ch() will power
+        * on something when the channel is otherwise unused.
+        * When the port is off and the override is removed
+        * the lanes power down anyway, so otherwise it doesn't
+        * really matter what the state of power down bits is
+        * after this.
+        */
+       chv_phy_powergate_lanes(encoder, false, 0x0);
+}
+
 /*
  * Native read with retry for link status and receiver capability reads for
  * cases where the sink may still be asleep.
@@ -2966,7 +3184,7 @@ intel_dp_dpcd_read_wake(struct drm_dp_aux *aux, unsigned int offset,
  * Fetch AUX CH registers 0x202 - 0x207 which contain
  * link status information
  */
-static bool
+bool
 intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
 {
        return intel_dp_dpcd_read_wake(&intel_dp->aux,
@@ -2976,7 +3194,7 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_
 }
 
 /* These are source-specific values. */
-static uint8_t
+uint8_t
 intel_dp_voltage_max(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -2999,7 +3217,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp)
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
 }
 
-static uint8_t
+uint8_t
 intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -3167,6 +3385,12 @@ static uint32_t vlv_signal_levels(struct intel_dp *intel_dp)
        return 0;
 }
 
+static bool chv_need_uniq_trans_scale(uint8_t train_set)
+{
+       return (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) == DP_TRAIN_PRE_EMPH_LEVEL_0 &&
+               (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) == DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
+}
+
 static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -3258,24 +3482,28 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
        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);
+       if (intel_crtc->config->lane_count > 2) {
+               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);
+       if (intel_crtc->config->lane_count > 2) {
+               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++) {
+       for (i = 0; i < intel_crtc->config->lane_count; i++) {
                val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i));
                val &= ~DPIO_SWING_DEEMPH9P5_MASK;
                val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT;
@@ -3283,43 +3511,36 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
        }
 
        /* Program swing margin */
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < intel_crtc->config->lane_count; i++) {
                val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
+
                val &= ~DPIO_SWING_MARGIN000_MASK;
                val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT;
+
+               /*
+                * Supposedly this value shouldn't matter when unique transition
+                * scale is disabled, but in fact it does matter. Let's just
+                * always program the same value and hope it's OK.
+                */
+               val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT);
+               val |= 0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT;
+
                vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
        }
 
-       /* Disable unique transition scale */
-       for (i = 0; i < 4; i++) {
+       /*
+        * The document said it needs to set bit 27 for ch0 and bit 26
+        * for ch1. Might be a typo in the doc.
+        * For now, for this unique transition scale selection, set bit
+        * 27 for ch0 and ch1.
+        */
+       for (i = 0; i < intel_crtc->config->lane_count; i++) {
                val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
-               val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN;
-               vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
-       }
-
-       if (((train_set & DP_TRAIN_PRE_EMPHASIS_MASK)
-                       == DP_TRAIN_PRE_EMPH_LEVEL_0) &&
-               ((train_set & DP_TRAIN_VOLTAGE_SWING_MASK)
-                       == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)) {
-
-               /*
-                * The document said it needs to set bit 27 for ch0 and bit 26
-                * for ch1. Might be a typo in the doc.
-                * For now, for this unique transition scale selection, set bit
-                * 27 for ch0 and ch1.
-                */
-               for (i = 0; i < 4; i++) {
-                       val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
+               if (chv_need_uniq_trans_scale(train_set))
                        val |= DPIO_TX_UNIQ_TRANS_SCALE_EN;
-                       vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
-               }
-
-               for (i = 0; i < 4; i++) {
-                       val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
-                       val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT);
-                       val |= (0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT);
-                       vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
-               }
+               else
+                       val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN;
+               vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
        }
 
        /* Start swing calculation */
@@ -3327,52 +3548,17 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
        val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
        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;
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
-
-       /* LRC Bypass */
-       val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30);
-       val |= DPIO_LRC_BYPASS;
-       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val);
+       if (intel_crtc->config->lane_count > 2) {
+               val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
+               val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
+               vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
+       }
 
        mutex_unlock(&dev_priv->sb_lock);
 
        return 0;
 }
 
-static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
-                      const uint8_t link_status[DP_LINK_STATUS_SIZE])
-{
-       uint8_t v = 0;
-       uint8_t p = 0;
-       int lane;
-       uint8_t voltage_max;
-       uint8_t preemph_max;
-
-       for (lane = 0; lane < intel_dp->lane_count; lane++) {
-               uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
-               uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
-
-               if (this_v > v)
-                       v = this_v;
-               if (this_p > p)
-                       p = this_p;
-       }
-
-       voltage_max = intel_dp_voltage_max(intel_dp);
-       if (v >= voltage_max)
-               v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
-
-       preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
-       if (p >= preemph_max)
-               p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
-
-       for (lane = 0; lane < 4; lane++)
-               intel_dp->train_set[lane] = v | p;
-}
-
 static uint32_t
 gen4_signal_levels(uint8_t train_set)
 {
@@ -3470,13 +3656,13 @@ gen7_edp_signal_levels(uint8_t train_set)
        }
 }
 
-/* Properly updates "DP" with the correct signal levels. */
-static void
-intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
+void
+intel_dp_set_signal_levels(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        enum port port = intel_dig_port->port;
        struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t signal_levels, mask = 0;
        uint8_t train_set = intel_dp->train_set[0];
 
@@ -3511,74 +3697,27 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
                (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
                        DP_TRAIN_PRE_EMPHASIS_SHIFT);
 
-       *DP = (*DP & ~mask) | signal_levels;
-}
+       intel_dp->DP = (intel_dp->DP & ~mask) | signal_levels;
 
-static bool
-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;
-       uint8_t buf[sizeof(intel_dp->train_set) + 1];
-       int ret, len;
-
-       _intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
-
-       I915_WRITE(intel_dp->output_reg, *DP);
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
        POSTING_READ(intel_dp->output_reg);
-
-       buf[0] = dp_train_pat;
-       if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
-           DP_TRAINING_PATTERN_DISABLE) {
-               /* don't write DP_TRAINING_LANEx_SET on disable */
-               len = 1;
-       } else {
-               /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
-               memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
-               len = intel_dp->lane_count + 1;
-       }
-
-       ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
-                               buf, len);
-
-       return ret == len;
 }
 
-static bool
-intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP,
-                       uint8_t dp_train_pat)
-{
-       if (!intel_dp->train_set_valid)
-               memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
-       intel_dp_set_signal_levels(intel_dp, DP);
-       return intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
-}
-
-static bool
-intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP,
-                          const uint8_t link_status[DP_LINK_STATUS_SIZE])
+void
+intel_dp_program_link_training_pattern(struct intel_dp *intel_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;
-       int ret;
+       struct drm_i915_private *dev_priv =
+               to_i915(intel_dig_port->base.base.dev);
 
-       intel_get_adjust_train(intel_dp, link_status);
-       intel_dp_set_signal_levels(intel_dp, DP);
+       _intel_dp_set_link_train(intel_dp, &intel_dp->DP, dp_train_pat);
 
-       I915_WRITE(intel_dp->output_reg, *DP);
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
        POSTING_READ(intel_dp->output_reg);
-
-       ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
-                               intel_dp->train_set, intel_dp->lane_count);
-
-       return ret == intel_dp->lane_count;
 }
 
-static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
+void intel_dp_set_idle_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;
@@ -3609,206 +3748,6 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
                DRM_ERROR("Timed out waiting for DP idle patterns\n");
 }
 
-/* Enable corresponding port and start training pattern 1 */
-void
-intel_dp_start_link_train(struct intel_dp *intel_dp)
-{
-       struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base;
-       struct drm_device *dev = encoder->dev;
-       int i;
-       uint8_t voltage;
-       int voltage_tries, loop_tries;
-       uint32_t DP = intel_dp->DP;
-       uint8_t link_config[2];
-
-       if (HAS_DDI(dev))
-               intel_ddi_prepare_link_retrain(encoder);
-
-       /* Write the link configuration data */
-       link_config[0] = intel_dp->link_bw;
-       link_config[1] = intel_dp->lane_count;
-       if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
-               link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
-       drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
-       if (intel_dp->num_sink_rates)
-               drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
-                               &intel_dp->rate_select, 1);
-
-       link_config[0] = 0;
-       link_config[1] = DP_SET_ANSI_8B10B;
-       drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
-
-       DP |= DP_PORT_EN;
-
-       /* clock recovery */
-       if (!intel_dp_reset_link_train(intel_dp, &DP,
-                                      DP_TRAINING_PATTERN_1 |
-                                      DP_LINK_SCRAMBLING_DISABLE)) {
-               DRM_ERROR("failed to enable link training\n");
-               return;
-       }
-
-       voltage = 0xff;
-       voltage_tries = 0;
-       loop_tries = 0;
-       for (;;) {
-               uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-               drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
-               if (!intel_dp_get_link_status(intel_dp, link_status)) {
-                       DRM_ERROR("failed to get link status\n");
-                       break;
-               }
-
-               if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
-                       DRM_DEBUG_KMS("clock recovery OK\n");
-                       break;
-               }
-
-               /*
-                * if we used previously trained voltage and pre-emphasis values
-                * and we don't get clock recovery, reset link training values
-                */
-               if (intel_dp->train_set_valid) {
-                       DRM_DEBUG_KMS("clock recovery not ok, reset");
-                       /* clear the flag as we are not reusing train set */
-                       intel_dp->train_set_valid = false;
-                       if (!intel_dp_reset_link_train(intel_dp, &DP,
-                                                      DP_TRAINING_PATTERN_1 |
-                                                      DP_LINK_SCRAMBLING_DISABLE)) {
-                               DRM_ERROR("failed to enable link training\n");
-                               return;
-                       }
-                       continue;
-               }
-
-               /* Check to see if we've tried the max voltage */
-               for (i = 0; i < intel_dp->lane_count; i++)
-                       if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
-                               break;
-               if (i == intel_dp->lane_count) {
-                       ++loop_tries;
-                       if (loop_tries == 5) {
-                               DRM_ERROR("too many full retries, give up\n");
-                               break;
-                       }
-                       intel_dp_reset_link_train(intel_dp, &DP,
-                                                 DP_TRAINING_PATTERN_1 |
-                                                 DP_LINK_SCRAMBLING_DISABLE);
-                       voltage_tries = 0;
-                       continue;
-               }
-
-               /* Check to see if we've tried the same voltage 5 times */
-               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-                       ++voltage_tries;
-                       if (voltage_tries == 5) {
-                               DRM_ERROR("too many voltage retries, give up\n");
-                               break;
-                       }
-               } else
-                       voltage_tries = 0;
-               voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
-
-               /* Update training set as requested by target */
-               if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
-                       DRM_ERROR("failed to update link training\n");
-                       break;
-               }
-       }
-
-       intel_dp->DP = DP;
-}
-
-void
-intel_dp_complete_link_train(struct intel_dp *intel_dp)
-{
-       bool channel_eq = false;
-       int tries, cr_tries;
-       uint32_t DP = intel_dp->DP;
-       uint32_t training_pattern = DP_TRAINING_PATTERN_2;
-
-       /* Training Pattern 3 for HBR2 ot 1.2 devices that support it*/
-       if (intel_dp->link_bw == DP_LINK_BW_5_4 || intel_dp->use_tps3)
-               training_pattern = DP_TRAINING_PATTERN_3;
-
-       /* channel equalization */
-       if (!intel_dp_set_link_train(intel_dp, &DP,
-                                    training_pattern |
-                                    DP_LINK_SCRAMBLING_DISABLE)) {
-               DRM_ERROR("failed to start channel equalization\n");
-               return;
-       }
-
-       tries = 0;
-       cr_tries = 0;
-       channel_eq = false;
-       for (;;) {
-               uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-               if (cr_tries > 5) {
-                       DRM_ERROR("failed to train DP, aborting\n");
-                       break;
-               }
-
-               drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
-               if (!intel_dp_get_link_status(intel_dp, link_status)) {
-                       DRM_ERROR("failed to get link status\n");
-                       break;
-               }
-
-               /* Make sure clock is still ok */
-               if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
-                       intel_dp->train_set_valid = false;
-                       intel_dp_start_link_train(intel_dp);
-                       intel_dp_set_link_train(intel_dp, &DP,
-                                               training_pattern |
-                                               DP_LINK_SCRAMBLING_DISABLE);
-                       cr_tries++;
-                       continue;
-               }
-
-               if (drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
-                       channel_eq = true;
-                       break;
-               }
-
-               /* Try 5 times, then try clock recovery if that fails */
-               if (tries > 5) {
-                       intel_dp->train_set_valid = false;
-                       intel_dp_start_link_train(intel_dp);
-                       intel_dp_set_link_train(intel_dp, &DP,
-                                               training_pattern |
-                                               DP_LINK_SCRAMBLING_DISABLE);
-                       tries = 0;
-                       cr_tries++;
-                       continue;
-               }
-
-               /* Update training set as requested by target */
-               if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
-                       DRM_ERROR("failed to update link training\n");
-                       break;
-               }
-               ++tries;
-       }
-
-       intel_dp_set_idle_link_train(intel_dp);
-
-       intel_dp->DP = DP;
-
-       if (channel_eq) {
-               intel_dp->train_set_valid = true;
-               DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
-       }
-}
-
-void intel_dp_stop_link_train(struct intel_dp *intel_dp)
-{
-       intel_dp_set_link_train(intel_dp, &intel_dp->DP,
-                               DP_TRAINING_PATTERN_DISABLE);
-}
-
 static void
 intel_dp_link_down(struct intel_dp *intel_dp)
 {
@@ -3851,6 +3790,13 @@ intel_dp_link_down(struct intel_dp *intel_dp)
         * matching HDMI port to be enabled on transcoder A.
         */
        if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B && port != PORT_A) {
+               /*
+                * We get CPU/PCH FIFO underruns on the other pipe when
+                * doing the workaround. Sweep them under the rug.
+                */
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
                /* always enable with pattern 1 (as per spec) */
                DP &= ~(DP_PIPEB_SELECT | DP_LINK_TRAIN_MASK);
                DP |= DP_PORT_EN | DP_LINK_TRAIN_PAT_1;
@@ -3860,9 +3806,15 @@ intel_dp_link_down(struct intel_dp *intel_dp)
                DP &= ~DP_PORT_EN;
                I915_WRITE(intel_dp->output_reg, DP);
                POSTING_READ(intel_dp->output_reg);
+
+               intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A);
+               intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+               intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
        }
 
        msleep(intel_dp->panel_power_down_delay);
+
+       intel_dp->DP = DP;
 }
 
 static bool
@@ -3909,19 +3861,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
                }
        }
 
-       /* Training Pattern 3 support, Intel platforms that support HBR2 alone
-        * have support for TP3 hence that check is used along with dpcd check
-        * to ensure TP3 can be enabled.
-        * SKL < B0: due it's WaDisableHBR2 is the only exception where TP3 is
-        * supported but still not enabled.
-        */
-       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
-           intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED &&
-           intel_dp_source_supports_hbr2(dev)) {
-               intel_dp->use_tps3 = true;
-               DRM_DEBUG_KMS("Displayport TPS3 supported\n");
-       } else
-               intel_dp->use_tps3 = false;
+       DRM_DEBUG_KMS("Display Port TPS3 support: source %s, sink %s\n",
+                     yesno(intel_dp_source_supports_hbr2(intel_dp)),
+                     yesno(drm_dp_tps3_supported(intel_dp->dpcd)));
 
        /* Intermediate frequency support */
        if (is_edp(intel_dp) &&
@@ -4007,22 +3949,30 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
        return intel_dp->is_mst;
 }
 
-static void intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
+static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
        u8 buf;
+       int ret = 0;
 
        if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) {
                DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
-               return;
+               ret = -EIO;
+               goto out;
        }
 
        if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
-                              buf & ~DP_TEST_SINK_START) < 0)
+                              buf & ~DP_TEST_SINK_START) < 0) {
                DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
+               ret = -EIO;
+               goto out;
+       }
 
+       intel_dp->sink_crc.started = false;
+ out:
        hsw_enable_ips(intel_crtc);
+       return ret;
 }
 
 static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
@@ -4030,6 +3980,13 @@ static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
        u8 buf;
+       int ret;
+
+       if (intel_dp->sink_crc.started) {
+               ret = intel_dp_sink_crc_stop(intel_dp);
+               if (ret)
+                       return ret;
+       }
 
        if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0)
                return -EIO;
@@ -4037,6 +3994,8 @@ static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
        if (!(buf & DP_TEST_CRC_SUPPORTED))
                return -ENOTTY;
 
+       intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK;
+
        if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0)
                return -EIO;
 
@@ -4048,6 +4007,7 @@ static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
                return -EIO;
        }
 
+       intel_dp->sink_crc.started = true;
        return 0;
 }
 
@@ -4057,38 +4017,55 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
        struct drm_device *dev = dig_port->base.base.dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
        u8 buf;
-       int test_crc_count;
+       int count, ret;
        int attempts = 6;
-       int ret;
+       bool old_equal_new;
 
        ret = intel_dp_sink_crc_start(intel_dp);
        if (ret)
                return ret;
 
-       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) {
-               ret = -EIO;
-               goto stop;
-       }
-
-       test_crc_count = buf & DP_TEST_COUNT_MASK;
-
        do {
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+
                if (drm_dp_dpcd_readb(&intel_dp->aux,
                                      DP_TEST_SINK_MISC, &buf) < 0) {
                        ret = -EIO;
                        goto stop;
                }
-               intel_wait_for_vblank(dev, intel_crtc->pipe);
-       } while (--attempts && (buf & DP_TEST_COUNT_MASK) == test_crc_count);
+               count = buf & DP_TEST_COUNT_MASK;
+
+               /*
+                * Count might be reset during the loop. In this case
+                * last known count needs to be reset as well.
+                */
+               if (count == 0)
+                       intel_dp->sink_crc.last_count = 0;
+
+               if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) {
+                       ret = -EIO;
+                       goto stop;
+               }
+
+               old_equal_new = (count == intel_dp->sink_crc.last_count &&
+                                !memcmp(intel_dp->sink_crc.last_crc, crc,
+                                        6 * sizeof(u8)));
+
+       } while (--attempts && (count == 0 || old_equal_new));
+
+       intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK;
+       memcpy(intel_dp->sink_crc.last_crc, crc, 6 * sizeof(u8));
 
        if (attempts == 0) {
-               DRM_DEBUG_KMS("Panel is unable to calculate CRC after 6 vblanks\n");
-               ret = -ETIMEDOUT;
-               goto stop;
+               if (old_equal_new) {
+                       DRM_DEBUG_KMS("Unreliable Sink CRC counter: Current returned CRC is identical to the previous one\n");
+               } else {
+                       DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n");
+                       ret = -ETIMEDOUT;
+                       goto stop;
+               }
        }
 
-       if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0)
-               ret = -EIO;
 stop:
        intel_dp_sink_crc_stop(intel_dp);
        return ret;
@@ -4186,13 +4163,6 @@ static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
        uint8_t rxdata = 0;
        int status = 0;
 
-       intel_dp->compliance_test_active = 0;
-       intel_dp->compliance_test_type = 0;
-       intel_dp->compliance_test_data = 0;
-
-       intel_dp->aux.i2c_nack_count = 0;
-       intel_dp->aux.i2c_defer_count = 0;
-
        status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_REQUEST, &rxdata, 1);
        if (status <= 0) {
                DRM_DEBUG_KMS("Could not read test request from sink\n");
@@ -4248,10 +4218,10 @@ go_again:
                if (bret == true) {
 
                        /* check link status - esi[10] = 0x200c */
-                       if (intel_dp->active_mst_links && !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
+                       if (intel_dp->active_mst_links &&
+                           !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
                                DRM_DEBUG_KMS("channel EQ not ok, retraining\n");
                                intel_dp_start_link_train(intel_dp);
-                               intel_dp_complete_link_train(intel_dp);
                                intel_dp_stop_link_train(intel_dp);
                        }
 
@@ -4308,6 +4278,14 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
 
        WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
 
+       /*
+        * Clearing compliance test variables to allow capturing
+        * of values for next automated test request.
+        */
+       intel_dp->compliance_test_active = 0;
+       intel_dp->compliance_test_type = 0;
+       intel_dp->compliance_test_data = 0;
+
        if (!intel_encoder->base.crtc)
                return;
 
@@ -4338,11 +4316,12 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
                        DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
        }
 
-       if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
+       /* if link training is requested we should perform it always */
+       if ((intel_dp->compliance_test_type == DP_TEST_LINK_TRAINING) ||
+               (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count))) {
                DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
                              intel_encoder->base.name);
                intel_dp_start_link_train(intel_dp);
-               intel_dp_complete_link_train(intel_dp);
                intel_dp_stop_link_train(intel_dp);
        }
 }
@@ -4410,58 +4389,164 @@ edp_detect(struct intel_dp *intel_dp)
        return status;
 }
 
-static enum drm_connector_status
-ironlake_dp_detect(struct intel_dp *intel_dp)
+static bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
+                                      struct intel_digital_port *port)
 {
-       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);
+       u32 bit;
 
-       if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
-               return connector_status_disconnected;
+       switch (port->port) {
+       case PORT_A:
+               return true;
+       case PORT_B:
+               bit = SDE_PORTB_HOTPLUG;
+               break;
+       case PORT_C:
+               bit = SDE_PORTC_HOTPLUG;
+               break;
+       case PORT_D:
+               bit = SDE_PORTD_HOTPLUG;
+               break;
+       default:
+               MISSING_CASE(port->port);
+               return false;
+       }
 
-       return intel_dp_detect_dpcd(intel_dp);
+       return I915_READ(SDEISR) & bit;
+}
+
+static bool cpt_digital_port_connected(struct drm_i915_private *dev_priv,
+                                      struct intel_digital_port *port)
+{
+       u32 bit;
+
+       switch (port->port) {
+       case PORT_A:
+               return true;
+       case PORT_B:
+               bit = SDE_PORTB_HOTPLUG_CPT;
+               break;
+       case PORT_C:
+               bit = SDE_PORTC_HOTPLUG_CPT;
+               break;
+       case PORT_D:
+               bit = SDE_PORTD_HOTPLUG_CPT;
+               break;
+       case PORT_E:
+               bit = SDE_PORTE_HOTPLUG_SPT;
+               break;
+       default:
+               MISSING_CASE(port->port);
+               return false;
+       }
+
+       return I915_READ(SDEISR) & bit;
+}
+
+static bool g4x_digital_port_connected(struct drm_i915_private *dev_priv,
+                                      struct intel_digital_port *port)
+{
+       u32 bit;
+
+       switch (port->port) {
+       case PORT_B:
+               bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
+               break;
+       case PORT_C:
+               bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
+               break;
+       case PORT_D:
+               bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
+               break;
+       default:
+               MISSING_CASE(port->port);
+               return false;
+       }
+
+       return I915_READ(PORT_HOTPLUG_STAT) & bit;
+}
+
+static bool vlv_digital_port_connected(struct drm_i915_private *dev_priv,
+                                      struct intel_digital_port *port)
+{
+       u32 bit;
+
+       switch (port->port) {
+       case PORT_B:
+               bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
+               break;
+       case PORT_C:
+               bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
+               break;
+       case PORT_D:
+               bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
+               break;
+       default:
+               MISSING_CASE(port->port);
+               return false;
+       }
+
+       return I915_READ(PORT_HOTPLUG_STAT) & bit;
 }
 
-static int g4x_digital_port_connected(struct drm_device *dev,
+static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
                                       struct intel_digital_port *intel_dig_port)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t bit;
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
+       enum port port;
+       u32 bit;
 
-       if (IS_VALLEYVIEW(dev)) {
-               switch (intel_dig_port->port) {
-               case PORT_B:
-                       bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
-                       break;
-               case PORT_C:
-                       bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
-                       break;
-               case PORT_D:
-                       bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       } else {
-               switch (intel_dig_port->port) {
-               case PORT_B:
-                       bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
-                       break;
-               case PORT_C:
-                       bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
-                       break;
-               case PORT_D:
-                       bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
-                       break;
-               default:
-                       return -EINVAL;
-               }
+       intel_hpd_pin_to_port(intel_encoder->hpd_pin, &port);
+       switch (port) {
+       case PORT_A:
+               bit = BXT_DE_PORT_HP_DDIA;
+               break;
+       case PORT_B:
+               bit = BXT_DE_PORT_HP_DDIB;
+               break;
+       case PORT_C:
+               bit = BXT_DE_PORT_HP_DDIC;
+               break;
+       default:
+               MISSING_CASE(port);
+               return false;
        }
 
-       if ((I915_READ(PORT_HOTPLUG_STAT) & bit) == 0)
-               return 0;
-       return 1;
+       return I915_READ(GEN8_DE_PORT_ISR) & bit;
+}
+
+/*
+ * intel_digital_port_connected - is the specified port connected?
+ * @dev_priv: i915 private structure
+ * @port: the port to test
+ *
+ * Return %true if @port is connected, %false otherwise.
+ */
+bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
+                                        struct intel_digital_port *port)
+{
+       if (HAS_PCH_IBX(dev_priv))
+               return ibx_digital_port_connected(dev_priv, port);
+       if (HAS_PCH_SPLIT(dev_priv))
+               return cpt_digital_port_connected(dev_priv, port);
+       else if (IS_BROXTON(dev_priv))
+               return bxt_digital_port_connected(dev_priv, port);
+       else if (IS_VALLEYVIEW(dev_priv))
+               return vlv_digital_port_connected(dev_priv, port);
+       else
+               return g4x_digital_port_connected(dev_priv, port);
+}
+
+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);
+
+       if (!intel_digital_port_connected(dev_priv, intel_dig_port))
+               return connector_status_disconnected;
+
+       return intel_dp_detect_dpcd(intel_dp);
 }
 
 static enum drm_connector_status
@@ -4469,7 +4554,6 @@ g4x_dp_detect(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);
-       int ret;
 
        /* Can't disconnect eDP, but you can close the lid... */
        if (is_edp(intel_dp)) {
@@ -4481,10 +4565,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
                return status;
        }
 
-       ret = g4x_digital_port_connected(dev, intel_dig_port);
-       if (ret == -EINVAL)
-               return connector_status_unknown;
-       else if (ret == 0)
+       if (!intel_digital_port_connected(dev->dev_private, intel_dig_port))
                return connector_status_disconnected;
 
        return intel_dp_detect_dpcd(intel_dp);
@@ -4585,8 +4666,13 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                status = ironlake_dp_detect(intel_dp);
        else
                status = g4x_dp_detect(intel_dp);
-       if (status != connector_status_connected)
+       if (status != connector_status_connected) {
+               intel_dp->compliance_test_active = 0;
+               intel_dp->compliance_test_type = 0;
+               intel_dp->compliance_test_data = 0;
+
                goto out;
+       }
 
        intel_dp_probe_oui(intel_dp);
 
@@ -4600,6 +4686,14 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                goto out;
        }
 
+       /*
+        * Clearing NACK and defer counts to get their exact values
+        * while reading EDID which are required by Compliance tests
+        * 4.2.2.4 and 4.2.2.5
+        */
+       intel_dp->aux.i2c_nack_count = 0;
+       intel_dp->aux.i2c_defer_count = 0;
+
        intel_dp_set_edid(intel_dp);
 
        if (intel_encoder->type != INTEL_OUTPUT_EDP)
@@ -4728,7 +4822,7 @@ intel_dp_set_property(struct drm_connector *connector,
 
        if (property == dev_priv->broadcast_rgb_property) {
                bool old_auto = intel_dp->color_range_auto;
-               uint32_t old_range = intel_dp->color_range;
+               bool old_range = intel_dp->limited_color_range;
 
                switch (val) {
                case INTEL_BROADCAST_RGB_AUTO:
@@ -4736,18 +4830,18 @@ intel_dp_set_property(struct drm_connector *connector,
                        break;
                case INTEL_BROADCAST_RGB_FULL:
                        intel_dp->color_range_auto = false;
-                       intel_dp->color_range = 0;
+                       intel_dp->limited_color_range = false;
                        break;
                case INTEL_BROADCAST_RGB_LIMITED:
                        intel_dp->color_range_auto = false;
-                       intel_dp->color_range = DP_COLOR_RANGE_16_235;
+                       intel_dp->limited_color_range = true;
                        break;
                default:
                        return -EINVAL;
                }
 
                if (old_auto == intel_dp->color_range_auto &&
-                   old_range == intel_dp->color_range)
+                   old_range == intel_dp->limited_color_range)
                        return 0;
 
                goto done;
@@ -4802,7 +4896,7 @@ 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;
 
-       drm_dp_aux_unregister(&intel_dp->aux);
+       intel_dp_aux_fini(intel_dp);
        intel_dp_mst_encoder_cleanup(intel_dig_port);
        if (is_edp(intel_dp)) {
                cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
@@ -4947,13 +5041,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                /* indicate that we need to restart link training */
                intel_dp->train_set_valid = false;
 
-               if (HAS_PCH_SPLIT(dev)) {
-                       if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
-                               goto mst_fail;
-               } else {
-                       if (g4x_digital_port_connected(dev, intel_dig_port) != 1)
-                               goto mst_fail;
-               }
+               if (!intel_digital_port_connected(dev_priv, intel_dig_port))
+                       goto mst_fail;
 
                if (!intel_dp_get_dpcd(intel_dp)) {
                        goto mst_fail;
@@ -5028,6 +5117,13 @@ bool intel_dp_is_edp(struct drm_device *dev, enum port port)
                [PORT_E] = DVO_PORT_DPE,
        };
 
+       /*
+        * eDP not supported on g4x. so bail out early just
+        * for a bit extra safety in case the VBT is bonkers.
+        */
+       if (INTEL_INFO(dev)->gen < 5)
+               return false;
+
        if (port == PORT_A)
                return true;
 
@@ -5302,7 +5398,6 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
        struct intel_dp *intel_dp = dev_priv->drrs.dp;
        struct intel_crtc_state *config = NULL;
        struct intel_crtc *intel_crtc = NULL;
-       u32 reg, val;
        enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
 
        if (refresh_rate <= 0) {
@@ -5364,9 +5459,10 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
                        DRM_ERROR("Unsupported refreshrate type\n");
                }
        } else if (INTEL_INFO(dev)->gen > 6) {
-               reg = PIPECONF(intel_crtc->config->cpu_transcoder);
-               val = I915_READ(reg);
+               u32 reg = PIPECONF(intel_crtc->config->cpu_transcoder);
+               u32 val;
 
+               val = I915_READ(reg);
                if (index > DRRS_HIGH_RR) {
                        if (IS_VALLEYVIEW(dev))
                                val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
@@ -5765,7 +5861,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_connector->panel.backlight.power = intel_edp_backlight_power;
        intel_panel_setup_backlight(connector, pipe);
 
        return true;
@@ -5781,7 +5877,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum port port = intel_dig_port->port;
-       int type;
+       int type, ret;
 
        intel_dp->pps_pipe = INVALID_PIPE;
 
@@ -5802,6 +5898,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        else
                intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl;
 
+       if (HAS_DDI(dev))
+               intel_dp->prepare_link_retrain = intel_ddi_prepare_link_retrain;
+
        /* Preserve the current hw state. */
        intel_dp->DP = I915_READ(intel_dp->output_reg);
        intel_dp->attached_connector = intel_connector;
@@ -5853,6 +5952,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                break;
        case PORT_B:
                intel_encoder->hpd_pin = HPD_PORT_B;
+               if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
+                       intel_encoder->hpd_pin = HPD_PORT_A;
                break;
        case PORT_C:
                intel_encoder->hpd_pin = HPD_PORT_C;
@@ -5877,7 +5978,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                pps_unlock(intel_dp);
        }
 
-       intel_dp_aux_init(intel_dp, intel_connector);
+       ret = intel_dp_aux_init(intel_dp, intel_connector);
+       if (ret)
+               goto fail;
 
        /* init MST on ports that can support it */
        if (HAS_DP_MST(dev) &&
@@ -5886,20 +5989,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                                          intel_connector->base.base.id);
 
        if (!intel_edp_init_connector(intel_dp, intel_connector)) {
-               drm_dp_aux_unregister(&intel_dp->aux);
-               if (is_edp(intel_dp)) {
-                       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-                       /*
-                        * 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);
-               }
-               drm_connector_unregister(connector);
-               drm_connector_cleanup(connector);
-               return false;
+               intel_dp_aux_fini(intel_dp);
+               intel_dp_mst_encoder_cleanup(intel_dig_port);
+               goto fail;
        }
 
        intel_dp_add_properties(intel_dp, connector);
@@ -5916,6 +6008,22 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        i915_debugfs_connector_add(connector);
 
        return true;
+
+fail:
+       if (is_edp(intel_dp)) {
+               cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+               /*
+                * 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);
+       }
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+
+       return false;
 }
 
 void
@@ -5932,10 +6040,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
                return;
 
        intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(intel_dig_port);
-               return;
-       }
+       if (!intel_connector)
+               goto err_connector_alloc;
 
        intel_encoder = &intel_dig_port->base;
        encoder = &intel_encoder->base;
@@ -5953,6 +6059,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
                intel_encoder->pre_enable = chv_pre_enable_dp;
                intel_encoder->enable = vlv_enable_dp;
                intel_encoder->post_disable = chv_post_disable_dp;
+               intel_encoder->post_pll_disable = chv_dp_post_pll_disable;
        } else if (IS_VALLEYVIEW(dev)) {
                intel_encoder->pre_pll_enable = vlv_dp_pre_pll_enable;
                intel_encoder->pre_enable = vlv_pre_enable_dp;
@@ -5982,11 +6089,18 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
        intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
        dev_priv->hotplug.irq_port[port] = intel_dig_port;
 
-       if (!intel_dp_init_connector(intel_dig_port, intel_connector)) {
-               drm_encoder_cleanup(encoder);
-               kfree(intel_dig_port);
-               kfree(intel_connector);
-       }
+       if (!intel_dp_init_connector(intel_dig_port, intel_connector))
+               goto err_init_connector;
+
+       return;
+
+err_init_connector:
+       drm_encoder_cleanup(encoder);
+       kfree(intel_connector);
+err_connector_alloc:
+       kfree(intel_dig_port);
+
+       return;
 }
 
 void intel_dp_mst_suspend(struct drm_device *dev)