[Intel-gfx] [PATCH 1/3] drm/i915: Allow arbitrary refresh rates with VRR eDP panels

Golani, Mitulkumar Ajitkumar mitulkumar.ajitkumar.golani at intel.com
Thu Apr 13 17:22:40 UTC 2023


Hi Ville,

> -----Original Message-----
> From: Intel-gfx <intel-gfx-bounces at lists.freedesktop.org> On Behalf Of Ville
> Syrjala
> Sent: 04 April 2023 23:24
> To: intel-gfx at lists.freedesktop.org
> Subject: [Intel-gfx] [PATCH 1/3] drm/i915: Allow arbitrary refresh rates with
> VRR eDP panels
> 
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> 
> If the panel supports VRR it must be capable of accepting timings with
> arbitrary vblank length, within the valid VRR range. Use that fact to allow the
> user to request any refresh rate they like. We simply pick the next highest
> fixed mode from our list, and adjust the vblank to get the desired refresh
> rate in the end.
> 
> Of course currently everything to do with the vrefresh is using 1Hz precision,
> so might not be exact. But we can improve that in the future by just upping
> our vrefresh precision.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_panel.c | 80 ++++++++++++++++++----
>  1 file changed, 66 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_panel.c
> b/drivers/gpu/drm/i915/display/intel_panel.c
> index ce2a34a25211..9acdd68b2dbc 100644
> --- a/drivers/gpu/drm/i915/display/intel_panel.c
> +++ b/drivers/gpu/drm/i915/display/intel_panel.c
> @@ -42,6 +42,7 @@
>  #include "intel_lvds_regs.h"
>  #include "intel_panel.h"
>  #include "intel_quirks.h"
> +#include "intel_vrr.h"
> 
>  bool intel_panel_use_ssc(struct drm_i915_private *i915)  { @@ -58,6 +59,38
> @@ intel_panel_preferred_fixed_mode(struct intel_connector *connector)
>  					struct drm_display_mode, head);
>  }
> 
> +static bool is_in_vrr_range(struct intel_connector *connector, int
> +vrefresh) {
> +	const struct drm_display_info *info = &connector-
> >base.display_info;
> +
> +	return intel_vrr_is_capable(connector) &&
> +		vrefresh >= info->monitor_range.min_vfreq &&
> +		vrefresh <= info->monitor_range.max_vfreq; }
> +
> +static bool is_best_fixed_mode(struct intel_connector *connector,
> +			       int vrefresh, int fixed_mode_vrefresh,
> +			       const struct drm_display_mode *best_mode) {
> +	/* we want to always return something */
> +	if (!best_mode)
> +		return true;
> +
> +	/*
> +	 * With VRR always pick a mode with equal/higher than requested
> +	 * vrefresh, which we can then reduce to match the requested
> +	 * vrefresh by extending the vblank length.
> +	 */
> +	if (is_in_vrr_range(connector, vrefresh) &&
> +	    is_in_vrr_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); }
> +
>  const struct drm_display_mode *
>  intel_panel_fixed_mode(struct intel_connector *connector,
>  		       const struct drm_display_mode *mode) @@ -65,11
> +98,11 @@ intel_panel_fixed_mode(struct intel_connector *connector,
>  	const struct drm_display_mode *fixed_mode, *best_mode = NULL;
>  	int vrefresh = drm_mode_vrefresh(mode);
> 
> -	/* pick the fixed_mode that is closest in terms of vrefresh */
>  	list_for_each_entry(fixed_mode, &connector->panel.fixed_modes,
> head) {
> -		if (!best_mode ||
> -		    abs(drm_mode_vrefresh(fixed_mode) - vrefresh) <
> -		    abs(drm_mode_vrefresh(best_mode) - vrefresh))
> +		int fixed_mode_vrefresh =
> drm_mode_vrefresh(fixed_mode);
> +
> +		if (is_best_fixed_mode(connector, vrefresh,
> +				       fixed_mode_vrefresh, best_mode))
>  			best_mode = fixed_mode;
>  	}
> 
> @@ -178,27 +211,46 @@ int intel_panel_compute_config(struct
> intel_connector *connector,  {
>  	const struct drm_display_mode *fixed_mode =
>  		intel_panel_fixed_mode(connector, adjusted_mode);
> +	int vrefresh, fixed_mode_vrefresh;
> +	bool is_vrr;
> 
>  	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.
> +	 * Assume that we shouldn't muck about with the
> +	 * timings if they don't land in the VRR range.
>  	 */
> -	if (abs(drm_mode_vrefresh(adjusted_mode) -
> drm_mode_vrefresh(fixed_mode)) > 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,
> -			    drm_mode_vrefresh(adjusted_mode),
> drm_mode_vrefresh(fixed_mode));
> +	is_vrr = is_in_vrr_range(connector, vrefresh) &&
> +		is_in_vrr_range(connector, fixed_mode_vrefresh);
> 
> -		return -EINVAL;
> +	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)
> +		adjusted_mode->vtotal =
> +			DIV_ROUND_CLOSEST(adjusted_mode->clock * 1000,
> +					  adjusted_mode->htotal * vrefresh);
> +

Changes LGTM
Thanks

Reviewed-by: Mitul Golani <mitulkumar.ajitkumar.golani at intel.com>

>  	drm_mode_set_crtcinfo(adjusted_mode, 0);
> 
>  	return 0;
> --
> 2.39.2



More information about the Intel-gfx mailing list