intel_panel_fixed_mode() intends to choose a fixed mode at or above the
requested refresh rate for VRR panels, so the requested refresh can be
reached by extending vblank.

However, as per the current logic in is_best_fixed_mode(), the helper
can return a lower refresh rate mode if it appears first in the list of
fixed modes. This is because is_best_fixed_mode() picks the closest
match, and the VRR check only rejects candidates where both rates are in
VRR range and the candidate is lower, but the first mode bypasses this
via the !best_mode early return.

For seamless switch features like LRR (Lower Refresh Rate) this creates
a problem as selecting a lower fixed mode results in a change in
vsync_start/end, forcing a full modeset.

To fix this, introduce need_higher_rr_mode() which returns true for all
VRR capable panels when the requested rate is in VRR range. When true,
intel_panel_fixed_mode() returns the highest refresh rate mode upfront,
which can then be reduced to match the requested vrefresh by extending
the vblank length.

Also remove the VRR check from is_best_fixed_mode() since the selection
is now handled upfront in intel_panel_fixed_mode().

Signed-off-by: Ankit Nautiyal <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_panel.c | 37 ++++++++++++++--------
 1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 2765d87ddca7..1c2a8cd454be 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -59,29 +59,32 @@ intel_panel_preferred_fixed_mode(struct intel_connector 
*connector)
                                        struct drm_display_mode, head);
 }
 
-static bool is_best_fixed_mode(struct intel_connector *connector,
-                              int vrefresh, int fixed_mode_vrefresh,
+static bool is_best_fixed_mode(int vrefresh, int fixed_mode_vrefresh,
                               const struct drm_display_mode *best_mode)
 {
        /* we want to always return something */
        if (!best_mode)
                return true;
 
-       /*
-        * With VRR always pick a mode with equal/higher than requested
-        * vrefresh, which we can then reduce to match the requested
-        * vrefresh by extending the vblank length.
-        */
-       if (intel_vrr_is_in_range(connector, vrefresh) &&
-           intel_vrr_is_in_range(connector, fixed_mode_vrefresh) &&
-           fixed_mode_vrefresh < vrefresh)
-               return false;
-
        /* pick the fixed_mode that is closest in terms of vrefresh */
        return abs(fixed_mode_vrefresh - vrefresh) <
                abs(drm_mode_vrefresh(best_mode) - vrefresh);
 }
 
+static bool need_higher_rr_mode(struct intel_connector *connector,
+                               const struct drm_display_mode *mode)
+{
+       int vrefresh = drm_mode_vrefresh(mode);
+
+       if (!intel_vrr_is_capable(connector))
+               return false;
+
+       if (!intel_vrr_is_in_range(connector, vrefresh))
+               return false;
+
+       return true;
+}
+
 const struct drm_display_mode *
 intel_panel_fixed_mode(struct intel_connector *connector,
                       const struct drm_display_mode *mode)
@@ -89,10 +92,18 @@ intel_panel_fixed_mode(struct intel_connector *connector,
        const struct drm_display_mode *fixed_mode, *best_mode = NULL;
        int vrefresh = drm_mode_vrefresh(mode);
 
+       /*
+        * With VRR always pick the highest refresh rate mode,
+        * which we can then reduce to match the requested
+        * vrefresh by extending the vblank length.
+        */
+       if (need_higher_rr_mode(connector, mode))
+               return intel_panel_highest_vrefresh_mode(connector);
+
        list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
                int fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
 
-               if (is_best_fixed_mode(connector, vrefresh,
+               if (is_best_fixed_mode(vrefresh,
                                       fixed_mode_vrefresh, best_mode))
                        best_mode = fixed_mode;
        }
-- 
2.45.2

Reply via email to