diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dp.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp.c | 137 |
1 files changed, 92 insertions, 45 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7976fec88606..2eab591a8ef5 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -27,6 +27,7 @@ #include <linux/export.h> #include <linux/i2c.h> +#include <linux/iopoll.h> #include <linux/log2.h> #include <linux/math.h> #include <linux/notifier.h> @@ -174,7 +175,6 @@ int intel_dp_link_symbol_clock(int rate) static int max_dprx_rate(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; int max_rate; if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) @@ -183,16 +183,13 @@ static int max_dprx_rate(struct intel_dp *intel_dp) max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); /* - * Some broken eDP sinks illegally declare support for - * HBR3 without TPS4, and are unable to produce a stable - * output. Reject HBR3 when TPS4 is not available. + * Some platforms + eDP panels may not reliably support HBR3 + * due to signal integrity limitations, despite advertising it. + * Cap the link rate to HBR2 to avoid unstable configurations for the + * known machines. */ - if (max_rate >= 810000 && !drm_dp_tps4_supported(intel_dp->dpcd)) { - drm_dbg_kms(display->drm, - "[ENCODER:%d:%s] Rejecting HBR3 due to missing TPS4 support\n", - encoder->base.base.id, encoder->base.name); - max_rate = 540000; - } + if (intel_dp_is_edp(intel_dp) && intel_has_quirk(display, QUIRK_EDP_LIMIT_RATE_HBR2)) + max_rate = min(max_rate, 540000); return max_rate; } @@ -1418,6 +1415,7 @@ intel_dp_mode_valid(struct drm_connector *_connector, struct intel_display *display = to_intel_display(_connector->dev); struct intel_connector *connector = to_intel_connector(_connector); struct intel_dp *intel_dp = intel_attached_dp(connector); + enum intel_output_format sink_format, output_format; const struct drm_display_mode *fixed_mode; int target_clock = mode->clock; int max_rate, mode_rate, max_lanes, max_link_clock; @@ -1451,6 +1449,13 @@ intel_dp_mode_valid(struct drm_connector *_connector, mode->hdisplay, target_clock); max_dotclk *= num_joined_pipes; + sink_format = intel_dp_sink_format(connector, mode); + output_format = intel_dp_output_format(connector, sink_format); + + status = intel_pfit_mode_valid(display, mode, output_format, num_joined_pipes); + if (status != MODE_OK) + return status; + if (target_clock > max_dotclk) return MODE_CLOCK_HIGH; @@ -1466,11 +1471,8 @@ intel_dp_mode_valid(struct drm_connector *_connector, intel_dp_mode_min_output_bpp(connector, mode)); if (intel_dp_has_dsc(connector)) { - enum intel_output_format sink_format, output_format; int pipe_bpp; - sink_format = intel_dp_sink_format(connector, mode); - output_format = intel_dp_output_format(connector, sink_format); /* * TBD pass the connector BPC, * for now U8_MAX so that max BPC on that platform would be picked @@ -2535,13 +2537,15 @@ intel_dp_dsc_compute_pipe_bpp_limits(struct intel_dp *intel_dp, bool intel_dp_compute_config_limits(struct intel_dp *intel_dp, - struct intel_connector *connector, + struct drm_connector_state *conn_state, struct intel_crtc_state *crtc_state, bool respect_downstream_limits, bool dsc, struct link_config_limits *limits) { bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST); + struct intel_connector *connector = + to_intel_connector(conn_state->connector); limits->min_rate = intel_dp_min_link_rate(intel_dp); limits->max_rate = intel_dp_max_link_rate(intel_dp); @@ -2551,7 +2555,8 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp, limits->min_lane_count = intel_dp_min_lane_count(intel_dp); limits->max_lane_count = intel_dp_max_lane_count(intel_dp); - limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format); + limits->pipe.min_bpp = intel_dp_in_hdr_mode(conn_state) ? 30 : + intel_dp_min_bpp(crtc_state->output_format); if (is_mst) { /* * FIXME: If all the streams can't fit into the link with their @@ -2650,7 +2655,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, joiner_needs_dsc = intel_dp_joiner_needs_dsc(display, num_joined_pipes); dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en || - !intel_dp_compute_config_limits(intel_dp, connector, pipe_config, + !intel_dp_compute_config_limits(intel_dp, conn_state, pipe_config, respect_downstream_limits, false, &limits); @@ -2684,7 +2689,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, str_yes_no(ret), str_yes_no(joiner_needs_dsc), str_yes_no(intel_dp->force_dsc_en)); - if (!intel_dp_compute_config_limits(intel_dp, connector, pipe_config, + if (!intel_dp_compute_config_limits(intel_dp, conn_state, pipe_config, respect_downstream_limits, true, &limits)) @@ -2916,6 +2921,19 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp, } } +bool +intel_dp_in_hdr_mode(const struct drm_connector_state *conn_state) +{ + struct hdr_output_metadata *hdr_metadata; + + if (!conn_state->hdr_output_metadata) + return false; + + hdr_metadata = conn_state->hdr_output_metadata->data; + + return hdr_metadata->hdmi_metadata_type1.eotf == HDMI_EOTF_SMPTE_ST2084; +} + static void intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state, @@ -3181,7 +3199,26 @@ int intel_dp_compute_min_hblank(struct intel_crtc_state *crtc_state, */ min_hblank = min_hblank - 2; - min_hblank = min(10, min_hblank); + /* + * min_hblank formula is undergoing a change, to avoid underrun use the + * recomended value in spec to compare with the calculated one and use the + * minimum value + */ + if (intel_dp_is_uhbr(crtc_state)) { + /* + * Note: Bspec requires a min_hblank of 2 for YCBCR420 + * with compressed bpp 6, but the minimum compressed bpp + * supported by the driver is 8. + */ + drm_WARN_ON(display->drm, + (crtc_state->dsc.compression_enable && + crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 && + crtc_state->dsc.compressed_bpp_x16 < fxp_q4_from_int(8))); + min_hblank = min(3, min_hblank); + } else { + min_hblank = min(10, min_hblank); + } + crtc_state->min_hblank = min_hblank; return 0; @@ -3842,10 +3879,11 @@ static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) if (ret < 0) return ret; /* Wait for PCON to be FRL Ready */ - wait_for(is_active = drm_dp_pcon_is_frl_ready(&intel_dp->aux) == true, TIMEOUT_FRL_READY_MS); - - if (!is_active) - return -ETIMEDOUT; + ret = poll_timeout_us(is_active = drm_dp_pcon_is_frl_ready(&intel_dp->aux), + is_active, + 1000, TIMEOUT_FRL_READY_MS * 1000, false); + if (ret) + return ret; ret = drm_dp_pcon_frl_configure_1(&intel_dp->aux, max_frl_bw, DP_PCON_ENABLE_SEQUENTIAL_LINK); @@ -3862,12 +3900,11 @@ static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp) * Wait for FRL to be completed * Check if the HDMI Link is up and active. */ - wait_for(is_active = - intel_dp_pcon_is_frl_trained(intel_dp, max_frl_bw_mask, &frl_trained_mask), - TIMEOUT_HDMI_LINK_ACTIVE_MS); - - if (!is_active) - return -ETIMEDOUT; + ret = poll_timeout_us(is_active = intel_dp_pcon_is_frl_trained(intel_dp, max_frl_bw_mask, &frl_trained_mask), + is_active, + 1000, TIMEOUT_HDMI_LINK_ACTIVE_MS * 1000, false); + if (ret) + return ret; frl_trained: drm_dbg(display->drm, "FRL_TRAINED_MASK = %u\n", frl_trained_mask); @@ -4277,10 +4314,26 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp) } static void +intel_edp_set_data_override_rates(struct intel_dp *intel_dp) +{ + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + int *sink_rates = intel_dp->sink_rates; + int i, count = 0; + + for (i = 0; i < intel_dp->num_sink_rates; i++) { + if (intel_bios_encoder_reject_edp_rate(encoder->devdata, + intel_dp->sink_rates[i])) + continue; + + sink_rates[count++] = intel_dp->sink_rates[i]; + } + intel_dp->num_sink_rates = count; +} + +static void intel_edp_set_sink_rates(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; intel_dp->num_sink_rates = 0; @@ -4306,16 +4359,13 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp) break; /* - * Some broken eDP sinks illegally declare support for - * HBR3 without TPS4, and are unable to produce a stable - * output. Reject HBR3 when TPS4 is not available. + * Some platforms cannot reliably drive HBR3 rates due to PHY limitations, + * even if the sink advertises support. Reject any sink rates above HBR2 on + * the known machines for stable output. */ - if (rate >= 810000 && !drm_dp_tps4_supported(intel_dp->dpcd)) { - drm_dbg_kms(display->drm, - "[ENCODER:%d:%s] Rejecting HBR3 due to missing TPS4 support\n", - encoder->base.base.id, encoder->base.name); + if (rate > 540000 && + intel_has_quirk(display, QUIRK_EDP_LIMIT_RATE_HBR2)) break; - } intel_dp->sink_rates[i] = rate; } @@ -4330,6 +4380,8 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp) intel_dp->use_rate_select = true; else intel_dp_set_sink_rates(intel_dp); + + intel_edp_set_data_override_rates(intel_dp); } static bool @@ -5611,14 +5663,9 @@ bool intel_digital_port_connected_locked(struct intel_encoder *encoder) intel_wakeref_t wakeref; with_intel_display_power(display, POWER_DOMAIN_DISPLAY_CORE, wakeref) { - unsigned long wait_expires = jiffies + msecs_to_jiffies_timeout(4); - - do { - is_connected = dig_port->connected(encoder); - if (is_connected || is_glitch_free) - break; - usleep_range(10, 30); - } while (time_before(jiffies, wait_expires)); + poll_timeout_us(is_connected = dig_port->connected(encoder), + is_connected || is_glitch_free, + 30, 4000, false); } return is_connected; |