]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/i915/intel_dp.c
drm/i915/dp: generate and cache sink rate array for all DP, not just eDP 1.4
[karo-tx-linux.git] / drivers / gpu / drm / i915 / intel_dp.c
index d1670b8afbf5794c2edf0399dc7271d62a1b55ba..b38cba7d5abc7e1bdd6fa495de7b4a43a995ea41 100644 (file)
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/types.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
+#include <asm/byteorder.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
@@ -131,6 +133,34 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
                                      enum pipe pipe);
 static void intel_dp_unset_edid(struct intel_dp *intel_dp);
 
+static int intel_dp_num_rates(u8 link_bw_code)
+{
+       switch (link_bw_code) {
+       default:
+               WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n",
+                    link_bw_code);
+       case DP_LINK_BW_1_62:
+               return 1;
+       case DP_LINK_BW_2_7:
+               return 2;
+       case DP_LINK_BW_5_4:
+               return 3;
+       }
+}
+
+/* update sink rates from dpcd */
+static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
+{
+       int i, num_rates;
+
+       num_rates = intel_dp_num_rates(intel_dp->dpcd[DP_MAX_LINK_RATE]);
+
+       for (i = 0; i < num_rates; i++)
+               intel_dp->sink_rates[i] = default_rates[i];
+
+       intel_dp->num_sink_rates = num_rates;
+}
+
 static int
 intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 {
@@ -203,34 +233,25 @@ intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp)
        return max_dotclk;
 }
 
-static int
-intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
-{
-       if (intel_dp->num_sink_rates) {
-               *sink_rates = intel_dp->sink_rates;
-               return intel_dp->num_sink_rates;
-       }
-
-       *sink_rates = default_rates;
-
-       return (intel_dp->max_sink_link_bw >> 3) + 1;
-}
-
-static int
-intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
+static void
+intel_dp_set_source_rates(struct intel_dp *intel_dp)
 {
        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);
+       const int *source_rates;
        int size;
 
+       /* This should only be done once */
+       WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates);
+
        if (IS_GEN9_LP(dev_priv)) {
-               *source_rates = bxt_rates;
+               source_rates = bxt_rates;
                size = ARRAY_SIZE(bxt_rates);
-       } else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
-               *source_rates = skl_rates;
+       } else if (IS_GEN9_BC(dev_priv)) {
+               source_rates = skl_rates;
                size = ARRAY_SIZE(skl_rates);
        } else {
-               *source_rates = default_rates;
+               source_rates = default_rates;
                size = ARRAY_SIZE(default_rates);
        }
 
@@ -238,7 +259,8 @@ intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
        if (!intel_dp_source_supports_hbr2(intel_dp))
                size--;
 
-       return size;
+       intel_dp->source_rates = source_rates;
+       intel_dp->num_source_rates = size;
 }
 
 static int intersect_rates(const int *source_rates, int source_len,
@@ -264,33 +286,47 @@ static int intersect_rates(const int *source_rates, int source_len,
        return k;
 }
 
+/* return index of rate in rates array, or -1 if not found */
+static int intel_dp_rate_index(const int *rates, int len, int rate)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (rate == rates[i])
+                       return i;
+
+       return -1;
+}
+
 static int intel_dp_common_rates(struct intel_dp *intel_dp,
                                 int *common_rates)
 {
-       const int *source_rates, *sink_rates;
-       int source_len, sink_len;
+       int max_rate = drm_dp_bw_code_to_link_rate(intel_dp->max_sink_link_bw);
+       int i, common_len;
 
-       sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-       source_len = intel_dp_source_rates(intel_dp, &source_rates);
+       common_len = intersect_rates(intel_dp->source_rates,
+                                    intel_dp->num_source_rates,
+                                    intel_dp->sink_rates,
+                                    intel_dp->num_sink_rates,
+                                    common_rates);
+
+       /* Limit results by potentially reduced max rate */
+       for (i = 0; i < common_len; i++) {
+               if (common_rates[common_len - i - 1] <= max_rate)
+                       return common_len - i;
+       }
 
-       return intersect_rates(source_rates, source_len,
-                              sink_rates, sink_len,
-                              common_rates);
+       return 0;
 }
 
 static int intel_dp_link_rate_index(struct intel_dp *intel_dp,
                                    int *common_rates, int link_rate)
 {
        int common_len;
-       int index;
 
        common_len = intel_dp_common_rates(intel_dp, common_rates);
-       for (index = 0; index < common_len; index++) {
-               if (link_rate == common_rates[common_len - index - 1])
-                       return common_len - index - 1;
-       }
 
-       return -1;
+       return intel_dp_rate_index(common_rates, common_len, link_rate);
 }
 
 int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
