]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/i915/cx0: Verify C10/C20 pll dividers
authorMika Kahola <mika.kahola@intel.com>
Mon, 19 Jan 2026 09:37:52 +0000 (09:37 +0000)
committerMika Kahola <mika.kahola@intel.com>
Tue, 20 Jan 2026 08:52:58 +0000 (10:52 +0200)
Add verification for pll table dividers. The port clock
is computed based on pll tables and, for hdmi case, the
algorithmic model is applied to calculate pll dividers.
If port clock differs more than +-1 kHz from expected value
an drm_warn() is thrown and pll divider differences are
printed out for debugging purposes.

v2:
- Move clock derivation from dividers in intel_cx0pll_enable()
  earlier in the patchset.
- Keep intel_cx0_pll_power_save_wa() in intel_dpll_sanitize_state()
- Use tables[i].name != NULL as a terminating condition.
- Drop duplicate intel_cx0pll_clock_matches() declaration in header.
- Use state vs. params term consistently in intel_c10pll_verify_clock()
  and intel_c20pll_verify_clock().

Signed-off-by: Mika Kahola <mika.kahola@intel.com>
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com>
Link: https://patch.msgid.link/20260119093757.2850233-12-mika.kahola@intel.com
drivers/gpu/drm/i915/display/intel_cx0_phy.c
drivers/gpu/drm/i915/display/intel_cx0_phy.h
drivers/gpu/drm/i915/display/intel_dpll_mgr.c

index 3b56d25c8db8b74e8b87bd1c8a2f253e136d05aa..ce4b7582b73777364c3578d74f9d76eb0d63b4c6 100644 (file)
@@ -3838,3 +3838,124 @@ void intel_cx0_pll_power_save_wa(struct intel_display *display)
                intel_cx0pll_disable(encoder);
        }
 }
