Intel-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Alan Stead" <alan.stead@intel.com>,
	intel-gfx@lists.freedesktop.org, intel-xe@lists.freedesktop.org
Subject: Re: [RFC v1 2/3] drm/i915/dip: Send the HDMI 2.1 VTEM when VRR is enabled
Date: Fri, 30 Oct 2026 20:59:23 +0000	[thread overview]
Message-ID: <sashiko-outbox-191505@kernel.org> (raw)
In-Reply-To: <20261030203314.1085262-3-alan.stead@intel.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] drm/i915/dip: undeclared HDMI_EMP_DATA in intel_dip_write_hdmi_vtem()
- [Medium] drm/i915/dip: misordered and unsent VRR disable VTEM in intel_vrr_disable()
- [Medium] drm/i915/dip: unpopulated vrr.in_range check in intel_dip_write_hdmi_vtem()
--

commit a0eb4dbdb4fb231ddf6c7b2a3526d3d1a7f9707a
Author: Alan Stead <alan.stead@intel.com>

drm/i915/dip: Send the HDMI 2.1 VTEM when VRR is enabled

This commit adds intel_dip_write_hdmi_vtem() to program an HDMI 2.1 Video
Timing Extended Metadata (VTEM) packet when enabling or disabling VRR on
an HDMI transcoder via intel_vrr_enable() and intel_vrr_disable().

