From: Ville Syrjälä <[email protected]>

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ä <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_cdclk.c | 41 ++++++++++++++++++----
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c 
b/drivers/gpu/drm/i915/display/intel_cdclk.c
index 189ae2d3cfc9..7bc9b956554b 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -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");
-- 
2.53.0

Reply via email to