[PATCH v2 7/8] drm/i915/dp: Allow PCON DSC modes through FRL bw check

Ankit Nautiyal <[email protected]>
Newsgroups org.freedesktop.lists.intel-gfx,org.freedesktop.lists.intel-xe
Message-ID <[email protected]>
intel_dp_frl_bw_valid() rejects any mode whose uncompressed FRL
bandwidth exceeds the PCON/sink max FRL bandwidth, even though we are
capable of enabling PCON DSC encoding at modeset time. As a result,
high-bandwidth HDMI2.1 modes (e.g. 4K120, 8K60) get pruned for sinks
behind a PCON, despite the PCON + sink being able to carry them with
DSC compression.

Now, that the HDMI DSC helpers no longer depend on intel_crtc_state,
reuse them from the FRL bandwidth check. When uncompressed transport does
not fit, compute the lowest compressed bpp allowed for the output format
and verify it:
 - fits the sink's per-scanline chunk-bytes limit and
 - resulets in the required FRL bandwidth within the PCON/sink limits.

This takes care of the existing FIXME in the FRL bandwidth check.

Signed-off-by: Ankit Nautiyal <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 80 ++++++++++++++++++++++---
 1 file changed, 71 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 652215fdb1a7..938e11bc6a46 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -125,6 +125,7 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp)
 
 static void intel_dp_unset_edid(struct intel_dp *intel_dp);
 static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp);
+static bool intel_dp_is_hdmi_2_1_sink(struct intel_dp *intel_dp);
 
 /* Is link rate UHBR and thus 128b/132b? */
 bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state)
@@ -1179,8 +1180,58 @@ static int frl_required_bw(int clock, int bpc,
 	return clock * bpc * 3;
 }
 
+static int frl_required_bw_dsc(int target_clock, int comp_bpp_x16)
+{
+	return DIV_ROUND_UP(target_clock * comp_bpp_x16, 16);
+}
+
+static bool
+intel_dp_pcon_dsc_fits_frl_bw(struct intel_dp *intel_dp,
+			      const struct drm_display_mode *mode,
+			      int bpc, enum intel_output_format sink_format,
+			      int max_frl_bw)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	const struct drm_display_info *info = &connector->base.display_info;
+	int min_dsc_bpp, max_dsc_bpp;
+	int num_slices, slice_width;
+	int hdmi_max_chunk_bytes;
+	int pcon_max_slices, pcon_max_slice_width;
+
+	/* PCON and HDMI sink must both support DSC 1.2 */
+	if (!info->hdmi.dsc_cap.v_1p2 ||
+	    !drm_dp_pcon_enc_is_dsc_1_2(intel_dp->pcon_dsc_dpcd))
+		return false;
+
+	pcon_max_slices = drm_dp_pcon_dsc_max_slices(intel_dp->pcon_dsc_dpcd);
+	pcon_max_slice_width = drm_dp_pcon_dsc_max_slice_width(intel_dp->pcon_dsc_dpcd);
+
+	num_slices = intel_hdmi_dsc_get_num_slices(mode, sink_format,
+						   pcon_max_slices,
+						   pcon_max_slice_width,
+						   info->hdmi.dsc_cap.max_slices,
+						   info->hdmi.dsc_cap.clk_per_slice);
+	if (!num_slices)
+		return false;
+
+	slice_width = DIV_ROUND_UP(mode->hdisplay, num_slices);
+
+	intel_hdmi_dsc_get_min_max_bpp(sink_format, bpc, info->hdmi.dsc_cap.all_bpp,
+				       &min_dsc_bpp, &max_dsc_bpp);
+
+	/* Use the lowest allowed compressed bpp for the best-case bandwidth */
+	hdmi_max_chunk_bytes = info->hdmi.dsc_cap.total_chunk_kbytes * 1024;
+	if (!intel_hdmi_dsc_bpp_fits_chunk_bytes(min_dsc_bpp, num_slices, slice_width,
+						 hdmi_max_chunk_bytes))
+		return false;
+
+	return frl_required_bw_dsc(mode->clock, min_dsc_bpp * 16) <= max_frl_bw;
+}
+
 static enum drm_mode_status
-intel_dp_frl_bw_valid(struct intel_dp *intel_dp, int target_clock,
+intel_dp_frl_bw_valid(struct intel_dp *intel_dp,
+		      const struct drm_display_mode *mode,
+		      int target_clock,
 		      int bpc, enum intel_output_format sink_format,
 		      bool respect_downstream_limits)
 {
@@ -1199,11 +1250,19 @@ intel_dp_frl_bw_valid(struct intel_dp *intel_dp, int target_clock,
 	/* converting bw from Gbps to Kbps*/
 	max_frl_bw = max_frl_bw * 1000000;
 
-	/* #FIXME check bandwidth with DSC if both PCON and HDMI sink support DSC */
-	if (target_bw > max_frl_bw)
-		return MODE_CLOCK_HIGH;
+	if (target_bw <= max_frl_bw)
+		return MODE_OK;
 
-	return MODE_OK;
+	/*
+	 * Uncompressed transport doesn't fit; if both PCON and HDMI sink
+	 * support DSC, check whether DSC compression brings it within limits.
+	 */
+	if (intel_dp_is_hdmi_2_1_sink(intel_dp) &&
+	    intel_dp_pcon_dsc_fits_frl_bw(intel_dp, mode, bpc, sink_format,
+					  max_frl_bw))
+		return MODE_OK;
+
+	return MODE_CLOCK_HIGH;
 }
 
 static bool
@@ -1215,13 +1274,14 @@ intel_dp_pcon_sink_support_frl(struct intel_dp *intel_dp)
 
 static enum drm_mode_status
 intel_dp_hdmi_bw_valid(struct intel_dp *intel_dp,
+		       const struct drm_display_mode *mode,
 		       int target_clock, int bpc,
 		       enum intel_output_format sink_format,
 		       bool respect_downstream_limits)
 {
 	if (intel_dp_pcon_sink_support_frl(intel_dp))
-		return intel_dp_frl_bw_valid(intel_dp, target_clock, bpc,
-					     sink_format,
+		return intel_dp_frl_bw_valid(intel_dp, mode,
+					     target_clock, bpc, sink_format,
 					     respect_downstream_limits);
 
 	return intel_dp_tmds_clock_valid(intel_dp, target_clock, bpc, sink_format,
@@ -1241,7 +1301,8 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
 	    target_clock > intel_dp->dfp.max_dotclock)
 		return MODE_CLOCK_HIGH;
 
-	return intel_dp_hdmi_bw_valid(intel_dp, target_clock, bpc, sink_format, true);
+	return intel_dp_hdmi_bw_valid(intel_dp, mode, target_clock, bpc,
+				      sink_format, true);
 }
 
 static enum drm_mode_status
@@ -1661,7 +1722,8 @@ static int intel_dp_hdmi_compute_bpc(struct intel_dp *intel_dp,
 	for (; bpc >= 8; bpc -= 2) {
 		if (intel_hdmi_bpc_possible(crtc_state, bpc,
 					    intel_dp_has_hdmi_sink(intel_dp)) &&
-		    intel_dp_hdmi_bw_valid(intel_dp, clock, bpc, crtc_state->sink_format,
+		    intel_dp_hdmi_bw_valid(intel_dp, &crtc_state->hw.adjusted_mode,
+					   clock, bpc, crtc_state->sink_format,
 					   respect_downstream_limits) == MODE_OK)
 			return bpc;
 	}
-- 
2.50.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.