dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP
@ 2026-06-22 21:35 Ville Syrjala
  2026-06-22 21:35 ` [PATCH v2 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages Ville Syrjala
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Ville Syrjala @ 2026-06-22 21:35 UTC (permalink / raw)
  To: intel-gfx; +Cc: intel-xe, dri-devel, Suraj Kandpal, Ankit Nautiyal

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Tweak the eDP fixed mode selection algorithm to allow
userspace to do refresh rate changes on VRR capable
eDP panels without full modesets.

v2: Cleaner split for VRR vs. fixed refresh rate fixed mode
    selection to avoid some corner cases

Cc: Suraj Kandpal <suraj.kandpal@intel.com>
Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>

Ville Syrjälä (5):
  drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection
    into separate stages
  drm/modes: Add DRM_MODE_MATCH_TIMINGS_VRR
  drm/i915: Pass the full atomic state to .compute_config()
  drm/i915/panel: Adjust intel_panel_compute_config() calling convention
  drm/i915/panel: Attempt VRR based refresh rate change for
    !allow_modeset

 drivers/gpu/drm/drm_modes.c                   |  23 +++
 drivers/gpu/drm/i915/display/g4x_dp.c         |   5 +-
 drivers/gpu/drm/i915/display/g4x_hdmi.c       |   4 +-
 drivers/gpu/drm/i915/display/icl_dsi.c        |   5 +-
 drivers/gpu/drm/i915/display/intel_crt.c      |   9 +-
 drivers/gpu/drm/i915/display/intel_ddi.c      |   8 +-
 drivers/gpu/drm/i915/display/intel_display.c  |   4 +-
 .../drm/i915/display/intel_display_types.h    |   6 +-
 drivers/gpu/drm/i915/display/intel_dp.c       |   6 +-
 drivers/gpu/drm/i915/display/intel_dp.h       |   3 +-
 drivers/gpu/drm/i915/display/intel_dp_mst.c   |   8 +-
 drivers/gpu/drm/i915/display/intel_dvo.c      |   5 +-
 drivers/gpu/drm/i915/display/intel_lvds.c     |   5 +-
 drivers/gpu/drm/i915/display/intel_panel.c    | 167 +++++++++++++-----
 drivers/gpu/drm/i915/display/intel_panel.h    |   6 +-
 drivers/gpu/drm/i915/display/intel_sdvo.c     |   7 +-
 drivers/gpu/drm/i915/display/intel_tv.c       |   5 +-
 drivers/gpu/drm/i915/display/vlv_dsi.c        |   5 +-
 include/drm/drm_modes.h                       |   1 +
 19 files changed, 203 insertions(+), 79 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages
  2026-06-22 21:35 [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Ville Syrjala
@ 2026-06-22 21:35 ` Ville Syrjala
  2026-06-23  4:24   ` Nautiyal, Ankit K
  2026-06-23 11:40   ` [PATCH v3 " Ville Syrjala
  2026-06-22 21:35 ` [PATCH v2 2/5] drm/modes: Add DRM_MODE_MATCH_TIMINGS_VRR Ville Syrjala
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 12+ messages in thread
From: Ville Syrjala @ 2026-06-22 21:35 UTC (permalink / raw)
  To: intel-gfx; +Cc: intel-xe, dri-devel, Suraj Kandpal, Ankit Nautiyal

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

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.

Cc: Suraj Kandpal <suraj.kandpal@intel.com>
Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_panel.c | 123 ++++++++++++++-------
 1 file changed, 84 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
index 81fb349ece5f..12a27edf8bc8 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,23 @@ 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);
 	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 +252,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);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 2/5] drm/modes: Add DRM_MODE_MATCH_TIMINGS_VRR
  2026-06-22 21:35 [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Ville Syrjala
  2026-06-22 21:35 ` [PATCH v2 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages Ville Syrjala
@ 2026-06-22 21:35 ` Ville Syrjala
  2026-06-22 21:36 ` [PATCH v2 3/5] drm/i915: Pass the full atomic state to .compute_config() Ville Syrjala
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Ville Syrjala @ 2026-06-22 21:35 UTC (permalink / raw)
  To: intel-gfx; +Cc: intel-xe, dri-devel, Suraj Kandpal, Maarten Lankhorst

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add a new mode matching flag DRM_MODE_MATCH_TIMINGS_VRR. This is
identical to DRM_MODE_MATCH_TIMINGS, except it requires the vsync
pulse to remain anchored to the end of vtotal, as opposed to the
start of the frame. VRR capable hardware can therefore treat
matching modes as just variants of the same mode with a different
vblank lengths.

Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com>
Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_modes.c | 23 +++++++++++++++++++++++
 include/drm/drm_modes.h     |  1 +
 2 files changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 3f8e025fd6d9..e1eed13a8e94 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1469,6 +1469,25 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_mode_duplicate);
 
+static bool drm_mode_match_timings_vrr(const struct drm_display_mode *mode1,
+				       const struct drm_display_mode *mode2)
+{
+	int mode1_vsync_start_offset = mode1->vtotal - mode1->vsync_start;
+	int mode1_vsync_end_offset = mode1->vtotal - mode1->vsync_end;
+	int mode2_vsync_start_offset = mode2->vtotal - mode2->vsync_start;
+	int mode2_vsync_end_offset = mode2->vtotal - mode2->vsync_end;
+
+	return mode1->hdisplay == mode2->hdisplay &&
+		mode1->hsync_start == mode2->hsync_start &&
+		mode1->hsync_end == mode2->hsync_end &&
+		mode1->htotal == mode2->htotal &&
+		mode1->hskew == mode2->hskew &&
+		mode1->vdisplay == mode2->vdisplay &&
+		mode1_vsync_start_offset == mode2_vsync_start_offset &&
+		mode1_vsync_end_offset == mode2_vsync_end_offset &&
+		mode1->vscan == mode2->vscan;
+}
+
 static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
 				   const struct drm_display_mode *mode2)
 {
@@ -1538,6 +1557,10 @@ bool drm_mode_match(const struct drm_display_mode *mode1,
 	if (!mode1 || !mode2)
 		return false;
 
+	if (match_flags & DRM_MODE_MATCH_TIMINGS_VRR &&
+	    !drm_mode_match_timings_vrr(mode1, mode2))
+		return false;
+
 	if (match_flags & DRM_MODE_MATCH_TIMINGS &&
 	    !drm_mode_match_timings(mode1, mode2))
 		return false;
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index b9bb92e4b029..6e3eccc3c349 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -193,6 +193,7 @@ enum drm_mode_status {
 #define DRM_MODE_MATCH_FLAGS (1 << 2)
 #define DRM_MODE_MATCH_3D_FLAGS (1 << 3)
 #define DRM_MODE_MATCH_ASPECT_RATIO (1 << 4)
+#define DRM_MODE_MATCH_TIMINGS_VRR (1 << 5)
 
 /**
  * struct drm_display_mode - DRM kernel-internal display mode structure
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 3/5] drm/i915: Pass the full atomic state to .compute_config()
  2026-06-22 21:35 [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Ville Syrjala
  2026-06-22 21:35 ` [PATCH v2 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages Ville Syrjala
  2026-06-22 21:35 ` [PATCH v2 2/5] drm/modes: Add DRM_MODE_MATCH_TIMINGS_VRR Ville Syrjala
@ 2026-06-22 21:36 ` Ville Syrjala
  2026-06-22 21:36 ` [PATCH v2 4/5] drm/i915/panel: Adjust intel_panel_compute_config() calling convention Ville Syrjala
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Ville Syrjala @ 2026-06-22 21:36 UTC (permalink / raw)
  To: intel-gfx; +Cc: intel-xe, dri-devel, Suraj Kandpal

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Upcoming changes will need access to the full atomic state
in .compute_config(). Pass it in from the top.

Couple of the implementations already dug this out via the
crtc_state/conn_state->state pointer, but we don't want to
use that anywhere because it's a bit of a footgun by only
being valid during the early stages of the commit.

Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/display/g4x_dp.c              | 5 +++--
 drivers/gpu/drm/i915/display/g4x_hdmi.c            | 4 ++--
 drivers/gpu/drm/i915/display/icl_dsi.c             | 3 ++-
 drivers/gpu/drm/i915/display/intel_crt.c           | 9 ++++++---
 drivers/gpu/drm/i915/display/intel_ddi.c           | 8 +++++---
 drivers/gpu/drm/i915/display/intel_display.c       | 4 ++--
 drivers/gpu/drm/i915/display/intel_display_types.h | 6 ++++--
 drivers/gpu/drm/i915/display/intel_dp.c            | 4 ++--
 drivers/gpu/drm/i915/display/intel_dp.h            | 3 ++-
 drivers/gpu/drm/i915/display/intel_dp_mst.c        | 8 ++++----
 drivers/gpu/drm/i915/display/intel_dvo.c           | 3 ++-
 drivers/gpu/drm/i915/display/intel_lvds.c          | 3 ++-
 drivers/gpu/drm/i915/display/intel_sdvo.c          | 3 ++-
 drivers/gpu/drm/i915/display/intel_tv.c            | 5 ++---
 drivers/gpu/drm/i915/display/vlv_dsi.c             | 3 ++-
 15 files changed, 42 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index d211e6c49e0a..b867443ff227 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -1222,7 +1222,8 @@ static bool ilk_digital_port_connected(struct intel_encoder *encoder)
 	return intel_de_read(display, DEISR) & bit;
 }
 
-static int g4x_dp_compute_config(struct intel_encoder *encoder,
+static int g4x_dp_compute_config(struct intel_atomic_state *state,
+				 struct intel_encoder *encoder,
 				 struct intel_crtc_state *crtc_state,
 				 struct drm_connector_state *conn_state)
 {
@@ -1232,7 +1233,7 @@ static int g4x_dp_compute_config(struct intel_encoder *encoder,
 	if (HAS_PCH_SPLIT(display) && encoder->port != PORT_A)
 		crtc_state->has_pch_encoder = true;
 
-	ret = intel_dp_compute_config(encoder, crtc_state, conn_state);
+	ret = intel_dp_compute_config(state, encoder, crtc_state, conn_state);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
index acb36cab999c..4c33aa1d1d32 100644
--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
+++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
@@ -126,12 +126,12 @@ static bool g4x_compute_has_hdmi_sink(struct intel_atomic_state *state,
 	return false;
 }
 
-static int g4x_hdmi_compute_config(struct intel_encoder *encoder,
+static int g4x_hdmi_compute_config(struct intel_atomic_state *state,
+				   struct intel_encoder *encoder,
 				   struct intel_crtc_state *crtc_state,
 				   struct drm_connector_state *conn_state)
 {
 	struct intel_display *display = to_intel_display(encoder);
-	struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state);
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 
 	if (HAS_PCH_SPLIT(display))
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index a549f1fac810..59184f2f805c 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -1657,7 +1657,8 @@ static int gen11_dsi_dsc_compute_config(struct intel_encoder *encoder,
 	return 0;
 }
 
-static int gen11_dsi_compute_config(struct intel_encoder *encoder,
+static int gen11_dsi_compute_config(struct intel_atomic_state *state,
+				    struct intel_encoder *encoder,
 				    struct intel_crtc_state *pipe_config,
 				    struct drm_connector_state *conn_state)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 243e332bef57..5b8968197fbc 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -397,7 +397,8 @@ intel_crt_mode_valid(struct drm_connector *connector,
 	return MODE_OK;
 }
 
-static int intel_crt_compute_config(struct intel_encoder *encoder,
+static int intel_crt_compute_config(struct intel_atomic_state *state,
+				    struct intel_encoder *encoder,
 				    struct intel_crtc_state *crtc_state,
 				    struct drm_connector_state *conn_state)
 {
@@ -413,7 +414,8 @@ static int intel_crt_compute_config(struct intel_encoder *encoder,
 	return 0;
 }
 
-static int pch_crt_compute_config(struct intel_encoder *encoder,
+static int pch_crt_compute_config(struct intel_atomic_state *state,
+				  struct intel_encoder *encoder,
 				  struct intel_crtc_state *crtc_state,
 				  struct drm_connector_state *conn_state)
 {
@@ -432,7 +434,8 @@ static int pch_crt_compute_config(struct intel_encoder *encoder,
 	return 0;
 }
 
-static int hsw_crt_compute_config(struct intel_encoder *encoder,
+static int hsw_crt_compute_config(struct intel_atomic_state *state,
+				  struct intel_encoder *encoder,
 				  struct intel_crtc_state *crtc_state,
 				  struct drm_connector_state *conn_state)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 25314ec65ae7..2b7eb010511b 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4485,7 +4485,8 @@ intel_ddi_compute_output_type(struct intel_encoder *encoder,
 	}
 }
 
-static int intel_ddi_compute_config(struct intel_encoder *encoder,
+static int intel_ddi_compute_config(struct intel_atomic_state *state,
+				    struct intel_encoder *encoder,
 				    struct intel_crtc_state *pipe_config,
 				    struct drm_connector_state *conn_state)
 {
@@ -4503,7 +4504,7 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder,
 
 		ret = intel_hdmi_compute_config(encoder, pipe_config, conn_state);
 	} else {
-		ret = intel_dp_compute_config(encoder, pipe_config, conn_state);
+		ret = intel_dp_compute_config(state, encoder, pipe_config, conn_state);
 	}
 
 	if (ret)
@@ -4608,7 +4609,8 @@ intel_ddi_port_sync_transcoders(const struct intel_crtc_state *ref_crtc_state,
 	return transcoders;
 }
 
-static int intel_ddi_compute_config_late(struct intel_encoder *encoder,
+static int intel_ddi_compute_config_late(struct intel_atomic_state *state,
+					 struct intel_encoder *encoder,
 					 struct intel_crtc_state *crtc_state,
 					 struct drm_connector_state *conn_state)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 805066b02aaa..5bc8e6ea10a5 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -4781,7 +4781,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
 		if (connector_state->crtc != &crtc->base)
 			continue;
 
-		ret = encoder->compute_config(encoder, crtc_state,
+		ret = encoder->compute_config(state, encoder, crtc_state,
 					      connector_state);
 		if (ret == -EDEADLK)
 			return ret;
@@ -4841,7 +4841,7 @@ intel_modeset_pipe_config_late(struct intel_atomic_state *state,
 		    !encoder->compute_config_late)
 			continue;
 
-		ret = encoder->compute_config_late(encoder, crtc_state,
+		ret = encoder->compute_config_late(state, encoder, crtc_state,
 						   conn_state);
 		if (ret)
 			return ret;
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index ebd00922bf3c..2689321609a5 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -178,10 +178,12 @@ struct intel_encoder {
 	enum intel_output_type (*compute_output_type)(struct intel_encoder *,
 						      struct intel_crtc_state *,
 						      struct drm_connector_state *);
-	int (*compute_config)(struct intel_encoder *,
+	int (*compute_config)(struct intel_atomic_state *,
+			      struct intel_encoder *,
 			      struct intel_crtc_state *,
 			      struct drm_connector_state *);
-	int (*compute_config_late)(struct intel_encoder *,
+	int (*compute_config_late)(struct intel_atomic_state *,
+				   struct intel_encoder *,
 				   struct intel_crtc_state *,
 				   struct drm_connector_state *);
 	void (*pre_pll_enable)(struct intel_atomic_state *,
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 3569e61e7fee..b9324b590ee9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3627,12 +3627,12 @@ int intel_dp_compute_min_hblank(struct intel_crtc_state *crtc_state,
 }
 
 int
-intel_dp_compute_config(struct intel_encoder *encoder,
+intel_dp_compute_config(struct intel_atomic_state *state,
+			struct intel_encoder *encoder,
 			struct intel_crtc_state *pipe_config,
 			struct drm_connector_state *conn_state)
 {
 	struct intel_display *display = to_intel_display(encoder);
-	struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
 	struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	struct intel_connector *connector = intel_dp->attached_connector;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 92ce04852326..b233739b89ce 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -71,7 +71,8 @@ void intel_dp_sink_disable_decompression(struct intel_atomic_state *state,
 void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
 void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder);
 void intel_dp_encoder_flush_work(struct drm_encoder *encoder);
-int intel_dp_compute_config(struct intel_encoder *encoder,
+int intel_dp_compute_config(struct intel_atomic_state *state,
+			    struct intel_encoder *encoder,
 			    struct intel_crtc_state *pipe_config,
 			    struct drm_connector_state *conn_state);
 bool intel_dp_needs_8b10b_fec(const struct intel_crtc_state *crtc_state,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 0aa3e6b4c781..ecc90e8faee1 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -697,12 +697,12 @@ static int mst_stream_compute_link_for_joined_pipes(struct intel_encoder *encode
 	return 0;
 }
 
-static int mst_stream_compute_config(struct intel_encoder *encoder,
+static int mst_stream_compute_config(struct intel_atomic_state *state,
+				     struct intel_encoder *encoder,
 				     struct intel_crtc_state *pipe_config,
 				     struct drm_connector_state *conn_state)
 {
 	struct intel_display *display = to_intel_display(encoder);
-	struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
 	struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
 	struct intel_dp *intel_dp = to_primary_dp(encoder);
 	struct intel_connector *connector =
@@ -925,11 +925,11 @@ int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state,
 	return 0;
 }
 
-static int mst_stream_compute_config_late(struct intel_encoder *encoder,
+static int mst_stream_compute_config_late(struct intel_atomic_state *state,
+					  struct intel_encoder *encoder,
 					  struct intel_crtc_state *crtc_state,
 					  struct drm_connector_state *conn_state)
 {
-	struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
 	struct intel_dp *intel_dp = to_primary_dp(encoder);
 
 	/* lowest numbered transcoder will be designated master */
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index dd1a995c2979..181722c41b96 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -242,7 +242,8 @@ intel_dvo_mode_valid(struct drm_connector *_connector,
 	return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
 }
 
-static int intel_dvo_compute_config(struct intel_encoder *encoder,
+static int intel_dvo_compute_config(struct intel_atomic_state *state,
+				    struct intel_encoder *encoder,
 				    struct intel_crtc_state *pipe_config,
 				    struct drm_connector_state *conn_state)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index c8098104d853..30e4809b36ac 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -413,7 +413,8 @@ intel_lvds_mode_valid(struct drm_connector *_connector,
 	return MODE_OK;
 }
 
-static int intel_lvds_compute_config(struct intel_encoder *encoder,
+static int intel_lvds_compute_config(struct intel_atomic_state *state,
+				     struct intel_encoder *encoder,
 				     struct intel_crtc_state *crtc_state,
 				     struct drm_connector_state *conn_state)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index d83d350959d8..6b73c9a5ec7f 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -1354,7 +1354,8 @@ static bool intel_sdvo_has_audio(struct intel_encoder *encoder,
 		return intel_conn_state->force_audio == HDMI_AUDIO_ON;
 }
 
-static int intel_sdvo_compute_config(struct intel_encoder *encoder,
+static int intel_sdvo_compute_config(struct intel_atomic_state *state,
+				     struct intel_encoder *encoder,
 				     struct intel_crtc_state *pipe_config,
 				     struct drm_connector_state *conn_state)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index 0a926c6f25f4..840e1dcdc2d0 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -1187,13 +1187,12 @@ static bool intel_tv_vert_scaling(const struct drm_display_mode *tv_mode,
 }
 
 static int
-intel_tv_compute_config(struct intel_encoder *encoder,
+intel_tv_compute_config(struct intel_atomic_state *state,
+			struct intel_encoder *encoder,
 			struct intel_crtc_state *pipe_config,
 			struct drm_connector_state *conn_state)
 {
 	struct intel_display *display = to_intel_display(encoder);
-	struct intel_atomic_state *state =
-		to_intel_atomic_state(pipe_config->uapi.state);
 	struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
 	struct intel_tv_connector_state *tv_conn_state =
 		to_intel_tv_connector_state(conn_state);
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index 877eab75f19a..b89318f5bdc2 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -266,7 +266,8 @@ static void band_gap_reset(struct intel_display *display)
 	vlv_flisdsi_put(display);
 }
 
-static int intel_dsi_compute_config(struct intel_encoder *encoder,
+static int intel_dsi_compute_config(struct intel_atomic_state *state,
+				    struct intel_encoder *encoder,
 				    struct intel_crtc_state *pipe_config,
 				    struct drm_connector_state *conn_state)
 {
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 4/5] drm/i915/panel: Adjust intel_panel_compute_config() calling convention
  2026-06-22 21:35 [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Ville Syrjala
                   ` (2 preceding siblings ...)
  2026-06-22 21:36 ` [PATCH v2 3/5] drm/i915: Pass the full atomic state to .compute_config() Ville Syrjala
@ 2026-06-22 21:36 ` Ville Syrjala
  2026-06-23 11:41   ` [PATCH v3 " Ville Syrjala
  2026-06-22 21:36 ` [PATCH v2 5/5] drm/i915/panel: Attempt VRR based refresh rate change for !allow_modeset Ville Syrjala
  2026-06-23 16:05 ` [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Srinivas, Vidya
  5 siblings, 1 reply; 12+ messages in thread
From: Ville Syrjala @ 2026-06-22 21:36 UTC (permalink / raw)
  To: intel-gfx; +Cc: intel-xe, dri-devel, Suraj Kandpal

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Pass the full atomic state to intel_panel_compute_config(). We'll
need this for some upcoming VRR fastset tricks. And to accompany
full state we'll also need the crtc (or its state) as well.

Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/display/icl_dsi.c     |  2 +-
 drivers/gpu/drm/i915/display/intel_dp.c    |  2 +-
 drivers/gpu/drm/i915/display/intel_dvo.c   |  2 +-
 drivers/gpu/drm/i915/display/intel_lvds.c  |  2 +-
 drivers/gpu/drm/i915/display/intel_panel.c | 24 +++++++++++++---------
 drivers/gpu/drm/i915/display/intel_panel.h |  6 ++++--
 drivers/gpu/drm/i915/display/intel_sdvo.c  |  4 ++--
 drivers/gpu/drm/i915/display/vlv_dsi.c     |  2 +-
 8 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index 59184f2f805c..ea0cdb7822f3 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -1672,7 +1672,7 @@ static int gen11_dsi_compute_config(struct intel_atomic_state *state,
 	pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
 	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
-	ret = intel_panel_compute_config(intel_connector, adjusted_mode);
+	ret = intel_panel_compute_config(state, pipe_config, intel_connector);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index b9324b590ee9..da8a94821c11 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3639,7 +3639,7 @@ intel_dp_compute_config(struct intel_atomic_state *state,
 	int ret = 0, link_bpp_x16;
 
 	if (intel_dp_is_edp(intel_dp)) {
-		ret = intel_panel_compute_config(connector, adjusted_mode);
+		ret = intel_panel_compute_config(state, pipe_config, connector);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index 181722c41b96..f157699a7c4c 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -257,7 +257,7 @@ static int intel_dvo_compute_config(struct intel_atomic_state *state,
 	 * with the panel scaling set up to source from the H/VDisplay
 	 * of the original mode.
 	 */
-	ret = intel_panel_compute_config(connector, adjusted_mode);
+	ret = intel_panel_compute_config(state, pipe_config, connector);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index 30e4809b36ac..872753478cf2 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -460,7 +460,7 @@ static int intel_lvds_compute_config(struct intel_atomic_state *state,
 	 * with the panel scaling set up to source from the H/VDisplay
 	 * of the original mode.
 	 */
-	ret = intel_panel_compute_config(connector, adjusted_mode);
+	ret = intel_panel_compute_config(state, crtc_state, connector);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
index 12a27edf8bc8..faa24537ef63 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -219,11 +219,12 @@ enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
 	return connector->panel.vbt.drrs_type;
 }
 
-static int intel_panel_compute_config_vrr(struct intel_connector *connector,
-					  struct drm_display_mode *adjusted_mode)
+static int intel_panel_compute_config_vrr(struct intel_atomic_state *state,
+					  struct intel_crtc_state *crtc_state,
+					  struct intel_connector *connector)
 {
-	const struct drm_display_mode *fixed_mode =
-		intel_panel_fixed_mode(connector, adjusted_mode);
+	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
+	const struct drm_display_mode *fixed_mode;
 	int vrefresh, fixed_mode_vrefresh;
 
 	fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode);
@@ -252,9 +253,11 @@ static int intel_panel_compute_config_vrr(struct intel_connector *connector,
 	return 0;
 }
 
-static int intel_panel_compute_config_fixed_rr(struct intel_connector *connector,
-					       struct drm_display_mode *adjusted_mode)
+static int intel_panel_compute_config_fixed_rr(struct intel_atomic_state *state,
+					       struct intel_crtc_state *crtc_state,
+					       struct intel_connector *connector)
 {
+	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
 	const struct drm_display_mode *fixed_mode;
 	int vrefresh, fixed_mode_vrefresh;
 
@@ -287,14 +290,15 @@ static int intel_panel_compute_config_fixed_rr(struct intel_connector *connector
 	return 0;
 }
 
-int intel_panel_compute_config(struct intel_connector *connector,
-			       struct drm_display_mode *adjusted_mode)
+int intel_panel_compute_config(struct intel_atomic_state *state,
+			       struct intel_crtc_state *crtc_state,
+			       struct intel_connector *connector)
 {
 	int ret;
 
-	ret = intel_panel_compute_config_vrr(connector, adjusted_mode);
+	ret = intel_panel_compute_config_vrr(state, crtc_state, connector);
 	if (ret)
-		ret = intel_panel_compute_config_fixed_rr(connector, adjusted_mode);
+		ret = intel_panel_compute_config_fixed_rr(state, crtc_state, connector);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h
index 23bd227826c9..30c6078ecb1b 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.h
+++ b/drivers/gpu/drm/i915/display/intel_panel.h
@@ -14,6 +14,7 @@ struct drm_connector;
 struct drm_connector_state;
 struct drm_display_mode;
 struct drm_edid;
+struct intel_atomic_state;
 struct intel_connector;
 struct intel_crtc_state;
 struct intel_display;
@@ -45,8 +46,9 @@ enum drm_mode_status
 intel_panel_mode_valid(struct intel_connector *connector,
 		       const struct drm_display_mode *mode,
 		       int *target_clock);
-int intel_panel_compute_config(struct intel_connector *connector,
-			       struct drm_display_mode *adjusted_mode);
+int intel_panel_compute_config(struct intel_atomic_state *state,
+			       struct intel_crtc_state *crtc_state,
+			       struct intel_connector *connector);
 void intel_panel_add_edid_fixed_modes(struct intel_connector *connector,
 				      bool use_alt_fixed_modes);
 void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector);
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 6b73c9a5ec7f..3075ef04df56 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -1399,8 +1399,8 @@ static int intel_sdvo_compute_config(struct intel_atomic_state *state,
 		const struct drm_display_mode *fixed_mode;
 		int ret;
 
-		ret = intel_panel_compute_config(&intel_sdvo_connector->base,
-						 adjusted_mode);
+		ret = intel_panel_compute_config(state, pipe_config,
+						 &intel_sdvo_connector->base);
 		if (ret)
 			return ret;
 
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index b89318f5bdc2..8829f365592e 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -281,7 +281,7 @@ static int intel_dsi_compute_config(struct intel_atomic_state *state,
 	pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
 	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
-	ret = intel_panel_compute_config(intel_connector, adjusted_mode);
+	ret = intel_panel_compute_config(state, pipe_config, intel_connector);
 	if (ret)
 		return ret;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 5/5] drm/i915/panel: Attempt VRR based refresh rate change for !allow_modeset
  2026-06-22 21:35 [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Ville Syrjala
                   ` (3 preceding siblings ...)
  2026-06-22 21:36 ` [PATCH v2 4/5] drm/i915/panel: Adjust intel_panel_compute_config() calling convention Ville Syrjala
@ 2026-06-22 21:36 ` Ville Syrjala
  2026-06-23  4:28   ` Nautiyal, Ankit K
  2026-06-23 16:05 ` [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Srinivas, Vidya
  5 siblings, 1 reply; 12+ messages in thread
From: Ville Syrjala @ 2026-06-22 21:36 UTC (permalink / raw)
  To: intel-gfx; +Cc: intel-xe, dri-devel, Ankit Nautiyal

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Adjust the panel fixed mode selection algorithm to only consider
fixed modes that are "VRR compatible" with the old fixed mode
when userspace doesn't want to allow full modesets. This will
allow a VRR based refresh rate changes (ie. just a change in
the vblank length) via the fastset path.

When full modesets are allowed, we still use the original algorithm
as that may pick a fixed mode with a more optimal dotclock, potentially
leading to reduced power consumption.

This approach works as long as userspace does the initial
allow_modeset=true commit using the highest refresh rate it will
want to use. Subsequent commits with allow_modeset=false can then
switch between lower refresh rates without blinks.

One remaining hurdle we may need to solve is the guardband length.
Assuming the highest refresh rate vblank is too short for
intel_vrr_compute_optimized_guardband() the intitial guardband will
match the highest refresh rate vblank. A subsequent switch to a lower
refresh rate will then recompute the guardband and select a value
that is higher (since the vblank will be longer). The mismatch in
guardband lengths will prevent the fastset. We may either have to
preserve the original (sub-optimal) guardband, or we'll have to
revisit the idea of changing the guardband without a full modeset.

Note that I'm not 100% happy with this solution because
intel_panel_fixed_mode() is no longer fully idempotent, but I wasn't
able to come up with anything truly better either :/ The simple
solution would be just to always pick the fixed mode with the highest
dotclock, but that could lead to increased power consumption even
when high refresh rates are never used.

Perhaps the proper solution would be to just deprecate this
idea of taking in random modes for internal panels and then
cooking up a compatible fixed modes. Life would be easier if
userspace was required to provide the desired fixed mode directly.
But in order to do that we'd need to introduce new uapi properties
to control the pfit aspect of this, and we'd probably need a new
client cap to select between the old and new userspace behaviour.
Something to consider in the future...

v2: Rebase due to earlier changes to VRR fixed mode selection

Reviewed-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com> #v1
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_panel.c | 42 ++++++++++++++++++++--
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
index faa24537ef63..81e638d0c7b3 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -72,9 +72,20 @@ static bool is_best_fixed_mode(struct intel_connector *connector,
 		abs(drm_mode_vrefresh(best_mode) - vrefresh);
 }
 
+static bool is_vrr_compatible(const struct drm_display_mode *mode1,
+			      const struct drm_display_mode *mode2)
+{
+	return drm_mode_match(mode1, mode2,
+			      DRM_MODE_MATCH_CLOCK |
+			      DRM_MODE_MATCH_TIMINGS_VRR |
+			      DRM_MODE_MATCH_FLAGS |
+			      DRM_MODE_MATCH_3D_FLAGS);
+}
+
 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 *mode,
+			   const struct drm_display_mode *vrr_ref_mode)
 {
 	const struct drm_display_mode *fixed_mode, *best_mode = NULL;
 	int vrefresh = drm_mode_vrefresh(mode);
@@ -82,6 +93,10 @@ intel_panel_fixed_mode_vrr(struct intel_connector *connector,
 	if (!intel_vrr_is_in_range(connector, vrefresh))
 		return NULL;
 
+	if (vrr_ref_mode &&
+	    !intel_vrr_is_in_range(connector, drm_mode_vrefresh(vrr_ref_mode)))
+		return NULL;
+
 	list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
 		int fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
 
@@ -96,6 +111,10 @@ intel_panel_fixed_mode_vrr(struct intel_connector *connector,
 		if (fixed_mode_vrefresh < vrefresh)
 			continue;
 
+		if (vrr_ref_mode &&
+		    !is_vrr_compatible(fixed_mode, vrr_ref_mode))
+			continue;
+
 		if (is_best_fixed_mode(connector, vrefresh,
 				       fixed_mode_vrefresh, best_mode))
 			best_mode = fixed_mode;
@@ -224,10 +243,27 @@ static int intel_panel_compute_config_vrr(struct intel_atomic_state *state,
 					  struct intel_connector *connector)
 {
 	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
-	const struct drm_display_mode *fixed_mode;
+	const struct drm_display_mode *fixed_mode = NULL;
 	int vrefresh, fixed_mode_vrefresh;
 
-	fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode);
+	/*
+	 * Attempt a VRR based refresh rate change if possible
+	 * when userspace has forbidden a full modeset.
+	 */
+	if (!state->base.allow_modeset) {
+		struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+		const struct intel_crtc_state *old_crtc_state =
+			intel_atomic_get_old_crtc_state(state, crtc);
+
+		if (old_crtc_state->hw.enable &&
+		    old_crtc_state->uapi.encoder_mask == crtc_state->uapi.encoder_mask)
+			fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode,
+								&old_crtc_state->hw.adjusted_mode);
+	}
+
+	if (!fixed_mode)
+		fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode, NULL);
+
 	if (!fixed_mode)
 		return -EINVAL;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages
  2026-06-22 21:35 ` [PATCH v2 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages Ville Syrjala
@ 2026-06-23  4:24   ` Nautiyal, Ankit K
  2026-06-23 11:40   ` [PATCH v3 " Ville Syrjala
  1 sibling, 0 replies; 12+ messages in thread
From: Nautiyal, Ankit K @ 2026-06-23  4:24 UTC (permalink / raw)
  To: Ville Syrjala, intel-gfx; +Cc: intel-xe, dri-devel, Suraj Kandpal


On 6/23/2026 3:05 AM, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> 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.
>
> Cc: Suraj Kandpal <suraj.kandpal@intel.com>
> Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/display/intel_panel.c | 123 ++++++++++++++-------
>   1 file changed, 84 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
> index 81fb349ece5f..12a27edf8bc8 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,23 @@ 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);


This is not needed now, we are overwriting this anyways.

Otherwise LGTM.

Reviewed-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>


>   	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 +252,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);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 5/5] drm/i915/panel: Attempt VRR based refresh rate change for !allow_modeset
  2026-06-22 21:36 ` [PATCH v2 5/5] drm/i915/panel: Attempt VRR based refresh rate change for !allow_modeset Ville Syrjala
@ 2026-06-23  4:28   ` Nautiyal, Ankit K
  2026-06-23 11:48     ` Ville Syrjälä
  0 siblings, 1 reply; 12+ messages in thread
From: Nautiyal, Ankit K @ 2026-06-23  4:28 UTC (permalink / raw)
  To: Ville Syrjala, intel-gfx; +Cc: intel-xe, dri-devel


On 6/23/2026 3:06 AM, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Adjust the panel fixed mode selection algorithm to only consider
> fixed modes that are "VRR compatible" with the old fixed mode
> when userspace doesn't want to allow full modesets. This will
> allow a VRR based refresh rate changes (ie. just a change in
> the vblank length) via the fastset path.
>
> When full modesets are allowed, we still use the original algorithm
> as that may pick a fixed mode with a more optimal dotclock, potentially
> leading to reduced power consumption.
>
> This approach works as long as userspace does the initial
> allow_modeset=true commit using the highest refresh rate it will
> want to use. Subsequent commits with allow_modeset=false can then
> switch between lower refresh rates without blinks.
>
> One remaining hurdle we may need to solve is the guardband length.
> Assuming the highest refresh rate vblank is too short for
> intel_vrr_compute_optimized_guardband() the intitial guardband will
> match the highest refresh rate vblank. A subsequent switch to a lower
> refresh rate will then recompute the guardband and select a value
> that is higher (since the vblank will be longer). The mismatch in
> guardband lengths will prevent the fastset. We may either have to
> preserve the original (sub-optimal) guardband, or we'll have to
> revisit the idea of changing the guardband without a full modeset.
>
> Note that I'm not 100% happy with this solution because
> intel_panel_fixed_mode() is no longer fully idempotent, but I wasn't
> able to come up with anything truly better either :/ The simple
> solution would be just to always pick the fixed mode with the highest
> dotclock, but that could lead to increased power consumption even
> when high refresh rates are never used.
>
> Perhaps the proper solution would be to just deprecate this
> idea of taking in random modes for internal panels and then
> cooking up a compatible fixed modes. Life would be easier if
> userspace was required to provide the desired fixed mode directly.
> But in order to do that we'd need to introduce new uapi properties
> to control the pfit aspect of this, and we'd probably need a new
> client cap to select between the old and new userspace behaviour.
> Something to consider in the future...
>
> v2: Rebase due to earlier changes to VRR fixed mode selection
>
> Reviewed-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com> #v1
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/display/intel_panel.c | 42 ++++++++++++++++++++--
>   1 file changed, 39 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
> index faa24537ef63..81e638d0c7b3 100644
> --- a/drivers/gpu/drm/i915/display/intel_panel.c
> +++ b/drivers/gpu/drm/i915/display/intel_panel.c
> @@ -72,9 +72,20 @@ static bool is_best_fixed_mode(struct intel_connector *connector,
>   		abs(drm_mode_vrefresh(best_mode) - vrefresh);
>   }
>   
> +static bool is_vrr_compatible(const struct drm_display_mode *mode1,
> +			      const struct drm_display_mode *mode2)
> +{
> +	return drm_mode_match(mode1, mode2,
> +			      DRM_MODE_MATCH_CLOCK |
> +			      DRM_MODE_MATCH_TIMINGS_VRR |
> +			      DRM_MODE_MATCH_FLAGS |
> +			      DRM_MODE_MATCH_3D_FLAGS);
> +}
> +
>   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 *mode,
> +			   const struct drm_display_mode *vrr_ref_mode)
>   {
>   	const struct drm_display_mode *fixed_mode, *best_mode = NULL;
>   	int vrefresh = drm_mode_vrefresh(mode);
> @@ -82,6 +93,10 @@ intel_panel_fixed_mode_vrr(struct intel_connector *connector,
>   	if (!intel_vrr_is_in_range(connector, vrefresh))
>   		return NULL;
>   
> +	if (vrr_ref_mode &&
> +	    !intel_vrr_is_in_range(connector, drm_mode_vrefresh(vrr_ref_mode)))
> +		return NULL;
> +
>   	list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
>   		int fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
>   
> @@ -96,6 +111,10 @@ intel_panel_fixed_mode_vrr(struct intel_connector *connector,
>   		if (fixed_mode_vrefresh < vrefresh)
>   			continue;
>   
> +		if (vrr_ref_mode &&
> +		    !is_vrr_compatible(fixed_mode, vrr_ref_mode))
> +			continue;
> +
>   		if (is_best_fixed_mode(connector, vrefresh,
>   				       fixed_mode_vrefresh, best_mode))
>   			best_mode = fixed_mode;
> @@ -224,10 +243,27 @@ static int intel_panel_compute_config_vrr(struct intel_atomic_state *state,
>   					  struct intel_connector *connector)
>   {
>   	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
> -	const struct drm_display_mode *fixed_mode;
> +	const struct drm_display_mode *fixed_mode = NULL;
>   	int vrefresh, fixed_mode_vrefresh;
>   

Perhaps an early return for if (!vrr_is_capable()) here will avoid two 
calls for intel_panel_fixed_mode_vrr().

I leave it to you.

In any case the patch LGTM.

Reviewed-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>

> -	fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode);
> +	/*
> +	 * Attempt a VRR based refresh rate change if possible
> +	 * when userspace has forbidden a full modeset.
> +	 */
> +	if (!state->base.allow_modeset) {
> +		struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +		const struct intel_crtc_state *old_crtc_state =
> +			intel_atomic_get_old_crtc_state(state, crtc);
> +
> +		if (old_crtc_state->hw.enable &&
> +		    old_crtc_state->uapi.encoder_mask == crtc_state->uapi.encoder_mask)
> +			fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode,
> +								&old_crtc_state->hw.adjusted_mode);
> +	}
> +
> +	if (!fixed_mode)
> +		fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode, NULL);
> +
>   	if (!fixed_mode)
>   		return -EINVAL;
>   

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages
  2026-06-22 21:35 ` [PATCH v2 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages Ville Syrjala
  2026-06-23  4:24   ` Nautiyal, Ankit K
@ 2026-06-23 11:40   ` Ville Syrjala
  1 sibling, 0 replies; 12+ messages in thread
From: Ville Syrjala @ 2026-06-23 11:40 UTC (permalink / raw)
  To: intel-gfx; +Cc: intel-xe, dri-devel, Suraj Kandpal, Ankit Nautiyal

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

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>
---
 drivers/gpu/drm/i915/display/intel_panel.c | 126 ++++++++++++++-------
 1 file 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);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/5] drm/i915/panel: Adjust intel_panel_compute_config() calling convention
  2026-06-22 21:36 ` [PATCH v2 4/5] drm/i915/panel: Adjust intel_panel_compute_config() calling convention Ville Syrjala
@ 2026-06-23 11:41   ` Ville Syrjala
  0 siblings, 0 replies; 12+ messages in thread
From: Ville Syrjala @ 2026-06-23 11:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: intel-xe, dri-devel, Suraj Kandpal

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Pass the full atomic state to intel_panel_compute_config(). We'll
need this for some upcoming VRR fastset tricks. And to accompany
full state we'll also need the crtc (or its state) as well.

v2: Rebase

Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/display/icl_dsi.c     |  2 +-
 drivers/gpu/drm/i915/display/intel_dp.c    |  2 +-
 drivers/gpu/drm/i915/display/intel_dvo.c   |  2 +-
 drivers/gpu/drm/i915/display/intel_lvds.c  |  2 +-
 drivers/gpu/drm/i915/display/intel_panel.c | 21 +++++++++++++--------
 drivers/gpu/drm/i915/display/intel_panel.h |  6 ++++--
 drivers/gpu/drm/i915/display/intel_sdvo.c  |  4 ++--
 drivers/gpu/drm/i915/display/vlv_dsi.c     |  2 +-
 8 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index 59184f2f805c..ea0cdb7822f3 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -1672,7 +1672,7 @@ static int gen11_dsi_compute_config(struct intel_atomic_state *state,
 	pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
 	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
-	ret = intel_panel_compute_config(intel_connector, adjusted_mode);
+	ret = intel_panel_compute_config(state, pipe_config, intel_connector);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index b9324b590ee9..da8a94821c11 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3639,7 +3639,7 @@ intel_dp_compute_config(struct intel_atomic_state *state,
 	int ret = 0, link_bpp_x16;
 
 	if (intel_dp_is_edp(intel_dp)) {
-		ret = intel_panel_compute_config(connector, adjusted_mode);
+		ret = intel_panel_compute_config(state, pipe_config, connector);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index 181722c41b96..f157699a7c4c 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -257,7 +257,7 @@ static int intel_dvo_compute_config(struct intel_atomic_state *state,
 	 * with the panel scaling set up to source from the H/VDisplay
 	 * of the original mode.
 	 */
-	ret = intel_panel_compute_config(connector, adjusted_mode);
+	ret = intel_panel_compute_config(state, pipe_config, connector);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index 30e4809b36ac..872753478cf2 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -460,7 +460,7 @@ static int intel_lvds_compute_config(struct intel_atomic_state *state,
 	 * with the panel scaling set up to source from the H/VDisplay
 	 * of the original mode.
 	 */
-	ret = intel_panel_compute_config(connector, adjusted_mode);
+	ret = intel_panel_compute_config(state, crtc_state, connector);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
index 2b8401b6d4d6..faa24537ef63 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -219,9 +219,11 @@ enum drrs_type intel_panel_drrs_type(struct intel_connector *connector)
 	return connector->panel.vbt.drrs_type;
 }
 
-static int intel_panel_compute_config_vrr(struct intel_connector *connector,
-					  struct drm_display_mode *adjusted_mode)
+static int intel_panel_compute_config_vrr(struct intel_atomic_state *state,
+					  struct intel_crtc_state *crtc_state,
+					  struct intel_connector *connector)
 {
+	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
 	const struct drm_display_mode *fixed_mode;
 	int vrefresh, fixed_mode_vrefresh;
 
@@ -251,9 +253,11 @@ static int intel_panel_compute_config_vrr(struct intel_connector *connector,
 	return 0;
 }
 
-static int intel_panel_compute_config_fixed_rr(struct intel_connector *connector,
-					       struct drm_display_mode *adjusted_mode)
+static int intel_panel_compute_config_fixed_rr(struct intel_atomic_state *state,
+					       struct intel_crtc_state *crtc_state,
+					       struct intel_connector *connector)
 {
+	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
 	const struct drm_display_mode *fixed_mode;
 	int vrefresh, fixed_mode_vrefresh;
 
@@ -286,14 +290,15 @@ static int intel_panel_compute_config_fixed_rr(struct intel_connector *connector
 	return 0;
 }
 
-int intel_panel_compute_config(struct intel_connector *connector,
-			       struct drm_display_mode *adjusted_mode)
+int intel_panel_compute_config(struct intel_atomic_state *state,
+			       struct intel_crtc_state *crtc_state,
+			       struct intel_connector *connector)
 {
 	int ret;
 
-	ret = intel_panel_compute_config_vrr(connector, adjusted_mode);
+	ret = intel_panel_compute_config_vrr(state, crtc_state, connector);
 	if (ret)
-		ret = intel_panel_compute_config_fixed_rr(connector, adjusted_mode);
+		ret = intel_panel_compute_config_fixed_rr(state, crtc_state, connector);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h
index 23bd227826c9..30c6078ecb1b 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.h
+++ b/drivers/gpu/drm/i915/display/intel_panel.h
@@ -14,6 +14,7 @@ struct drm_connector;
 struct drm_connector_state;
 struct drm_display_mode;
 struct drm_edid;
+struct intel_atomic_state;
 struct intel_connector;
 struct intel_crtc_state;
 struct intel_display;
@@ -45,8 +46,9 @@ enum drm_mode_status
 intel_panel_mode_valid(struct intel_connector *connector,
 		       const struct drm_display_mode *mode,
 		       int *target_clock);
-int intel_panel_compute_config(struct intel_connector *connector,
-			       struct drm_display_mode *adjusted_mode);
+int intel_panel_compute_config(struct intel_atomic_state *state,
+			       struct intel_crtc_state *crtc_state,
+			       struct intel_connector *connector);
 void intel_panel_add_edid_fixed_modes(struct intel_connector *connector,
 				      bool use_alt_fixed_modes);
 void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector);
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 6b73c9a5ec7f..3075ef04df56 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -1399,8 +1399,8 @@ static int intel_sdvo_compute_config(struct intel_atomic_state *state,
 		const struct drm_display_mode *fixed_mode;
 		int ret;
 
-		ret = intel_panel_compute_config(&intel_sdvo_connector->base,
-						 adjusted_mode);
+		ret = intel_panel_compute_config(state, pipe_config,
+						 &intel_sdvo_connector->base);
 		if (ret)
 			return ret;
 
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index b89318f5bdc2..8829f365592e 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -281,7 +281,7 @@ static int intel_dsi_compute_config(struct intel_atomic_state *state,
 	pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
 	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
 
-	ret = intel_panel_compute_config(intel_connector, adjusted_mode);
+	ret = intel_panel_compute_config(state, pipe_config, intel_connector);
 	if (ret)
 		return ret;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 5/5] drm/i915/panel: Attempt VRR based refresh rate change for !allow_modeset
  2026-06-23  4:28   ` Nautiyal, Ankit K
@ 2026-06-23 11:48     ` Ville Syrjälä
  0 siblings, 0 replies; 12+ messages in thread
From: Ville Syrjälä @ 2026-06-23 11:48 UTC (permalink / raw)
  To: Nautiyal, Ankit K; +Cc: intel-gfx, intel-xe, dri-devel

On Tue, Jun 23, 2026 at 09:58:03AM +0530, Nautiyal, Ankit K wrote:
> 
> On 6/23/2026 3:06 AM, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > Adjust the panel fixed mode selection algorithm to only consider
> > fixed modes that are "VRR compatible" with the old fixed mode
> > when userspace doesn't want to allow full modesets. This will
> > allow a VRR based refresh rate changes (ie. just a change in
> > the vblank length) via the fastset path.
> >
> > When full modesets are allowed, we still use the original algorithm
> > as that may pick a fixed mode with a more optimal dotclock, potentially
> > leading to reduced power consumption.
> >
> > This approach works as long as userspace does the initial
> > allow_modeset=true commit using the highest refresh rate it will
> > want to use. Subsequent commits with allow_modeset=false can then
> > switch between lower refresh rates without blinks.
> >
> > One remaining hurdle we may need to solve is the guardband length.
> > Assuming the highest refresh rate vblank is too short for
> > intel_vrr_compute_optimized_guardband() the intitial guardband will
> > match the highest refresh rate vblank. A subsequent switch to a lower
> > refresh rate will then recompute the guardband and select a value
> > that is higher (since the vblank will be longer). The mismatch in
> > guardband lengths will prevent the fastset. We may either have to
> > preserve the original (sub-optimal) guardband, or we'll have to
> > revisit the idea of changing the guardband without a full modeset.
> >
> > Note that I'm not 100% happy with this solution because
> > intel_panel_fixed_mode() is no longer fully idempotent, but I wasn't
> > able to come up with anything truly better either :/ The simple
> > solution would be just to always pick the fixed mode with the highest
> > dotclock, but that could lead to increased power consumption even
> > when high refresh rates are never used.
> >
> > Perhaps the proper solution would be to just deprecate this
> > idea of taking in random modes for internal panels and then
> > cooking up a compatible fixed modes. Life would be easier if
> > userspace was required to provide the desired fixed mode directly.
> > But in order to do that we'd need to introduce new uapi properties
> > to control the pfit aspect of this, and we'd probably need a new
> > client cap to select between the old and new userspace behaviour.
> > Something to consider in the future...
> >
> > v2: Rebase due to earlier changes to VRR fixed mode selection
> >
> > Reviewed-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com> #v1
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >   drivers/gpu/drm/i915/display/intel_panel.c | 42 ++++++++++++++++++++--
> >   1 file changed, 39 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
> > index faa24537ef63..81e638d0c7b3 100644
> > --- a/drivers/gpu/drm/i915/display/intel_panel.c
> > +++ b/drivers/gpu/drm/i915/display/intel_panel.c
> > @@ -72,9 +72,20 @@ static bool is_best_fixed_mode(struct intel_connector *connector,
> >   		abs(drm_mode_vrefresh(best_mode) - vrefresh);
> >   }
> >   
> > +static bool is_vrr_compatible(const struct drm_display_mode *mode1,
> > +			      const struct drm_display_mode *mode2)
> > +{
> > +	return drm_mode_match(mode1, mode2,
> > +			      DRM_MODE_MATCH_CLOCK |
> > +			      DRM_MODE_MATCH_TIMINGS_VRR |
> > +			      DRM_MODE_MATCH_FLAGS |
> > +			      DRM_MODE_MATCH_3D_FLAGS);
> > +}
> > +
> >   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 *mode,
> > +			   const struct drm_display_mode *vrr_ref_mode)
> >   {
> >   	const struct drm_display_mode *fixed_mode, *best_mode = NULL;
> >   	int vrefresh = drm_mode_vrefresh(mode);
> > @@ -82,6 +93,10 @@ intel_panel_fixed_mode_vrr(struct intel_connector *connector,
> >   	if (!intel_vrr_is_in_range(connector, vrefresh))
> >   		return NULL;
> >   
> > +	if (vrr_ref_mode &&
> > +	    !intel_vrr_is_in_range(connector, drm_mode_vrefresh(vrr_ref_mode)))
> > +		return NULL;
> > +
> >   	list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
> >   		int fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode);
> >   
> > @@ -96,6 +111,10 @@ intel_panel_fixed_mode_vrr(struct intel_connector *connector,
> >   		if (fixed_mode_vrefresh < vrefresh)
> >   			continue;
> >   
> > +		if (vrr_ref_mode &&
> > +		    !is_vrr_compatible(fixed_mode, vrr_ref_mode))
> > +			continue;
> > +
> >   		if (is_best_fixed_mode(connector, vrefresh,
> >   				       fixed_mode_vrefresh, best_mode))
> >   			best_mode = fixed_mode;
> > @@ -224,10 +243,27 @@ static int intel_panel_compute_config_vrr(struct intel_atomic_state *state,
> >   					  struct intel_connector *connector)
> >   {
> >   	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
> > -	const struct drm_display_mode *fixed_mode;
> > +	const struct drm_display_mode *fixed_mode = NULL;
> >   	int vrefresh, fixed_mode_vrefresh;
> >   
> 
> Perhaps an early return for if (!vrr_is_capable()) here will avoid two 
> calls for intel_panel_fixed_mode_vrr().

That's essentially the first thing intel_panel_fixed_mode_vrr() will
end up doing. Granted, we do go through a few extra functions calls
to get there, but I expect that to be negligible given we're about
to run through the whole state compute machinery anyway.

There are probably much more fruitful places to optimize if we were
to actually measure the whole thing.

> 
> I leave it to you.
> 
> In any case the patch LGTM.
> 
> Reviewed-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>

Thanks.

> 
> > -	fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode);
> > +	/*
> > +	 * Attempt a VRR based refresh rate change if possible
> > +	 * when userspace has forbidden a full modeset.
> > +	 */
> > +	if (!state->base.allow_modeset) {
> > +		struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> > +		const struct intel_crtc_state *old_crtc_state =
> > +			intel_atomic_get_old_crtc_state(state, crtc);
> > +
> > +		if (old_crtc_state->hw.enable &&
> > +		    old_crtc_state->uapi.encoder_mask == crtc_state->uapi.encoder_mask)
> > +			fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode,
> > +								&old_crtc_state->hw.adjusted_mode);
> > +	}
> > +
> > +	if (!fixed_mode)
> > +		fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode, NULL);
> > +
> >   	if (!fixed_mode)
> >   		return -EINVAL;
> >   

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP
  2026-06-22 21:35 [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Ville Syrjala
                   ` (4 preceding siblings ...)
  2026-06-22 21:36 ` [PATCH v2 5/5] drm/i915/panel: Attempt VRR based refresh rate change for !allow_modeset Ville Syrjala
@ 2026-06-23 16:05 ` Srinivas, Vidya
  5 siblings, 0 replies; 12+ messages in thread
From: Srinivas, Vidya @ 2026-06-23 16:05 UTC (permalink / raw)
  To: Ville Syrjala, intel-gfx@lists.freedesktop.org
  Cc: intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org,
	Kandpal, Suraj, Nautiyal, Ankit K, Lee, Shawn C

Thank you very much Ville for the patch series.
Tested-by: Vidya Srinivas <vidya.srinivas@intel.com>

> -----Original Message-----
> From: Intel-gfx <intel-gfx-bounces@lists.freedesktop.org> On Behalf Of Ville
> Syrjala
> Sent: 23 June 2026 03:06
> To: intel-gfx@lists.freedesktop.org
> Cc: intel-xe@lists.freedesktop.org; dri-devel@lists.freedesktop.org; Kandpal,
> Suraj <suraj.kandpal@intel.com>; Nautiyal, Ankit K
> <ankit.k.nautiyal@intel.com>
> Subject: [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh
> rate changes on eDP
> 
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Tweak the eDP fixed mode selection algorithm to allow userspace to do
> refresh rate changes on VRR capable eDP panels without full modesets.
> 
> v2: Cleaner split for VRR vs. fixed refresh rate fixed mode
>     selection to avoid some corner cases
> 
> Cc: Suraj Kandpal <suraj.kandpal@intel.com>
> Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
> 
> Ville Syrjälä (5):
>   drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection
>     into separate stages
>   drm/modes: Add DRM_MODE_MATCH_TIMINGS_VRR
>   drm/i915: Pass the full atomic state to .compute_config()
>   drm/i915/panel: Adjust intel_panel_compute_config() calling convention
>   drm/i915/panel: Attempt VRR based refresh rate change for
>     !allow_modeset
> 
>  drivers/gpu/drm/drm_modes.c                   |  23 +++
>  drivers/gpu/drm/i915/display/g4x_dp.c         |   5 +-
>  drivers/gpu/drm/i915/display/g4x_hdmi.c       |   4 +-
>  drivers/gpu/drm/i915/display/icl_dsi.c        |   5 +-
>  drivers/gpu/drm/i915/display/intel_crt.c      |   9 +-
>  drivers/gpu/drm/i915/display/intel_ddi.c      |   8 +-
>  drivers/gpu/drm/i915/display/intel_display.c  |   4 +-
>  .../drm/i915/display/intel_display_types.h    |   6 +-
>  drivers/gpu/drm/i915/display/intel_dp.c       |   6 +-
>  drivers/gpu/drm/i915/display/intel_dp.h       |   3 +-
>  drivers/gpu/drm/i915/display/intel_dp_mst.c   |   8 +-
>  drivers/gpu/drm/i915/display/intel_dvo.c      |   5 +-
>  drivers/gpu/drm/i915/display/intel_lvds.c     |   5 +-
>  drivers/gpu/drm/i915/display/intel_panel.c    | 167 +++++++++++++-----
>  drivers/gpu/drm/i915/display/intel_panel.h    |   6 +-
>  drivers/gpu/drm/i915/display/intel_sdvo.c     |   7 +-
>  drivers/gpu/drm/i915/display/intel_tv.c       |   5 +-
>  drivers/gpu/drm/i915/display/vlv_dsi.c        |   5 +-
>  include/drm/drm_modes.h                       |   1 +
>  19 files changed, 203 insertions(+), 79 deletions(-)
> 
> --
> 2.53.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-06-23 16:05 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22 21:35 [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Ville Syrjala
2026-06-22 21:35 ` [PATCH v2 1/5] drm/i915/panel: Split VRR vs. fixed refresh rate fixed mode selection into separate stages Ville Syrjala
2026-06-23  4:24   ` Nautiyal, Ankit K
2026-06-23 11:40   ` [PATCH v3 " Ville Syrjala
2026-06-22 21:35 ` [PATCH v2 2/5] drm/modes: Add DRM_MODE_MATCH_TIMINGS_VRR Ville Syrjala
2026-06-22 21:36 ` [PATCH v2 3/5] drm/i915: Pass the full atomic state to .compute_config() Ville Syrjala
2026-06-22 21:36 ` [PATCH v2 4/5] drm/i915/panel: Adjust intel_panel_compute_config() calling convention Ville Syrjala
2026-06-23 11:41   ` [PATCH v3 " Ville Syrjala
2026-06-22 21:36 ` [PATCH v2 5/5] drm/i915/panel: Attempt VRR based refresh rate change for !allow_modeset Ville Syrjala
2026-06-23  4:28   ` Nautiyal, Ankit K
2026-06-23 11:48     ` Ville Syrjälä
2026-06-23 16:05 ` [PATCH v2 0/5] drm/i915: Work harder to enable VRR based refresh rate changes on eDP Srinivas, Vidya

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox