drm/i915: Suppress old PLL pipe_mask checks for MG/TC/TBT PLLs
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Tue, 23 Jan 2024 09:31:36 +0000 (11:31 +0200)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 26 Jan 2024 09:28:49 +0000 (11:28 +0200)
TC ports have both the MG/TC and TBT PLLs selected simultanously (so
that we can switch from MG/TC to TBT as a fallback). This doesn't play
well with the state checker that assumes that the old PLL shouldn't
have the pipe in its pipe_mask anymore. Suppress that check for these
PLLs to avoid spurious WARNs when you disconnect a TC port and a
non-disabling modeset happens before actually disabling the port.

v2: Only suppress when one of the PLLs is the TBT PLL and the
    other one is not

Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/9816
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240123093137.9133-2-ville.syrjala@linux.intel.com
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
drivers/gpu/drm/i915/display/intel_dpll_mgr.c
drivers/gpu/drm/i915/display/intel_dpll_mgr.h

index ce97677d44f09a25973d34ed54ea30848edd2223..085cd62045200128f4f55fd70225f9eb3ea42980 100644 (file)
@@ -4029,7 +4029,8 @@ static const struct intel_shared_dpll_funcs mg_pll_funcs = {
 static const struct dpll_info icl_plls[] = {
        { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
        { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
-       { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, },
+       { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
+         .flags = INTEL_DPLL_IS_ALT_PORT_DPLL, },
        { .name = "MG PLL 1", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
        { .name = "MG PLL 2", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
        { .name = "MG PLL 3", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, },
@@ -4074,7 +4075,8 @@ static const struct intel_shared_dpll_funcs dkl_pll_funcs = {
 static const struct dpll_info tgl_plls[] = {
        { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
        { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
-       { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, },
+       { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
+         .flags = INTEL_DPLL_IS_ALT_PORT_DPLL, },
        { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
        { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
        { .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, },
@@ -4147,7 +4149,8 @@ static const struct intel_dpll_mgr adls_pll_mgr = {
 static const struct dpll_info adlp_plls[] = {
        { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, },
        { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, },
-       { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, },
+       { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL,
+         .flags = INTEL_DPLL_IS_ALT_PORT_DPLL, },
        { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, },
        { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, },
        { .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, },
@@ -4520,6 +4523,14 @@ verify_single_dpll_state(struct drm_i915_private *i915,
                        pll->info->name);
 }
 
+static bool has_alt_port_dpll(const struct intel_shared_dpll *old_pll,
+                             const struct intel_shared_dpll *new_pll)
+{
+       return old_pll && new_pll && old_pll != new_pll &&
+               (old_pll->info->flags & INTEL_DPLL_IS_ALT_PORT_DPLL ||
+                new_pll->info->flags & INTEL_DPLL_IS_ALT_PORT_DPLL);
+}
+
 void intel_shared_dpll_state_verify(struct intel_atomic_state *state,
                                    struct intel_crtc *crtc)
 {
@@ -4541,7 +4552,11 @@ void intel_shared_dpll_state_verify(struct intel_atomic_state *state,
                I915_STATE_WARN(i915, pll->active_mask & pipe_mask,
                                "%s: pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n",
                                pll->info->name, pipe_name(crtc->pipe), pll->active_mask);
-               I915_STATE_WARN(i915, pll->state.pipe_mask & pipe_mask,
+
+               /* TC ports have both MG/TC and TBT PLL referenced simultaneously */
+               I915_STATE_WARN(i915, !has_alt_port_dpll(old_crtc_state->shared_dpll,
+                                                        new_crtc_state->shared_dpll) &&
+                               pll->state.pipe_mask & pipe_mask,
                                "%s: pll enabled crtcs mismatch (found pipe %c in enabled mask (0x%x))\n",
                                pll->info->name, pipe_name(crtc->pipe), pll->state.pipe_mask);
        }
index 2e7ea0d8d3ffb3628f4b65ec657e3df63eada52a..5cdec77cfd9d4878a3ed3178ac33176c87a4953e 100644 (file)
@@ -277,12 +277,16 @@ struct dpll_info {
        enum intel_display_power_domain power_domain;
 
 #define INTEL_DPLL_ALWAYS_ON   (1 << 0)
+#define INTEL_DPLL_IS_ALT_PORT_DPLL    (1 << 1)
        /**
         * @flags:
         *
         * INTEL_DPLL_ALWAYS_ON
         *     Inform the state checker that the DPLL is kept enabled even if
         *     not in use by any CRTC.
+        * INTEL_DPLL_IS_ALT_PORT_DPLL
+        *     Inform the state checker that the DPLL can be used as a fallback
+        *     (for TC->TBT fallback).
         */
        u32 flags;
 };