drm/i915: Ensure DSC has enough BW and stays within HW limits
authorStanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Mon, 6 Mar 2023 08:04:01 +0000 (10:04 +0200)
committerStanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Fri, 10 Mar 2023 08:29:49 +0000 (10:29 +0200)
We currently have an issue with some BPPs when using DSC.
According to the HW team, the reason is that a single VDSC engine
instance has some BW limitations that must be accounted for.
So, whenever we approach around 90% of the CDCLK, a second VDSC engine
has to be used.
This always means using two slices. However, in our current code,
the amount of slices is calculated independently of whether
we need to enable the second VDSC engine or not.
This leads to some logical issues when, according to the pixel clock needs,
we need to enable the second VDSC engine.
But as we calculated previously that we can only use a single slice,
we can't do that and fail.
So, we need to fix that so that the number of VDSC engines enabled
should depend on the number of slices, and the number of slices
should also depend on BW requirements.
Lastly, we didn't have BPP limitation for ADLP/MTL/DG2 implemented,
which says that DSC output BPPs can only be chosen within the range of 8 to 27
(BSpec 49259).
All of this applied together allows us to fix existing FIFO underruns,
which we have in many DSC tests.

v2: - Replace min with clamp_t(Jani Nikula)
    - Fix commit message(Swati Sharma)
    - Added "Closes"(Swati Sharma)

BSpec: 49259
HSDES: 18027167222

Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/8231
Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Reviewed-by: Vinod Govindapillai <vinod.govindapillai@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230306080401.22552-1-stanislav.lisovskiy@intel.com
drivers/gpu/drm/i915/display/intel_dp.c

index aee93b0..8e16745 100644 (file)
@@ -687,6 +687,12 @@ u32 intel_dp_dsc_nearest_valid_bpp(struct drm_i915_private *i915, u32 bpp, u32 p
        /* From XE_LPD onwards we support from bpc upto uncompressed bpp-1 BPPs */
        if (DISPLAY_VER(i915) >= 13) {
                bits_per_pixel = min(bits_per_pixel, pipe_bpp - 1);
+
+               /*
+                * According to BSpec, 27 is the max DSC output bpp,
+                * 8 is the min DSC output bpp
+                */
+               bits_per_pixel = clamp_t(u32, bits_per_pixel, 8, 27);
        } else {
                /* Find the nearest match in the array of known BPPs from VESA */
                for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) {
@@ -771,6 +777,13 @@ u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
                min_slice_count = DIV_ROUND_UP(mode_clock,
                                               DP_DSC_MAX_ENC_THROUGHPUT_1);
 
+       /*
+        * Due to some DSC engine BW limitations, we need to enable second
+        * slice and VDSC engine, whenever we approach close enough to max CDCLK
+        */
+       if (mode_clock >= ((i915->display.cdclk.max_cdclk_freq * 85) / 100))
+               min_slice_count = max_t(u8, min_slice_count, 2);
+
        max_slice_width = drm_dp_dsc_sink_max_slice_width(intel_dp->dsc_dpcd);
        if (max_slice_width < DP_DSC_MIN_SLICE_WIDTH_VALUE) {
                drm_dbg_kms(&i915->drm,
@@ -1597,16 +1610,8 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
         * is greater than the maximum Cdclock and if slice count is even
         * then we need to use 2 VDSC instances.
         */
-       if (adjusted_mode->crtc_clock > dev_priv->display.cdclk.max_cdclk_freq ||
-           pipe_config->bigjoiner_pipes) {
-               if (pipe_config->dsc.slice_count > 1) {
-                       pipe_config->dsc.dsc_split = true;
-               } else {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "Cannot split stream to use 2 VDSC instances\n");
-                       return -EINVAL;
-               }
-       }
+       if (pipe_config->bigjoiner_pipes || pipe_config->dsc.slice_count > 1)
+               pipe_config->dsc.dsc_split = true;
 
        ret = intel_dp_dsc_compute_params(&dig_port->base, pipe_config);
        if (ret < 0) {