@@ -394,14 +430,12 @@ static void pps_lock(struct intel_dp *intel_dp)
        struct intel_encoder *encoder = &intel_dig_port->base;
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum intel_display_power_domain power_domain;
 
        /*
         * See vlv_power_sequencer_reset() why we need
         * a power domain reference here.
         */
-       power_domain = intel_display_port_aux_power_domain(encoder);
-       intel_display_power_get(dev_priv, power_domain);
+       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
 
        mutex_lock(&dev_priv->pps_mutex);
 }
@@ -412,12 +446,10 @@ static void pps_unlock(struct intel_dp *intel_dp)
        struct intel_encoder *encoder = &intel_dig_port->base;
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum intel_display_power_domain power_domain;
 
        mutex_unlock(&dev_priv->pps_mutex);
 
-       power_domain = intel_display_port_aux_power_domain(encoder);
-       intel_display_power_put(dev_priv, power_domain);
+       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
 }
 
 static void
@@ -916,7 +948,7 @@ static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
         * divide by 2000 and use that
         */
        if (intel_dig_port->port == PORT_A)
-               return DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 2000);
+               return DIV_ROUND_CLOSEST(dev_priv->cdclk.hw.cdclk, 2000);
        else
                return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
 }
@@ -1488,20 +1520,19 @@ static void snprintf_int_array(char *str, size_t len,
 
 static void intel_dp_print_rates(struct intel_dp *intel_dp)
 {
-       const int *source_rates, *sink_rates;
-       int source_len, sink_len, common_len;
+       int common_len;
        int common_rates[DP_MAX_SUPPORTED_RATES];
        char str[128]; /* FIXME: too big for stack? */
 
        if ((drm_debug & DRM_UT_KMS) == 0)
                return;
 
-       source_len = intel_dp_source_rates(intel_dp, &source_rates);
-       snprintf_int_array(str, sizeof(str), source_rates, source_len);
+       snprintf_int_array(str, sizeof(str),
+                          intel_dp->source_rates, intel_dp->num_source_rates);
        DRM_DEBUG_KMS("source rates: %s\n", str);
 
-       sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-       snprintf_int_array(str, sizeof(str), sink_rates, sink_len);
+       snprintf_int_array(str, sizeof(str),
+                          intel_dp->sink_rates, intel_dp->num_sink_rates);
        DRM_DEBUG_KMS("sink rates: %s\n", str);
 
        common_len = intel_dp_common_rates(intel_dp, common_rates);
@@ -1540,17 +1571,6 @@ bool intel_dp_read_desc(struct intel_dp *intel_dp)
        return true;
 }
 
-static int rate_to_index(int find, const int *rates)
-{
-       int i = 0;
-
-       for (i = 0; i < DP_MAX_SUPPORTED_RATES; ++i)
-               if (find == rates[i])
-                       break;
-
-       return i;
-}
-
 int
 intel_dp_max_link_rate(struct intel_dp *intel_dp)
 {
@@ -1566,13 +1586,20 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
 {
-       return rate_to_index(rate, intel_dp->sink_rates);
+       int i = intel_dp_rate_index(intel_dp->sink_rates,
+                                   intel_dp->num_sink_rates, rate);
+
+       if (WARN_ON(i < 0))
+               i = 0;
+
+       return i;
 }
 
 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) {
+       /* eDP 1.4 rate select method. */
+       if (intel_dp->use_rate_select) {
                *link_bw = 0;
                *rate_select =
                        intel_dp_rate_select(intel_dp, port_clock);
@@ -1593,6 +1620,13 @@ static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
        if (bpc > 0)
                bpp = min(bpp, 3*bpc);
 
+       /* For DP Compliance we override the computed bpp for the pipe */
+       if (intel_dp->compliance.test_data.bpc != 0) {
+               pipe_config->pipe_bpp = 3*intel_dp->compliance.test_data.bpc;
+               pipe_config->dither_force_disable = pipe_config->pipe_bpp == 6*3;
+               DRM_DEBUG_KMS("Setting pipe_bpp to %d\n",
+                             pipe_config->pipe_bpp);
+       }
        return bpp;
 }
 
@@ -1613,6 +1647,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        /* Conveniently, the link BW constants become indices with a shift...*/
        int min_clock = 0;
        int max_clock;
+       int link_rate_index;
        int bpp, mode_rate;
        int link_avail, link_clock;
        int common_rates[DP_MAX_SUPPORTED_RATES] = {};
@@ -1654,6 +1689,15 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
                return false;
 
+       /* Use values requested by Compliance Test Request */
+       if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
+               link_rate_index = intel_dp_link_rate_index(intel_dp,
+                                                          common_rates,
+                                                          intel_dp->compliance.test_link_rate);
+               if (link_rate_index >= 0)
+                       min_clock = max_clock = link_rate_index;
+               min_lane_count = max_lane_count = intel_dp->compliance.test_lane_count;
+       }
        DRM_DEBUG_KMS("DP link computation with max lane count %i "
                      "max bw %d pixel clock %iKHz\n",
                      max_lane_count, common_rates[max_clock],
@@ -1753,8 +1797,7 @@ found:
         * DPLL0 VCO may need to be adjusted to get the correct
         * clock for eDP. This will affect cdclk as well.
         */
-       if (is_edp(intel_dp) &&
-           (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))) {
+       if (is_edp(intel_dp) && IS_GEN9_BC(dev_priv)) {
                int vco;
 
                switch (pipe_config->port_clock / 2) {
@@ -1767,7 +1810,7 @@ found:
                        break;
                }
 
-               to_intel_atomic_state(pipe_config->base.state)->cdclk_pll_vco = vco;
+               to_intel_atomic_state(pipe_config->base.state)->cdclk.logical.vco = vco;
        }
 
        if (!HAS_DDI(dev_priv))
@@ -1987,9 +2030,7 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum intel_display_power_domain power_domain;
        u32 pp;
        i915_reg_t pp_stat_reg, pp_ctrl_reg;
        bool need_to_disable = !intel_dp->want_panel_vdd;
@@ -2005,8 +2046,7 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
        if (edp_have_panel_vdd(intel_dp))
                return need_to_disable;
 
-       power_domain = intel_display_port_aux_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
+       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
 
        DRM_DEBUG_KMS("Turning eDP port %c VDD on\n",
                      port_name(intel_dig_port->port));
@@ -2064,8 +2104,6 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_digital_port *intel_dig_port =
                dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
-       enum intel_display_power_domain power_domain;
        u32 pp;
        i915_reg_t pp_stat_reg, pp_ctrl_reg;
 
@@ -2095,8 +2133,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
        if ((pp & PANEL_POWER_ON) == 0)
                intel_dp->panel_power_off_time = ktime_get_boottime();
 
-       power_domain = intel_display_port_aux_power_domain(intel_encoder);
-       intel_display_power_put(dev_priv, power_domain);
+       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
 }
 
 static void edp_panel_vdd_work(struct work_struct *__work)
@@ -2209,11 +2246,8 @@ void intel_edp_panel_on(struct intel_dp *intel_dp)
 
 static void edp_panel_off(struct intel_dp *intel_dp)
 {
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum intel_display_power_domain power_domain;
        u32 pp;
        i915_reg_t pp_ctrl_reg;
 
@@ -2245,8 +2279,7 @@ static void edp_panel_off(struct intel_dp *intel_dp)
        wait_panel_off(intel_dp);
 
        /* We got a reference when we enabled the VDD. */
-       power_domain = intel_display_port_aux_power_domain(intel_encoder);
-       intel_display_power_put(dev_priv, power_domain);
+       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
 }
 
 void intel_edp_panel_off(struct intel_dp *intel_dp)
@@ -2492,12 +2525,11 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
        enum port port = dp_to_dig_port(intel_dp)->port;
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum intel_display_power_domain power_domain;
        u32 tmp;
        bool ret;
 
-       power_domain = intel_display_port_power_domain(encoder);
-       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+       if (!intel_display_power_get_if_enabled(dev_priv,
+                                               encoder->power_domain))
                return false;
 
        ret = false;
@@ -2533,7 +2565,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
        ret = true;
 
 out:
-       intel_display_power_put(dev_priv, power_domain);
+       intel_display_power_put(dev_priv, encoder->power_domain);
 
        return ret;
 }
@@ -3080,9 +3112,8 @@ intel_dp_voltage_max(struct intel_dp *intel_dp)
        if (IS_GEN9_LP(dev_priv))
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
        else if (INTEL_GEN(dev_priv) >= 9) {
-               if (dev_priv->vbt.edp.low_vswing && port == PORT_A)
-                       return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
-               return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
+               struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+               return intel_ddi_dp_voltage_max(encoder);
        } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
        else if (IS_GEN7(dev_priv) && port == PORT_A)
@@ -3693,6 +3724,11 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
                intel_dp->num_sink_rates = i;
        }
 
+       if (intel_dp->num_sink_rates)
+               intel_dp->use_rate_select = true;
+       else
+               intel_dp_set_sink_rates(intel_dp);
+
        return true;
 }
 
@@ -3703,6 +3739,10 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        if (!intel_dp_read_dpcd(intel_dp))
                return false;
 
+       /* Don't clobber cached eDP rates. */
+       if (!is_edp(intel_dp))
+               intel_dp_set_sink_rates(intel_dp);
+
        if (drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT,
                             &intel_dp->sink_count, 1) < 0)
                return false;
@@ -3922,19 +3962,112 @@ intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
 
 static uint8_t intel_dp_autotest_link_training(struct intel_dp *intel_dp)
 {
-       uint8_t test_result = DP_TEST_ACK;
-       return test_result;
+       int status = 0;
+       int min_lane_count = 1;
+       int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+       int link_rate_index, test_link_rate;
+       uint8_t test_lane_count, test_link_bw;
+       /* (DP CTS 1.2)
+        * 4.3.1.11
+        */
+       /* Read the TEST_LANE_COUNT and TEST_LINK_RTAE fields (DP CTS 3.1.4) */
+       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LANE_COUNT,
+                                  &test_lane_count);
+
+       if (status <= 0) {
+               DRM_DEBUG_KMS("Lane count read failed\n");
+               return DP_TEST_NAK;
+       }
+       test_lane_count &= DP_MAX_LANE_COUNT_MASK;
+       /* Validate the requested lane count */
+       if (test_lane_count < min_lane_count ||
+           test_lane_count > intel_dp->max_sink_lane_count)
+               return DP_TEST_NAK;
+
+       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LINK_RATE,
+                                  &test_link_bw);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("Link Rate read failed\n");
+               return DP_TEST_NAK;
+       }
+       /* Validate the requested link rate */
+       test_link_rate = drm_dp_bw_code_to_link_rate(test_link_bw);
+       link_rate_index = intel_dp_link_rate_index(intel_dp,
+                                                  common_rates,
+                                                  test_link_rate);
+       if (link_rate_index < 0)
+               return DP_TEST_NAK;
+
+       intel_dp->compliance.test_lane_count = test_lane_count;
+       intel_dp->compliance.test_link_rate = test_link_rate;
+
+       return DP_TEST_ACK;
 }
 
 static uint8_t intel_dp_autotest_video_pattern(struct intel_dp *intel_dp)
 {
-       uint8_t test_result = DP_TEST_NAK;
-       return test_result;
+       uint8_t test_pattern;
+       uint16_t test_misc;
+       __be16 h_width, v_height;
+       int status = 0;
+
+       /* Read the TEST_PATTERN (DP CTS 3.1.5) */
+       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_PATTERN,
+                                 &test_pattern, 1);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("Test pattern read failed\n");
+               return DP_TEST_NAK;
+       }
+       if (test_pattern != DP_COLOR_RAMP)
+               return DP_TEST_NAK;
+
+       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_H_WIDTH_HI,
+                                 &h_width, 2);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("H Width read failed\n");
+               return DP_TEST_NAK;
+       }
+
+       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_V_HEIGHT_HI,
+                                 &v_height, 2);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("V Height read failed\n");
+               return DP_TEST_NAK;
+       }
+
+       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_MISC0,
+                                 &test_misc, 1);
+       if (status <= 0) {
+               DRM_DEBUG_KMS("TEST MISC read failed\n");
+               return DP_TEST_NAK;
+       }
+       if ((test_misc & DP_TEST_COLOR_FORMAT_MASK) != DP_COLOR_FORMAT_RGB)
+               return DP_TEST_NAK;
+       if (test_misc & DP_TEST_DYNAMIC_RANGE_CEA)
+               return DP_TEST_NAK;
+       switch (test_misc & DP_TEST_BIT_DEPTH_MASK) {
+       case DP_TEST_BIT_DEPTH_6:
+               intel_dp->compliance.test_data.bpc = 6;
+               break;
+       case DP_TEST_BIT_DEPTH_8:
+               intel_dp->compliance.test_data.bpc = 8;
+               break;
+       default:
+               return DP_TEST_NAK;
+       }
+
+       intel_dp->compliance.test_data.video_pattern = test_pattern;
+       intel_dp->compliance.test_data.hdisplay = be16_to_cpu(h_width);
+       intel_dp->compliance.test_data.vdisplay = be16_to_cpu(v_height);
+       /* Set test active flag here so userspace doesn't interrupt things */
+       intel_dp->compliance.test_active = 1;
+
+       return DP_TEST_ACK;
 }
 
 static uint8_t intel_dp_autotest_edid(struct intel_dp *intel_dp)
 {
-       uint8_t test_result = DP_TEST_NAK;
+       uint8_t test_result = DP_TEST_ACK;
        struct intel_connector *intel_connector = intel_dp->attached_connector;
        struct drm_connector *connector = &intel_connector->base;
 
@@ -3969,7 +4102,7 @@ static uint8_t intel_dp_autotest_edid(struct intel_dp *intel_dp)
                        DRM_DEBUG_KMS("Failed to write EDID checksum\n");
 
                test_result = DP_TEST_ACK | DP_TEST_EDID_CHECKSUM_WRITE;
-               intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_STANDARD;
+               intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_PREFERRED;
        }
 
        /* Set test active flag here so userspace doesn't interrupt things */
@@ -3987,45 +4120,42 @@ static uint8_t intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp)
 static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
 {
        uint8_t response = DP_TEST_NAK;
-       uint8_t rxdata = 0;
-       int status = 0;
+       uint8_t request = 0;
+       int status;
 
-       status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_REQUEST, &rxdata, 1);
+       status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_REQUEST, &request);
        if (status <= 0) {
                DRM_DEBUG_KMS("Could not read test request from sink\n");
                goto update_status;
        }
 
-       switch (rxdata) {
+       switch (request) {
        case DP_TEST_LINK_TRAINING:
                DRM_DEBUG_KMS("LINK_TRAINING test requested\n");
-               intel_dp->compliance.test_type = DP_TEST_LINK_TRAINING;
                response = intel_dp_autotest_link_training(intel_dp);
                break;
        case DP_TEST_LINK_VIDEO_PATTERN:
                DRM_DEBUG_KMS("TEST_PATTERN test requested\n");
-               intel_dp->compliance.test_type = DP_TEST_LINK_VIDEO_PATTERN;
                response = intel_dp_autotest_video_pattern(intel_dp);
                break;
        case DP_TEST_LINK_EDID_READ:
                DRM_DEBUG_KMS("EDID test requested\n");
-               intel_dp->compliance.test_type = DP_TEST_LINK_EDID_READ;
                response = intel_dp_autotest_edid(intel_dp);
                break;
        case DP_TEST_LINK_PHY_TEST_PATTERN:
                DRM_DEBUG_KMS("PHY_PATTERN test requested\n");
-               intel_dp->compliance.test_type = DP_TEST_LINK_PHY_TEST_PATTERN;
                response = intel_dp_autotest_phy_pattern(intel_dp);
                break;
        default:
-               DRM_DEBUG_KMS("Invalid test request '%02x'\n", rxdata);
+               DRM_DEBUG_KMS("Invalid test request '%02x'\n", request);
                break;
        }
 
+       if (response & DP_TEST_ACK)
+               intel_dp->compliance.test_type = request;
+
 update_status:
-       status = drm_dp_dpcd_write(&intel_dp->aux,
-                                  DP_TEST_RESPONSE,
-                                  &response, 1);
+       status = drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, response);
        if (status <= 0)
                DRM_DEBUG_KMS("Could not write test response to sink\n");
 }
@@ -4137,9 +4267,8 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
        if (!intel_dp->lane_count)
                return;
 
-       /* 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))) {
+       /* Retrain if Channel EQ or CR not ok */
+       if (!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);
 
@@ -4164,6 +4293,7 @@ static bool
 intel_dp_short_pulse(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
        u8 sink_irq_vector = 0;
        u8 old_sink_count = intel_dp->sink_count;
        bool ret;
@@ -4197,7 +4327,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
                                   sink_irq_vector);
 
                if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST)
-                       DRM_DEBUG_DRIVER("Test request in short pulse not handled\n");
+                       intel_dp_handle_test_request(intel_dp);
                if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ))
                        DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
        }
@@ -4205,6 +4335,11 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
        drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
        intel_dp_check_link_status(intel_dp);
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
+               DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
+               /* Send a Hotplug Uevent to userspace to start modeset */
+               drm_kms_helper_hotplug_event(intel_encoder->base.dev);
+       }
 
        return true;
 }
@@ -4213,9 +4348,13 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
 static enum drm_connector_status
 intel_dp_detect_dpcd(struct intel_dp *intel_dp)
 {
+       struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
        uint8_t *dpcd = intel_dp->dpcd;
        uint8_t type;
 
+       if (lspcon->active)
+               lspcon_resume(lspcon);
+
        if (!intel_dp_get_dpcd(intel_dp))
                return connector_status_disconnected;
 
@@ -4474,11 +4613,9 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
        struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_device *dev = connector->dev;
        enum drm_connector_status status;
-       enum intel_display_power_domain power_domain;
        u8 sink_irq_vector = 0;
 
-       power_domain = intel_display_port_aux_power_domain(intel_encoder);
-       intel_display_power_get(to_i915(dev), power_domain);
+       intel_display_power_get(to_i915(dev), intel_dp->aux_power_domain);
 
        /* Can't disconnect eDP, but you can close the lid... */
        if (is_edp(intel_dp))
@@ -4511,11 +4648,15 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
                      yesno(intel_dp_source_supports_hbr2(intel_dp)),
                      yesno(drm_dp_tps3_supported(intel_dp->dpcd)));
 
