return true;
}
+static
+bool intel_dp_can_join(struct intel_display *display,
+ int num_joined_pipes)
+{
+ switch (num_joined_pipes) {
+ case 1:
+ return true;
+ case 2:
+ return HAS_BIGJOINER(display) ||
+ HAS_UNCOMPRESSED_JOINER(display);
+ case 4:
+ return HAS_ULTRAJOINER(display);
+ default:
+ return false;
+ }
+}
+
static enum drm_mode_status
intel_dp_mode_valid(struct drm_connector *_connector,
const struct drm_display_mode *mode)
const struct drm_display_mode *fixed_mode;
int target_clock = mode->clock;
int max_rate, mode_rate, max_lanes, max_link_clock;
- int max_dotclk = display->cdclk.max_dotclk_freq;
u16 dsc_max_compressed_bpp = 0;
u8 dsc_slice_count = 0;
enum drm_mode_status status;
target_clock, mode->hdisplay,
link_bpp_x16, 0);
- num_joined_pipes = intel_dp_num_joined_pipes(intel_dp, connector,
- mode->hdisplay, target_clock);
- max_dotclk *= num_joined_pipes;
+ /*
+ * We cannot determine the required pipe‑join count before knowing whether
+ * DSC is needed, nor can we determine DSC need without knowing the pipe
+ * count.
+ * Because of this dependency cycle, the only correct approach is to iterate
+ * over candidate pipe counts and evaluate each combination.
+ */
+ status = MODE_CLOCK_HIGH;
+ for (num_joined_pipes = 1; num_joined_pipes <= I915_MAX_PIPES; num_joined_pipes++) {
+ int max_dotclk = display->cdclk.max_dotclk_freq;
- if (target_clock > max_dotclk)
- return MODE_CLOCK_HIGH;
+ if (connector->force_joined_pipes &&
+ num_joined_pipes != connector->force_joined_pipes)
+ continue;
- status = intel_pfit_mode_valid(display, mode, output_format, num_joined_pipes);
- if (status != MODE_OK)
- return status;
+ if (!intel_dp_can_join(display, num_joined_pipes))
+ continue;
- if (intel_dp_has_dsc(connector)) {
- int pipe_bpp;
+ if (mode->hdisplay > num_joined_pipes * intel_dp_max_hdisplay_per_pipe(display))
+ continue;
- /*
- * TBD pass the connector BPC,
- * for now U8_MAX so that max BPC on that platform would be picked
- */
- pipe_bpp = intel_dp_dsc_compute_max_bpp(connector, U8_MAX);
+ status = intel_pfit_mode_valid(display, mode, output_format, num_joined_pipes);
+ if (status != MODE_OK)
+ continue;
- /*
- * Output bpp is stored in 6.4 format so right shift by 4 to get the
- * integer value since we support only integer values of bpp.
- */
- if (intel_dp_is_edp(intel_dp)) {
- dsc_max_compressed_bpp =
- drm_edp_dsc_sink_output_bpp(connector->dp.dsc_dpcd) >> 4;
-
- dsc_slice_count =
- intel_dp_dsc_get_slice_count(connector,
- target_clock,
- mode->hdisplay,
- num_joined_pipes);
-
- dsc = dsc_max_compressed_bpp && dsc_slice_count;
- } else if (drm_dp_sink_supports_fec(connector->dp.fec_capability)) {
- unsigned long bw_overhead_flags = 0;
-
- if (!drm_dp_is_uhbr_rate(max_link_clock))
- bw_overhead_flags |= DRM_DP_BW_OVERHEAD_FEC;
-
- dsc = intel_dp_mode_valid_with_dsc(connector,
- max_link_clock, max_lanes,
- target_clock, mode->hdisplay,
- num_joined_pipes,
- output_format, pipe_bpp,
- bw_overhead_flags);
+ if (intel_dp_has_dsc(connector)) {
+ int pipe_bpp;
+
+ /*
+ * TBD pass the connector BPC,
+ * for now U8_MAX so that max BPC on that platform would be picked
+ */
+ pipe_bpp = intel_dp_dsc_compute_max_bpp(connector, U8_MAX);
+
+ /*
+ * Output bpp is stored in 6.4 format so right shift by 4 to get the
+ * integer value since we support only integer values of bpp.
+ */
+ if (intel_dp_is_edp(intel_dp)) {
+ dsc_max_compressed_bpp =
+ drm_edp_dsc_sink_output_bpp(connector->dp.dsc_dpcd) >> 4;
+
+ dsc_slice_count =
+ intel_dp_dsc_get_slice_count(connector,
+ target_clock,
+ mode->hdisplay,
+ num_joined_pipes);
+
+ dsc = dsc_max_compressed_bpp && dsc_slice_count;
+ } else if (drm_dp_sink_supports_fec(connector->dp.fec_capability)) {
+ unsigned long bw_overhead_flags = 0;
+
+ if (!drm_dp_is_uhbr_rate(max_link_clock))
+ bw_overhead_flags |= DRM_DP_BW_OVERHEAD_FEC;
+
+ dsc = intel_dp_mode_valid_with_dsc(connector,
+ max_link_clock, max_lanes,
+ target_clock, mode->hdisplay,
+ num_joined_pipes,
+ output_format, pipe_bpp,
+ bw_overhead_flags);
+ }
}
- }
- if (intel_dp_joiner_needs_dsc(display, num_joined_pipes) && !dsc)
- return MODE_CLOCK_HIGH;
+ if (intel_dp_joiner_needs_dsc(display, num_joined_pipes) && !dsc) {
+ status = MODE_CLOCK_HIGH;
+ continue;
+ }
+
+ if (mode_rate > max_rate && !dsc) {
+ status = MODE_CLOCK_HIGH;
+ continue;
+ }
+
+ status = intel_mode_valid_max_plane_size(display, mode, num_joined_pipes);
+ if (status != MODE_OK)
+ continue;
+
+ max_dotclk *= num_joined_pipes;
+
+ if (target_clock > max_dotclk) {
+ status = MODE_CLOCK_HIGH;
+ continue;
+ }
+
+ break;
+ }
- status = intel_mode_valid_max_plane_size(display, mode, num_joined_pipes);
if (status != MODE_OK)
return status;
- if (mode_rate > max_rate && !dsc)
- return MODE_CLOCK_HIGH;
-
return intel_dp_mode_valid_downstream(connector, mode, target_clock);
}