From: Vidya Srinivas <[email protected]>

The existing icl_plane_min_cdclk() uses a simple pixel_rate/PPC
calculation that does not account for the pipeline granularity
adjustment when horizontal downscaling is active. The effective
pixels-per-clock throughput is reduced due to integer pipeline
granularity, requiring a higher CDCLK than the current one computes.
This causes FIFO underruns on multi-pipe configurations near max CDCLK.

Additionally, limit second scaler to 1:1
(no horizontal or vertical downscaling) on DISPLAY_VER > 14

Also apply CDCLK PLL disable/enable WA for DISPLAY_VER 30

Signed-off-by: Vidya Srinivas <[email protected]>
Signed-off-by: Charlton Lin <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_cdclk.c    |  3 +-
 drivers/gpu/drm/i915/display/skl_scaler.c     |  4 +-
 .../drm/i915/display/skl_universal_plane.c    | 58 +++++++++++++++++--
 3 files changed, 57 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c 
b/drivers/gpu/drm/i915/display/intel_cdclk.c
index 189ae2d3cfc9..f724227c3726 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -2149,7 +2149,8 @@ static bool 
cdclk_compute_crawl_and_squash_midpoint(struct intel_display *displa
 
 static bool pll_enable_wa_needed(struct intel_display *display)
 {
-       return (DISPLAY_VERx100(display) == 2000 ||
+       return (DISPLAY_VERx100(display) == 3000 ||
+               DISPLAY_VERx100(display) == 2000 ||
                DISPLAY_VERx100(display) == 1400 ||
                display->platform.dg2) &&
                display->cdclk.hw.vco > 0;
diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c 
b/drivers/gpu/drm/i915/display/skl_scaler.c
index 7994b983d509..3673b52de4da 100644
--- a/drivers/gpu/drm/i915/display/skl_scaler.c
+++ b/drivers/gpu/drm/i915/display/skl_scaler.c
@@ -382,8 +382,10 @@ calculate_max_scale(struct intel_crtc *crtc,
 
                if (scaler_id == 0)
                        *max_vscale = 0x30000 - 1;
-               else
+               else {
+                       *max_hscale = 0x10000;
                        *max_vscale = 0x10000;
+               }
        } else if (DISPLAY_VER(display) >= 10 || !is_yuv_semiplanar) {
                *max_hscale = 0x30000 - 1;
                *max_vscale = 0x30000 - 1;
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c 
b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index ad4bfff6903d..c49f330c4878 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -264,12 +264,58 @@ bool icl_is_hdr_plane(struct intel_display *display, enum 
plane_id plane_id)
 }
 
 static int icl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
-                              const struct intel_plane_state *plane_state)
-{
-       unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, 
plane_state);
-
-       /* two pixels per clock */
-       return DIV_ROUND_UP(pixel_rate, 2);
+                   const struct intel_plane_state *plane_state)
+{
+    struct intel_display *display = to_intel_display(crtc_state);
+    unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
+
+    if (DISPLAY_VER(display) >= 30) {
+        unsigned int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
+        unsigned int dst_w = drm_rect_width(&plane_state->uapi.dst);
+        unsigned int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
+        unsigned int dst_h = drm_rect_height(&plane_state->uapi.dst);
+        const unsigned int ppc = 2;
+
+        /*
+         * "Resolution Support" PPC-granularity:
+         *   Hscale_PPC = (src_w / dst_w) * PPC
+         *   int_part = floor(Hscale_PPC)
+         *   frac = Hscale_PPC - int_part
+         *   adjusted_frac = frac > 0 ? 1/ROUNDUP(1/frac) : 0
+         *   H_down = int_part/PPC + adjusted_frac
+         *   min_cdclk = crtc_clock * H_down * V_down / PPC
+         */
+        if (dst_w && dst_h && src_w > dst_w) {
+            unsigned int hscale_ppc = src_w * ppc;
+            unsigned int int_part = hscale_ppc / dst_w;
+            unsigned int frac_num = hscale_ppc % dst_w;
+            unsigned int v_num = max(src_h, dst_h);
+            u64 num;
+
+            if (frac_num) {
+                unsigned int recip_ceil = DIV_ROUND_UP(dst_w, frac_num);
+                /* H_down = (int_part * recip_ceil + ppc) / (ppc * recip_ceil) 
*/
+                unsigned int h_num = int_part * recip_ceil + ppc;
+                unsigned int h_den = ppc * recip_ceil;
+
+                num = mul_u32_u32(crtc_state->pixel_rate, h_num);
+                num *= v_num;
+                return DIV_ROUND_UP_ULL(num,
+                            (u64)h_den * ppc * dst_h);
+            }
+
+            /* frac == 0: H_down = int_part / ppc exactly */
+            num = mul_u32_u32(crtc_state->pixel_rate, int_part);
+            num *= v_num;
+            return DIV_ROUND_UP_ULL(num, (u64)ppc * ppc * dst_h);
+        }
+
+        /* No horizontal downscale */
+        return DIV_ROUND_UP(pixel_rate, ppc);
+    }
+
+    /* two pixels per clock */
+    return DIV_ROUND_UP(pixel_rate, 2);
 }
 
 static void
-- 
2.45.2

Reply via email to