All of lore.kernel.org
 help / color / mirror / Atom feed
From: ElXreno <elxreno@gmail.com>
To: intel-gfx@lists.freedesktop.org, intel-xe@lists.freedesktop.org
Cc: jani.nikula@linux.intel.com, rodrigo.vivi@intel.com,
	joonas.lahtinen@linux.intel.com, tursulin@ursulin.net,
	ville.syrjala@linux.intel.com, ankit.k.nautiyal@intel.com,
	mitulkumar.ajitkumar.golani@intel.com, airlied@gmail.com,
	simona@ffwll.ch, dri-devel@lists.freedesktop.org,
	linux-kernel@vger.kernel.org, ElXreno <elxreno@gmail.com>
Subject: [PATCH 7/7] drm/i915/vrr: Allow VRR with the pipe joiner
Date: Sat, 14 Nov 2026 04:43:35 +0300	[thread overview]
Message-ID: <20261114014335.2132756-8-elxreno@gmail.com> (raw)
In-Reply-To: <20261114014335.2132756-1-elxreno@gmail.com>

VRR has been limited to the fixed refresh rate timing generator with
the joiner, as the transcoder level VRR operations were not sequenced
against the pipe level updates of the joined pipes. That keeps VRR
away from every mode that needs the joiner, such as 3840x2400@240 on
the eDP panels of current 18" laptops.

The transcoder is now programmed only by the joiner primary, and on
the MMIO path all joined pipes are armed inside one vblank evasion
critical section, with the push sent at its end. Take that path for
VRR with the joiner and let VRR through.

A commit whose new state has VRR enabled with the joiner does not use
the DSB. The push must not be sent before every joined pipe has been
armed, but each pipe runs its own DSB and nothing orders them against
each other. Leaving the push to the DSB of the primary, on the
grounds that it is committed last, is not enough. The secondary's DSB
waits for the safe window after it has armed (DSB_OPCODE_WAIT_VBLANKS
with the safe window chicken bits, then the wait in
intel_dsb_wait_for_delayed_vblank()). When the primary's push ends
the safe window before the secondary's DSB gets there, that DSB waits
for the safe window of the next frame, and it is still busy when
intel_dsb_wait() gives it 1 ms after the flip of the primary has
completed:

 [CRTC:271:pipe B] DSB 0 timed out waiting for idle (current head=0x100, head=0x0, tail=0x140)

