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