+
+static void intel_c10pll_verify_clock(struct intel_display *display,
+                                     int precomputed_clock,
+                                     const char *pll_state_name,
+                                     const struct intel_c10pll_state *pll_state,
+                                     bool is_precomputed_state)
+{
+       struct drm_printer p;
+       int clock;
+
+       clock = intel_c10pll_calc_port_clock(pll_state);
+
+       if (intel_dpll_clock_matches(clock, precomputed_clock))
+               return;
+
+       drm_warn(display->drm,
+                "PLL state %s (%s): clock difference too high: computed %d, pre-computed %d\n",
+                pll_state_name,
+                is_precomputed_state ? "precomputed" : "computed",
+                clock, precomputed_clock);
+
+       if (!drm_debug_enabled(DRM_UT_KMS))
+               return;
+
+       p = drm_dbg_printer(display->drm, DRM_UT_KMS, NULL);
+
+       drm_printf(&p, "PLL state %s (%s):\n",
+                  pll_state_name,
+                  is_precomputed_state ? "precomputed" : "computed");
+       intel_c10pll_dump_hw_state(&p, pll_state);
+}
+
+static void intel_c10pll_verify_params(struct intel_display *display,
+                                      const struct intel_cx0pll_params *pll_params)
+{
+       struct intel_c10pll_state pll_state;
+
+       intel_c10pll_verify_clock(display, pll_params->clock_rate, pll_params->name, pll_params->c10, true);
+
+       if (!pll_params->is_hdmi)
+               return;
+
+       intel_snps_hdmi_pll_compute_c10pll(&pll_state, pll_params->clock_rate);
+
+       intel_c10pll_verify_clock(display, pll_params->clock_rate, pll_params->name, &pll_state, false);
+}
+
+static void intel_c20pll_verify_clock(struct intel_display *display,
+                                     int precomputed_clock,
+                                     const char *pll_state_name,
+                                     const struct intel_c20pll_state *pll_state,
+                                     bool is_precomputed_state)
+{
+       struct drm_printer p;
+       int clock;
+
+       clock = intel_c20pll_calc_port_clock(pll_state);
+
+       if (intel_dpll_clock_matches(clock, precomputed_clock))
+               return;
+
+       drm_warn(display->drm,
+                "PLL state %s (%s): clock difference too high: computed %d, pre-computed %d\n",
+                pll_state_name,
+                is_precomputed_state ? "precomputed" : "computed",
+                clock, precomputed_clock);
+
+       if (!drm_debug_enabled(DRM_UT_KMS))
+               return;
+
+       p = drm_dbg_printer(display->drm, DRM_UT_KMS, NULL);
+
+       drm_printf(&p, "PLL state %s (%s):\n",
+                  pll_state_name,
+                  is_precomputed_state ? "precomputed" : "computed");
+       intel_c20pll_dump_hw_state(&p, pll_state);
+}
+
+static void intel_c20pll_verify_params(struct intel_display *display,
+                                      const struct intel_cx0pll_params *pll_params)
+{
+       struct intel_c20pll_state pll_state;
+
+       intel_c20pll_verify_clock(display, pll_params->clock_rate, pll_params->name, pll_params->c20, true);
+
+       if (!pll_params->is_hdmi)
+               return;
+
+       if (intel_c20_compute_hdmi_tmds_pll(display, pll_params->clock_rate, &pll_state) != 0)
+               return;
+
+       intel_c20pll_verify_clock(display, pll_params->clock_rate, pll_params->name, &pll_state, false);
+}
+
+static void intel_cx0pll_verify_tables(struct intel_display *display,
+                                      const struct intel_cx0pll_params *tables)
+{
+       int i;
+
+       for (i = 0; tables[i].name; i++) {
+               if (tables[i].is_c10)
+                       intel_c10pll_verify_params(display, &tables[i]);
+               else
+                       intel_c20pll_verify_params(display, &tables[i]);
+       }
+}
+
+void intel_cx0pll_verify_plls(struct intel_display *display)
+{
+       /* C10 */
+       intel_cx0pll_verify_tables(display, mtl_c10_edp_tables);
+       intel_cx0pll_verify_tables(display, mtl_c10_dp_tables);
+       intel_cx0pll_verify_tables(display, mtl_c10_hdmi_tables);
+
+       /* C20 */
+       intel_cx0pll_verify_tables(display, xe2hpd_c20_edp_tables);
+       intel_cx0pll_verify_tables(display, mtl_c20_dp_tables);
+       intel_cx0pll_verify_tables(display, xe2hpd_c20_dp_tables);
+       intel_cx0pll_verify_tables(display, xe3lpd_c20_dp_edp_tables);
+       intel_cx0pll_verify_tables(display, mtl_c20_hdmi_tables);
+}
index ae98ac23ea2222acd14c62ddca74d03cc8ef9452..347fdbc0af73bb1b2221ce86b465cefee1e733f8 100644 (file)
@@ -77,6 +77,7 @@ bool intel_mtl_tbt_pll_readout_hw_state(struct intel_display *display,
                                        struct intel_dpll_hw_state *hw_state);
 int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder);
 
+void intel_cx0pll_verify_plls(struct intel_display *display);
 void intel_cx0_pll_power_save_wa(struct intel_display *display);
 void intel_lnl_mac_transmit_lfps(struct intel_encoder *encoder,
                                 const struct intel_crtc_state *crtc_state);
index 9aa84a430f098e0e0d3d72b74466e0e681d9acc5..7127bc2a0898269a2ffcc0a903b2f1d0c78493bf 100644 (file)
@@ -4613,7 +4613,7 @@ void intel_dpll_init(struct intel_display *display)
                dpll_mgr = &pch_pll_mgr;
 
        if (!dpll_mgr)
-               return;
+               goto out_verify;
 
        dpll_info = dpll_mgr->dpll_info;
 
@@ -4632,6 +4632,13 @@ void intel_dpll_init(struct intel_display *display)
 
        display->dpll.mgr = dpll_mgr;
        display->dpll.num_dpll = i;
+
+out_verify:
+       /*
+        * TODO: Convert these to a KUnit test or dependent on a kconfig
+        * debug option.
+        */
+       intel_cx0pll_verify_plls(display);
 }
 
 /**