@@ -1596,6 +1596,16 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
return ret;
}
+ return 0;
+}
+
+static void
+intel_dp_print_link_config(struct intel_crtc_state *pipe_config)
+{
+ struct drm_i915_private *i915 = to_i915(pipe_config->uapi.crtc->dev);
+ const struct drm_display_mode *adjusted_mode =
+ &pipe_config->hw.adjusted_mode;
+
if (pipe_config->dsc.compression_enable) {
drm_dbg_kms(&i915->drm,
"DP lane count %d clock %d Input bpp %d Compressed bpp %d\n",
@@ -1621,7 +1631,6 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
intel_dp_max_data_rate(pipe_config->port_clock,
pipe_config->lane_count));
}
- return 0;
}
bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
@@ -1915,6 +1924,72 @@ static bool intel_dp_has_audio(struct intel_encoder *encoder,
return intel_conn_state->force_audio == HDMI_AUDIO_ON;
}
+/*
+ * If modeset is not allowed it checks for link computed state and if different
+ * it checks if is possible to fallback to previous configuration.
+ *
+ * Returns 0 if modeset is allowed, link computed states matches or fallback is
+ * possible otherwise returns a errno.
+ */
+static int
+intel_dp_compute_link_config_no_modeset_fallback(struct intel_crtc_state *crtc_state)
+{
+ struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state);
+ struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+ const struct intel_crtc_state *old_crtc_state;
+ int output_bpp, mode_rate, old_link_avail;
+ struct intel_crtc *crtc;
+
+ if (state->base.allow_modeset)
+ return 0;
+
+ crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
+
+ /* Check if both states matches */
+ if (crtc_state->output_format == old_crtc_state->output_format &&
+ crtc_state->port_clock == old_crtc_state->port_clock &&
+ crtc_state->lane_count == old_crtc_state->lane_count &&
+ crtc_state->pipe_bpp == old_crtc_state->pipe_bpp &&
+ crtc_state->dsc.compression_enable == old_crtc_state->dsc.compression_enable &&
+ crtc_state->dsc.compressed_bpp == old_crtc_state->dsc.compressed_bpp &&
+ crtc_state->dsc.slice_count == old_crtc_state->dsc.slice_count &&
+ crtc_state->bigjoiner_pipes == old_crtc_state->bigjoiner_pipes)
+ return 0;
+
+ /*
+ * Modeset will be required if any of this changed, there is no way
+ * around it
+ */
+ if (crtc_state->output_format != old_crtc_state->output_format ||
+ crtc_state->bigjoiner_pipes != old_crtc_state->bigjoiner_pipes ||
+ crtc_state->dsc.compression_enable != old_crtc_state->dsc.compression_enable)
+ return -EINVAL;
+
+ /* TODO: Not supporting DSC fallback but it might be possible */
+ if (crtc_state->dsc.compression_enable)
+ return -EINVAL;
+
+ output_bpp = intel_dp_output_bpp(crtc_state->output_format,
+ old_crtc_state->pipe_bpp);
+ mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+ output_bpp);
+
+ old_link_avail = intel_dp_max_data_rate(old_crtc_state->port_clock,
+ old_crtc_state->lane_count);
+
+ /* Check if old link configuration has enough bandwidth for new mode */
+ if (mode_rate > old_link_avail)
+ return -EINVAL;
+
+ /* Fallback is possible */
+ crtc_state->lane_count = old_crtc_state->lane_count;
+ crtc_state->pipe_bpp = old_crtc_state->pipe_bpp;
+ crtc_state->port_clock = old_crtc_state->port_clock;
+
+ return 0;
+}
+
static int
intel_dp_compute_output_format(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
@@ -1950,8 +2025,17 @@ intel_dp_compute_output_format(struct intel_encoder *encoder,
crtc_state->output_format = intel_dp_output_format(connector, true);
ret = intel_dp_compute_link_config(encoder, crtc_state, conn_state,
respect_downstream_limits);
+ if (ret)
+ return ret;
}
+ ret = intel_dp_compute_link_config_no_modeset_fallback(crtc_state);
+ if (ret)
+ drm_dbg_kms(&i915->drm, "DP link configuration requires "
+ "changes but modeset is not allowed\n");
+
+ intel_dp_print_link_config(crtc_state);
+
return ret;
}
When an atomic commit has changes that allows it to go to a lower DP link configuration it will require a modeset but userspace might not want it, so it would not set the modeset allowed flag causing commit to fail. Here in such case it tries to keep previous and trained link configuration for the new state. Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> --- drivers/gpu/drm/i915/display/intel_dp.c | 86 ++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-)