diff options
| author | Ville Syrjälä <ville.syrjala@linux.intel.com> | 2026-06-23 14:40:35 +0300 |
|---|---|---|
| committer | Ville Syrjälä <ville.syrjala@linux.intel.com> | 2026-06-24 18:53:39 +0300 |
| commit | d392b88dce93ae1a88d932c8f6680be598d22cd5 (patch) | |
| tree | 629e91a3615e3a9af4055d29b212d1b93e7926d9 | |
| parent | 53f12a266c3244b4895f7a3619ca1dd2ad54cffc (diff) | |
| download | linux-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.c | 126 |
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); |
