RE: [PATCH v3 3/8] drm/i915/vrr: Compute CMRR fractional timings generically

"Golani, Mitulkumar Ajitkumar" <[email protected]>
Newsgroups org.freedesktop.lists.intel-gfx,org.freedesktop.lists.intel-xe
Message-ID <IA1PR11MB6348585FD5B08F43ED67B0D6B2C22@IA1PR11MB6348.namprd11.prod.outlook.com>

> -----Original Message-----
> From: Intel-gfx <[email protected]> On Behalf Of
> Golani, Mitulkumar Ajitkumar
> Sent: 16 July 2026 13:34
> To: Borah, Chaitanya Kumar <[email protected]>; intel-
> [email protected]
> Cc: [email protected]; Shankar, Uma <[email protected]>;
> Nautiyal, Ankit K <[email protected]>
> Subject: RE: [PATCH v3 3/8] drm/i915/vrr: Compute CMRR fractional timings
> generically
> 
> Thanks for the review Chaitanya,
> 
> 
> > -----Original Message-----
> > From: Borah, Chaitanya Kumar <[email protected]>
> > Sent: 15 July 2026 18:44
> > To: Golani, Mitulkumar Ajitkumar
> > <[email protected]>;
> > [email protected]
> > Cc: [email protected]; Shankar, Uma
> > <[email protected]>; Nautiyal, Ankit K
> > <[email protected]>
> > Subject: Re: [PATCH v3 3/8] drm/i915/vrr: Compute CMRR fractional
> > timings generically
> >
> >
> >
> > On 7/14/2026 4:09 PM, Mitul Golani wrote:
> > > Rework the fractional-CMRR computation into a generic,
> > > transcoder-agnostic helper driven by an explicit per-CRTC debugfs
> > > target, replacing the previous disabled, eDP-only code path. Compute
> > > CMRR_M and CMRR_N timings based on the video mode requirement.
> > Note
> > > the CMRR enable path is wired up separately; this patch only lays
> > > down the generic computation.
> > >
> >
> > mention the logic behind removing the MODE_FLAG
> 
> Applied your suggestion. Will be addressed in v4
> 
> >
> > > --v2:
> > > - Derive video_mode locally instead of caching it in persistent
> > >    struct intel_crtc state (Jani, Chaitanya)
> > > - Fix numerator unit in comment: milli-Hz, not kHz (Chaitanya)
> > > - Fix "reqirement" typo and clarify CMRR is not yet enabled in the
> > >    commit message (Chaitanya)
> > > - Fix precision issue while computing M/N ration (Chaitanya)
> > > - Multiplier_m and n naming update to increase readability.
> > > (Chaitanya)
> > > - Compute vtotal as it is required to deither as per algo
> > > implementation. (Chaitanya)
> > > - Replace misleading adjusted_pixel_rate to dividend which is
> > > somewhat relatable.
> > >
> > > Signed-off-by: Mitul Golani <[email protected]>
> > > ---
> > >   drivers/gpu/drm/i915/display/intel_vrr.c | 128 +++++++++++------------
> > >   1 file changed, 63 insertions(+), 65 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c
> > > b/drivers/gpu/drm/i915/display/intel_vrr.c
> > > index b36026183399..25ce56d48bb1 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_vrr.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_vrr.c
> > > @@ -27,9 +27,6 @@
> > >   #include "skl_prefill.h"
> > >   #include "skl_watermark.h"
> > >
> > > -#define FIXED_POINT_PRECISION		100
> > > -#define CMRR_PRECISION_TOLERANCE	10
> > > -
> > >   /*
> > >    * Tunable parameters for DC Balance correction.
> > >    * These are captured based on experimentations.
> > > @@ -191,69 +188,72 @@ int intel_vrr_vmax_vblank_start(const struct
> > intel_crtc_state *crtc_state)
> > >   	return intel_vrr_vmax_vtotal(crtc_state) - crtc_state->vrr.guardband;
> > >   }
> > >
> > > -static bool
> > > -is_cmrr_frac_required(struct intel_crtc_state *crtc_state)
> > > +static void
> > > +intel_vrr_cmrr_compute_config(struct intel_crtc_state *crtc_state)
> > >   {
> > >   	struct intel_display *display = to_intel_display(crtc_state);
> > > -	int calculated_refresh_k, actual_refresh_k, pixel_clock_per_line;
> > > +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> > >   	struct drm_display_mode *adjusted_mode =
> > > &crtc_state->hw.adjusted_mode;
> > > +	u64 dividend;
> > > +	int requested_refresh_rate, current_refresh_rate;
> > > +	int rr_multiplier = 1, rr_divider = 1;
> > > +	bool video_mode;
> > >
> > > -	/* Avoid CMRR for now till we have VRR with fixed timings working */
> > > -	if (!HAS_CMRR(display) || true)
> > > -		return false;
> > > -
> > > -	actual_refresh_k =
> > > -		drm_mode_vrefresh(adjusted_mode) *
> > FIXED_POINT_PRECISION;
> > > -	pixel_clock_per_line =
> > > -		adjusted_mode->crtc_clock * 1000 / adjusted_mode-
> > >crtc_htotal;
> > > -	calculated_refresh_k =
> > > -		pixel_clock_per_line * FIXED_POINT_PRECISION /
> > adjusted_mode->crtc_vtotal;
> > > -
> > > -	if ((actual_refresh_k - calculated_refresh_k) <
> > CMRR_PRECISION_TOLERANCE)
> > > -		return false;
> > > -
> > > -	return true;
> > > -}
> > > -
> > > -static unsigned int
> > > -cmrr_get_vtotal(struct intel_crtc_state *crtc_state, bool
> > > video_mode_required) -{
> > > -	int multiplier_m = 1, multiplier_n = 1, vtotal, desired_refresh_rate;
> > > -	u64 adjusted_pixel_rate;
> > > -	struct drm_display_mode *adjusted_mode = &crtc_state-
> > >hw.adjusted_mode;
> > > +	if (!HAS_CMRR(display))
> > > +		return;
> >
> > We compute CMRR for DISPLAY_VER >= 20 (gated on HAS_CMRR), but
> looking
> > at later patches in the series, CMRR only gets enabled when
> > intel_vrr_always_use_vrr_tg() is true, which is DISPLAY_VER >= 30. On
> > <
> > 30 the CMRR_ENABLE bit gets armed via the TRANS_CMRR_N_HI write but
> is
> > then cleared by the subsequent TRANS_VRR_CTL write in
> > intel_vrr_set_transcoder_timings() (it carries neither VRR_ENABLE nor
> > CMRR_ENABLE), and intel_vrr_tg_enable() never runs to restore it since
> > vrr.enable isn't set for CMRR. So CMRR ends up computed but inactive
> > on < 30.
> >
> > This needs a closer look.
> 
> As, had discussion offline, we will enable CMRR from the platform when VRR
> timing generator is also enabled.
> 
> So, will need to add additional check intel_vrr_always_use_vrr_tg. I will
> comment this into code as well so that can be documented in-place.
> 
> So with this addition, patch #1 and #2 will also needs this check to make sure
> we have correct state programmed.
> 
> I will add this change with v4
> 
> Thanks
> 
> >
> > >
> > > -	desired_refresh_rate = drm_mode_vrefresh(adjusted_mode);
> > > +	/* No CMRR ratio configured through debugfs */
> > > +	if (!crtc->force_cmrr.numerator)
> > > +		return;
> > >
> > > -	if (video_mode_required) {
> > > -		multiplier_m = 1001;
> > > -		multiplier_n = 1000;
> > > +	/*
> > > +	 * The numerator encodes the requested refresh rate in milli-Hz,
> > > +so
> > the
> > > +	 * requested refresh rate in Hz is numerator / 1000. It must match the
> > > +	 * refresh rate of the current mode.
> > > +	 */
> > > +	requested_refresh_rate = crtc->force_cmrr.numerator / 1000;
> > > +	current_refresh_rate = drm_mode_vrefresh(adjusted_mode);
> > > +
> > > +	if (requested_refresh_rate != current_refresh_rate) {
> > > +		drm_dbg_kms(display->drm,
> > > +			    "[CRTC:%d:%s] CMRR requested refresh rate %d Hz
> > does not match current mode refresh rate %d Hz\n",
> > > +				crtc->base.base.id, crtc->base.name,
> > > +				requested_refresh_rate,
> > current_refresh_rate);
> > > +		return;
> > >   	}
> > >
> > > -	crtc_state->vrr.cmrr.cmrr_n = mul_u32_u32(desired_refresh_rate *
> > adjusted_mode->crtc_htotal,
> > > -						  multiplier_n);
> > > -	vtotal = DIV_ROUND_UP_ULL(mul_u32_u32(adjusted_mode-
> > >crtc_clock * 1000, multiplier_n),
> > > -				  crtc_state->vrr.cmrr.cmrr_n);
> > > -	adjusted_pixel_rate = mul_u32_u32(adjusted_mode->crtc_clock *
> > 1000, multiplier_m);
> > > -	crtc_state->vrr.cmrr.cmrr_m = do_div(adjusted_pixel_rate, crtc_state-
> > >vrr.cmrr.cmrr_n);
> > > -
> > > -	return vtotal;
> > > -}
> > > +	/*
> > > +	 * A 1:1 ratio (denominator == 1000) means no video timing is
> > required
> > > +	 * Any other ratio (e.g. 1000/1001) requires the video timing.
> > > +	 */
> > > +	video_mode = crtc->force_cmrr.denominator != 1000;
> > > +	if (video_mode) {
> > > +		rr_multiplier = 1000;
> > > +		rr_divider = 1001;
> > > +	}
> > >
> > > -static
> > > -void intel_vrr_compute_cmrr_timings(struct intel_crtc_state
> > > *crtc_state) -{
> > >   	/*
> > > -	 * TODO: Compute precise target refresh rate to determine
> > > -	 * if video_mode_required should be true. Currently set to
> > > -	 * false due to uncertainty about the precise target
> > > -	 * refresh Rate.
> > > +	 * Let pixel_clock_hz = adjusted_mode->crtc_clock * 1000.
> > > +	 *
> > > +	 * cmrr_n = requested_refresh_rate x htotal x rr_multiplier
> > > +	 * cmrr_m = (pixel_clock_hz x scale_m) % cmrr_n
> > > +	 *
> > > +	 * where rr_multiplier/rr_divider = 1000/1001 when the
> > > +	 * video timing is required, else 1/1. The integer vtotal
> > > +	 * term is tracked in SW (it is the programmed mode vtotal)
> > > +	 * while the fractional part represented by cmrr_m/cmrr_n
> > > +	 * is tracked in HW.
> > >   	 */
> > > -	crtc_state->vrr.vmax = cmrr_get_vtotal(crtc_state, false);
> > > -	crtc_state->vrr.vmin = crtc_state->vrr.vmax;
> > > -	crtc_state->vrr.flipline = crtc_state->vrr.vmin;
> > >
> > > -	crtc_state->vrr.cmrr.enable = true;
> > > -	crtc_state->mode_flags |= I915_MODE_FLAG_VRR;
> > > +	crtc_state->vrr.cmrr.cmrr_n =
> > > +		(mul_u32_u32(crtc->force_cmrr.numerator, adjusted_mode-
> > >crtc_htotal) *
> > > +		rr_multiplier) / 1000;
> > > +	dividend = mul_u32_u32(adjusted_mode->crtc_clock, 1000) *
> > > +rr_divider;
> >
> > By only using the numerator here you are never calculating the desired
> > refresh rate.
> 
> 
> Good point. I will address this in v4,
> 
> As we discussed, this basically we need to divide with denominator instead of
> hardcoded value, "1000"
> 
> Thanks

Hi Chaitanya,

As we discussed offline and with some hands-on experiments with vbltests, it looks like, adding denominator (1001) here, dithering more than expectation from desired refresh rate. (due to already present multiplier/divider presence)

Somehow, hardcoded 1000 is working well to achieve desired refresh rate. For this we need more clarificationon  Bspec given example.

For now I will add hardcoded 1000 and add later TODO comment, once get some more clarity, we can add a fix if it is ok. 

Thanks

> 
> 
> >
> > > +	adjusted_mode->crtc_vtotal = div64_u64_rem(dividend,
> > > +						   crtc_state->vrr.cmrr.cmrr_n,
> > > +						   &crtc_state-
> > >vrr.cmrr.cmrr_m);
> > > +
> > > +	return;
> >
> > redundant
> 
> Good point. I will address this in v4.
> 
> >
> > >   }
> > >
> > >   static
> > > @@ -429,8 +429,6 @@ intel_vrr_compute_config(struct intel_crtc_state
> > *crtc_state,
> > >   	struct intel_display *display = to_intel_display(crtc_state);
> > >   	struct intel_connector *connector =
> > >   		to_intel_connector(conn_state->connector);
> > > -	struct intel_dp *intel_dp = intel_attached_dp(connector);
> > > -	bool is_edp = intel_dp_is_edp(intel_dp);
> > >   	struct drm_display_mode *adjusted_mode = &crtc_state-
> > >hw.adjusted_mode;
> > >   	int vmin, vmax;
> > >
> > > @@ -464,12 +462,17 @@ intel_vrr_compute_config(struct
> > > intel_crtc_state
> > *crtc_state,
> > >   		vmax = vmin;
> > >   	}
> > >
> > > -	if (crtc_state->uapi.vrr_enabled && vmin < vmax)
> > > +	if (crtc_state->uapi.vrr_enabled && vmin < vmax) {
> > >   		intel_vrr_compute_vrr_timings(crtc_state, vmin, vmax);
> > > -	else if (is_cmrr_frac_required(crtc_state) && is_edp)
> > > -		intel_vrr_compute_cmrr_timings(crtc_state);
> > > -	else
> > > +	} else {
> > > +		/*
> > > +		 * CMRR is a fixed average Vtotal mode and is only computed
> > on
> > > +		 * the fixed refresh rate path. It is generic across transcoders
> > > +		 * and gated on platform support and a valid debugfs ratio.
> > > +		 */
> > > +		intel_vrr_cmrr_compute_config(crtc_state);
> > >   		intel_vrr_compute_fixed_rr_timings(crtc_state);
> > > +	}
> > >
> > >   	if (HAS_AS_SDP(display)) {
> > >   		crtc_state->vrr.vsync_start =
> > > @@ -1136,11 +1139,6 @@ void intel_vrr_get_config(struct
> > > intel_crtc_state *crtc_state)
> > >
> > >   	intel_vrr_get_dc_balance_config(crtc_state);
> > >
> > > -	/*
> > > -	 * #TODO: For Both VRR and CMRR the flag I915_MODE_FLAG_VRR is
> > set for mode_flags.
> > > -	 * Since CMRR is currently disabled, set this flag for VRR for now.
> > > -	 * Need to keep this in mind while re-enabling CMRR.
> > > -	 */
> > >   	if (crtc_state->vrr.enable)
> > >   		crtc_state->mode_flags |= I915_MODE_FLAG_VRR;
> > >
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.