[PATCH 090/108] drm/i915/dp: Add a mask of valid configurations for modeset computation

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

Add link_config_mask to link_config_limits to track the set of allowed
link configurations during modeset state computation. Keep the existing
min/max rate and lane count limits for now, until all users are
converted to use the configuration mask.

Also add helpers to select the maximum configuration from a mask in the
connector's iteration order. This allows callers to pick the effective
maximum configuration directly from the allowed set without iterating
the configurations.

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

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 0255aeff84b85..f561e984b4d4b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2207,6 +2207,40 @@ static int align_max_compressed_bpp_x16(const struct intel_connector *connector,
}
}

+static int
+intel_dp_get_connector_max_link_config_idx(struct intel_connector *connector,
+ const struct link_config_limits *limits)
+{
+ struct intel_display *display = to_intel_display(connector);
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ struct intel_dp_link_caps_config_order order =
+ intel_dp_link_caps_config_order_for_connector(connector);
+ int config_idx;
+
+ config_idx = intel_dp_link_caps_get_max_config_idx(link_caps, order.key,
+ limits->link_config_mask);
+ drm_WARN_ON(display->drm, config_idx < 0);
+
+ return config_idx;
+}
+
+bool
+intel_dp_get_connector_max_link_config(struct intel_connector *connector,
+ const struct link_config_limits *limits,
+ struct intel_dp_link_config *max_link_config)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ int config_idx;
+
+ config_idx = intel_dp_get_connector_max_link_config_idx(connector, limits);
+ if (config_idx < 0)
+ return false;
+
+ return intel_dp_link_caps_get_config_by_idx(link_caps, config_idx, max_link_config);
+}
+
/*
* Find the max compressed BPP we can find a link configuration for. The BPPs to
* try depend on the source (platform) and sink.
@@ -2560,6 +2594,7 @@ intel_dp_compute_config_link_bpp_limits(struct intel_connector *connector,
&crtc_state->hw.adjusted_mode;
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct intel_dp_link_config max_link_config;
int max_link_bpp_x16;

max_link_bpp_x16 = min(crtc_state->max_link_bpp_x16,
@@ -2589,14 +2624,17 @@ intel_dp_compute_config_link_bpp_limits(struct intel_connector *connector,

limits->link.max_bpp_x16 = max_link_bpp_x16;

+ if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+ return false;
+
drm_dbg_kms(display->drm,
- "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max lanes %d max rate %d max pipe_bpp %d min link_bpp " FXP_Q4_FMT " max link_bpp " FXP_Q4_FMT "\n",
+ "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max link %dx%d max pipe_bpp %d min link_bpp " FXP_Q4_FMT " max link_bpp " FXP_Q4_FMT "\n",
encoder->base.base.id, encoder->base.name,
crtc->base.base.id, crtc->base.name,
adjusted_mode->crtc_clock,
str_on_off(dsc),
- limits->max_lane_count,
- limits->max_rate,
+ max_link_config.lane_count,
+ max_link_config.rate,
limits->pipe.max_bpp,
FXP_Q4_ARGS(limits->link.min_bpp_x16),
FXP_Q4_ARGS(limits->link.max_bpp_x16));
@@ -2647,10 +2685,15 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
struct link_config_limits *limits)
{
struct intel_display *display = to_intel_display(intel_dp);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
struct intel_connector *connector =
to_intel_connector(conn_state->connector);

+ /*
+ * Remove the following min/max rate and lane count setup, once
+ * all users are converted to use link_config_mask instead.
+ */
limits->min_rate = intel_dp_min_link_rate(intel_dp);
limits->max_rate = intel_dp_max_link_rate(intel_dp);

@@ -2659,6 +2702,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->link_config_mask = intel_dp_link_caps_get_allowed_config_mask(link_caps);
+
limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format);
if (is_mst) {
/*
@@ -2733,8 +2778,17 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
* configuration, and typically on older panels these
* values correspond to the native resolution of the panel.
*/
+ int max_config_idx;
+
limits->min_lane_count = limits->max_lane_count;
limits->min_rate = limits->max_rate;
+
+ max_config_idx = intel_dp_get_connector_max_link_config_idx(connector,
+ limits);
+ if (max_config_idx < 0)
+ return false;
+
+ limits->link_config_mask = BIT(max_config_idx);
}

intel_dp_test_compute_config(intel_dp, crtc_state, limits);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 6d6bb9e23ff26..bfba29ba715d5 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -22,11 +22,18 @@ struct intel_crtc_state;
struct intel_digital_port;
struct intel_display;
struct intel_dp;
+struct intel_dp_link_config;
struct intel_encoder;

struct link_config_limits {
+ /*
+ * Remove the following min/max rate and lane count limits
+ * once all users are converted to use link_config_mask
+ * instead.
+ */
int min_rate, max_rate;
int min_lane_count, max_lane_count;
+ u32 link_config_mask;
struct {
/* Uncompressed DSC input or link output bpp in 1 bpp units */
int min_bpp, max_bpp;
@@ -138,6 +145,9 @@ int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector,
u8 dsc_max_bpc);
int intel_dp_compute_min_compressed_bpp_x16(struct intel_connector *connector,
enum intel_output_format output_format);
+bool intel_dp_get_connector_max_link_config(struct intel_connector *connector,
+ const struct link_config_limits *limits,
+ struct intel_dp_link_config *max_link_config);
bool intel_dp_mode_valid_with_dsc(struct intel_connector *connector,
int link_clock, int lane_count,
int mode_clock, int mode_hdisplay,
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 13d39d07b42b5..70f72a32a9a7a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -734,6 +734,50 @@ int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_c
link_config);
}

+static int 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)
+{
+ struct intel_display *display = to_intel_display(link_caps->dp);
+ struct intel_dp_link_caps_config_order order = {
+ .key = order_key,
+ .dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC
+ };
+ int config_idx;
+
+ for_each_dp_link_config_idx(link_caps, order, config_mask, config, &config_idx)
+ break;
+
+ drm_WARN_ON(display->drm, config_idx < 0);
+
+ return config_idx;
+}
+
+/**
+ * intel_dp_link_caps_get_max_config_idx - get the index of the maximum config
+ * @link_caps: link capabilities state
+ * @order_key: ordering key used to choose the maximum config
+ * @config_mask: mask of candidate configurations
+ *
+ * Find the maximum configuration from @config_mask according to @order_key.
+ *
+ * See also:
+ * - &enum intel_dp_link_caps_config_order_key
+ *
+ * Return:
+ * - Configuration index of the maximum matching configuration.
+ * - %-1 if no configuration is selected by @config_mask.
+ */
+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)
+{
+ struct intel_dp_link_config config;
+
+ return get_max_config(link_caps, order_key, config_mask, &config);
+}
+
static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
const struct intel_dp_link_config *max_link_limits)
{
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 009bee0f7dffb..1dfd66380a96f 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_idx()
*/
enum intel_dp_link_caps_config_order_key {
INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW,
@@ -193,6 +194,10 @@ 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);

+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);
+
void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
struct intel_dp_link_config *max_link_limits);
bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
--
2.49.1