[PATCH 095/108] drm/i915/dp_mst: Use link caps for MST DSC config selection

Imre Deak
2026-04-28T12:55:35Z

Use the link caps helper to select the maximum DP MST link configuration
for DSC computation, instead of using the separate max rate and lane
count limits, which may not form a valid configuration after individual
configs are disabled by fallback.

Also look up the maximum rate for state computation via the configuration
mask when checking the DSC hblank expansion quirk.

This is a step towards unifying configuration selection and iteration
across connector types and between compute and fallback paths.

The state computation should likely consider all allowed configurations,
as noted in the code comment; for now keep the existing DP MST DSC
behavior of selecting the maximum BW configuration determined by the MST
connector BW config iteration order.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
.../gpu/drm/i915/display/intel_dp_link_caps.c | 21 +++++++++
.../gpu/drm/i915/display/intel_dp_link_caps.h | 4 ++
drivers/gpu/drm/i915/display/intel_dp_mst.c | 44 ++++++++++++++++---
3 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 2ec55856636f5..f822c8952df3b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -749,6 +749,27 @@ static int get_max_config(struct intel_dp_link_caps *link_caps,
return config_idx;
}

+/**
+ * intel_dp_link_caps_get_max_config - get the maximum config in a given order
+ * @link_caps: link capabilities state
+ * @order_key: ordering key used to rank candidate configurations
+ * @config_mask: mask of candidate configurations
+ * @max_config: returned maximum link configuration
+ *
+ * Find the last configuration from @config_mask in the iteration order
+ * selected by @order_key, and store it in @max_config.
+ *
+ * See also:
+ * - &enum intel_dp_link_caps_config_order_key
+ */
+void intel_dp_link_caps_get_max_config(struct intel_dp_link_caps *link_caps,
+ enum intel_dp_link_caps_config_order_key order_key,
+ u32 config_mask,
+ struct intel_dp_link_config *max_config)
+{
+ get_max_config(link_caps, order_key, config_mask, max_config);
+}
+
/**
* intel_dp_link_caps_get_max_config_idx - get the index of the maximum config
* @link_caps: link capabilities state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index a907b99cd4cf9..742b88e6b0643 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -27,6 +27,7 @@ struct intel_dp_link_config;
*
* See also:
* - &struct intel_dp_link_caps_config_order
+ * - intel_dp_link_caps_get_max_config()
* - intel_dp_link_caps_get_max_config_idx()
*/
enum intel_dp_link_caps_config_order_key {
@@ -193,6 +194,9 @@ int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_c
enum intel_dp_link_caps_config_match_type match_type,
const struct intel_dp_link_config *config);

+void intel_dp_link_caps_get_max_config(struct intel_dp_link_caps *link_caps,
+ enum intel_dp_link_caps_config_order_key order_key,
+ u32 config_mask, struct intel_dp_link_config *config);
int intel_dp_link_caps_get_max_config_idx(struct intel_dp_link_caps *link_caps,
enum intel_dp_link_caps_config_order_key order_key,
u32 config_mask);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 35f298255a677..080966ec3fd31 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -477,6 +477,7 @@ static int mst_stream_dsc_compute_link_config(struct intel_dp *intel_dp,
{
struct intel_display *display = to_intel_display(intel_dp);
struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_dp_link_config max_link_config;

crtc_state->pipe_bpp = limits->pipe.max_bpp;

@@ -484,8 +485,17 @@ static int mst_stream_dsc_compute_link_config(struct intel_dp *intel_dp,
"DSC Sink supported compressed min bpp " FXP_Q4_FMT " compressed max bpp " FXP_Q4_FMT "\n",
FXP_Q4_ARGS(limits->link.min_bpp_x16), FXP_Q4_ARGS(limits->link.max_bpp_x16));

- crtc_state->lane_count = limits->max_lane_count;
- crtc_state->port_clock = limits->max_rate;
+ /*
+ * FIXME: Use a proper iteration over the link configurations, instead
+ * of using only the max BW config. For instance UHBR rate configs may
+ * have additional limitations over non-UHBR ones, due to the DSC DPT
+ * bpp maximum limit.
+ */
+ if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+ return -EINVAL;
+
+ crtc_state->port_clock = max_link_config.rate;
+ crtc_state->lane_count = max_link_config.lane_count;

return intel_dp_mtp_tu_compute_config(intel_dp, crtc_state, conn_state,
limits->link.min_bpp_x16,
@@ -501,6 +511,20 @@ static int mode_hblank_period_ns(const struct drm_display_mode *mode)
mode->crtc_clock);
}

+static int get_connector_max_rate(const struct intel_connector *connector,
+ const struct link_config_limits *limits)
+{
+ struct intel_dp *intel_dp = intel_attached_dp((struct intel_connector *)connector);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ struct intel_dp_link_config max_link_config;
+
+ intel_dp_link_caps_get_max_config(link_caps,
+ INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE,
+ limits->link_config_mask, &max_link_config);
+
+ return max_link_config.rate;
+}
+
static bool
hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector,
const struct intel_crtc_state *crtc_state,
@@ -511,11 +535,13 @@ hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector,
bool is_uhbr_sink = connector->mst.dp &&
drm_dp_128b132b_supported(connector->mst.dp->dpcd);
int hblank_limit = is_uhbr_sink ? 500 : 300;
+ int max_rate;

if (!connector->dp.dsc_hblank_expansion_quirk)
return false;

- if (is_uhbr_sink && !drm_dp_is_uhbr_rate(limits->max_rate))
+ max_rate = get_connector_max_rate(connector, limits);
+ if (is_uhbr_sink && !drm_dp_is_uhbr_rate(max_rate))
return false;

if (mode_hblank_period_ns(adjusted_mode) > hblank_limit)
@@ -537,6 +563,7 @@ adjust_limits_for_dsc_hblank_expansion_quirk(struct intel_dp *intel_dp,
struct intel_display *display = to_intel_display(connector);
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
int min_bpp_x16 = limits->link.min_bpp_x16;
+ int max_rate;

if (!hblank_expansion_quirk_needs_dsc(connector, crtc_state, limits))
return true;
@@ -563,11 +590,16 @@ adjust_limits_for_dsc_hblank_expansion_quirk(struct intel_dp *intel_dp,
return true;
}

- drm_WARN_ON(display->drm, limits->min_rate != limits->max_rate);
+ /*
+ * Atm, supporting only a single allowed link configuration, which
+ * ensures that max_rate == min_rate.
+ */
+ drm_WARN_ON(display->drm, !is_power_of_2(limits->link_config_mask));

- if (limits->max_rate < 540000)
+ max_rate = get_connector_max_rate(connector, limits);
+ if (max_rate < 540000)
min_bpp_x16 = fxp_q4_from_int(13);
- else if (limits->max_rate < 810000)
+ else if (max_rate < 810000)
min_bpp_x16 = fxp_q4_from_int(10);

if (limits->link.min_bpp_x16 >= min_bpp_x16)
--
2.49.1