> diff --git a/drivers/gpu/drm/i915/display/intel_dip.c b/drivers/gpu/drm/i915/display/intel_dip.c
> index 831881e6c15ec..4748f6012337b 100644
> --- a/drivers/gpu/drm/i915/display/intel_dip.c
> +++ b/drivers/gpu/drm/i915/display/intel_dip.c
[ ... ]
> @@ -74,6 +77,78 @@ void intel_dip_write_emp_as_sdp_tl(const struct intel_crtc_state *crtc_state)
>  		       EMP_AS_SDP_DB_TL(crtc_state->dip.emp_as_sdp_tl));
>  }
>  
> +/* VTEM: 7 byte EM Data Set header (PB0-PB6) + 4 byte data set (MD0-MD3) */
> +#define VTEM_DATA_SET_LENGTH	4
> +#define VTEM_EMP_SIZE		(7 + VTEM_DATA_SET_LENGTH)
> +/* Payload bytes carried by one EMP data island packet */
> +#define HDMI_EMP_PACKET_BODY	28
> +
> +/*
> + * Tell an HDMI 2.1 sink whether VRR is active with a Class 0 (Gaming-VRR)
> + * Video Timing Extended Metadata (VTEM) packet. It is a periodic
> + * pseudo-static EM Data Set: the hardware sends it every frame until it is
> + * reprogrammed. On disable, a last VTEM with VRR_EN=0 and END set is sent,
> + * after which the hardware stops sending it.
> + */
> +void intel_dip_write_hdmi_vtem(const struct intel_crtc_state *crtc_state,
> +			       bool enable)
> +{
> +	struct intel_display *display = to_intel_display(crtc_state);
> +	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
> +	const struct drm_display_mode *mode = &crtc_state->hw.adjusted_mode;
> +	u8 vic = crtc_state->infoframes.avi.avi.video_code;
> +	int base_rr = drm_mode_vrefresh(mode);
> +	u8 pb[HDMI_EMP_PACKET_BODY] = {};
> +	int i;
> +
> +	if (DISPLAY_VER(display) < 20 ||
> +	    !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
> +	    !crtc_state->vrr.in_range)
> +		return;

[Severity: Medium]
When intel_vrr_disable() calls intel_dip_write_hdmi_vtem(old_crtc_state,
false) to disable VRR from an inherited hardware state read out at driver
load, will this !crtc_state->vrr.in_range check cause an early return and
skip sending the terminating VTEM packet (VRR_EN=0 and END=1)?

During hardware state readout in intel_modeset_readout_hw_state() ->
intel_vrr_get_config(), old_crtc_state->vrr.enable is populated from
TRANS_VRR_CTL, but old_crtc_state->vrr.in_range is never set:

drivers/gpu/drm/i915/display/intel_vrr.c:intel_vrr_get_config() {
	...
	if (intel_vrr_always_use_vrr_tg(display))
		crtc_state->vrr.enable = vrr_enable && !intel_vrr_is_fixed_rr(crtc_state);
	else
		crtc_state->vrr.enable = vrr_enable;
	...
}

Since both callers of intel_dip_write_hdmi_vtem() — intel_vrr_enable() and
intel_vrr_disable() — already guard on crtc_state->vrr.enable (and
intel_vrr_compute_config() only sets vrr.enable when vrr.in_range is true),
is the !crtc_state->vrr.in_range check in intel_dip_write_hdmi_vtem()
needed?

> +
> +	/* PB0-PB6: EM Data Set header (Sync = 0, DS_Type = pseudo-static) */
> +	pb[0] = BIT(7) |			/* NEW */
> +		BIT(2) |			/* VFR */
> +		(enable ? 0 : BIT(6));		/* END */
> +	pb[2] = 1;				/* Organization_ID: HDMI */
> +	pb[4] = 1;				/* Data_Set_Tag: VTEM */
> +	pb[6] = VTEM_DATA_SET_LENGTH;		/* Data_Set_Length */
> +
> +	/* PB7-PB10: MD0-MD3 (M_CONST = 0, FVA_Factor_M1 = 0, MD2 bit 2 reserved) */
> +	if (enable) {
> +		pb[7] = BIT(0);			/* VRR_EN */
> +		/* Base_Vfront and Base_Refresh_Rate are only sent without a VIC */
> +		if (!vic) {
> +			pb[8] = min(mode->crtc_vsync_start - mode->crtc_vdisplay, 255);
> +			pb[9] = (base_rr >> 8) & 0x3;
> +			pb[10] = base_rr & 0xff;
> +		}
> +	}
> +
> +	drm_dbg_kms(display->drm,
> +		    "[TRANSCODER %s] VTEM: VRR_EN=%d VIC=%u Base_Vfront=%u Base_RR=%u\n",
> +		    transcoder_name(cpu_transcoder), enable, vic, pb[8],
> +		    pb[9] << 8 | pb[10]);
> +
> +	/*
> +	 * HDMI_EMP_CTL first, then the payload dwords (PB0 in bits 7:0), then
> +	 * the header, whose write clock crosses the whole packet. HB0 must be
> +	 * set to the EMP packet type, the hardware doesn't fill it in.
> +	 */
> +	intel_de_write(display, HDMI_EMP_CTL(display, cpu_transcoder),
> +		       HDMI_EMP_CTL_TYPE_VTEM);
> +	for (i = 0; i < ARRAY_SIZE(pb); i += 4)
> +		intel_de_write(display, HDMI_EMP_DATA(display, cpu_transcoder),
> +			       pb[i] | pb[i + 1] << 8 | pb[i + 2] << 16 |
> +			       pb[i + 3] << 24);

[Severity: High]
Does drivers/gpu/drm/i915/display/intel_dip.c fail to compile here because
HDMI_EMP_DATA is not defined?

In drivers/gpu/drm/i915/display/intel_dip_regs.h, the patch defines
HDMI_EMP_CTL and HDMI_EMP_HEADER with a comment noting that the payload is
HDMI_EMP_DATA, but neither intel_dip_regs.h nor intel_display_regs.h (nor
follow-up commit d2e831520b52) defines HDMI_EMP_DATA or _HDMI_EMP_DATA_A,
causing an implicit declaration build failure when CONFIG_DRM_I915 or
CONFIG_DRM_XE_DISPLAY is enabled.

In addition, the loop writes all 7 payload dwords to HDMI_EMP_DATA(display,
cpu_transcoder) without a dword index, whereas the transcoder Video DIP
Adaptive Sync / EMP packet buffer uses indexed data registers
ADL_TVIDEO_DIP_AS_SDP_DATA(display, trans, i) (0x60484 + i * 4) controlled
via VIDEO_DIP_ENABLE_AS_ADL in HSW_TVIDEO_DIP_CTL (0x60200). Should this
be programming the indexed Video DIP AS SDP / EMP buffer instead of
HDMI_EMP_CTL, HDMI_EMP_DATA, and HDMI_EMP_HEADER?

[ ... ]
> diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
> index d43a06907d18a..142ba2db52fda 100644
> --- a/drivers/gpu/drm/i915/display/intel_vrr.c
> +++ b/drivers/gpu/drm/i915/display/intel_vrr.c
> @@ -1010,6 +1010,8 @@ void intel_vrr_enable(const struct intel_crtc_state *crtc_state)
>  
>  	if (!intel_vrr_always_use_vrr_tg(display))
>  		intel_vrr_tg_enable(crtc_state);
> +
> +	intel_dip_write_hdmi_vtem(crtc_state, true);
>  }
>  
>  void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state)
> @@ -1024,6 +1026,8 @@ void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state)
>  
>  	intel_vrr_disable_dc_balancing(old_crtc_state);
>  	intel_vrr_set_fixed_rr_timings(old_crtc_state, old_crtc_state->cpu_transcoder);
> +
> +	intel_dip_write_hdmi_vtem(old_crtc_state, false);
>  }

