aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_dp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dp.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c414
1 files changed, 248 insertions, 166 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index e05e25cd4a94..3903f6ead6e6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -48,6 +48,7 @@
#include "i915_drv.h"
#include "i915_irq.h"
#include "i915_reg.h"
+#include "intel_alpm.h"
#include "intel_atomic.h"
#include "intel_audio.h"
#include "intel_backlight.h"
@@ -68,6 +69,7 @@
#include "intel_dpio_phy.h"
#include "intel_dpll.h"
#include "intel_drrs.h"
+#include "intel_encoder.h"
#include "intel_fifo_underrun.h"
#include "intel_hdcp.h"
#include "intel_hdmi.h"
@@ -75,6 +77,7 @@
#include "intel_hotplug_irq.h"
#include "intel_lspcon.h"
#include "intel_lvds.h"
+#include "intel_modeset_lock.h"
#include "intel_panel.h"
#include "intel_pch_display.h"
#include "intel_pps.h"
@@ -329,7 +332,7 @@ static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
intel_dp->num_common_rates, max_rate);
}
-static int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
+int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
{
if (drm_WARN_ON(&dp_to_i915(intel_dp)->drm,
index < 0 || index >= intel_dp->num_common_rates))
@@ -344,7 +347,7 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp)
return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
}
-static int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port)
+int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port)
{
int vbt_max_lanes = intel_bios_dp_max_lane_count(dig_port->base.devdata);
int max_lanes = dig_port->max_lanes;
@@ -370,19 +373,39 @@ int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
return min3(source_max, sink_max, lane_max);
}
+static int forced_lane_count(struct intel_dp *intel_dp)
+{
+ return clamp(intel_dp->link.force_lane_count, 1, intel_dp_max_common_lane_count(intel_dp));
+}
+
int intel_dp_max_lane_count(struct intel_dp *intel_dp)
{
- switch (intel_dp->max_link_lane_count) {
+ int lane_count;
+
+ if (intel_dp->link.force_lane_count)
+ lane_count = forced_lane_count(intel_dp);
+ else
+ lane_count = intel_dp->link.max_lane_count;
+
+ switch (lane_count) {
case 1:
case 2:
case 4:
- return intel_dp->max_link_lane_count;
+ return lane_count;
default:
- MISSING_CASE(intel_dp->max_link_lane_count);
+ MISSING_CASE(lane_count);
return 1;
}
}
+static int intel_dp_min_lane_count(struct intel_dp *intel_dp)
+{
+ if (intel_dp->link.force_lane_count)
+ return forced_lane_count(intel_dp);
+
+ return 1;
+}
+
/*
* The required data bandwidth for a mode with given pixel clock and bpp. This
* is the required net bandwidth independent of the data bandwidth efficiency.
@@ -436,12 +459,16 @@ int intel_dp_max_link_data_rate(struct intel_dp *intel_dp,
return max_rate;
}
-bool intel_dp_has_bigjoiner(struct intel_dp *intel_dp)
+bool intel_dp_has_joiner(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);
+ /* eDP MSO is not compatible with joiner */
+ if (intel_dp->mso_link_count)
+ return false;
+
return DISPLAY_VER(dev_priv) >= 12 ||
(DISPLAY_VER(dev_priv) == 11 &&
encoder->port != PORT_A);
@@ -477,6 +504,9 @@ static int mtl_max_source_rate(struct intel_dp *intel_dp)
if (intel_encoder_is_c10phy(encoder))
return 810000;
+ if (DISPLAY_VER_FULL(to_i915(encoder->base.dev)) == IP_VER(14, 1))
+ return 1350000;
+
return 2000000;
}
@@ -601,7 +631,7 @@ static int intersect_rates(const int *source_rates, int source_len,
}
/* 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 intel_dp_rate_index(const int *rates, int len, int rate)
{
int i;
@@ -641,7 +671,7 @@ static bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
* boot-up.
*/
if (link_rate == 0 ||
- link_rate > intel_dp->max_link_rate)
+ link_rate > intel_dp->link.max_rate)
return false;
if (lane_count == 0 ||
@@ -651,78 +681,6 @@ static bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
return true;
}
-static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
- int link_rate,
- u8 lane_count)
-{
- /* FIXME figure out what we actually want here */
- const struct drm_display_mode *fixed_mode =
- intel_panel_preferred_fixed_mode(intel_dp->attached_connector);
- int mode_rate, max_rate;
-
- mode_rate = intel_dp_link_required(fixed_mode->clock, 18);
- max_rate = intel_dp_max_link_data_rate(intel_dp, link_rate, lane_count);
- if (mode_rate > max_rate)
- return false;
-
- return true;
-}
-
-int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
- int link_rate, u8 lane_count)
-{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- int index;
-
- /*
- * TODO: Enable fallback on MST links once MST link compute can handle
- * the fallback params.
- */
- if (intel_dp->is_mst) {
- drm_err(&i915->drm, "Link Training Unsuccessful\n");
- return -1;
- }
-
- if (intel_dp_is_edp(intel_dp) && !intel_dp->use_max_params) {
- drm_dbg_kms(&i915->drm,
- "Retrying Link training for eDP with max parameters\n");
- intel_dp->use_max_params = true;
- return 0;
- }
-
- index = intel_dp_rate_index(intel_dp->common_rates,
- intel_dp->num_common_rates,
- link_rate);
- if (index > 0) {
- if (intel_dp_is_edp(intel_dp) &&
- !intel_dp_can_link_train_fallback_for_edp(intel_dp,
- intel_dp_common_rate(intel_dp, index - 1),
- lane_count)) {
- drm_dbg_kms(&i915->drm,
- "Retrying Link training for eDP with same parameters\n");
- return 0;
- }
- intel_dp->max_link_rate = intel_dp_common_rate(intel_dp, index - 1);
- intel_dp->max_link_lane_count = lane_count;
- } else if (lane_count > 1) {
- if (intel_dp_is_edp(intel_dp) &&
- !intel_dp_can_link_train_fallback_for_edp(intel_dp,
- intel_dp_max_common_rate(intel_dp),
- lane_count >> 1)) {
- drm_dbg_kms(&i915->drm,
- "Retrying Link training for eDP with same parameters\n");
- return 0;
- }
- intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
- intel_dp->max_link_lane_count = lane_count >> 1;
- } else {
- drm_err(&i915->drm, "Link Training Unsuccessful\n");
- return -1;
- }
-
- return 0;
-}
-
u32 intel_dp_mode_to_fec_clock(u32 mode_clock)
{
return div_u64(mul_u32_u32(mode_clock, DP_DSC_FEC_OVERHEAD_FACTOR),
@@ -1204,19 +1162,39 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
return MODE_OK;
}
-bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp,
- struct intel_connector *connector,
- int hdisplay, int clock)
+bool intel_dp_need_joiner(struct intel_dp *intel_dp,
+ struct intel_connector *connector,
+ int hdisplay, int clock)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
- if (!intel_dp_has_bigjoiner(intel_dp))
+ if (!intel_dp_has_joiner(intel_dp))
return false;
return clock > i915->display.cdclk.max_dotclk_freq || hdisplay > 5120 ||
connector->force_bigjoiner_enable;
}
+bool intel_dp_has_dsc(const struct intel_connector *connector)
+{
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+
+ if (!HAS_DSC(i915))
+ return false;
+
+ if (connector->mst_port && !HAS_DSC_MST(i915))
+ return false;
+
+ if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
+ connector->panel.vbt.edp.dsc_disable)
+ return false;
+
+ if (!drm_dp_sink_supports_dsc(connector->dp.dsc_dpcd))
+ return false;
+
+ return true;
+}
+
static enum drm_mode_status
intel_dp_mode_valid(struct drm_connector *_connector,
struct drm_display_mode *mode)
@@ -1231,7 +1209,7 @@ intel_dp_mode_valid(struct drm_connector *_connector,
u16 dsc_max_compressed_bpp = 0;
u8 dsc_slice_count = 0;
enum drm_mode_status status;
- bool dsc = false, bigjoiner = false;
+ bool dsc = false, joiner = false;
status = intel_cpu_transcoder_mode_valid(dev_priv, mode);
if (status != MODE_OK)
@@ -1252,9 +1230,9 @@ intel_dp_mode_valid(struct drm_connector *_connector,
target_clock = fixed_mode->clock;
}
- if (intel_dp_need_bigjoiner(intel_dp, connector,
- mode->hdisplay, target_clock)) {
- bigjoiner = true;
+ if (intel_dp_need_joiner(intel_dp, connector,
+ mode->hdisplay, target_clock)) {
+ joiner = true;
max_dotclk *= 2;
}
if (target_clock > max_dotclk)
@@ -1271,8 +1249,7 @@ intel_dp_mode_valid(struct drm_connector *_connector,
mode_rate = intel_dp_link_required(target_clock,
intel_dp_mode_min_output_bpp(connector, mode));
- if (HAS_DSC(dev_priv) &&
- drm_dp_sink_supports_dsc(connector->dp.dsc_dpcd)) {
+ if (intel_dp_has_dsc(connector)) {
enum intel_output_format sink_format, output_format;
int pipe_bpp;
@@ -1301,20 +1278,20 @@ intel_dp_mode_valid(struct drm_connector *_connector,
max_lanes,
target_clock,
mode->hdisplay,
- bigjoiner,
+ joiner,
output_format,
pipe_bpp, 64);
dsc_slice_count =
intel_dp_dsc_get_slice_count(connector,
target_clock,
mode->hdisplay,
- bigjoiner);
+ joiner);
}
dsc = dsc_max_compressed_bpp && dsc_slice_count;
}
- if (intel_dp_joiner_needs_dsc(dev_priv, bigjoiner) && !dsc)
+ if (intel_dp_joiner_needs_dsc(dev_priv, joiner) && !dsc)
return MODE_CLOCK_HIGH;
if (mode_rate > max_rate && !dsc)
@@ -1324,7 +1301,7 @@ intel_dp_mode_valid(struct drm_connector *_connector,
if (status != MODE_OK)
return status;
- return intel_mode_valid_max_plane_size(dev_priv, mode, bigjoiner);
+ return intel_mode_valid_max_plane_size(dev_priv, mode, joiner);
}
bool intel_dp_source_supports_tps3(struct drm_i915_private *i915)
@@ -1374,16 +1351,38 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
drm_dbg_kms(&i915->drm, "common rates: %s\n", str);
}
+static int forced_link_rate(struct intel_dp *intel_dp)
+{
+ int len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.force_rate);
+
+ if (len == 0)
+ return intel_dp_common_rate(intel_dp, 0);
+
+ return intel_dp_common_rate(intel_dp, len - 1);
+}
+
int
intel_dp_max_link_rate(struct intel_dp *intel_dp)
{
int len;
- len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->max_link_rate);
+ if (intel_dp->link.force_rate)
+ return forced_link_rate(intel_dp);
+
+ len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
return intel_dp_common_rate(intel_dp, len - 1);
}
+static int
+intel_dp_min_link_rate(struct intel_dp *intel_dp)
+{
+ if (intel_dp->link.force_rate)
+ return forced_link_rate(intel_dp);
+
+ return intel_dp_common_rate(intel_dp, 0);
+}
+
int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
@@ -1441,15 +1440,16 @@ bool intel_dp_supports_fec(struct intel_dp *intel_dp,
drm_dp_sink_supports_fec(connector->dp.fec_capability);
}
-static bool intel_dp_supports_dsc(const struct intel_connector *connector,
- const struct intel_crtc_state *crtc_state)
+bool intel_dp_supports_dsc(const struct intel_connector *connector,
+ const struct intel_crtc_state *crtc_state)
{
+ if (!intel_dp_has_dsc(connector))
+ return false;
+
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP) && !crtc_state->fec_enable)
return false;
- return intel_dsc_source_support(crtc_state) &&
- connector->dp.dsc_decompression_aux &&
- drm_dp_sink_supports_dsc(connector->dp.dsc_dpcd);
+ return intel_dsc_source_support(crtc_state);
}
static int intel_dp_hdmi_compute_bpc(struct intel_dp *intel_dp,
@@ -2015,7 +2015,7 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp,
dsc_joiner_max_bpp = get_max_compressed_bpp_with_joiner(i915, adjusted_mode->clock,
adjusted_mode->hdisplay,
- pipe_config->bigjoiner_pipes);
+ pipe_config->joiner_pipes);
dsc_max_bpp = min(dsc_max_bpp, dsc_joiner_max_bpp);
dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16));
@@ -2249,7 +2249,7 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
intel_dp_dsc_get_slice_count(connector,
adjusted_mode->crtc_clock,
adjusted_mode->crtc_hdisplay,
- pipe_config->bigjoiner_pipes);
+ pipe_config->joiner_pipes);
if (!dsc_dp_slice_count) {
drm_dbg_kms(&dev_priv->drm,
"Compressed Slice Count not supported\n");
@@ -2263,7 +2263,7 @@ 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 (pipe_config->bigjoiner_pipes || pipe_config->dsc.slice_count > 1)
+ if (pipe_config->joiner_pipes || pipe_config->dsc.slice_count > 1)
pipe_config->dsc.dsc_split = true;
ret = intel_dp_dsc_compute_params(connector, pipe_config);
@@ -2353,13 +2353,14 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
bool dsc,
struct link_config_limits *limits)
{
- limits->min_rate = intel_dp_common_rate(intel_dp, 0);
+ limits->min_rate = intel_dp_min_link_rate(intel_dp);
limits->max_rate = intel_dp_max_link_rate(intel_dp);
/* FIXME 128b/132b SST support missing */
limits->max_rate = min(limits->max_rate, 810000);
+ limits->min_rate = min(limits->min_rate, limits->max_rate);
- limits->min_lane_count = 1;
+ 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);
@@ -2429,12 +2430,12 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
!intel_dp_supports_fec(intel_dp, connector, pipe_config))
return -EINVAL;
- if (intel_dp_need_bigjoiner(intel_dp, connector,
- adjusted_mode->crtc_hdisplay,
- adjusted_mode->crtc_clock))
- pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
+ if (intel_dp_need_joiner(intel_dp, connector,
+ adjusted_mode->crtc_hdisplay,
+ adjusted_mode->crtc_clock))
+ pipe_config->joiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
- joiner_needs_dsc = intel_dp_joiner_needs_dsc(i915, pipe_config->bigjoiner_pipes);
+ joiner_needs_dsc = intel_dp_joiner_needs_dsc(i915, pipe_config->joiner_pipes);
dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en ||
!intel_dp_compute_config_limits(intel_dp, pipe_config,
@@ -2633,11 +2634,19 @@ static void intel_dp_compute_as_sdp(struct intel_dp *intel_dp,
/* Currently only DP_AS_SDP_AVT_FIXED_VTOTAL mode supported */
as_sdp->sdp_type = DP_SDP_ADAPTIVE_SYNC;
as_sdp->length = 0x9;
- as_sdp->mode = DP_AS_SDP_AVT_FIXED_VTOTAL;
- as_sdp->vtotal = adjusted_mode->vtotal;
- as_sdp->target_rr = 0;
as_sdp->duration_incr_ms = 0;
as_sdp->duration_incr_ms = 0;
+
+ if (crtc_state->cmrr.enable) {
+ as_sdp->mode = DP_AS_SDP_FAVT_TRR_REACHED;
+ as_sdp->vtotal = adjusted_mode->vtotal;
+ as_sdp->target_rr = drm_mode_vrefresh(adjusted_mode);
+ as_sdp->target_rr_divider = true;
+ } else {
+ as_sdp->mode = DP_AS_SDP_AVT_FIXED_VTOTAL;
+ as_sdp->vtotal = adjusted_mode->vtotal;
+ as_sdp->target_rr = 0;
+ }
}
static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp,
@@ -2660,14 +2669,6 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp,
if (intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
intel_dp_compute_vsc_colorimetry(crtc_state, conn_state,
vsc);
- } else if (crtc_state->has_psr2) {
- /*
- * [PSR2 without colorimetry]
- * Prepare VSC Header for SU as per eDP 1.4 spec, Table 6-11
- * 3D stereo + PSR/PSR2 + Y-coordinate.
- */
- vsc->revision = 0x4;
- vsc->length = 0xe;
} else if (crtc_state->has_panel_replay) {
/*
* [Panel Replay without colorimetry info]
@@ -2676,6 +2677,14 @@ static void intel_dp_compute_vsc_sdp(struct intel_dp *intel_dp,
*/
vsc->revision = 0x6;
vsc->length = 0x10;
+ } else if (crtc_state->has_sel_update) {
+ /*
+ * [PSR2 without colorimetry]
+ * Prepare VSC Header for SU as per eDP 1.4 spec, Table 6-11
+ * 3D stereo + PSR/PSR2 + Y-coordinate.
+ */
+ vsc->revision = 0x4;
+ vsc->length = 0xe;
} else {
/*
* [PSR1]
@@ -2754,7 +2763,7 @@ intel_dp_drrs_compute_config(struct intel_connector *connector,
* FIXME all joined pipes share the same transcoder.
* Need to account for that when updating M/N live.
*/
- if (has_seamless_m_n(connector) && !pipe_config->bigjoiner_pipes)
+ if (has_seamless_m_n(connector) && !pipe_config->joiner_pipes)
pipe_config->update_m_n = true;
if (!can_enable_drrs(connector, pipe_config, downclock_mode)) {
@@ -2783,7 +2792,6 @@ intel_dp_drrs_compute_config(struct intel_connector *connector,
}
static bool intel_dp_has_audio(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
@@ -2792,8 +2800,7 @@ static bool intel_dp_has_audio(struct intel_encoder *encoder,
struct intel_connector *connector =
to_intel_connector(conn_state->connector);
- if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) &&
- !intel_dp_port_has_audio(i915, encoder->port))
+ if (!intel_dp_port_has_audio(i915, encoder->port))
return false;
if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
@@ -2852,14 +2859,14 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder,
struct drm_connector_state *conn_state)
{
pipe_config->has_audio =
- intel_dp_has_audio(encoder, pipe_config, conn_state) &&
+ intel_dp_has_audio(encoder, conn_state) &&
intel_audio_compute_config(encoder, pipe_config, conn_state);
pipe_config->sdp_split_enable = pipe_config->has_audio &&
intel_dp_is_uhbr(pipe_config);
}
-void intel_dp_queue_modeset_retry_work(struct intel_connector *connector)
+static void intel_dp_queue_modeset_retry_work(struct intel_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
@@ -2868,6 +2875,7 @@ void intel_dp_queue_modeset_retry_work(struct intel_connector *connector)
drm_connector_put(&connector->base);
}
+/* NOTE: @state is only valid for MST links and can be %NULL for SST. */
void
intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state,
struct intel_encoder *encoder,
@@ -2876,6 +2884,7 @@ intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state,
struct intel_connector *connector;
struct intel_digital_connector_state *conn_state;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
int i;
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
@@ -2884,6 +2893,9 @@ intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state,
return;
}
+ if (drm_WARN_ON(&i915->drm, !state))
+ return;
+
for_each_new_intel_connector_in_state(state, connector, conn_state, i) {
if (!conn_state->base.crtc)
continue;
@@ -2997,6 +3009,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
intel_vrr_compute_config(pipe_config, conn_state);
intel_dp_compute_as_sdp(intel_dp, pipe_config);
intel_psr_compute_config(intel_dp, pipe_config, conn_state);
+ intel_alpm_lobf_compute_config(intel_dp, pipe_config, conn_state);
intel_dp_drrs_compute_config(connector, pipe_config, link_bpp_x16);
intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
@@ -3014,10 +3027,12 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
intel_dp->lane_count = lane_count;
}
-static void intel_dp_reset_max_link_params(struct intel_dp *intel_dp)
+void intel_dp_reset_link_params(struct intel_dp *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);
+ intel_dp->link.max_lane_count = intel_dp_max_common_lane_count(intel_dp);
+ intel_dp->link.max_rate = intel_dp_max_common_rate(intel_dp);
+ intel_dp->link.retrain_disabled = false;
+ intel_dp->link.seq_train_failures = 0;
}
/* Enable backlight PWM and backlight PP control. */
@@ -3352,7 +3367,7 @@ void intel_dp_sync_state(struct intel_encoder *encoder,
intel_dp_tunnel_resume(intel_dp, crtc_state, dpcd_updated);
if (crtc_state)
- intel_dp_reset_max_link_params(intel_dp);
+ intel_dp_reset_link_params(intel_dp);
}
bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
@@ -4227,6 +4242,9 @@ static ssize_t intel_dp_as_sdp_pack(const struct drm_dp_as_sdp *as_sdp,
sdp->db[3] = as_sdp->target_rr & 0xFF;
sdp->db[4] = (as_sdp->target_rr >> 8) & 0x3;
+ if (as_sdp->target_rr_divider)
+ sdp->db[4] |= 0x20;
+
return length;
}
@@ -4350,7 +4368,8 @@ void intel_dp_set_infoframes(struct intel_encoder *encoder,
const struct drm_connector_state *conn_state)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
+ i915_reg_t reg = HSW_TVIDEO_DIP_CTL(dev_priv,
+ crtc_state->cpu_transcoder);
u32 dip_enable = VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_GCP_HSW |
VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW |
VIDEO_DIP_ENABLE_SPD_HSW | VIDEO_DIP_ENABLE_DRM_GLK;
@@ -4407,6 +4426,7 @@ int intel_dp_as_sdp_unpack(struct drm_dp_as_sdp *as_sdp,
as_sdp->mode = sdp->db[0] & DP_ADAPTIVE_SYNC_SDP_OPERATION_MODE;
as_sdp->vtotal = (sdp->db[2] << 8) | sdp->db[1];
as_sdp->target_rr = (u64)sdp->db[3] | ((u64)sdp->db[4] & 0x3);
+ as_sdp->target_rr_divider = sdp->db[4] & 0x20 ? true : false;
return 0;
}
@@ -4432,7 +4452,8 @@ static int intel_dp_vsc_sdp_unpack(struct drm_dp_vsc_sdp *vsc,
vsc->length = sdp->sdp_header.HB3;
if ((sdp->sdp_header.HB2 == 0x2 && sdp->sdp_header.HB3 == 0x8) ||
- (sdp->sdp_header.HB2 == 0x4 && sdp->sdp_header.HB3 == 0xe)) {
+ (sdp->sdp_header.HB2 == 0x4 && sdp->sdp_header.HB3 == 0xe) ||
+ (sdp->sdp_header.HB2 == 0x6 && sdp->sdp_header.HB3 == 0x10)) {
/*
* - HB2 = 0x2, HB3 = 0x8
* VSC SDP supporting 3D stereo + PSR
@@ -4440,6 +4461,8 @@ static int intel_dp_vsc_sdp_unpack(struct drm_dp_vsc_sdp *vsc,
* VSC SDP supporting 3D stereo + PSR2 with Y-coordinate of
* first scan line of the SU region (applies to eDP v1.4b
* and higher).
+ * - HB2 = 0x6, HB3 = 0x10
+ * VSC SDP supporting 3D stereo + Panel Replay.
*/
return 0;
} else if (sdp->sdp_header.HB2 == 0x5 && sdp->sdp_header.HB3 == 0x13) {
@@ -5017,6 +5040,8 @@ static bool
intel_dp_check_mst_status(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct intel_encoder *encoder = &dig_port->base;
bool link_ok = true;
bool reprobe_needed = false;
@@ -5062,7 +5087,10 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
drm_dp_mst_hpd_irq_send_new_request(&intel_dp->mst_mgr);
}
- return link_ok && !reprobe_needed;
+ if (!link_ok || intel_dp->link.force_retrain)
+ intel_encoder_link_check_queue_work(encoder, 0);
+
+ return !reprobe_needed;
}
static void
@@ -5108,6 +5136,9 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
if (intel_psr_enabled(intel_dp))
return false;
+ if (intel_dp->link.force_retrain)
+ return true;
+
if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
link_status) < 0)
return false;
@@ -5124,6 +5155,12 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
intel_dp->lane_count))
return false;
+ if (intel_dp->link.retrain_disabled)
+ return false;
+
+ if (intel_dp->link.seq_train_failures)
+ return true;
+
/* Retrain if link not ok */
return !intel_dp_link_ok(intel_dp, link_status);
}
@@ -5209,12 +5246,13 @@ static bool intel_dp_is_connected(struct intel_dp *intel_dp)
intel_dp->is_mst;
}
-int intel_dp_retrain_link(struct intel_encoder *encoder,
- struct drm_modeset_acquire_ctx *ctx)
+static int intel_dp_retrain_link(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;
+ bool mst_output = false;
u8 pipe_mask;
int ret;
@@ -5239,13 +5277,19 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
if (!intel_dp_needs_link_retrain(intel_dp))
return 0;
- drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] retraining link\n",
- encoder->base.base.id, encoder->base.name);
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] retraining link (forced %s)\n",
+ encoder->base.base.id, encoder->base.name,
+ str_yes_no(intel_dp->link.force_retrain));
for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, crtc, pipe_mask) {
const struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
+ mst_output = true;
+ break;
+ }
+
/* Suppress underruns caused by re-training */
intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
if (crtc_state->has_pch_encoder)
@@ -5253,19 +5297,26 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
intel_crtc_pch_transcoder(crtc), false);
}
+ /* TODO: use a modeset for SST as well. */
+ if (mst_output) {
+ ret = intel_modeset_commit_pipes(dev_priv, pipe_mask, ctx);
+
+ if (ret && ret != -EDEADLK)
+ drm_dbg_kms(&dev_priv->drm,
+ "[ENCODER:%d:%s] link retraining failed: %pe\n",
+ encoder->base.base.id, encoder->base.name,
+ ERR_PTR(ret));
+
+ goto out;
+ }
+
for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, crtc, pipe_mask) {
const struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
- /* retrain on the MST master transcoder */
- if (DISPLAY_VER(dev_priv) >= 12 &&
- intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) &&
- !intel_dp_mst_is_master_trans(crtc_state))
- continue;
-
intel_dp_check_frl_training(intel_dp);
intel_dp_pcon_dsc_configure(intel_dp, crtc_state);
- intel_dp_start_link_train(intel_dp, crtc_state);
+ intel_dp_start_link_train(NULL, intel_dp, crtc_state);
intel_dp_stop_link_train(intel_dp, crtc_state);
break;
}
@@ -5283,7 +5334,37 @@ int intel_dp_retrain_link(struct intel_encoder *encoder,
intel_crtc_pch_transcoder(crtc), true);
}
- return 0;
+out:
+ if (ret != -EDEADLK)
+ intel_dp->link.force_retrain = false;
+
+ return ret;
+}
+
+void intel_dp_link_check(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct drm_modeset_acquire_ctx ctx;
+ int ret;
+
+ intel_modeset_lock_ctx_retry(&ctx, NULL, 0, ret)
+ ret = intel_dp_retrain_link(encoder, &ctx);
+
+ drm_WARN_ON(&i915->drm, ret);
+}
+
+void intel_dp_check_link_state(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct intel_encoder *encoder = &dig_port->base;
+
+ if (!intel_dp_is_connected(intel_dp))
+ return;
+
+ if (!intel_dp_needs_link_retrain(intel_dp))
+ return;
+
+ intel_encoder_link_check_queue_work(encoder, 0);
}
static int intel_dp_prep_phy_test(struct intel_dp *intel_dp,
@@ -5496,9 +5577,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
/* Handle CEC interrupts, if any */
drm_dp_cec_irq(&intel_dp->aux);
- /* defer to the hotplug work for link retraining if needed */
- if (intel_dp_needs_link_retrain(intel_dp))
- return false;
+ intel_dp_check_link_state(intel_dp);
intel_psr_short_pulse(intel_dp);
@@ -5858,6 +5937,7 @@ intel_dp_detect(struct drm_connector *connector,
memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
memset(intel_connector->dp.dsc_dpcd, 0, sizeof(intel_connector->dp.dsc_dpcd));
intel_dp->psr.sink_panel_replay_support = false;
+ intel_dp->psr.sink_panel_replay_su_support = false;
intel_dp_mst_disconnect(intel_dp);
@@ -5880,12 +5960,8 @@ intel_dp_detect(struct drm_connector *connector,
intel_dp_mst_configure(intel_dp);
- /*
- * TODO: Reset link params when switching to MST mode, until MST
- * supports link training fallback params.
- */
- if (intel_dp->reset_link_params || intel_dp->is_mst) {
- intel_dp_reset_max_link_params(intel_dp);
+ if (intel_dp->reset_link_params) {
+ intel_dp_reset_link_params(intel_dp);
intel_dp->reset_link_params = false;
}
@@ -5904,12 +5980,13 @@ intel_dp_detect(struct drm_connector *connector,
/*
* Some external monitors do not signal loss of link synchronization
* with an IRQ_HPD, so force a link status check.
+ *
+ * TODO: this probably became redundant, so remove it: the link state
+ * is rechecked/recovered now after modesets, where the loss of
+ * synchronization tends to occur.
*/
- if (!intel_dp_is_edp(intel_dp)) {
- ret = intel_dp_retrain_link(encoder, ctx);
- if (ret)
- return ret;
- }
+ if (!intel_dp_is_edp(intel_dp))
+ intel_dp_check_link_state(intel_dp);
/*
* Clearing NACK and defer counts to get their exact values
@@ -6051,11 +6128,14 @@ void intel_dp_connector_sync_state(struct intel_connector *connector,
}
}
-void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
+void intel_dp_encoder_flush_work(struct drm_encoder *_encoder)
{
- struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+ struct intel_encoder *encoder = to_intel_encoder(_encoder);
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct intel_dp *intel_dp = &dig_port->dp;
+ intel_encoder_link_check_flush_work(encoder);
+
intel_dp_mst_encoder_cleanup(dig_port);
intel_dp_tunnel_destroy(intel_dp);
@@ -6361,8 +6441,8 @@ bool intel_dp_is_port_edp(struct drm_i915_private *i915, enum port port)
return _intel_dp_is_port_edp(i915, devdata, port);
}
-static bool
-has_gamut_metadata_dip(struct intel_encoder *encoder)
+bool
+intel_dp_has_gamut_metadata_dip(struct intel_encoder *encoder)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
enum port port = encoder->port;
@@ -6409,7 +6489,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
intel_attach_dp_colorspace_property(connector);
}
- if (has_gamut_metadata_dip(&dp_to_dig_port(intel_dp)->base))
+ if (intel_dp_has_gamut_metadata_dip(&dp_to_dig_port(intel_dp)->base))
drm_connector_attach_hdr_output_metadata_property(connector);
if (HAS_VRR(dev_priv))
@@ -6508,6 +6588,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
*/
intel_hpd_enable_detection(encoder);
+ intel_alpm_init_dpcd(intel_dp);
+
/* Cache DPCD and EDID for edp. */
has_dpcd = intel_edp_init_dpcd(intel_dp, intel_connector);
@@ -6737,7 +6819,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
intel_dp_set_source_rates(intel_dp);
intel_dp_set_common_rates(intel_dp);
- intel_dp_reset_max_link_params(intel_dp);
+ intel_dp_reset_link_params(intel_dp);
/* init MST on ports that can support it */
intel_dp_mst_encoder_init(dig_port,