-       /* Set the max lane count for sink */
-       intel_dp->max_sink_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
+       if (intel_dp->reset_link_params) {
+               /* Set the max lane count for sink */
+               intel_dp->max_sink_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
 
-       /* Set the max link BW for sink */
-       intel_dp->max_sink_link_bw = intel_dp_max_link_bw(intel_dp);
+               /* Set the max link BW for sink */
+               intel_dp->max_sink_link_bw = intel_dp_max_link_bw(intel_dp);
+
+               intel_dp->reset_link_params = false;
+       }
 
        intel_dp_print_rates(intel_dp);
 
@@ -4575,7 +4716,7 @@ out:
        if (status != connector_status_connected && !intel_dp->is_mst)
                intel_dp_unset_edid(intel_dp);
 
-       intel_display_power_put(to_i915(dev), power_domain);
+       intel_display_power_put(to_i915(dev), intel_dp->aux_power_domain);
        return status;
 }
 
@@ -4603,7 +4744,6 @@ intel_dp_force(struct drm_connector *connector)
        struct intel_dp *intel_dp = intel_attached_dp(connector);
        struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
        struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
-       enum intel_display_power_domain power_domain;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
@@ -4612,12 +4752,11 @@ intel_dp_force(struct drm_connector *connector)
        if (connector->status != connector_status_connected)
                return;
 
-       power_domain = intel_display_port_aux_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
+       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
 
        intel_dp_set_edid(intel_dp);
 
-       intel_display_power_put(dev_priv, power_domain);
+       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
 
        if (intel_encoder->type != INTEL_OUTPUT_EDP)
                intel_encoder->type = INTEL_OUTPUT_DP;
@@ -4852,7 +4991,6 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum intel_display_power_domain power_domain;
 
        lockdep_assert_held(&dev_priv->pps_mutex);
 
@@ -4866,8 +5004,7 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
         * indefinitely.
         */
        DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
-       power_domain = intel_display_port_aux_power_domain(&intel_dig_port->base);
-       intel_display_power_get(dev_priv, power_domain);
+       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
 
        edp_panel_vdd_schedule_off(intel_dp);
 }
@@ -4897,6 +5034,8 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder)
        if (lspcon->active)
                lspcon_resume(lspcon);
 
+       intel_dp->reset_link_params = true;
+
        pps_lock(intel_dp);
 
        if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
@@ -4939,10 +5078,8 @@ enum irqreturn
 intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 {
        struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       enum intel_display_power_domain power_domain;
        enum irqreturn ret = IRQ_NONE;
 
        if (intel_dig_port->base.type != INTEL_OUTPUT_EDP &&
@@ -4966,12 +5103,12 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                      long_hpd ? "long" : "short");
 
        if (long_hpd) {
+               intel_dp->reset_link_params = true;
                intel_dp->detect_done = false;
                return IRQ_NONE;
        }
 
-       power_domain = intel_display_port_aux_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
+       intel_display_power_get(dev_priv, intel_dp->aux_power_domain);
 
        if (intel_dp->is_mst) {
                if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
@@ -4999,7 +5136,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
        ret = IRQ_HANDLED;
 
 put_power:
-       intel_display_power_put(dev_priv, power_domain);
+       intel_display_power_put(dev_priv, intel_dp->aux_power_domain);
 
        return ret;
 }
@@ -5790,6 +5927,41 @@ out_vdd_off:
        return false;
 }
 
+/* Set up the hotplug pin and aux power domain. */
+static void
+intel_dp_init_connector_port_info(struct intel_digital_port *intel_dig_port)
+{
+       struct intel_encoder *encoder = &intel_dig_port->base;
+       struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+       switch (intel_dig_port->port) {
+       case PORT_A:
+               encoder->hpd_pin = HPD_PORT_A;
+               intel_dp->aux_power_domain = POWER_DOMAIN_AUX_A;
+               break;
+       case PORT_B:
+               encoder->hpd_pin = HPD_PORT_B;
+               intel_dp->aux_power_domain = POWER_DOMAIN_AUX_B;
+               break;
+       case PORT_C:
+               encoder->hpd_pin = HPD_PORT_C;
+               intel_dp->aux_power_domain = POWER_DOMAIN_AUX_C;
+               break;
+       case PORT_D:
+               encoder->hpd_pin = HPD_PORT_D;
+               intel_dp->aux_power_domain = POWER_DOMAIN_AUX_D;
+               break;
+       case PORT_E:
+               encoder->hpd_pin = HPD_PORT_E;
+
+               /* FIXME: Check VBT for actual wiring of PORT E */
+               intel_dp->aux_power_domain = POWER_DOMAIN_AUX_D;
+               break;
+       default:
+               MISSING_CASE(intel_dig_port->port);
+       }
+}
+
 bool
 intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                        struct intel_connector *intel_connector)
@@ -5807,6 +5979,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                 intel_dig_port->max_lanes, port_name(port)))
                return false;
 
+       intel_dp_set_source_rates(intel_dp);
+
+       intel_dp->reset_link_params = true;
        intel_dp->pps_pipe = INVALID_PIPE;
        intel_dp->active_pipe = INVALID_PIPE;
 
@@ -5863,6 +6038,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        connector->interlace_allowed = true;
        connector->doublescan_allowed = 0;
 
+       intel_dp_init_connector_port_info(intel_dig_port);
+
        intel_dp_aux_init(intel_dp);
 
        INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
@@ -5875,29 +6052,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        else
                intel_connector->get_hw_state = intel_connector_get_hw_state;
 
-       /* Set up the hotplug pin. */
-       switch (port) {
-       case PORT_A:
-               intel_encoder->hpd_pin = HPD_PORT_A;
-               break;
-       case PORT_B:
-               intel_encoder->hpd_pin = HPD_PORT_B;
-               if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
-                       intel_encoder->hpd_pin = HPD_PORT_A;
-               break;
-       case PORT_C:
-               intel_encoder->hpd_pin = HPD_PORT_C;
-               break;
-       case PORT_D:
-               intel_encoder->hpd_pin = HPD_PORT_D;
-               break;
-       case PORT_E:
-               intel_encoder->hpd_pin = HPD_PORT_E;
-               break;
-       default:
-               BUG();
-       }
-
        /* init MST on ports that can support it */
        if (HAS_DP_MST(dev_priv) && !is_edp(intel_dp) &&
            (port == PORT_B || port == PORT_C || port == PORT_D))
@@ -5982,6 +6136,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
        intel_dig_port->max_lanes = 4;
 
        intel_encoder->type = INTEL_OUTPUT_DP;
+       intel_encoder->power_domain = intel_port_to_power_domain(port);
        if (IS_CHERRYVIEW(dev_priv)) {
                if (port == PORT_D)
                        intel_encoder->crtc_mask = 1 << 2;