]> 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)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Mon, 30 Mar 2026 15:56:46 +0000 (18:56 +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>
drivers/gpu/drm/i915/display/intel_cdclk.c

index 121a12c5b8ac2be615c83a6cbddf46eb4ec36242..a47736613f6e89f65c0f826de34881937a090f77 100644 (file)
@@ -2972,6 +2972,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)
@@ -3387,6 +3434,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;