diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_dp.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 187 |
1 files changed, 169 insertions, 18 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d1141d3..ca60060 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) @@ -129,7 +134,10 @@ intel_dp_max_link_bw(struct intel_dp *intel_dp) case DP_LINK_BW_2_7: break; case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */ - if (((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || + if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) + /* WaDisableHBR2:skl */ + max_link_bw = DP_LINK_BW_2_7; + else if (((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || INTEL_INFO(dev)->gen >= 8) && intel_dp->dpcd[DP_DPCD_REV] >= 0x12) max_link_bw = DP_LINK_BW_5_4; @@ -1075,7 +1083,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector) } static void -skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_bw) +skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) { u32 ctrl1; @@ -1084,19 +1092,35 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_bw) pipe_config->dpll_hw_state.cfgcr2 = 0; ctrl1 = DPLL_CTRL1_OVERRIDE(SKL_DPLL0); - switch (link_bw) { - case DP_LINK_BW_1_62: + switch (link_clock / 2) { + case 81000: ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_810, SKL_DPLL0); break; - case DP_LINK_BW_2_7: + case 135000: ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1350, SKL_DPLL0); break; - case DP_LINK_BW_5_4: + case 270000: ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2700, SKL_DPLL0); break; + case 162000: + ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1620, + SKL_DPLL0); + break; + /* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which + results in CDCLK change. Need to handle the change of CDCLK by + disabling pipes and re-enabling them */ + case 108000: + ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1080, + SKL_DPLL0); + break; + case 216000: + ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2160, + SKL_DPLL0); + break; + } pipe_config->dpll_hw_state.ctrl1 = ctrl1; } @@ -1117,6 +1141,52 @@ hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw) } } +static int +intel_read_sink_rates(struct intel_dp *intel_dp, uint32_t *sink_rates) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + int i = 0; + uint16_t val; + + if (INTEL_INFO(dev)->gen >= 9 && intel_dp->supported_rates[0]) { + /* + * Receiver supports only main-link rate selection by + * link rate table method, so read link rates from + * supported_link_rates + */ + for (i = 0; i < DP_MAX_SUPPORTED_RATES; ++i) { + val = le16_to_cpu(intel_dp->supported_rates[i]); + if (val == 0) + break; + + sink_rates[i] = val * 200; + } + + if (i <= 0) + DRM_ERROR("No rates in SUPPORTED_LINK_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) @@ -1150,6 +1220,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) @@ -1166,10 +1275,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; @@ -1193,8 +1317,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 @@ -1223,8 +1347,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); @@ -1253,10 +1380,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, @@ -1279,7 +1415,7 @@ found: } if (IS_SKYLAKE(dev) && is_edp(intel_dp)) - skl_edp_set_pll_config(pipe_config, intel_dp->link_bw); + skl_edp_set_pll_config(pipe_config, supported_rates[clock]); else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw); else @@ -3366,6 +3502,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; @@ -3578,6 +3717,7 @@ intel_dp_get_dpcd(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; struct drm_i915_private *dev_priv = dev->dev_private; + uint8_t rev; if (intel_dp_dpcd_read_wake(&intel_dp->aux, 0x000, intel_dp->dpcd, sizeof(intel_dp->dpcd)) < 0) @@ -3609,6 +3749,16 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) } else intel_dp->use_tps3 = false; + /* Intermediate frequency support */ + if (is_edp(intel_dp) && + (intel_dp->dpcd[DP_EDP_CONFIGURATION_CAP] & DP_DPCD_DISPLAY_CONTROL_CAPABLE) && + (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_EDP_DPCD_REV, &rev, 1) == 1) && + (rev >= 0x03)) { /* eDp v1.4 or higher */ + intel_dp_dpcd_read_wake(&intel_dp->aux, + DP_SUPPORTED_LINK_RATES, + intel_dp->supported_rates, + sizeof(intel_dp->supported_rates)); + } if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT)) return true; /* native DP sink */ @@ -4966,12 +5116,13 @@ void intel_edp_drrs_invalidate(struct drm_device *dev, if (!dev_priv->drrs.dp) return; + cancel_delayed_work_sync(&dev_priv->drrs.work); + mutex_lock(&dev_priv->drrs.mutex); crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) { - cancel_delayed_work_sync(&dev_priv->drrs.work); intel_dp_set_drrs_state(dev_priv->dev, dev_priv->drrs.dp->attached_connector->panel. fixed_mode->vrefresh); @@ -5004,13 +5155,13 @@ void intel_edp_drrs_flush(struct drm_device *dev, if (!dev_priv->drrs.dp) return; + cancel_delayed_work_sync(&dev_priv->drrs.work); + mutex_lock(&dev_priv->drrs.mutex); crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; - cancel_delayed_work_sync(&dev_priv->drrs.work); - if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR && !dev_priv->drrs.busy_frontbuffer_bits) schedule_delayed_work(&dev_priv->drrs.work, |