summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2026-06-23 14:40:35 +0300
committerVille Syrjälä <ville.syrjala@linux.intel.com>2026-06-24 18:53:39 +0300
commitd392b88dce93ae1a88d932c8f6680be598d22cd5 (patch)
tree629e91a3615e3a9af4055d29b212d1b93e7926d9
parent53f12a266c3244b4895f7a3619ca1dd2ad54cffc (diff)
downloadlinux-next-d392b88dce93ae1a88d932c8f6680be598d22cd5.tar.gz
linux-next-d392b88dce93ae1a88d932c8f6680be598d22cd5.zip
drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages
Split the VRR vs. fixed refresh rate fixed mode selection into two completely separate stages. First try the VRR method, which will only accept fixed modes that are in the VRR range and whose refresh rate is equal or higher to the user's requested mode's refresh rate. If the VRR method doesn't find anything we fall back to the fixed refresh rate method of simply looking for the fixed mode with the closest refresh rate to the user's request. The main benefit is that we will only perform the VRR vtotal adjustment on fixed modes that have equal or higher refresh rate to the user's requested mode, thus we will never end up in a situation where we'd have to shrink the fixed mode's vtotal. This avoids any risk of ending up with a vtotal that is too short. v2: Drop redundant intel_panel_fixed_mode() call (Ankit) Cc: Suraj Kandpal <suraj.kandpal@intel.com> Reviewed-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patch.msgid.link/20260623114035.7185-1-ville.syrjala@linux.intel.com Tested-by: Vidya Srinivas <vidya.srinivas@intel.com> Acked-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r--drivers/gpu/drm/i915/display/intel_panel.c126
1 files changed, 85 insertions, 41 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
index 81fb349ece5f..2b8401b6d4d6 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -67,21 +67,43 @@ static bool is_best_fixed_mode(struct intel_connector *connector,
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 const struct drm_display_mode *
+intel_panel_fixed_mode_vrr(struct intel_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ const struct drm_display_mode *fixed_mode, *best_mode = NULL;
+ int vrefresh = drm_mode_vrefresh(mode);
+
+ if (!intel_vrr_is_in_range(connector, vrefresh))
+ return NULL;
+
+ list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
+ int fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
+
+ if (!intel_vrr_is_in_range(connector, fixed_mode_vrefresh))
+ continue;
+
+ /*
+ * 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 (fixed_mode_vrefresh < vrefresh)
+ continue;
+
+ if (is_best_fixed_mode(connector, vrefresh,
+ fixed_mode_vrefresh, best_mode))
+ best_mode = fixed_mode;
+ }
+
+ return best_mode;
+}
+
const struct drm_display_mode *
intel_panel_fixed_mode(struct intel_connector *connector,
const struct drm_display_mode *mode)
@@ -197,47 +219,22 @@ enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
return connector->panel.vbt.drrs_type;
}
-int intel_panel_compute_config(struct intel_connector *connector,
- struct drm_display_mode *adjusted_mode)
+static int intel_panel_compute_config_vrr(struct intel_connector *connector,
+ struct drm_display_mode *adjusted_mode)
{
- const struct drm_display_mode *fixed_mode =
- intel_panel_fixed_mode(connector, adjusted_mode);
+ const struct drm_display_mode *fixed_mode;
int vrefresh, fixed_mode_vrefresh;
- bool is_vrr;
+ fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode);
if (!fixed_mode)
- return 0;
+ return -EINVAL;
vrefresh = drm_mode_vrefresh(adjusted_mode);
fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
- /*
- * Assume that we shouldn't muck about with the
- * timings if they don't land in the VRR range.
- */
- is_vrr = intel_vrr_is_in_range(connector, vrefresh) &&
- intel_vrr_is_in_range(connector, fixed_mode_vrefresh);
-
- if (!is_vrr) {
- /*
- * We don't want to lie too much to the user about the refresh
- * rate they're going to get. But we have to allow a bit of latitude
- * for Xorg since it likes to automagically cook up modes with slightly
- * off refresh rates.
- */
- if (abs(vrefresh - fixed_mode_vrefresh) > 1) {
- drm_dbg_kms(connector->base.dev,
- "[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n",
- connector->base.base.id, connector->base.name,
- vrefresh, fixed_mode_vrefresh);
-
- return -EINVAL;
- }
- }
-
drm_mode_copy(adjusted_mode, fixed_mode);
- if (is_vrr && fixed_mode_vrefresh != vrefresh) {
+ if (fixed_mode_vrefresh != vrefresh) {
int vsync_start_offset = adjusted_mode->vtotal - adjusted_mode->vsync_start;
int vsync_end_offset = adjusted_mode->vtotal - adjusted_mode->vsync_end;
@@ -254,6 +251,53 @@ int intel_panel_compute_config(struct intel_connector *connector,
return 0;
}
+static int intel_panel_compute_config_fixed_rr(struct intel_connector *connector,
+ struct drm_display_mode *adjusted_mode)
+{
+ const struct drm_display_mode *fixed_mode;
+ int vrefresh, fixed_mode_vrefresh;
+
+ fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode);
+ if (!fixed_mode)
+ return 0;
+
+ vrefresh = drm_mode_vrefresh(adjusted_mode);
+ fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
+
+ /*
+ * We don't want to lie too much to the user about the refresh
+ * rate they're going to get. But we have to allow a bit of latitude
+ * for Xorg since it likes to automagically cook up modes with slightly
+ * off refresh rates.
+ */
+ if (abs(vrefresh - fixed_mode_vrefresh) > 1) {
+ drm_dbg_kms(connector->base.dev,
+ "[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n",
+ connector->base.base.id, connector->base.name,
+ vrefresh, fixed_mode_vrefresh);
+
+ return -EINVAL;
+ }
+
+ drm_mode_copy(adjusted_mode, fixed_mode);
+
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+ return 0;
+}
+
+int intel_panel_compute_config(struct intel_connector *connector,
+ struct drm_display_mode *adjusted_mode)
+{
+ int ret;
+
+ ret = intel_panel_compute_config_vrr(connector, adjusted_mode);
+ if (ret)
+ ret = intel_panel_compute_config_fixed_rr(connector, adjusted_mode);
+
+ return ret;
+}
+
static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(connector);