]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/msm/dpu: Filter modes based on adjusted mode clock
authorJessica Zhang <jessica.zhang@oss.qualcomm.com>
Wed, 7 May 2025 01:38:39 +0000 (18:38 -0700)
committerDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Thu, 28 Aug 2025 22:51:46 +0000 (01:51 +0300)
Filter out modes that have a clock rate greater than the max core clock
rate when adjusted for the perf clock factor

This is especially important for chipsets such as QCS615 that have lower
limits for the MDP max core clock.

Since the core CRTC clock is at least the mode clock (adjusted for the
perf clock factor) [1], the modes supported by the driver should be less
than the max core clock rate.

[1] https://elixir.bootlin.com/linux/v6.12.4/source/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c#L83

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/652041/
Link: https://lore.kernel.org/r/20250506-filter-modes-v2-1-c20a0b7aa241@oss.qualcomm.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c

index 0fb5789c60d0d1b3fa63148c2410ef4e2815772c..13cc658065c56a00a7dcdd0af4dec4aadfd0e6ed 100644 (file)
@@ -31,6 +31,26 @@ enum dpu_perf_mode {
        DPU_PERF_MODE_MAX
 };
 
+/**
+ * dpu_core_perf_adjusted_mode_clk - Adjust given mode clock rate according to
+ *   the perf clock factor.
+ * @crtc_clk_rate - Unadjusted mode clock rate
+ * @perf_cfg: performance configuration
+ */
+u64 dpu_core_perf_adjusted_mode_clk(u64 mode_clk_rate,
+                                   const struct dpu_perf_cfg *perf_cfg)
+{
+       u32 clk_factor;
+
+       clk_factor = perf_cfg->clk_inefficiency_factor;
+       if (clk_factor) {
+               mode_clk_rate *= clk_factor;
+               do_div(mode_clk_rate, 100);
+       }
+
+       return mode_clk_rate;
+}
+
 /**
  * _dpu_core_perf_calc_bw() - to calculate BW per crtc
  * @perf_cfg: performance configuration
@@ -75,28 +95,21 @@ static u64 _dpu_core_perf_calc_clk(const struct dpu_perf_cfg *perf_cfg,
        struct drm_plane *plane;
        struct dpu_plane_state *pstate;
        struct drm_display_mode *mode;
-       u64 crtc_clk;
-       u32 clk_factor;
+       u64 mode_clk;
 
        mode = &state->adjusted_mode;
 
-       crtc_clk = (u64)mode->vtotal * mode->hdisplay * drm_mode_vrefresh(mode);
+       mode_clk = (u64)mode->vtotal * mode->hdisplay * drm_mode_vrefresh(mode);
 
        drm_atomic_crtc_for_each_plane(plane, crtc) {
                pstate = to_dpu_plane_state(plane->state);
                if (!pstate)
                        continue;
 
-               crtc_clk = max(pstate->plane_clk, crtc_clk);
-       }
-
-       clk_factor = perf_cfg->clk_inefficiency_factor;
-       if (clk_factor) {
-               crtc_clk *= clk_factor;
-               do_div(crtc_clk, 100);
+               mode_clk = max(pstate->plane_clk, mode_clk);
        }
 
-       return crtc_clk;
+       return dpu_core_perf_adjusted_mode_clk(mode_clk, perf_cfg);
 }
 
 static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)
index d2f21d34e501e443ec89604217929eea476e88fb..3740bc97422caf94e790e11fb2b8d08851f00d46 100644 (file)
@@ -54,6 +54,9 @@ struct dpu_core_perf {
        u32 fix_core_ab_vote;
 };
 
+u64 dpu_core_perf_adjusted_mode_clk(u64 clk_rate,
+                                   const struct dpu_perf_cfg *perf_cfg);
+
 int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
                struct drm_crtc_state *state);
 
index 94912b4708fb5be937f1b3898a5676f7b481bd42..d59512e45af0531ab6bb59a2c8fdf42129ebef40 100644 (file)
@@ -1534,6 +1534,7 @@ static enum drm_mode_status dpu_crtc_mode_valid(struct drm_crtc *crtc,
                                                const struct drm_display_mode *mode)
 {
        struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
+       u64 adjusted_mode_clk;
 
        /* if there is no 3d_mux block we cannot merge LMs so we cannot
         * split the large layer into 2 LMs, filter out such modes
@@ -1541,6 +1542,17 @@ static enum drm_mode_status dpu_crtc_mode_valid(struct drm_crtc *crtc,
        if (!dpu_kms->catalog->caps->has_3d_merge &&
            mode->hdisplay > dpu_kms->catalog->caps->max_mixer_width)
                return MODE_BAD_HVALUE;
+
+       adjusted_mode_clk = dpu_core_perf_adjusted_mode_clk(mode->clock,
+                                                           dpu_kms->perf.perf_cfg);
+
+       /*
+        * The given mode, adjusted for the perf clock factor, should not exceed
+        * the max core clock rate
+        */
+       if (dpu_kms->perf.max_core_clk_rate < adjusted_mode_clk * 1000)
+               return MODE_CLOCK_HIGH;
+
        /*
         * max crtc width is equal to the max mixer width * 2 and max height is 4K
         */