diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dp.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp.c | 800 |
1 files changed, 547 insertions, 253 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index bf1e9cf1c0f3..2165398d2c7c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -28,7 +28,6 @@ #include <linux/export.h> #include <linux/i2c.h> #include <linux/notifier.h> -#include <linux/reboot.h> #include <linux/slab.h> #include <linux/types.h> @@ -161,6 +160,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) 162000, 270000, 540000, 810000 }; int i, max_rate; + int max_lttpr_rate; if (drm_dp_has_quirk(&intel_dp->desc, 0, DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) { @@ -174,6 +174,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) } max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); + max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps); + if (max_lttpr_rate) + max_rate = min(max_rate, max_lttpr_rate); for (i = 0; i < ARRAY_SIZE(dp_rates); i++) { if (dp_rates[i] > max_rate) @@ -219,6 +222,10 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) int source_max = dig_port->max_lanes; int sink_max = drm_dp_max_lane_count(intel_dp->dpcd); int fia_max = intel_tc_port_fia_max_lane_count(dig_port); + int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps); + + if (lttpr_max) + sink_max = min(sink_max, lttpr_max); return min3(source_max, sink_max, fia_max); } @@ -247,6 +254,17 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes) return max_link_clock * max_lanes; } +bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *encoder = &intel_dig_port->base; + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + return INTEL_GEN(dev_priv) >= 12 || + (INTEL_GEN(dev_priv) == 11 && + encoder->port != PORT_A); +} + static int cnl_max_source_rate(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); @@ -277,13 +295,20 @@ static int icl_max_source_rate(struct intel_dp *intel_dp) enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port); if (intel_phy_is_combo(dev_priv, phy) && - !IS_ELKHARTLAKE(dev_priv) && !intel_dp_is_edp(intel_dp)) return 540000; return 810000; } +static int ehl_max_source_rate(struct intel_dp *intel_dp) +{ + if (intel_dp_is_edp(intel_dp)) + return 540000; + + return 810000; +} + static void intel_dp_set_source_rates(struct intel_dp *intel_dp) { @@ -318,6 +343,8 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) size = ARRAY_SIZE(cnl_rates); if (IS_GEN(dev_priv, 10)) max_rate = cnl_max_source_rate(intel_dp); + else if (IS_JSL_EHL(dev_priv)) + max_rate = ehl_max_source_rate(intel_dp); else max_rate = icl_max_source_rate(intel_dp); } else if (IS_GEN9_LP(dev_priv)) { @@ -503,7 +530,8 @@ small_joiner_ram_size_bits(struct drm_i915_private *i915) static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, u32 link_clock, u32 lane_count, - u32 mode_clock, u32 mode_hdisplay) + u32 mode_clock, u32 mode_hdisplay, + bool bigjoiner) { u32 bits_per_pixel, max_bpp_small_joiner_ram; int i; @@ -521,6 +549,10 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, /* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */ max_bpp_small_joiner_ram = small_joiner_ram_size_bits(i915) / mode_hdisplay; + + if (bigjoiner) + max_bpp_small_joiner_ram *= 2; + drm_dbg_kms(&i915->drm, "Max small joiner bpp: %u\n", max_bpp_small_joiner_ram); @@ -530,6 +562,15 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, */ bits_per_pixel = min(bits_per_pixel, max_bpp_small_joiner_ram); + if (bigjoiner) { + u32 max_bpp_bigjoiner = + i915->max_cdclk_freq * 48 / + intel_dp_mode_to_fec_clock(mode_clock); + + DRM_DEBUG_KMS("Max big joiner bpp: %u\n", max_bpp_bigjoiner); + bits_per_pixel = min(bits_per_pixel, max_bpp_bigjoiner); + } + /* Error out if the max bpp is less than smallest allowed valid bpp */ if (bits_per_pixel < valid_dsc_bpp[0]) { drm_dbg_kms(&i915->drm, "Unsupported BPP %u, min %u\n", @@ -552,7 +593,8 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, } static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, - int mode_clock, int mode_hdisplay) + int mode_clock, int mode_hdisplay, + bool bigjoiner) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); u8 min_slice_count, i; @@ -573,18 +615,24 @@ static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, return 0; } /* Also take into account max slice width */ - min_slice_count = min_t(u8, min_slice_count, + min_slice_count = max_t(u8, min_slice_count, DIV_ROUND_UP(mode_hdisplay, max_slice_width)); /* Find the closest match to the valid slice count values */ for (i = 0; i < ARRAY_SIZE(valid_dsc_slicecount); i++) { - if (valid_dsc_slicecount[i] > - drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, - false)) + u8 test_slice_count = valid_dsc_slicecount[i] << bigjoiner; + + if (test_slice_count > + drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, false)) break; - if (min_slice_count <= valid_dsc_slicecount[i]) - return valid_dsc_slicecount[i]; + + /* big joiner needs small joiner to be enabled */ + if (bigjoiner && test_slice_count < 4) + continue; + + if (min_slice_count <= test_slice_count) + return test_slice_count; } drm_dbg_kms(&i915->drm, "Unsupported Slice Count %d\n", @@ -592,6 +640,54 @@ static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, return 0; } +static enum intel_output_format +intel_dp_output_format(struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector)); + const struct drm_display_info *info = &connector->display_info; + + if (!connector->ycbcr_420_allowed || + !drm_mode_is_420_only(info, mode)) + return INTEL_OUTPUT_FORMAT_RGB; + + if (intel_dp->dfp.ycbcr_444_to_420) + return INTEL_OUTPUT_FORMAT_YCBCR444; + else + return INTEL_OUTPUT_FORMAT_YCBCR420; +} + +int intel_dp_min_bpp(enum intel_output_format output_format) +{ + if (output_format == INTEL_OUTPUT_FORMAT_RGB) + return 6 * 3; + else + return 8 * 3; +} + +static int intel_dp_output_bpp(enum intel_output_format output_format, int bpp) +{ + /* + * bpp value was assumed to RGB format. And YCbCr 4:2:0 output + * format of the number of bytes per pixel will be half the number + * of bytes of RGB pixel. + */ + if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420) + bpp /= 2; + + return bpp; +} + +static int +intel_dp_mode_min_output_bpp(struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + enum intel_output_format output_format = + intel_dp_output_format(connector, mode); + + return intel_dp_output_bpp(output_format, intel_dp_min_bpp(output_format)); +} + static bool intel_dp_hdisplay_bad(struct drm_i915_private *dev_priv, int hdisplay) { @@ -653,10 +749,14 @@ intel_dp_mode_valid(struct drm_connector *connector, u16 dsc_max_output_bpp = 0; u8 dsc_slice_count = 0; enum drm_mode_status status; + bool dsc = false, bigjoiner = false; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_H_ILLEGAL; + if (intel_dp_is_edp(intel_dp) && fixed_mode) { if (mode->hdisplay > fixed_mode->hdisplay) return MODE_PANEL; @@ -667,11 +767,23 @@ intel_dp_mode_valid(struct drm_connector *connector, target_clock = fixed_mode->clock; } + if (mode->clock < 10000) + return MODE_CLOCK_LOW; + + if ((target_clock > max_dotclk || mode->hdisplay > 5120) && + intel_dp_can_bigjoiner(intel_dp)) { + bigjoiner = true; + max_dotclk *= 2; + } + if (target_clock > max_dotclk) + return MODE_CLOCK_HIGH; + max_link_clock = intel_dp_max_link_rate(intel_dp); max_lanes = intel_dp_max_lane_count(intel_dp); max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); - mode_rate = intel_dp_link_required(target_clock, 18); + mode_rate = intel_dp_link_required(target_clock, + intel_dp_mode_min_output_bpp(connector, mode)); if (intel_dp_hdisplay_bad(dev_priv, mode->hdisplay)) return MODE_H_ILLEGAL; @@ -694,30 +806,31 @@ intel_dp_mode_valid(struct drm_connector *connector, max_link_clock, max_lanes, target_clock, - mode->hdisplay) >> 4; + mode->hdisplay, + bigjoiner) >> 4; dsc_slice_count = intel_dp_dsc_get_slice_count(intel_dp, target_clock, - mode->hdisplay); + mode->hdisplay, + bigjoiner); } + + dsc = dsc_max_output_bpp && dsc_slice_count; } - if ((mode_rate > max_rate && !(dsc_max_output_bpp && dsc_slice_count)) || - target_clock > max_dotclk) + /* big joiner configuration needs DSC */ + if (bigjoiner && !dsc) return MODE_CLOCK_HIGH; - if (mode->clock < 10000) - return MODE_CLOCK_LOW; - - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - return MODE_H_ILLEGAL; + if (mode_rate > max_rate && !dsc) + return MODE_CLOCK_HIGH; status = intel_dp_mode_valid_downstream(intel_connector, mode, target_clock); if (status != MODE_OK) return status; - return intel_mode_valid_max_plane_size(dev_priv, mode); + return intel_mode_valid_max_plane_size(dev_priv, mode, bigjoiner); } u32 intel_dp_pack_aux(const u8 *src, int src_bytes) @@ -1143,41 +1256,6 @@ _pp_stat_reg(struct intel_dp *intel_dp) return regs.pp_stat; } -/* Reboot notifier handler to shutdown panel power to guarantee T12 timing - This function only applicable when panel PM state is not to be tracked */ -static int edp_notify_handler(struct notifier_block *this, unsigned long code, - void *unused) -{ - struct intel_dp *intel_dp = container_of(this, typeof(* intel_dp), - edp_notifier); - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - intel_wakeref_t wakeref; - - if (!intel_dp_is_edp(intel_dp) || code != SYS_RESTART) - return 0; - - with_pps_lock(intel_dp, wakeref) { - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - enum pipe pipe = vlv_power_sequencer_pipe(intel_dp); - i915_reg_t pp_ctrl_reg, pp_div_reg; - u32 pp_div; - - pp_ctrl_reg = PP_CONTROL(pipe); - pp_div_reg = PP_DIVISOR(pipe); - pp_div = intel_de_read(dev_priv, pp_div_reg); - pp_div &= PP_REFERENCE_DIVIDER_MASK; - - /* 0x1F write to PP_DIV_REG sets max cycle delay */ - intel_de_write(dev_priv, pp_div_reg, pp_div | 0x1F); - intel_de_write(dev_priv, pp_ctrl_reg, - PANEL_UNLOCK_REGS); - msleep(intel_dp->panel_power_cycle_delay); - } - } - - return 0; -} - static bool edp_have_panel_power(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -1744,7 +1822,6 @@ static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp) case AUX_CH_D: case AUX_CH_E: case AUX_CH_F: - case AUX_CH_G: return DP_AUX_CH_CTL(aux_ch); default: MISSING_CASE(aux_ch); @@ -1765,7 +1842,52 @@ static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index) case AUX_CH_D: case AUX_CH_E: case AUX_CH_F: - case AUX_CH_G: + return DP_AUX_CH_DATA(aux_ch, index); + default: + MISSING_CASE(aux_ch); + return DP_AUX_CH_DATA(AUX_CH_A, index); + } +} + +static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + enum aux_ch aux_ch = dig_port->aux_ch; + + switch (aux_ch) { + case AUX_CH_A: + case AUX_CH_B: + case AUX_CH_C: + case AUX_CH_USBC1: + case AUX_CH_USBC2: + case AUX_CH_USBC3: + case AUX_CH_USBC4: + case AUX_CH_USBC5: + case AUX_CH_USBC6: + return DP_AUX_CH_CTL(aux_ch); + default: + MISSING_CASE(aux_ch); + return DP_AUX_CH_CTL(AUX_CH_A); + } +} + +static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + enum aux_ch aux_ch = dig_port->aux_ch; + + switch (aux_ch) { + case AUX_CH_A: + case AUX_CH_B: + case AUX_CH_C: + case AUX_CH_USBC1: + case AUX_CH_USBC2: + case AUX_CH_USBC3: + case AUX_CH_USBC4: + case AUX_CH_USBC5: + case AUX_CH_USBC6: return DP_AUX_CH_DATA(aux_ch, index); default: MISSING_CASE(aux_ch); @@ -1785,8 +1907,12 @@ intel_dp_aux_init(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; + enum aux_ch aux_ch = dig_port->aux_ch; - if (INTEL_GEN(dev_priv) >= 9) { + if (INTEL_GEN(dev_priv) >= 12) { + intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg; + intel_dp->aux_ch_data_reg = tgl_aux_data_reg; + } else if (INTEL_GEN(dev_priv) >= 9) { intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg; intel_dp->aux_ch_data_reg = skl_aux_data_reg; } else if (HAS_PCH_SPLIT(dev_priv)) { @@ -1814,9 +1940,15 @@ intel_dp_aux_init(struct intel_dp *intel_dp) drm_dp_aux_init(&intel_dp->aux); /* Failure to allocate our preferred name is not critical */ - intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/port %c", - aux_ch_name(dig_port->aux_ch), - port_name(encoder->port)); + if (INTEL_GEN(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1) + intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s", + aux_ch - AUX_CH_USBC1 + '1', + encoder->base.name); + else + intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s", + aux_ch_name(aux_ch), + encoder->base.name); + intel_dp->aux.transfer = intel_dp_aux_transfer; } @@ -1968,12 +2100,10 @@ static bool intel_dp_supports_fec(struct intel_dp *intel_dp, static bool intel_dp_supports_dsc(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; - - if (!intel_dp_is_edp(intel_dp) && !crtc_state->fec_enable) + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP) && !crtc_state->fec_enable) return false; - return intel_dsc_source_support(encoder, crtc_state) && + return intel_dsc_source_support(crtc_state) && drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd); } @@ -2095,19 +2225,6 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, } } -static int intel_dp_output_bpp(const struct intel_crtc_state *crtc_state, int bpp) -{ - /* - * bpp value was assumed to RGB format. And YCbCr 4:2:0 output - * format of the number of bytes per pixel will be half the number - * of bytes of RGB pixel. - */ - if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) - bpp /= 2; - - return bpp; -} - /* Optimize link config in order: max bpp, min clock, min lanes */ static int intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, @@ -2119,7 +2236,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, int mode_rate, link_clock, link_avail; for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) { - int output_bpp = intel_dp_output_bpp(pipe_config, bpp); + int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp); mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock, output_bpp); @@ -2280,11 +2397,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->port_clock, pipe_config->lane_count, adjusted_mode->crtc_clock, - adjusted_mode->crtc_hdisplay); + adjusted_mode->crtc_hdisplay, + pipe_config->bigjoiner); dsc_dp_slice_count = intel_dp_dsc_get_slice_count(intel_dp, adjusted_mode->crtc_clock, - adjusted_mode->crtc_hdisplay); + adjusted_mode->crtc_hdisplay, + pipe_config->bigjoiner); if (!dsc_max_output_bpp || !dsc_dp_slice_count) { drm_dbg_kms(&dev_priv->drm, "Compressed BPP/Slice Count not supported\n"); @@ -2300,14 +2419,15 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, * is greater than the maximum Cdclock and if slice count is even * then we need to use 2 VDSC instances. */ - if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq) { - if (pipe_config->dsc.slice_count > 1) { - pipe_config->dsc.dsc_split = true; - } else { + if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq || + pipe_config->bigjoiner) { + if (pipe_config->dsc.slice_count < 2) { drm_dbg_kms(&dev_priv->drm, "Cannot split stream to use 2 VDSC instances\n"); return -EINVAL; } + + pipe_config->dsc.dsc_split = true; } ret = intel_dp_dsc_compute_params(&dig_port->base, pipe_config); @@ -2330,14 +2450,6 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return 0; } -int intel_dp_min_bpp(const struct intel_crtc_state *crtc_state) -{ - if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB) - return 6 * 3; - else - return 8 * 3; -} - static int intel_dp_compute_link_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, @@ -2363,7 +2475,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, limits.min_lane_count = 1; limits.max_lane_count = intel_dp_max_lane_count(intel_dp); - limits.min_bpp = intel_dp_min_bpp(pipe_config); + limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format); limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config); if (intel_dp_is_edp(intel_dp)) { @@ -2386,6 +2498,11 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, intel_dp->common_rates[limits.max_clock], limits.max_bpp, adjusted_mode->crtc_clock); + if ((adjusted_mode->crtc_clock > i915->max_dotclk_freq || + adjusted_mode->crtc_hdisplay > 5120) && + intel_dp_can_bigjoiner(intel_dp)) + pipe_config->bigjoiner = true; + /* * Optimize for slow and wide. This is the place to add alternative * optimization policy. @@ -2394,7 +2511,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, /* enable compression if the mode doesn't fit available BW */ drm_dbg_kms(&i915->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en); - if (ret || intel_dp->force_dsc_en) { + if (ret || intel_dp->force_dsc_en || pipe_config->bigjoiner) { ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, conn_state, &limits); if (ret < 0) @@ -2429,32 +2546,6 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, return 0; } -static int -intel_dp_ycbcr420_config(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state, - const struct drm_connector_state *conn_state) -{ - struct drm_connector *connector = conn_state->connector; - const struct drm_display_info *info = &connector->display_info; - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; - - if (!connector->ycbcr_420_allowed) - return 0; - - if (!drm_mode_is_420_only(info, adjusted_mode)) - return 0; - - if (intel_dp->dfp.ycbcr_444_to_420) { - crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444; - return 0; - } - - crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420; - - return intel_pch_panel_fitting(crtc_state, conn_state); -} - bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { @@ -2693,7 +2784,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct intel_lspcon *lspcon = enc_to_intel_lspcon(encoder); enum port port = encoder->port; struct intel_connector *intel_connector = intel_dp->attached_connector; struct intel_digital_connector_state *intel_conn_state = @@ -2705,15 +2795,14 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A) pipe_config->has_pch_encoder = true; - pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; + pipe_config->output_format = intel_dp_output_format(&intel_connector->base, + adjusted_mode); - if (lspcon->active) - lspcon_ycbcr420_config(&intel_connector->base, pipe_config); - else - ret = intel_dp_ycbcr420_config(intel_dp, pipe_config, - conn_state); - if (ret) - return ret; + if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { + ret = intel_pch_panel_fitting(pipe_config, conn_state); + if (ret) + return ret; + } if (!intel_dp_port_has_audio(dev_priv, port)) pipe_config->has_audio = false; @@ -2757,7 +2846,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (pipe_config->dsc.compression_enable) output_bpp = pipe_config->dsc.compressed_bpp; else - output_bpp = intel_dp_output_bpp(pipe_config, pipe_config->pipe_bpp); + output_bpp = intel_dp_output_bpp(pipe_config->output_format, + pipe_config->pipe_bpp); intel_link_compute_m_n(output_bpp, pipe_config->lane_count, @@ -2779,13 +2869,11 @@ intel_dp_compute_config(struct intel_encoder *encoder, } void intel_dp_set_link_params(struct intel_dp *intel_dp, - int link_rate, u8 lane_count, - bool link_mst) + int link_rate, int lane_count) { intel_dp->link_trained = false; intel_dp->link_rate = link_rate; intel_dp->lane_count = lane_count; - intel_dp->link_mst = link_mst; } static void intel_dp_prepare(struct intel_encoder *encoder, @@ -2797,10 +2885,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - intel_dp_set_link_params(intel_dp, pipe_config->port_clock, - pipe_config->lane_count, - intel_crtc_has_type(pipe_config, - INTEL_OUTPUT_DP_MST)); + intel_dp_set_link_params(intel_dp, + pipe_config->port_clock, + pipe_config->lane_count); /* * There are four kinds of DP registers: @@ -3492,32 +3579,33 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, enable ? "enable" : "disable"); } -/* If the sink supports it, try to set the power state appropriately */ -void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) +/* If the device supports it, try to set the power state appropriately */ +void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); int ret, i; /* Should have a valid DPCD by this point */ if (intel_dp->dpcd[DP_DPCD_REV] < 0x11) return; - if (mode != DRM_MODE_DPMS_ON) { + if (mode != DP_SET_POWER_D0) { if (downstream_hpd_needs_d0(intel_dp)) return; - ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, - DP_SET_POWER_D3); + ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, mode); } else { struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp); + lspcon_resume(dp_to_dig_port(intel_dp)); + /* * When turning on, we need to retry for 1ms to give the sink * time to wake up. */ for (i = 0; i < 3; i++) { - ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, - DP_SET_POWER_D0); + ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, mode); if (ret == 1) break; msleep(1); @@ -3528,8 +3616,9 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) } if (ret != 1) - drm_dbg_kms(&i915->drm, "failed to %s sink power state\n", - mode == DRM_MODE_DPMS_ON ? "enable" : "disable"); + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Set power to %s failed\n", + encoder->base.base.id, encoder->base.name, + mode == DP_SET_POWER_D0 ? "D0" : "D3"); } static bool cpt_dp_port_selected(struct drm_i915_private *dev_priv, @@ -3686,6 +3775,72 @@ static void intel_dp_get_config(struct intel_encoder *encoder, } } +static bool +intel_dp_get_dpcd(struct intel_dp *intel_dp); + +/** + * intel_dp_sync_state - sync the encoder state during init/resume + * @encoder: intel encoder to sync + * @crtc_state: state for the CRTC connected to the encoder + * + * Sync any state stored in the encoder wrt. HW state during driver init + * and system resume. + */ +void intel_dp_sync_state(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + /* + * Don't clobber DPCD if it's been already read out during output + * setup (eDP) or detect. + */ + if (intel_dp->dpcd[DP_DPCD_REV] == 0) + intel_dp_get_dpcd(intel_dp); + + intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp); + intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp); +} + +bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + /* + * If BIOS has set an unsupported or non-standard link rate for some + * reason force an encoder recompute and full modeset. + */ + if (intel_dp_rate_index(intel_dp->source_rates, intel_dp->num_source_rates, + crtc_state->port_clock) < 0) { + drm_dbg_kms(&i915->drm, "Forcing full modeset due to unsupported link rate\n"); + crtc_state->uapi.connectors_changed = true; + return false; + } + + /* + * FIXME hack to force full modeset when DSC is being used. + * + * As long as we do not have full state readout and config comparison + * of crtc_state->dsc, we have no way to ensure reliable fastset. + * Remove once we have readout for DSC. + */ + if (crtc_state->dsc.compression_enable) { + drm_dbg_kms(&i915->drm, "Forcing full modeset due to DSC being enabled\n"); + crtc_state->uapi.mode_changed = true; + return false; + } + + if (CAN_PSR(i915) && intel_dp_is_edp(intel_dp)) { + drm_dbg_kms(&i915->drm, "Forcing full modeset to compute PSR state\n"); + crtc_state->uapi.mode_changed = true; + return false; + } + + return true; +} + static void intel_disable_dp(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, @@ -3703,7 +3858,7 @@ static void intel_disable_dp(struct intel_atomic_state *state, * ensure that we have vdd while we switch off the panel. */ intel_edp_panel_vdd_on(intel_dp); intel_edp_backlight_off(old_conn_state); - intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); + intel_dp_set_power(intel_dp, DP_SET_POWER_D3); intel_edp_panel_off(intel_dp); } @@ -3771,6 +3926,7 @@ static void chv_post_disable_dp(struct intel_atomic_state *state, static void cpt_set_link_train(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, u8 dp_train_pat) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -3778,7 +3934,7 @@ cpt_set_link_train(struct intel_dp *intel_dp, *DP &= ~DP_LINK_TRAIN_MASK_CPT; - switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { + switch (intel_dp_training_pattern_symbol(dp_train_pat)) { case DP_TRAINING_PATTERN_DISABLE: *DP |= DP_LINK_TRAIN_OFF_CPT; break; @@ -3801,6 +3957,7 @@ cpt_set_link_train(struct intel_dp *intel_dp, static void g4x_set_link_train(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, u8 dp_train_pat) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -3808,7 +3965,7 @@ g4x_set_link_train(struct intel_dp *intel_dp, *DP &= ~DP_LINK_TRAIN_MASK; - switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { + switch (intel_dp_training_pattern_symbol(dp_train_pat)) { case DP_TRAINING_PATTERN_DISABLE: *DP |= DP_LINK_TRAIN_OFF; break; @@ -3830,13 +3987,14 @@ g4x_set_link_train(struct intel_dp *intel_dp, } static void intel_dp_enable_port(struct intel_dp *intel_dp, - const struct intel_crtc_state *old_crtc_state) + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); /* enable with pattern 1 (as per spec) */ - intel_dp_program_link_training_pattern(intel_dp, DP_TRAINING_PATTERN_1); + intel_dp_program_link_training_pattern(intel_dp, crtc_state, + DP_TRAINING_PATTERN_1); /* * Magic for VLV/CHV. We _must_ first set up the register @@ -3845,7 +4003,7 @@ 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 (old_crtc_state->has_audio) + if (crtc_state->has_audio) intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); @@ -3925,10 +4083,10 @@ static void intel_enable_dp(struct intel_atomic_state *state, lane_mask); } - intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp); - intel_dp_start_link_train(intel_dp); - intel_dp_stop_link_train(intel_dp); + intel_dp_start_link_train(intel_dp, pipe_config); + intel_dp_stop_link_train(intel_dp, pipe_config); if (pipe_config->has_audio) { drm_dbg(&dev_priv->drm, "Enabling DP audio on pipe %c\n", @@ -4126,38 +4284,30 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state, chv_phy_post_pll_disable(encoder, old_crtc_state); } -/* - * Fetch AUX CH registers 0x202 - 0x207 which contain - * link status information - */ -bool -intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE]) -{ - return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status, - DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE; -} - -static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp) +static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { return DP_TRAIN_VOLTAGE_SWING_LEVEL_2; } -static u8 intel_dp_voltage_max_3(struct intel_dp *intel_dp) +static u8 intel_dp_voltage_max_3(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { return DP_TRAIN_VOLTAGE_SWING_LEVEL_3; } -static u8 intel_dp_pre_empemph_max_2(struct intel_dp *intel_dp) +static u8 intel_dp_preemph_max_2(struct intel_dp *intel_dp) { return DP_TRAIN_PRE_EMPH_LEVEL_2; } -static u8 intel_dp_pre_empemph_max_3(struct intel_dp *intel_dp) +static u8 intel_dp_preemph_max_3(struct intel_dp *intel_dp) { return DP_TRAIN_PRE_EMPH_LEVEL_3; } -static void vlv_set_signal_levels(struct intel_dp *intel_dp) +static void vlv_set_signal_levels(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; unsigned long demph_reg_value, preemph_reg_value, @@ -4237,11 +4387,13 @@ static void vlv_set_signal_levels(struct intel_dp *intel_dp) return; } - vlv_set_phy_signal_level(encoder, demph_reg_value, preemph_reg_value, + vlv_set_phy_signal_level(encoder, crtc_state, + demph_reg_value, preemph_reg_value, uniqtranscale_reg_value, 0); } -static void chv_set_signal_levels(struct intel_dp *intel_dp) +static void chv_set_signal_levels(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; u32 deemph_reg_value, margin_reg_value; @@ -4318,8 +4470,9 @@ static void chv_set_signal_levels(struct intel_dp *intel_dp) return; } - chv_set_phy_signal_level(encoder, deemph_reg_value, - margin_reg_value, uniq_trans_scale); + chv_set_phy_signal_level(encoder, crtc_state, + deemph_reg_value, margin_reg_value, + uniq_trans_scale); } static u32 g4x_signal_levels(u8 train_set) @@ -4360,7 +4513,8 @@ static u32 g4x_signal_levels(u8 train_set) } static void -g4x_set_signal_levels(struct intel_dp *intel_dp) +g4x_set_signal_levels(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 train_set = intel_dp->train_set[0]; @@ -4407,7 +4561,8 @@ static u32 snb_cpu_edp_signal_levels(u8 train_set) } static void -snb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp) +snb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 train_set = intel_dp->train_set[0]; @@ -4458,7 +4613,8 @@ static u32 ivb_cpu_edp_signal_levels(u8 train_set) } static void -ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp) +ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 train_set = intel_dp->train_set[0]; @@ -4476,7 +4632,8 @@ ivb_cpu_edp_set_signal_levels(struct intel_dp *intel_dp) intel_de_posting_read(dev_priv, intel_dp->output_reg); } -void intel_dp_set_signal_levels(struct intel_dp *intel_dp) +void intel_dp_set_signal_levels(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 train_set = intel_dp->train_set[0]; @@ -4490,28 +4647,23 @@ void intel_dp_set_signal_levels(struct intel_dp *intel_dp) train_set & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED ? " (max)" : ""); - intel_dp->set_signal_levels(intel_dp); + intel_dp->set_signal_levels(intel_dp, crtc_state); } void intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, u8 dp_train_pat) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd); - if (dp_train_pat & train_pat_mask) + if ((intel_dp_training_pattern_symbol(dp_train_pat)) != + DP_TRAINING_PATTERN_DISABLE) drm_dbg_kms(&dev_priv->drm, "Using DP training pattern TPS%d\n", - dp_train_pat & train_pat_mask); - - intel_dp->set_link_train(intel_dp, dp_train_pat); -} + intel_dp_training_pattern_symbol(dp_train_pat)); -void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) -{ - if (intel_dp->set_idle_link_train) - intel_dp->set_idle_link_train(intel_dp); + intel_dp->set_link_train(intel_dp, crtc_state, dp_train_pat); } static void @@ -4732,6 +4884,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) { int ret; + intel_dp_lttpr_init(intel_dp); + if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd)) return false; @@ -5404,33 +5558,14 @@ static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp) return test_result; } -static u8 intel_dp_prepare_phytest(struct intel_dp *intel_dp) -{ - struct drm_dp_phy_test_params *data = - &intel_dp->compliance.test_data.phytest; - - if (drm_dp_get_phy_test_pattern(&intel_dp->aux, data)) { - DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n"); - return DP_TEST_NAK; - } - - /* - * link_mst is set to false to avoid executing mst related code - * during compliance testing. - */ - intel_dp->link_mst = false; - - return DP_TEST_ACK; -} - -static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp) +static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(dp_to_dig_port(intel_dp)->base.base.dev); - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_dp_phy_test_params *data = &intel_dp->compliance.test_data.phytest; - struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum pipe pipe = crtc->pipe; u32 pattern_val; @@ -5490,7 +5625,8 @@ static void intel_dp_phy_pattern_update(struct intel_dp *intel_dp) } static void -intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp) +intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; @@ -5516,7 +5652,8 @@ intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp) } static void -intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt) +intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; @@ -5542,27 +5679,30 @@ intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt) trans_ddi_func_ctl_value); } -void intel_dp_process_phy_request(struct intel_dp *intel_dp) +static void intel_dp_process_phy_request(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct drm_dp_phy_test_params *data = &intel_dp->compliance.test_data.phytest; u8 link_status[DP_LINK_STATUS_SIZE]; - if (!intel_dp_get_link_status(intel_dp, link_status)) { + if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX, + link_status) < 0) { DRM_DEBUG_KMS("failed to get link status\n"); return; } /* retrieve vswing & pre-emphasis setting */ - intel_dp_get_adjust_train(intel_dp, link_status); + intel_dp_get_adjust_train(intel_dp, crtc_state, DP_PHY_DPRX, + link_status); - intel_dp_autotest_phy_ddi_disable(intel_dp); + intel_dp_autotest_phy_ddi_disable(intel_dp, crtc_state); - intel_dp_set_signal_levels(intel_dp); + intel_dp_set_signal_levels(intel_dp, crtc_state); - intel_dp_phy_pattern_update(intel_dp); + intel_dp_phy_pattern_update(intel_dp, crtc_state); - intel_dp_autotest_phy_ddi_enable(intel_dp, data->num_lanes); + intel_dp_autotest_phy_ddi_enable(intel_dp, crtc_state); drm_dp_set_phy_test_pattern(&intel_dp->aux, data, link_status[DP_DPCD_REV]); @@ -5570,15 +5710,18 @@ void intel_dp_process_phy_request(struct intel_dp *intel_dp) static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp) { - u8 test_result; + struct drm_dp_phy_test_params *data = + &intel_dp->compliance.test_data.phytest; - test_result = intel_dp_prepare_phytest(intel_dp); - if (test_result != DP_TEST_ACK) - DRM_ERROR("Phy test preparation failed\n"); + if (drm_dp_get_phy_test_pattern(&intel_dp->aux, data)) { + DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n"); + return DP_TEST_NAK; + } - intel_dp_process_phy_request(intel_dp); + /* Set test active flag here so userspace doesn't interrupt things */ + intel_dp->compliance.test_active = true; - return test_result; + return DP_TEST_ACK; } static void intel_dp_handle_test_request(struct intel_dp *intel_dp) @@ -5709,12 +5852,17 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp) if (intel_psr_enabled(intel_dp)) return false; - if (!intel_dp_get_link_status(intel_dp, link_status)) + if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX, + link_status) < 0) return false; /* * Validate the cached values of intel_dp->link_rate and * intel_dp->lane_count before attempting to retrain. + * + * FIXME would be nice to user the crtc state here, but since + * we need to call this from the short HPD handler that seems + * a bit hard. */ if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate, intel_dp->lane_count)) @@ -5848,8 +5996,20 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, intel_crtc_pch_transcoder(crtc), false); } - intel_dp_start_link_train(intel_dp); - intel_dp_stop_link_train(intel_dp); + for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) { + const struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + + /* retrain on the MST master transcoder */ + if (INTEL_GEN(dev_priv) >= 12 && + intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) && + !intel_dp_mst_is_master_trans(crtc_state)) + continue; + + intel_dp_start_link_train(intel_dp, crtc_state); + intel_dp_stop_link_train(intel_dp, crtc_state); + break; + } for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) { const struct intel_crtc_state *crtc_state = @@ -5867,6 +6027,118 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, return 0; } +static int intel_dp_prep_phy_test(struct intel_dp *intel_dp, + struct drm_modeset_acquire_ctx *ctx, + u32 *crtc_mask) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct drm_connector_list_iter conn_iter; + struct intel_connector *connector; + int ret = 0; + + *crtc_mask = 0; + + drm_connector_list_iter_begin(&i915->drm, &conn_iter); + for_each_intel_connector_iter(connector, &conn_iter) { + struct drm_connector_state *conn_state = + connector->base.state; + struct intel_crtc_state *crtc_state; + struct intel_crtc *crtc; + + if (!intel_dp_has_connector(intel_dp, conn_state)) + continue; + + crtc = to_intel_crtc(conn_state->crtc); + if (!crtc) + continue; + + ret = drm_modeset_lock(&crtc->base.mutex, ctx); + if (ret) + break; + + crtc_state = to_intel_crtc_state(crtc->base.state); + + drm_WARN_ON(&i915->drm, !intel_crtc_has_dp_encoder(crtc_state)); + + if (!crtc_state->hw.active) + continue; + + if (conn_state->commit && + !try_wait_for_completion(&conn_state->commit->hw_done)) + continue; + + *crtc_mask |= drm_crtc_mask(&crtc->base); + } + drm_connector_list_iter_end(&conn_iter); + + return ret; +} + +static int intel_dp_do_phy_test(struct intel_encoder *encoder, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_crtc *crtc; + u32 crtc_mask; + int ret; + + ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, + ctx); + if (ret) + return ret; + + ret = intel_dp_prep_phy_test(intel_dp, ctx, &crtc_mask); + if (ret) + return ret; + + if (crtc_mask == 0) + return 0; + + drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] PHY test\n", + encoder->base.base.id, encoder->base.name); + + for_each_intel_crtc_mask(&dev_priv->drm, crtc, crtc_mask) { + const struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + + /* test on the MST master transcoder */ + if (INTEL_GEN(dev_priv) >= 12 && + intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) && + !intel_dp_mst_is_master_trans(crtc_state)) + continue; + + intel_dp_process_phy_request(intel_dp, crtc_state); + break; + } + + return 0; +} + +static void intel_dp_phy_test(struct intel_encoder *encoder) +{ + struct drm_modeset_acquire_ctx ctx; + int ret; + + drm_modeset_acquire_init(&ctx, 0); + + for (;;) { + ret = intel_dp_do_phy_test(encoder, &ctx); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + continue; + } + + break; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + drm_WARN(encoder->base.dev, ret, + "Acquiring modeset locks failed with %i\n", ret); +} + /* * If display is now connected check links status, * there has been known issues of link loss triggering @@ -5883,10 +6155,18 @@ static enum intel_hotplug_state intel_dp_hotplug(struct intel_encoder *encoder, struct intel_connector *connector) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_modeset_acquire_ctx ctx; enum intel_hotplug_state state; int ret; + if (intel_dp->compliance.test_active && + intel_dp->compliance.test_type == DP_TEST_LINK_PHY_TEST_PATTERN) { + intel_dp_phy_test(encoder); + /* just do the PHY test and nothing else */ + return INTEL_HOTPLUG_UNCHANGED; + } + state = intel_encoder_hotplug(encoder, connector); drm_modeset_acquire_init(&ctx, 0); @@ -5991,11 +6271,23 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) intel_psr_short_pulse(intel_dp); - if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) { + switch (intel_dp->compliance.test_type) { + case DP_TEST_LINK_TRAINING: drm_dbg_kms(&dev_priv->drm, "Link Training Compliance Test requested\n"); /* Send a Hotplug Uevent to userspace to start modeset */ drm_kms_helper_hotplug_event(&dev_priv->drm); + break; + case DP_TEST_LINK_PHY_TEST_PATTERN: + drm_dbg_kms(&dev_priv->drm, + "PHY test pattern Compliance Test requested\n"); + /* + * Schedule long hpd to do the test + * + * FIXME get rid of the ad-hoc phy test modeset code + * and properly incorporate it into the normal modeset. + */ + return false; } return true; @@ -6006,15 +6298,14 @@ static enum drm_connector_status intel_dp_detect_dpcd(struct intel_dp *intel_dp) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); - struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp); + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); u8 *dpcd = intel_dp->dpcd; u8 type; if (drm_WARN_ON(&i915->drm, intel_dp_is_edp(intel_dp))) return connector_status_connected; - if (lspcon->active) - lspcon_resume(lspcon); + lspcon_resume(dig_port); if (!intel_dp_get_dpcd(intel_dp)) return connector_status_disconnected; @@ -6220,7 +6511,9 @@ intel_dp_update_420(struct intel_dp *intel_dp) ycbcr_420_passthrough = drm_dp_downstream_420_passthrough(intel_dp->dpcd, intel_dp->downstream_ports); + /* on-board LSPCON always assumed to support 4:4:4->4:2:0 conversion */ ycbcr_444_to_420 = + dp_to_dig_port(intel_dp)->lspcon.active || drm_dp_downstream_444_to_420_conversion(intel_dp->dpcd, intel_dp->downstream_ports); @@ -6523,11 +6816,6 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder) */ with_pps_lock(intel_dp, wakeref) edp_panel_vdd_off_sync(intel_dp); - - if (intel_dp->edp_notifier.notifier_call) { - unregister_reboot_notifier(&intel_dp->edp_notifier); - intel_dp->edp_notifier.notifier_call = NULL; - } } intel_dp_aux_fini(intel_dp); @@ -6558,6 +6846,18 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) edp_panel_vdd_off_sync(intel_dp); } +void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder); + intel_wakeref_t wakeref; + + if (!intel_dp_is_edp(intel_dp)) + return; + + with_pps_lock(intel_dp, wakeref) + wait_panel_power_cycle(intel_dp); +} + static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -6598,15 +6898,11 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->dev); struct intel_dp *intel_dp = enc_to_intel_dp(to_intel_encoder(encoder)); - struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp); intel_wakeref_t wakeref; if (!HAS_DDI(dev_priv)) intel_dp->DP = intel_de_read(dev_priv, intel_dp->output_reg); - if (lspcon->active) - lspcon_resume(lspcon); - intel_dp->reset_link_params = true; if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) && @@ -7671,9 +7967,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, mutex_unlock(&dev->mode_config.mutex); if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - intel_dp->edp_notifier.notifier_call = edp_notify_handler; - register_reboot_notifier(&intel_dp->edp_notifier); - /* * Figure out the current pipe for the initial backlight setup. * If the current pipe isn't valid, try the PPS pipe, and if that @@ -7892,8 +8185,11 @@ bool intel_dp_init(struct drm_i915_private *dev_priv, intel_encoder->compute_config = intel_dp_compute_config; intel_encoder->get_hw_state = intel_dp_get_hw_state; intel_encoder->get_config = intel_dp_get_config; + intel_encoder->sync_state = intel_dp_sync_state; + intel_encoder->initial_fastset_check = intel_dp_initial_fastset_check; intel_encoder->update_pipe = intel_panel_update_backlight; intel_encoder->suspend = intel_dp_encoder_suspend; + intel_encoder->shutdown = intel_dp_encoder_shutdown; if (IS_CHERRYVIEW(dev_priv)) { intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable; intel_encoder->pre_enable = chv_pre_enable_dp; @@ -7933,17 +8229,15 @@ bool intel_dp_init(struct drm_i915_private *dev_priv, if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv) || (HAS_PCH_SPLIT(dev_priv) && port != PORT_A)) { - dig_port->dp.preemph_max = intel_dp_pre_empemph_max_3; + dig_port->dp.preemph_max = intel_dp_preemph_max_3; dig_port->dp.voltage_max = intel_dp_voltage_max_3; } else { - dig_port->dp.preemph_max = intel_dp_pre_empemph_max_2; + dig_port->dp.preemph_max = intel_dp_preemph_max_2; dig_port->dp.voltage_max = intel_dp_voltage_max_2; } dig_port->dp.output_reg = output_reg; dig_port->max_lanes = 4; - dig_port->dp.regs.dp_tp_ctl = DP_TP_CTL(port); - dig_port->dp.regs.dp_tp_status = DP_TP_STATUS(port); intel_encoder->type = INTEL_OUTPUT_DP; intel_encoder->power_domain = intel_port_to_power_domain(port); |