]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/i915/cdclk: Do the full CDCLK dance for min_voltage_level changes
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 25 Mar 2026 13:58:44 +0000 (15:58 +0200)
committerJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Tue, 31 Mar 2026 04:49:50 +0000 (07:49 +0300)
Apparently I forgot about the pipe min_voltage_level when I
decoupled the CDCLK calculations from modesets. Even if the
CDCLK frequency doesn't need changing we may still need to
bump the voltage level to accommodate an increase in the
port clock frequency.

Currently, even if there is a full modeset, we won't notice the
need to go through the full CDCLK calculations/programming,
unless the set of enabled/active pipes changes, or the
pipe/dbuf min CDCLK changes.

Duplicate the same logic we use the pipe's min CDCLK frequency
to also deal with its min voltage level.

Note that the 'allow_voltage_level_decrease' stuff isn't
really useful here since the min voltage level can only
change during a full modeset. But I think sticking to the
same approach in the three similar parts (pipe min cdclk,
pipe min voltage level, dbuf min cdclk) is a good idea.

Cc: stable@vger.kernel.org
Tested-by: Mikhail Rudenko <mike.rudenko@gmail.com>
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15826
Fixes: ba91b9eecb47 ("drm/i915/cdclk: Decouple cdclk from state->modeset")
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patch.msgid.link/20260325135849.12603-2-ville.syrjala@linux.intel.com
Reviewed-by: Michał Grzelak <michal.grzelak@intel.com>
(cherry picked from commit 0f21a14987ebae3c05ad1184ea872e7b7a7b8695)
Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
drivers/gpu/drm/i915/display/intel_cdclk.c

index f5946e677c93a705cdd7057cd3d6df8c04c206fe..3d7b4b0795cdfcc0fcada39b53a12875dbd87261 100644 (file)
@@ -2971,6 +2971,53 @@ static int intel_cdclk_update_crtc_min_cdclk(struct intel_atomic_state *state,
        return 0;
 }
 
+static int intel_cdclk_update_crtc_min_voltage_level(struct intel_atomic_state *state,
+                                                    struct intel_crtc *crtc,
+                                                    u8 old_min_voltage_level,
+                                                    u8 new_min_voltage_level,
+                                                    bool *need_cdclk_calc)
+{
+       struct intel_display *display = to_intel_display(state);
+       struct intel_cdclk_state *cdclk_state;
+       bool allow_voltage_level_decrease = intel_any_crtc_needs_modeset(state);
+       int ret;
+
+       if (new_min_voltage_level == old_min_voltage_level)
+               return 0;
+
+       if (!allow_voltage_level_decrease &&
+           new_min_voltage_level < old_min_voltage_level)
+               return 0;
+
+       cdclk_state = intel_atomic_get_cdclk_state(state);
+       if (IS_ERR(cdclk_state))
+               return PTR_ERR(cdclk_state);
+
+       old_min_voltage_level = cdclk_state->min_voltage_level[crtc->pipe];
+
+       if (new_min_voltage_level == old_min_voltage_level)
+               return 0;
+
+       if (!allow_voltage_level_decrease &&
+           new_min_voltage_level < old_min_voltage_level)
+               return 0;
+
+       cdclk_state->min_voltage_level[crtc->pipe] = new_min_voltage_level;
+
+       ret = intel_atomic_lock_global_state(&cdclk_state->base);
+       if (ret)
+               return ret;
+
+       *need_cdclk_calc = true;
+
+       drm_dbg_kms(display->drm,
+                   "[CRTC:%d:%s] min voltage level: %d -> %d\n",
+                   crtc->base.base.id, crtc->base.name,
+                   old_min_voltage_level, new_min_voltage_level);
+
+       return 0;
+}
+
 int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state,
                                         int old_min_cdclk, int new_min_cdclk,
                                         bool *need_cdclk_calc)
@@ -3386,6 +3433,13 @@ static int intel_crtcs_calc_min_cdclk(struct intel_atomic_state *state,
                                                        need_cdclk_calc);
                if (ret)
                        return ret;
+
+               ret = intel_cdclk_update_crtc_min_voltage_level(state, crtc,
+                                                               old_crtc_state->min_voltage_level,
+                                                               new_crtc_state->min_voltage_level,
+                                                               need_cdclk_calc);
+               if (ret)
+                       return ret;
        }
 
        return 0;