That is what a port which only skips the push on the secondaries
gives, 13 times in 27 minutes of desktop use on Arrow Lake. The DSB
of a secondary can't check on the push either: commit c3571a239e10
("drm/i915/vrr: Check that the push send bit is clear after delayed
vblank") notes that reading TRANS_PUSH from it ends in a DSB response
timeout.

The LUT load has the same ordering problem: a colour DSB either sends
the push itself or has to be ordered against the push that the CPU
sends, on each pipe. So no colour DSB is prepared for such a commit
either, and the LUTs are loaded the way they are without one: ahead
of the commit when they can be preloaded, by the vblank worker after
it otherwise, in which case the commit takes the per pipe critical
sections, or with MMIO inside the critical section on the platforms
with double buffered LUTs. The commit that turns VRR off has no VRR
push to order and keeps its colour DSBs, which are then started from
inside the joined critical section.

One thing changes for joined modes even while VRR is off, as it
follows vrr.in_range: the sink is told to ignore the MSA timing
parameters during link training, as for any other mode within the
VRR range.

intel_vrr_compute_config() does not ask for LRR with the joiner, and
DC balance is kept off, each with a FIXME. The vblank delay fastset
that reuses the LRR code is not touched: where it applies (inherited
state, or the always on VRR timing generator) it still writes the
transcoder timings from every joined pipe, with identical values.

Signed-off-by: ElXreno <elxreno@gmail.com>
---
 drivers/gpu/drm/i915/display/intel_color.c   |  4 +++
 drivers/gpu/drm/i915/display/intel_display.c |  4 +++
 drivers/gpu/drm/i915/display/intel_vrr.c     | 31 ++++++++++++--------
 drivers/gpu/drm/i915/display/intel_vrr.h     |  1 +
 4 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c
index 4070dc8d97d9..08d1c999637e 100644
--- a/drivers/gpu/drm/i915/display/intel_color.c
+++ b/drivers/gpu/drm/i915/display/intel_color.c
@@ -2023,6 +2023,10 @@ void intel_color_prepare_commit(struct intel_atomic_state *state,
 	if (!crtc_state->pre_csc_lut && !crtc_state->post_csc_lut)
 		return;
 
+	/* TODO sequence the LUT load vs. the VRR push for joined pipes via DSB */
+	if (intel_vrr_needs_mmio_commit(crtc_state))
+		return;
+
 	if (HAS_DOUBLE_BUFFERED_LUT(display))
 		crtc_state->dsb_color = intel_dsb_prepare(state, crtc, INTEL_DSB_0, 1024);
 	else
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 1fda1bb15674..8f30337c8967 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -7681,6 +7681,10 @@ intel_atomic_commit_type(struct intel_atomic_state *state,
 	if (new_crtc_state->do_async_flip)
 		return INTEL_COMMIT_MMIO;
 
+	/* TODO sequence the VRR push for joined pipes via DSB */
+	if (intel_vrr_needs_mmio_commit(new_crtc_state))
+		return INTEL_COMMIT_MMIO;
+
 	/* TODO handle VRR with flip queue */
 	if (intel_flipq_supported(display) &&
 	    !new_crtc_state->vrr.enable &&
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
index 668c495e7407..6543c140e2b5 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -450,6 +450,10 @@ intel_vrr_dc_balance_compute_config(struct intel_crtc_state *crtc_state)
 	    !crtc_state->vrr.enable || !display->params.enable_dc_balance)
 		return;
 
+	/* FIXME figure out DC balance with joined pipes */
+	if (crtc_state->joiner_pipes)
+		return;
+
 	crtc_state->vrr.dc_balance.vmax = crtc_state->vrr.vmax;
 	crtc_state->vrr.dc_balance.vmin = crtc_state->vrr.vmin;
 	crtc_state->vrr.dc_balance.max_increase =
@@ -495,21 +499,11 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state,
 	crtc_state->vrr.in_range =
 		intel_vrr_is_in_range(connector, drm_mode_vrefresh(adjusted_mode));
 
-	/*
-	 * Allow fixed refresh rate with VRR Timing Generator.
-	 * For now set the vrr.in_range to 0, to allow fixed_rr but skip actual
-	 * VRR and LRR.
-	 * #TODO For actual VRR with joiner, we need to figure out how to
-	 * correctly sequence transcoder level stuff vs. pipe level stuff
-	 * in the commit.
-	 */
-	if (crtc_state->joiner_pipes)
-		crtc_state->vrr.in_range = false;
-
 	vmin = intel_vrr_compute_vmin(crtc_state);
 
 	if (crtc_state->vrr.in_range) {
-		if (HAS_LRR(display))
+		/* FIXME sequence the LRR timing update for joined pipes */
+		if (HAS_LRR(display) && !crtc_state->joiner_pipes)
 			crtc_state->update_lrr = true;
 		vmax = intel_vrr_compute_vmax(connector, adjusted_mode);
 	} else {
@@ -832,6 +826,19 @@ void intel_vrr_check_push_sent(struct intel_dsb *dsb,
 	}
 }
 
+/*
+ * A VRR push latches all joined pipes at once, so it may be sent only
+ * after every one of them has been armed. Each pipe runs its own DSB
+ * and nothing orders the DSBs of the joined pipes against each other,
+ * so they can't sequence that between themselves. Such commits take
+ * the MMIO path, where the joined pipes are armed inside one vblank
+ * evasion critical section.
+ */
+bool intel_vrr_needs_mmio_commit(const struct intel_crtc_state *crtc_state)
+{
+	return crtc_state->vrr.enable && crtc_state->joiner_pipes;
+}
+
 bool intel_vrr_is_push_sent(const struct intel_crtc_state *crtc_state)
 {
 	struct intel_display *display = to_intel_display(crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h
index 19c7990be1b2..a72ffba47a80 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.h
+++ b/drivers/gpu/drm/i915/display/intel_vrr.h
@@ -32,6 +32,7 @@ void intel_vrr_check_push_sent(struct intel_dsb *dsb,
 			       const struct intel_crtc_state *crtc_state);
 void intel_vrr_dcb_increment_flip_count(struct intel_crtc_state *crtc_state,
 					struct intel_crtc *crtc);
+bool intel_vrr_needs_mmio_commit(const struct intel_crtc_state *crtc_state);
 bool intel_vrr_is_push_sent(const struct intel_crtc_state *crtc_state);
 void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state);
 void intel_vrr_psr_frame_change_enable(const struct intel_crtc_state *crtc_state);
-- 
2.56.0


      parent reply	other threads:[~2026-11-14  1:44 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-14  1:43 [PATCH 0/7] drm/i915: VRR with the pipe joiner ElXreno
2026-11-14  1:43 ` [PATCH 1/7] drm/i915/panel: Fix the pixel clock overflow in the VRR vtotal ElXreno
2026-11-14  1:43 ` [PATCH 2/7] drm/i915/vrr: Fix the pixel clock overflow in the vmax computation ElXreno
2026-11-14  1:43 ` [PATCH 3/7] drm/i915/vrr: Leave the transcoder to the joiner primary ElXreno
2026-11-14  1:43 ` [PATCH 4/7] drm/i915: Split intel_update_crtc() into its stages ElXreno
2026-11-14  1:43 ` [PATCH 5/7] drm/i915: Arm joined pipes within one vblank evasion for VRR ElXreno
2026-11-14  1:43 ` [PATCH 6/7] drm/i915: Evade the vblank on the scanline of the joiner primary ElXreno
2026-11-14  1:43 ` ElXreno [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261114014335.2132756-8-elxreno@gmail.com \
    --to=elxreno@gmail.com \
    --cc=airlied@gmail.com \
    --cc=ankit.k.nautiyal@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=jani.nikula@linux.intel.com \
    --cc=joonas.lahtinen@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mitulkumar.ajitkumar.golani@intel.com \
    --cc=rodrigo.vivi@intel.com \
    --cc=simona@ffwll.ch \
    --cc=tursulin@ursulin.net \
    --cc=ville.syrjala@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.