]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/i915/cdclk: Fix up CDCLK_FREQ_DECIMAL without a full PLL re-enable
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 12 Jun 2026 17:36:48 +0000 (20:36 +0300)
committerJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Wed, 24 Jun 2026 10:53:32 +0000 (13:53 +0300)
The GOP (and even Bspec on some platforms) is a bit inconsistent
on what the CDCLK_FREQ_DECIMAL divider should be. Currently any
mismatch there causes a full CDCLK PLL disable+re-enable, which
we really don't want to do if any displays are currently active.
Let's instead just reprogram CDCLK_FREQ_DECIMAL when that is the
only thing amiss. For any other (more serious) mismatch we still
punt to the full PLL reprogramming.

We also need to tweak the bxt_cdclk_cd2x_pipe() stuff a bit to
consistently select pipe==NONE since we have no idea which pipes
are enabled at this point. Since we're not actually changing the
CDCLK frequency here we don't need to sync the update to any
pipe.

Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/16209
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patch.msgid.link/20260612173653.7830-2-ville.syrjala@linux.intel.com
Reviewed-by: Michał Grzelak <michal.grzelak@intel.com>
(cherry picked from commit 3f9de66f8acbf8ff45a91b4920605ed10c6b7c06)
Fixes: ba91b9eecb47 ("drm/i915/cdclk: Decouple cdclk from state->modeset")
Fixes: d66a21947e21 ("drm/i915/bxt: Sanitize CDCLK to fix breakage during S4 resume")
Fixes: c73666f394fc ("drm/i915/skl: If needed sanitize bios programmed cdclk")
Cc: <stable@vger.kernel.org> # v4.5+
Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
drivers/gpu/drm/i915/display/intel_cdclk.c

index 189ae2d3cfc9e44eae5473cb4ef853f70716c48e..7bc9b956554ba3ca7c741f07c52affd2c37563fe 100644 (file)
@@ -1256,9 +1256,22 @@ static void skl_sanitize_cdclk(struct intel_display *display)
        cdctl = intel_de_read(display, CDCLK_CTL);
        expected = (cdctl & CDCLK_FREQ_SEL_MASK) |
                skl_cdclk_decimal(display->cdclk.hw.cdclk);
-       if (cdctl == expected)
-               /* All well; nothing to sanitize */
-               return;
+
+       if (cdctl != expected) {
+               cdctl &= ~CDCLK_FREQ_DECIMAL_MASK;
+               cdctl |= expected & CDCLK_FREQ_DECIMAL_MASK;
+
+               if (cdctl != expected)
+                       goto sanitize;
+
+               drm_dbg_kms(display->drm, "Sanitizing CDCLK decimal divider (CDCLK_CTL 0x%x, expected 0x%x)\n",
+                           intel_de_read(display, CDCLK_CTL), expected);
+
+               intel_de_write(display, CDCLK_CTL, expected);
+       }
+
+       /* All well; nothing to sanitize */
+       return;
 
 sanitize:
        drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n");
@@ -2354,11 +2367,25 @@ static void bxt_sanitize_cdclk(struct intel_display *display)
         * (PIPE_NONE).
         */
        cdctl &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
-       expected &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
+       cdctl |= bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
 
-       if (cdctl == expected)
-               /* All well; nothing to sanitize */
-               return;
+       if (cdctl != expected) {
+               if (DISPLAY_VER(display) < 20) {
+                       cdctl &= ~CDCLK_FREQ_DECIMAL_MASK;
+                       cdctl |= expected & CDCLK_FREQ_DECIMAL_MASK;
+               }
+
+               if (cdctl != expected)
+                       goto sanitize;
+
+               drm_dbg_kms(display->drm, "Sanitizing CDCLK decimal divider (CDCLK_CTL 0x%x, expected 0x%x)\n",
+                           intel_de_read(display, CDCLK_CTL), expected);
+
+               intel_de_write(display, CDCLK_CTL, expected);
+       }
+
+       /* All well; nothing to sanitize */
+       return;
 
 sanitize:
        drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n");