diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 834820b0b766..8aee7d77ce9d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -784,9 +784,18 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder, case DPLL_CRTL1_LINK_RATE_810: link_clock = 81000; break; + case DPLL_CRTL1_LINK_RATE_1080: + link_clock = 108000; + break; case DPLL_CRTL1_LINK_RATE_1350: link_clock = 135000; break; + case DPLL_CRTL1_LINK_RATE_1620: + link_clock = 162000; + break; + case DPLL_CRTL1_LINK_RATE_2160: + link_clock = 216000; + break; case DPLL_CRTL1_LINK_RATE_2700: link_clock = 270000; break; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 18d4a7cad652..a99f7fff47a8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -84,6 +84,11 @@ static const struct dp_link_dpll chv_dpll[] = { { DP_LINK_BW_5_4, /* m2_int = 27, m2_fraction = 0 */ { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } } }; +/* Skylake supports following rates */ +static const uint32_t gen9_rates[] = { 162000, 216000, 270000, 324000, + 432000, 540000 }; + +static const uint32_t default_rates[] = { 162000, 270000, 540000 }; /** * is_edp - is the given port attached to an eDP panel (either CPU or PCH) @@ -1144,6 +1149,25 @@ intel_read_sink_rates(struct intel_dp *intel_dp, uint32_t *sink_rates) return i; } +static int +intel_read_source_rates(struct intel_dp *intel_dp, uint32_t *source_rates) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + int i; + int max_default_rate; + + if (INTEL_INFO(dev)->gen >= 9 && intel_dp->supported_rates[0]) { + for (i = 0; i < ARRAY_SIZE(gen9_rates); ++i) + source_rates[i] = gen9_rates[i]; + } else { + /* Index of the max_link_bw supported + 1 */ + max_default_rate = (intel_dp_max_link_bw(intel_dp) >> 3) + 1; + for (i = 0; i < max_default_rate; ++i) + source_rates[i] = default_rates[i]; + } + return i; +} + static void intel_dp_set_clock(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, int link_bw) @@ -1177,6 +1201,45 @@ intel_dp_set_clock(struct intel_encoder *encoder, } } +static int intel_supported_rates(const uint32_t *source_rates, int source_len, +const uint32_t *sink_rates, int sink_len, uint32_t *supported_rates) +{ + int i = 0, j = 0, k = 0; + + /* For panels with edp version less than 1.4 */ + if (sink_len == 0) { + for (i = 0; i < source_len; ++i) + supported_rates[i] = source_rates[i]; + return source_len; + } + + /* For edp1.4 panels, find the common rates between source and sink */ + while (i < source_len && j < sink_len) { + if (source_rates[i] == sink_rates[j]) { + supported_rates[k] = source_rates[i]; + ++k; + ++i; + ++j; + } else if (source_rates[i] < sink_rates[j]) { + ++i; + } else { + ++j; + } + } + return k; +} + +static int rate_to_index(uint32_t find, const uint32_t *rates) +{ + int i = 0; + + for (i = 0; i < DP_MAX_SUPPORTED_RATES; ++i) + if (find == rates[i]) + break; + + return i; +} + bool intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) @@ -1193,10 +1256,25 @@ intel_dp_compute_config(struct intel_encoder *encoder, int max_lane_count = intel_dp_max_lane_count(intel_dp); /* Conveniently, the link BW constants become indices with a shift...*/ int min_clock = 0; - int max_clock = intel_dp_max_link_bw(intel_dp) >> 3; + int max_clock; int bpp, mode_rate; - static int bws[] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7, DP_LINK_BW_5_4 }; int link_avail, link_clock; + uint32_t sink_rates[8]; + uint32_t supported_rates[8] = {0}; + uint32_t source_rates[8]; + int source_len, sink_len, supported_len; + + sink_len = intel_read_sink_rates(intel_dp, sink_rates); + + source_len = intel_read_source_rates(intel_dp, source_rates); + + supported_len = intel_supported_rates(source_rates, source_len, + sink_rates, sink_len, supported_rates); + + /* No common link rates between source and sink */ + WARN_ON(supported_len <= 0); + + max_clock = supported_len - 1; if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A) pipe_config->has_pch_encoder = true; @@ -1220,8 +1298,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, return false; DRM_DEBUG_KMS("DP link computation with max lane count %i " - "max bw %02x pixel clock %iKHz\n", - max_lane_count, bws[max_clock], + "max bw %d pixel clock %iKHz\n", + max_lane_count, supported_rates[max_clock], adjusted_mode->crtc_clock); /* Walk through all bpp values. Luckily they're all nicely spaced with 2 @@ -1250,8 +1328,11 @@ intel_dp_compute_config(struct intel_encoder *encoder, bpp); for (clock = min_clock; clock <= max_clock; clock++) { - for (lane_count = min_lane_count; lane_count <= max_lane_count; lane_count <<= 1) { - link_clock = drm_dp_bw_code_to_link_rate(bws[clock]); + for (lane_count = min_lane_count; + lane_count <= max_lane_count; + lane_count <<= 1) { + + link_clock = supported_rates[clock]; link_avail = intel_dp_max_data_rate(link_clock, lane_count); @@ -1280,10 +1361,19 @@ found: if (intel_dp->color_range) pipe_config->limited_color_range = true; - intel_dp->link_bw = bws[clock]; intel_dp->lane_count = lane_count; + + intel_dp->link_bw = + drm_dp_link_rate_to_bw_code(supported_rates[clock]); + + if (INTEL_INFO(dev)->gen >= 9 && intel_dp->supported_rates[0]) { + intel_dp->rate_select = + rate_to_index(supported_rates[clock], sink_rates); + intel_dp->link_bw = 0; + } + pipe_config->pipe_bpp = bpp; - pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); + pipe_config->port_clock = supported_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, @@ -3393,6 +3483,9 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) 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_INFO(dev)->gen >= 9 && intel_dp->supported_rates[0]) + 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; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e05d153291bc..feb09490be71 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -622,6 +622,7 @@ struct intel_dp { uint32_t color_range; bool color_range_auto; uint8_t link_bw; + uint8_t rate_select; uint8_t lane_count; uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];