[Severity: Medium]
Is placing intel_dip_write_hdmi_vtem(old_crtc_state, false) at the end of
intel_vrr_disable() ordered and guarded as intended across the disable and
fastset paths?

1. On platforms where !intel_vrr_always_use_vrr_tg(display) (such as
display version 20), intel_vrr_tg_disable() clears VRR_CTL_VRR_ENABLE in
TRANS_VRR_CTL and waits for VRR_STATUS_VRR_EN_LIVE to clear at the next
vblank before intel_dip_write_hdmi_vtem(old_crtc_state, false) is called:

drivers/gpu/drm/i915/display/intel_vrr.c:intel_vrr_tg_disable() {
	...
	if (intel_de_wait_for_clear_ms(display,
				       TRANS_VRR_STATUS(display, cpu_transcoder),
				       VRR_STATUS_VRR_EN_LIVE, 1000))
		drm_err(display->drm, "Timed out waiting for VRR live status to clear\n");
	...
}

Because the VRR_EN=0, END=1 VTEM is only written after that vblank wait
completes, the vblank in which the VRR timing generator turns off will
still transmit the old VTEM with VRR_EN=1 and END=0.

2. On a full modeset in intel_commit_modeset_disables(),
intel_pre_plane_update() calls intel_vrr_disable(old_crtc_state) and then
intel_old_crtc_state_disables() -> hsw_crtc_disable() ->
intel_ddi_post_disable_hdmi_or_sst() -> intel_disable_transcoder() clears
TRANSCONF_ENABLE without waiting for another vblank after
intel_dip_write_hdmi_vtem(old_crtc_state, false), so the final VTEM with
VRR_EN=0 and END=1 is never transmitted before the transcoder stops.

3. In drivers/gpu/drm/i915/display/intel_display.c,
intel_crtc_vrr_disabling() also returns true during seamless fastsets where
VRR stays enabled (old_crtc_state->vrr.enable && new_crtc_state->vrr.enable)
if update_m_n, update_lrr, or vrr_params_changed() is set:

drivers/gpu/drm/i915/display/intel_display.c:intel_crtc_vrr_disabling() {
	return is_disabling(vrr.enable, old_crtc_state, new_crtc_state) ||
		(old_crtc_state->vrr.enable &&
		 (new_crtc_state->update_m_n || new_crtc_state->update_lrr ||
		  vrr_params_changed(old_crtc_state, new_crtc_state)));
}

In that case, intel_pre_update_crtc() -> intel_pre_plane_update() ->
intel_vrr_disable() programs a VTEM with VRR_EN=0 and END=1 before vblank
evasion even though VRR remains enabled in new_crtc_state. Should
intel_dip_write_hdmi_vtem(old_crtc_state, false) be programmed before the
vblank wait and avoided when VRR is only being reconfigured across a
fastset?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261030203314.1085262-1-alan.stead@intel.com?part=2

  reply	other threads:[~2026-10-30 20:59 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-30 20:32 [RFC v1 0/3] drm/i915/vrr: HDMI 2.1 VRR support Alan Stead
2026-10-30 20:32 ` [RFC v1 1/3] drm/i915/dip: Send HDMI EMPs early in V. Blank when VRR is in range Alan Stead
2026-10-30 20:46   ` sashiko-bot
2026-10-30 20:32 ` [RFC v1 2/3] drm/i915/dip: Send the HDMI 2.1 VTEM when VRR is enabled Alan Stead
2026-10-30 20:59   ` sashiko-bot [this message]
2026-10-30 20:32 ` [RFC v1 3/3] drm/i915/vrr: Allow VRR on HDMI 2.1 sinks Alan Stead
2026-10-30 20:58   ` sashiko-bot
2026-10-30 21:29 ` ✓ i915.CI.BAT: success for drm/i915/vrr: HDMI 2.1 VRR support Patchwork
2026-10-31  7:21 ` ✗ i915.CI.Full: failure " Patchwork

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=sashiko-outbox-191505@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=alan.stead@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox