* [PATCH v2 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block
2026-08-06 20:54 ` [PATCH v2 0/4] HDMI 2.1 VRR and ALLM support Fangzhi Zuo
@ 2026-08-06 20:54 ` Fangzhi Zuo
2026-08-06 21:13 ` sashiko-bot
2026-08-06 20:54 ` [PATCH v2 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
` (3 subsequent siblings)
4 siblings, 1 reply; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-06 20:54 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, Fangzhi Zuo, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
open list
From: Fangzhi Zuo <Jerry.Zuo@amd.com>
why:
HDMI FRL sinks were not parsed for the AMD VSDB and no VTEM info packet
was emitted for them, so 2.1 FreeSync over HDMI FRL did not work. It is
backward-compatible with 2.0 FreeSync.
how:
- Accept SIGNAL_TYPE_HDMI_FRL alongside SIGNAL_TYPE_HDMI_TYPE_A when
parsing the AMD VSDB in amdgpu_dm_update_freesync_caps().
- Build and send the VTEM info packet via mod_build_infopacket_vtem()
when the stream signal is HDMI FRL during the freesync state update.
- Set the VTEM Data_Set_Length to 0 when no VTEM feature is enabled.
build_infopacket_header_vtem() hardcodes Data_Set_Length = 4, so a VTEM
with Data_Set_Length = 4 would be transmitted even when no VTEM feature
is enabled (VRR_EN = 0 and no FVA), e.g. when the sink advertises
VRRMIN = 0 and vrr_capable is false. This fails HDMI GCTS HF1-58 step
6.2.
The VTEM must keep being transmitted every MTW while VRR is enabled
(HF1-58 steps 8.1 and 8.3), so it cannot simply be suppressed per
frame. Instead, follow the MLDS option in HDMI 2.1 10.10.2.4: keep
transmitting the VTEM but set Data_Set_Length = 0 when no feature is
enabled. When VRR becomes active the full Data_Set_Length = 4 payload
with VRR_EN = 1 is sent as before.
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 4 +-
.../display/amdgpu_dm/amdgpu_dm_freesync.c | 4 +
.../amd/display/modules/inc/mod_info_packet.h | 4 +
.../display/modules/info_packet/info_packet.c | 109 ++++++++++++++++++
4 files changed, 120 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 4304520d2484..5e7ab9158995 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3838,7 +3838,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
}
- } else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
+ } else if (drm_edid &&
+ (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+ sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)) {
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
if (i >= 0) {
amdgpu_dm_connector->vsdb_info = vsdb_info;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
index 7e484adb4120..1fa078cdba52 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
@@ -37,6 +37,7 @@
#include "amdgpu_dm_freesync.h"
#include "dm_helpers.h"
#include "modules/inc/mod_freesync.h"
+#include "modules/inc/mod_info_packet.h"
bool amdgpu_dm_is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
struct dm_crtc_state *new_state)
@@ -229,6 +230,9 @@ void amdgpu_dm_update_freesync_state_on_stream(
&vrr_infopacket,
pack_sdp_v1_3);
+ if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)
+ mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket);
+
new_crtc_state->freesync_vrr_info_changed |=
(memcmp(&new_crtc_state->vrr_infopacket,
&vrr_infopacket,
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
index eee8206bc531..5181d889fe7f 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
@@ -67,6 +67,10 @@ struct AS_Df_params {
struct frame_duration_op decrease;
};
+void mod_build_infopacket_vtem(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr, int fva_factor,
+ struct dc_info_packet *infopacket);
+
void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
enum adaptive_sync_type asType, const struct AS_Df_params *param,
struct dc_info_packet *info_packet);
diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
index f5ac4bf32a78..e956c707ac50 100644
--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
@@ -291,6 +291,21 @@ void set_vsc_packet_colorimetry_data(
info_packet->sb[18] = 0;
}
+static void setFieldWithMask(unsigned char *dest, unsigned int mask, unsigned int value)
+{
+ unsigned int shift = 0;
+
+ if (!mask || !dest)
+ return;
+
+ while (!((mask >> shift) & 1))
+ shift++;
+
+ *dest = *dest & ~mask;
+ value = value & (mask >> shift);
+ *dest = *dest | (value << shift);
+}
+
void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet,
enum dc_color_space cs,
@@ -644,6 +659,100 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
info_packet->valid = true;
}
+static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr, int fva_factor,
+ struct dc_info_packet *infopacket)
+{
+ unsigned int fieldRateInHz;
+
+ /* FVA Factor setting */
+ setFieldWithMask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__FVA_FACTOR_M1,
+ (fva_factor > 0)?(fva_factor-1):0);
+ /* VRR Parameters */
+ if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
+ vrr->state == VRR_STATE_ACTIVE_FIXED) {
+ setFieldWithMask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__VRR_EN, 1);
+ } else {
+ setFieldWithMask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__VRR_EN, 0);
+ }
+
+ if (vrr->state == VRR_STATE_ACTIVE_FIXED)
+ setFieldWithMask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__M_CONST, vrr->m_const);
+
+ if (!stream->timing.vic) {
+ setFieldWithMask(&infopacket->sb[VTEM_MD1], MASK_VTEM_MD1__BASE_VFRONT,
+ stream->timing.v_front_porch);
+
+
+ /* TODO: In dal2, we check mode flags for a reduced blanking timing.
+ * Need a way to relay that information to this function.
+ * if("ReducedBlanking")
+ * {
+ * setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__RB, 1;
+ * }
+ */
+
+ fieldRateInHz = stream->timing.pix_clk_100hz * 100;
+ fieldRateInHz /= stream->timing.h_total;
+ fieldRateInHz = (fieldRateInHz + stream->timing.v_total / 2)
+ / stream->timing.v_total;
+
+ setFieldWithMask(&infopacket->sb[VTEM_MD2], MASK_VTEM_MD2__BASE_REFRESH_RATE_98,
+ fieldRateInHz >> 8);
+ setFieldWithMask(&infopacket->sb[VTEM_MD3], MASK_VTEM_MD3__BASE_REFRESH_RATE_07,
+ fieldRateInHz);
+
+ }
+
+ /*
+ * When no VTEM feature is enabled (neither VRR nor FVA), signal a
+ * zero-length data set (MLDS) by clearing Data_Set_Length. HDMI 2.1
+ * 10.10.2.4 requires the Source to either stop transmitting the VTEM
+ * or set Data_Set_Length = 0 when no feature is enabled; keeping the
+ * VTEM with Data_Set_Length = 0 preserves the every-MTW cadence while
+ * staying compliant (e.g. HDMI GCTS HF1-58 step 6.2).
+ */
+ if (vrr->state != VRR_STATE_ACTIVE_VARIABLE &&
+ vrr->state != VRR_STATE_ACTIVE_FIXED && fva_factor == 0)
+ setFieldWithMask(&infopacket->sb[VTEM_PB6],
+ MASK_VTEM_PB6__DATA_SET_LENGTH_LSB, 0);
+
+ infopacket->valid = true;
+}
+
+static void build_infopacket_header_vtem(enum signal_type signal,
+ struct dc_info_packet *infopacket)
+{
+ // HEADER
+
+ // HB0, HB1, HB2 indicates PacketType VTEMPacket
+ infopacket->hb0 = 0x7F;
+ infopacket->hb1 = 0xC0;
+ infopacket->hb2 = 0x00; //sequence_index
+
+ setFieldWithMask(&infopacket->sb[VTEM_PB0], MASK_VTEM_PB0__VFR, 1);
+ setFieldWithMask(&infopacket->sb[VTEM_PB2], MASK_VTEM_PB2__ORGANIZATION_ID, 1);
+ setFieldWithMask(&infopacket->sb[VTEM_PB3], MASK_VTEM_PB3__DATA_SET_TAG_MSB, 0);
+ setFieldWithMask(&infopacket->sb[VTEM_PB4], MASK_VTEM_PB4__DATA_SET_TAG_LSB, 1);
+ setFieldWithMask(&infopacket->sb[VTEM_PB5], MASK_VTEM_PB5__DATA_SET_LENGTH_MSB, 0);
+ setFieldWithMask(&infopacket->sb[VTEM_PB6], MASK_VTEM_PB6__DATA_SET_LENGTH_LSB, 4);
+}
+
+void mod_build_infopacket_vtem(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr, int fva_factor,
+ struct dc_info_packet *infopacket)
+{
+ //VTEM info packet for HdmiVrr
+
+ memset(infopacket, 0, sizeof(struct dc_info_packet));
+
+ //VTEM Packet is structured differently
+ build_infopacket_header_vtem(stream->signal, infopacket);
+ build_vtem_infopacket_data(stream, vrr, fva_factor, infopacket);
+
+ infopacket->valid = true;
+}
+
void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
enum adaptive_sync_type asType,
const struct AS_Df_params *param,
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v2 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block
2026-08-06 20:54 ` [PATCH v2 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
@ 2026-08-06 21:13 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-06 21:13 UTC (permalink / raw)
To: Fangzhi Zuo; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Dereferencing deprecated `new_stream->sink` pointer risks a NULL pointer dereference.
- [High] VTEM packet overwrites the FreeSync SPD infopacket and is misrouted to the hardware's SPD slot.
- [Medium] Unconditional VTEM transmission to all HDMI FRL displays, including non-VRR sinks.
- [Medium] 32-bit integer overflow when calculating `fieldRateInHz` for VTEM packets in ultra-high bandwidth modes.
- [Low] Unused parameter `signal` in `build_infopacket_header_vtem()`.
--
--- Patch [1]: [PATCH v2 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block ---
commit b0ebd1a49b36a5e82edcd0396a4c4d22fe23f9d3
Author: Fangzhi Zuo <Jerry.Zuo@amd.com>
drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block
This commit adds 2.1 FreeSync support for AMD VSDB EDID block over HDMI FRL.
It updates the capability parsing to accept HDMI FRL signals and builds the
required VTEM info packet. The VTEM data set length is dynamically set to 0
when no VTEM feature is enabled to comply with HDMI GCTS.
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> index 7e484adb4120f..1fa078cdba527 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> @@ -229,6 +230,9 @@ void amdgpu_dm_update_freesync_state_on_stream(
> &vrr_infopacket,
> pack_sdp_v1_3);
>
> + if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)
^^^^^^^^^^^^^^^^
[Severity: High]
Can this dereference a NULL pointer? The sink pointer inside
dc_stream_state is officially deprecated and could be NULL in headless or
writeback scenarios. Would it be safer to use new_stream->signal here?
[Severity: Medium]
Will this transmit VTEM packets even to sinks that do not support VRR or FVA?
There doesn't appear to be a check for vrr_params.send_info_frame, which
could result in unconditional VTEM transmission to all HDMI FRL displays,
potentially violating the HDMI 2.1 specifications.
> + mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket);
^^^^^^^^^^^^^^^
[Severity: High]
Does this overwrite the previously built AMD Vendor Specific InfoFrame
(VSIF)? By passing &vrr_infopacket, the newly created VTEM packet is stored
in the same local variable.
Additionally, since dc_resource.c writes stream->vrr_infopacket exclusively
to the hardware's SPD slot, will this cause the VTEM packet to be incorrectly
transmitted through the SPD slot instead of the VTEM slot?
> +
> new_crtc_state->freesync_vrr_info_changed |=
> (memcmp(&new_crtc_state->vrr_infopacket,
> &vrr_infopacket,
> diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
> index f5ac4bf32a784..e956c707ac507 100644
> --- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
> +++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
[ ... ]
> @@ -644,6 +659,100 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
> info_packet->valid = true;
> }
>
> +static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
> + const struct mod_vrr_params *vrr, int fva_factor,
> + struct dc_info_packet *infopacket)
> +{
> + unsigned int fieldRateInHz;
> +
> + /* FVA Factor setting */
> + setFieldWithMask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__FVA_FACTOR_M1,
> + (fva_factor > 0)?(fva_factor-1):0);
[ ... ]
> + fieldRateInHz = stream->timing.pix_clk_100hz * 100;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[Severity: Medium]
Can this multiplication overflow for ultra-high bandwidth modes? For displays
like 8K@120Hz, stream->timing.pix_clk_100hz * 100 could exceed the 32-bit
unsigned integer limit before the subsequent division. Should this be cast
to a 64-bit integer?
> + fieldRateInHz /= stream->timing.h_total;
> + fieldRateInHz = (fieldRateInHz + stream->timing.v_total / 2)
> + / stream->timing.v_total;
> +
> + }
> +
[ ... ]
> +static void build_infopacket_header_vtem(enum signal_type signal,
^^^^^^^^^^^^^^^^^^^^^^^
[Severity: Low]
Is the signal parameter needed here? It doesn't appear to be evaluated or
used anywhere within the body of this function.
> + struct dc_info_packet *infopacket)
> +{
> + // HEADER
> +
> + // HB0, HB1, HB2 indicates PacketType VTEMPacket
> + infopacket->hb0 = 0x7F;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806205449.16806-1-jerry.zuo@amd.com?part=1
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB
2026-08-06 20:54 ` [PATCH v2 0/4] HDMI 2.1 VRR and ALLM support Fangzhi Zuo
2026-08-06 20:54 ` [PATCH v2 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
@ 2026-08-06 20:54 ` Fangzhi Zuo
2026-08-06 20:54 ` [PATCH v2 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
` (2 subsequent siblings)
4 siblings, 0 replies; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-06 20:54 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, Tomasz Pakuła, Fangzhi Zuo, Bernhard Berger,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, open list
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Parse the HDMI 2.1 gaming-related capabilities advertised in the HDMI
Forum VSDB (HF-VSDB) and expose them through struct drm_hdmi_info so
drivers can consume them.
Add struct drm_hdmi_vrr_cap describing the sink's VRR capabilities: Fast
VActive (Quick Frame Transport), Negative M VRR, Cinema VRR, MDelta, and
the VRRmin/VRRmax range, together with a "supported" flag derived from
that range. Add the fapa_start_location and allm (Auto Low Latency Mode)
flags to struct drm_hdmi_info.
drm_parse_hdmi_gaming_info() reads byte 8 of the HF-VSDB for the
FAPA/ALLM/FVA/CNMVRR/CinemaVRR/MDelta flags and bytes 9-10 for
VRRmin/VRRmax. Per HDMI 2.1, VRR is considered supported when VRRmin is
within 1-48 and VRRmax is either 0 (maximum based on the video mode) or
>= 100. It is invoked from drm_parse_hdmi_forum_scds(), and the parsed
values are logged for debugging.
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Tested-by: Bernhard Berger <bernhard.berger@gmail.com>
---
drivers/gpu/drm/drm_edid.c | 42 +++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 47 +++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index ae26618a9a57..d508ec633c9b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -6182,6 +6182,33 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector,
hdmi->y420_dc_modes = dc_mask;
}
+static void drm_parse_hdmi_gaming_info(struct drm_hdmi_info *hdmi, const u8 *db)
+{
+ struct drm_hdmi_vrr_cap *vrr = &hdmi->vrr_cap;
+
+ if (cea_db_payload_len(db) < 8)
+ return;
+
+ hdmi->fapa_start_location = db[8] & DRM_EDID_FAPA_START_LOCATION;
+ hdmi->allm = db[8] & DRM_EDID_ALLM;
+ vrr->fva = db[8] & DRM_EDID_FVA;
+ vrr->cnmvrr = db[8] & DRM_EDID_CNMVRR;
+ vrr->cinema_vrr = db[8] & DRM_EDID_CINEMA_VRR;
+ vrr->mdelta = db[8] & DRM_EDID_MDELTA;
+
+ if (cea_db_payload_len(db) < 9)
+ return;
+
+ vrr->vrr_min = db[9] & DRM_EDID_VRR_MIN_MASK;
+ vrr->supported = (vrr->vrr_min > 0 && vrr->vrr_min <= 48);
+
+ if (cea_db_payload_len(db) < 10)
+ return;
+
+ vrr->vrr_max = (db[9] & DRM_EDID_VRR_MAX_UPPER_MASK) << 2 | db[10];
+ vrr->supported &= (vrr->vrr_max == 0 || vrr->vrr_max >= 100);
+}
+
static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc,
const u8 *hf_scds)
{
@@ -6308,6 +6335,8 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
drm_parse_ycbcr420_deep_color_info(connector, hf_scds);
+ drm_parse_hdmi_gaming_info(&connector->display_info.hdmi, hf_scds);
+
if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) {
drm_parse_dsc_info(hdmi_dsc, hf_scds);
dsc_support = true;
@@ -6317,6 +6346,19 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
"[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n",
connector->base.id, connector->name,
max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support));
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] FAPA in blanking: %s, ALLM support: %s, Fast Vactive support: %s\n",
+ connector->base.id, connector->name, str_yes_no(hdmi->fapa_start_location),
+ str_yes_no(hdmi->allm), str_yes_no(hdmi->vrr_cap.fva));
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Negative M VRR support: %s, CinemaVRR support: %s, Mdelta: %d\n",
+ connector->base.id, connector->name, str_yes_no(hdmi->vrr_cap.cnmvrr),
+ str_yes_no(hdmi->vrr_cap.cinema_vrr), hdmi->vrr_cap.mdelta);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] VRRmin: %u, VRRmax: %u, VRR supported: %s\n",
+ connector->base.id, connector->name, hdmi->vrr_cap.vrr_min,
+ hdmi->vrr_cap.vrr_max, str_yes_no(hdmi->vrr_cap.supported));
+
}
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index cd06a3b914a0..9f8f109c2dd1 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -254,6 +254,44 @@ struct drm_scdc {
struct drm_scrambling scrambling;
};
+/**
+ * struct drm_hdmi_vrr_cap - Information about VRR capabilities of a HDMI sink
+ *
+ * Describes the VRR support provided by HDMI 2.1 sink. The information is
+ * fetched fom additional HFVSDB blocks defined for HDMI 2.1.
+ */
+struct drm_hdmi_vrr_cap {
+ /** @fva: flag for Fast VActive (Quick Frame Transport) support */
+ bool fva;
+
+ /** @mcnmvrr: flag for Negative M VRR support */
+ bool cnmvrr;
+
+ /** @mcinema_vrr: flag for Cinema VRR support */
+ bool cinema_vrr;
+
+ /** @mdelta: flag for limited frame-to-frame compensation support */
+ bool mdelta;
+
+ /**
+ * @vrr_min : minimum supported variable refresh rate in Hz.
+ * Valid values only inide 1 - 48 range
+ */
+ u16 vrr_min;
+
+ /**
+ * @vrr_max : maximum supported variable refresh rate in Hz (optional).
+ * Valid values are either 0 (max based on video mode) or >= 100
+ */
+ u16 vrr_max;
+
+ /**
+ * @supported: flag for vrr support based on checking for VRRmin and
+ * VRRmax values having correct values.
+ */
+ bool supported;
+};
+
/**
* struct drm_hdmi_dsc_cap - DSC capabilities of HDMI sink
*
@@ -330,6 +368,15 @@ struct drm_hdmi_info {
/** @max_lanes: supported by sink */
u8 max_lanes;
+ /** @fapa_start_location: flag for the FAPA in blanking support */
+ bool fapa_start_location;
+
+ /** @allm: flag for Auto Low Latency Mode support by sink */
+ bool allm;
+
+ /** @vrr_cap: VRR capabilities of the sink */
+ struct drm_hdmi_vrr_cap vrr_cap;
+
/** @dsc_cap: DSC capabilities of the sink */
struct drm_hdmi_dsc_cap dsc_cap;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH v2 3/4] drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB
2026-08-06 20:54 ` [PATCH v2 0/4] HDMI 2.1 VRR and ALLM support Fangzhi Zuo
2026-08-06 20:54 ` [PATCH v2 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
2026-08-06 20:54 ` [PATCH v2 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
@ 2026-08-06 20:54 ` Fangzhi Zuo
2026-08-06 21:07 ` sashiko-bot
2026-08-06 20:54 ` [PATCH v2 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 0/4] HDMI 2.1 VRR and " Fangzhi Zuo
4 siblings, 1 reply; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-06 20:54 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, Fangzhi Zuo, Fangzhi Zuo, Harry Wentland, Leo Li,
Rodrigo Siqueira, Alex Deucher, Christian König,
David Airlie, Simona Vetter, open list
why:
HDMI 2.1 sinks advertise their VRR range in the HDMI Forum VSDB
(HF-VSDB), but amdgpu derived FreeSync capability only from the AMD
VSDB. Sinks that expose just the HDMI Forum VRR capability (e.g. HDMI
compliance EDIDs) were therefore reported as not VRR capable.
how:
- In amdgpu_dm_update_freesync_caps(), when the AMD VSDB does not
provide a valid FreeSync range, fall back to the HDMI 2.1 VRR range
parsed by DRM core from the HF-VSDB
(connector->display_info.hdmi.vrr_cap). VRRMAX = 0 means "up to the
Base Refresh Rate"; when the EDID provides no monitor range maximum
either, fall back to the Base Refresh Rate (the highest refresh-rate
mode of the preferred timing) so a valid VRR range is still reported
to userspace.
- Add VRR debug logging along the FreeSync capability and config paths.
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 67 +++++++++++++++++++
.../display/amdgpu_dm/amdgpu_dm_freesync.c | 8 +++
2 files changed, 75 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 5e7ab9158995..df39bc70ec6c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3812,6 +3812,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version))
goto update;
+ drm_dbg_driver(adev_to_drm(adev),
+ "VRR: enter signal=%d hdmi_vrr=%d mrange[%d-%d] hdmi.vrr_cap[sup=%d min=%d max=%d]\n",
+ sink->sink_signal, connector->display_info.hdmi.vrr_cap.supported,
+ connector->display_info.monitor_range.min_vfreq,
+ connector->display_info.monitor_range.max_vfreq,
+ connector->display_info.hdmi.vrr_cap.supported,
+ connector->display_info.hdmi.vrr_cap.vrr_min,
+ connector->display_info.hdmi.vrr_cap.vrr_max);
+
/* FIXME: Get rid of drm_edid_raw() */
edid = drm_edid_raw(drm_edid);
@@ -3856,6 +3865,59 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
}
}
+
+ drm_dbg_driver(adev_to_drm(adev),
+ "VRR: amd_vsdb i=%d fs_sup=%d min=%d max=%d fs_capable=%d\n",
+ i, vsdb_info.freesync_supported,
+ vsdb_info.min_refresh_rate_hz,
+ vsdb_info.max_refresh_rate_hz, freesync_capable);
+
+ /*
+ * If AMD VSDB didn't provide a valid FreeSync range, fall back to
+ * the HDMI 2.1 VRR capability parsed from the HF-VSDB.
+ */
+ if (!freesync_capable && connector->display_info.hdmi.vrr_cap.supported) {
+ struct drm_hdmi_vrr_cap *vrr_cap =
+ &connector->display_info.hdmi.vrr_cap;
+
+ drm_dbg_driver(adev_to_drm(adev),
+ "VRR: HF-VSDB fallback: hdmi_vrr=1 vrr_cap[sup=%d min=%d max=%d] mrange_max=%d\n",
+ vrr_cap->supported, vrr_cap->vrr_min, vrr_cap->vrr_max,
+ connector->display_info.monitor_range.max_vfreq);
+
+ if (vrr_cap->supported && vrr_cap->vrr_min > 0) {
+ amdgpu_dm_connector->min_vfreq = vrr_cap->vrr_min;
+ amdgpu_dm_connector->max_vfreq = vrr_cap->vrr_max ?
+ vrr_cap->vrr_max :
+ connector->display_info.monitor_range.max_vfreq;
+
+ /*
+ * VRRMAX = 0 in the HF-VSDB means "up to the Base
+ * Refresh Rate". If the EDID also did not provide a
+ * monitor range max, fall back to the Base Refresh
+ * Rate (the highest refresh rate of the preferred
+ * timing) so a valid VRR range is still reported to
+ * userspace.
+ */
+ if (!amdgpu_dm_connector->max_vfreq) {
+ struct drm_display_mode *brr_mode =
+ amdgpu_dm_get_highest_refresh_rate_mode(amdgpu_dm_connector, true);
+
+ if (brr_mode)
+ amdgpu_dm_connector->max_vfreq =
+ drm_mode_vrefresh(brr_mode);
+ }
+
+ if (amdgpu_dm_connector->max_vfreq -
+ amdgpu_dm_connector->min_vfreq > 10)
+ freesync_capable = true;
+
+ connector->display_info.monitor_range.min_vfreq =
+ amdgpu_dm_connector->min_vfreq;
+ connector->display_info.monitor_range.max_vfreq =
+ amdgpu_dm_connector->max_vfreq;
+ }
+ }
}
if (amdgpu_dm_connector->dc_link)
@@ -3899,6 +3961,11 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (dm_con_state)
dm_con_state->freesync_capable = freesync_capable;
+ drm_dbg_driver(adev_to_drm(adev),
+ "VRR: caps result: freesync_capable=%d min_vfreq=%d max_vfreq=%d\n",
+ freesync_capable, amdgpu_dm_connector->min_vfreq,
+ amdgpu_dm_connector->max_vfreq);
+
if (connector->state && amdgpu_dm_connector->dc_link && !freesync_capable &&
amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported) {
amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported = false;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
index 1fa078cdba52..cb49184813de 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
@@ -152,6 +152,14 @@ void amdgpu_dm_get_freesync_config_for_crtc(
}
out:
new_crtc_state->freesync_config = config;
+
+ drm_dbg_driver(new_con_state->base.connector->dev,
+ "VRR: cfg vrr_enabled=%d vrr_supported=%d fs_capable=%d vrefresh=%d min=%d max=%d state=%d\n",
+ new_crtc_state->base.vrr_enabled,
+ new_crtc_state->vrr_supported,
+ new_con_state->freesync_capable, vrefresh,
+ aconnector->min_vfreq, aconnector->max_vfreq,
+ config.state);
}
EXPORT_IF_KUNIT(amdgpu_dm_get_freesync_config_for_crtc);
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v2 3/4] drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB
2026-08-06 20:54 ` [PATCH v2 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
@ 2026-08-06 21:07 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-06 21:07 UTC (permalink / raw)
To: Fangzhi Zuo; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The HF-VSDB VRR fallback is unconditionally overwritten to false for HDMI TMDS sinks because they lack an AMD FreeSync VCP code.
--
--- Patch [3]: [PATCH v2 3/4] drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB ---
commit 3db5053c0ea2b238965bfd80def111ee342642b8
Author: Fangzhi Zuo <jerry.zuo@amd.com>
drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB
This commit adds support for HDMI 2.1 VRR capabilities derived from the
HDMI Forum VSDB (HF-VSDB) as a fallback. It parses the VRR ranges and sets
the FreeSync capability appropriately when an AMD VSDB is missing or invalid.
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
[ ... ]
> @@ -3856,6 +3865,59 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
[ ... ]
> + /*
> + * If AMD VSDB didn't provide a valid FreeSync range, fall back to
> + * the HDMI 2.1 VRR capability parsed from the HF-VSDB.
> + */
> + if (!freesync_capable && connector->display_info.hdmi.vrr_cap.supported) {
[ ... ]
> + if (amdgpu_dm_connector->max_vfreq -
> + amdgpu_dm_connector->min_vfreq > 10)
> + freesync_capable = true;
[Severity: Medium]
Will this newly enabled HF-VSDB fallback be unconditionally overwritten to
false for HDMI TMDS sinks?
For a monitor advertising VRR only via HF-VSDB on an HDMI TMDS link, the
AMD VSDB parsing fails, leaving sink->edid_caps.freesync_vcp_code as 0.
While this new fallback block correctly sets freesync_capable to true, later
in amdgpu_dm_update_freesync_caps(), there is an existing check:
if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) &&
(!sink->edid_caps.freesync_vcp_code ||
(sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported)))
freesync_capable = false;
Since sink_signal == SIGNAL_TYPE_HDMI_TYPE_A and freesync_vcp_code is 0,
does this existing logic silently disable the fallback feature being
introduced here?
> +
> + connector->display_info.monitor_range.min_vfreq =
> + amdgpu_dm_connector->min_vfreq;
> + connector->display_info.monitor_range.max_vfreq =
> + amdgpu_dm_connector->max_vfreq;
> + }
> + }
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806205449.16806-1-jerry.zuo@amd.com?part=3
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 4/4] drm/amd/display: Add HDMI ALLM support
2026-08-06 20:54 ` [PATCH v2 0/4] HDMI 2.1 VRR and ALLM support Fangzhi Zuo
` (2 preceding siblings ...)
2026-08-06 20:54 ` [PATCH v2 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
@ 2026-08-06 20:54 ` Fangzhi Zuo
2026-08-06 21:08 ` sashiko-bot
2026-08-10 21:04 ` Harry Wentland
2026-08-11 0:39 ` [PATCH v3 0/4] HDMI 2.1 VRR and " Fangzhi Zuo
4 siblings, 2 replies; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-06 20:54 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, Fangzhi Zuo, Fangzhi Zuo, Harry Wentland, Leo Li,
Rodrigo Siqueira, Alex Deucher, Christian König,
David Airlie, Simona Vetter, open list
why:
HDMI 2.1 Auto Low-Latency Mode (ALLM) lets a Source request the Sink's
low-latency mode through the HF-VSIF. amdgpu never set ALLM_Mode in the
HF-VSIF, so ALLM was never signalled to the sink.
how:
- In create_stream_for_sink(), build the HF-VSIF with ALLM_Mode set when
the sink advertises ALLM (connector->display_info.hdmi.allm, parsed by
DRM core from the HF-VSDB) and the content type is Game (content-type =
Game is how userspace requests low-latency mode, HDMI GCTS HF1-56).
- In update_freesync_state_on_stream(), also set ALLM_Mode when
Gaming-VRR is active (VRR_EN=1, HDMI GCTS HF1-58 step 8.3.1), and push
the updated HF-VSIF (vsp_infopacket) as a stream update.
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++-
.../display/amdgpu_dm/amdgpu_dm_connector.c | 18 +++++++++--
.../display/amdgpu_dm/amdgpu_dm_freesync.c | 31 +++++++++++++++++++
3 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 567bf04979ee..ff0db0cb9880 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4029,9 +4029,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
}
if (acrtc_state->stream) {
- if (acrtc_state->freesync_vrr_info_changed)
+ if (acrtc_state->freesync_vrr_info_changed) {
bundle->stream_update.vrr_infopacket =
&acrtc_state->stream->vrr_infopacket;
+ bundle->stream_update.vsp_infopacket =
+ &acrtc_state->stream->vsp_infopacket;
+ }
}
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index df39bc70ec6c..6cfd7526ab56 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1572,8 +1572,22 @@ create_stream_for_sink(struct drm_connector *connector,
update_stream_signal(stream, sink);
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- stream->signal == SIGNAL_TYPE_HDMI_FRL)
- mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
+ stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+ /*
+ * Enable HDMI ALLM (Auto Low-Latency Mode) when the sink
+ * advertises ALLM in the SCDS and the content type is Game.
+ * Setting content-type = Game is how userspace requests the
+ * Sink's low-latency mode (HDMI GCTS HF1-56).
+ */
+ bool allm = connector->display_info.hdmi.allm &&
+ stream->content_type == DISPLAY_CONTENT_TYPE_GAME;
+
+ drm_dbg_driver(dev,
+ "ALLM: set mode: sink_allm=%d content_type=%d -> ALLM_Mode=%d\n",
+ connector->display_info.hdmi.allm, stream->content_type, allm);
+
+ mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, allm, allm);
+ }
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
index cb49184813de..c4bc6e717df9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
@@ -252,6 +252,37 @@ void amdgpu_dm_update_freesync_state_on_stream(
new_stream->vrr_infopacket = vrr_infopacket;
new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
+ /*
+ * HDMI ALLM: transmit the HF-VSIF with ALLM_Mode=1 when the sink
+ * advertises ALLM in the SCDS and either the content type is Game
+ * (HF1-56) or Gaming-VRR is active (VRR_EN=1, HF1-58 step 8.3.1).
+ * HDMI 2.1 7.6.6.
+ */
+ if (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+ new_stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+ struct dc_info_packet vsp_infopacket = {0};
+ bool sink_allm = aconn && aconn->base.display_info.hdmi.allm;
+ bool allm = sink_allm &&
+ (new_stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
+ vrr_params.state == VRR_STATE_ACTIVE_VARIABLE ||
+ vrr_params.state == VRR_STATE_ACTIVE_FIXED);
+ bool allm_changed;
+
+ mod_build_hf_vsif_infopacket(new_stream, &vsp_infopacket, allm, allm);
+
+ allm_changed = memcmp(&new_stream->vsp_infopacket, &vsp_infopacket,
+ sizeof(vsp_infopacket)) != 0;
+ new_crtc_state->freesync_vrr_info_changed |= allm_changed;
+ new_stream->vsp_infopacket = vsp_infopacket;
+
+ if (allm_changed)
+ drm_dbg_driver(adev_to_drm(adev),
+ "ALLM: flip on crtc=%u: sink_allm=%d content_type=%d vrr_state=%d -> ALLM_Mode=%d\n",
+ new_crtc_state->base.crtc->base.id,
+ sink_allm,
+ new_stream->content_type, vrr_params.state, allm);
+ }
+
if (new_crtc_state->freesync_vrr_info_changed)
drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
new_crtc_state->base.crtc->base.id,
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v2 4/4] drm/amd/display: Add HDMI ALLM support
2026-08-06 20:54 ` [PATCH v2 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
@ 2026-08-06 21:08 ` sashiko-bot
2026-08-10 21:04 ` Harry Wentland
1 sibling, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-06 21:08 UTC (permalink / raw)
To: Fangzhi Zuo; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Enabling ALLM replaces the HDMI 1.4 VSIF with the HF-VSIF, dropping `hdmi_vic` signaling required for legacy 4K formats.
Pre-existing issues:
- [High] HDMI VRR (VTEM) is artificially restricted to FRL links, breaking HDMI VRR over TMDS.
--
--- Patch [4]: [PATCH v2 4/4] drm/amd/display: Add HDMI ALLM support ---
commit 4ebe402fb25e863740386dee88638b0ecc01f7ba
Author: Fangzhi Zuo <jerry.zuo@amd.com>
drm/amd/display: Add HDMI ALLM support
This commit adds HDMI 2.1 Auto Low-Latency Mode (ALLM) support by setting
ALLM_Mode in the HF-VSIF. It builds the HF-VSIF when the sink advertises ALLM
and the content type is Game or Gaming-VRR is active.
[ ... ]
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index df39bc70ec6c3..6cfd7526ab56a 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> @@ -1572,8 +1572,22 @@ create_stream_for_sink(struct drm_connector *connector,
> update_stream_signal(stream, sink);
>
> if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
> - stream->signal == SIGNAL_TYPE_HDMI_FRL)
> - mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
> + stream->signal == SIGNAL_TYPE_HDMI_FRL) {
> + /*
> + * Enable HDMI ALLM (Auto Low-Latency Mode) when the sink
> + * advertises ALLM in the SCDS and the content type is Game.
> + * Setting content-type = Game is how userspace requests the
> + * Sink's low-latency mode (HDMI GCTS HF1-56).
> + */
> + bool allm = connector->display_info.hdmi.allm &&
> + stream->content_type == DISPLAY_CONTENT_TYPE_GAME;
> +
> + drm_dbg_driver(dev,
> + "ALLM: set mode: sink_allm=%d content_type=%d -> ALLM_Mode=%d\n",
> + connector->display_info.hdmi.allm, stream->content_type, allm);
> +
> + mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, allm, allm);
[Severity: High]
Does enabling ALLM replace the HDMI 1.4 VSIF with the HF-VSIF, dropping
hdmi_vic signaling for legacy 4K formats?
When ALLM is requested, calling mod_build_hf_vsif_infopacket() with allm=true
overrides the VSIF payload in vsp_infopacket.
Looking at the implementation in info_packet.c:mod_build_hf_vsif_infopacket():
if (!bALLM) {
info_packet->sb[1] = 0x03;
...
} else {
info_packet->sb[1] = 0xD8;
...
This acts as a mutually exclusive switch rather than populating two separate
info frames. If a user selects a display mode requiring hdmi_vic and sets the
content type to Game, will this cause the display to lose format signaling and
result in a black screen or corrupted display?
[ ... ]
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> index cb49184813dee..c4bc6e717df93 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> @@ -252,6 +252,37 @@ void amdgpu_dm_update_freesync_state_on_stream(
> new_stream->vrr_infopacket = vrr_infopacket;
[Severity: High]
This is a pre-existing issue, but does restricting VTEM generation strictly to
FRL links break HDMI VRR on HDMI 2.0 displays?
HDMI 2.1 VRR requires the VTEM packet to operate. Looking earlier in
amdgpu_dm_update_freesync_state_on_stream():
if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)
mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket);
By checking for SIGNAL_TYPE_HDMI_FRL, it appears the driver will silently
skip VTEM generation for TMDS-only sinks that support VRR (via firmware
updates or HDMI 2.1 features on TMDS), causing VRR to fail to engage.
> new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
>
> + /*
> + * HDMI ALLM: transmit the HF-VSIF with ALLM_Mode=1 when the sink
> + * advertises ALLM in the SCDS and either the content type is Game
> + * (HF1-56) or Gaming-VRR is active (VRR_EN=1, HF1-58 step 8.3.1).
> + * HDMI 2.1 7.6.6.
> + */
> + if (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
> + new_stream->signal == SIGNAL_TYPE_HDMI_FRL) {
> + struct dc_info_packet vsp_infopacket = {0};
> + bool sink_allm = aconn && aconn->base.display_info.hdmi.allm;
> + bool allm = sink_allm &&
> + (new_stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
> + vrr_params.state == VRR_STATE_ACTIVE_VARIABLE ||
> + vrr_params.state == VRR_STATE_ACTIVE_FIXED);
> + bool allm_changed;
> +
> + mod_build_hf_vsif_infopacket(new_stream, &vsp_infopacket, allm, allm);
> +
> + allm_changed = memcmp(&new_stream->vsp_infopacket, &vsp_infopacket,
> + sizeof(vsp_infopacket)) != 0;
> + new_crtc_state->freesync_vrr_info_changed |= allm_changed;
> + new_stream->vsp_infopacket = vsp_infopacket;
[Severity: High]
As noted above in create_stream_for_sink(), does unconditionally replacing
vsp_infopacket with the HF-VSIF here cause the display to lose hdmi_vic
signaling when Gaming-VRR is active?
> +
> + if (allm_changed)
> + drm_dbg_driver(adev_to_drm(adev),
> + "ALLM: flip on crtc=%u: sink_allm=%d content_type=%d vrr_state=%d -> ALLM_Mode=%d\n",
> + new_crtc_state->base.crtc->base.id,
> + sink_allm,
> + new_stream->content_type, vrr_params.state, allm);
> + }
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806205449.16806-1-jerry.zuo@amd.com?part=4
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v2 4/4] drm/amd/display: Add HDMI ALLM support
2026-08-06 20:54 ` [PATCH v2 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
2026-08-06 21:08 ` sashiko-bot
@ 2026-08-10 21:04 ` Harry Wentland
1 sibling, 0 replies; 26+ messages in thread
From: Harry Wentland @ 2026-08-10 21:04 UTC (permalink / raw)
To: Fangzhi Zuo, amd-gfx
Cc: dri-devel, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter, open list
On 2026-08-06 16:54, Fangzhi Zuo wrote:
> why:
> HDMI 2.1 Auto Low-Latency Mode (ALLM) lets a Source request the Sink's
> low-latency mode through the HF-VSIF. amdgpu never set ALLM_Mode in the
> HF-VSIF, so ALLM was never signalled to the sink.
>
> how:
> - In create_stream_for_sink(), build the HF-VSIF with ALLM_Mode set when
> the sink advertises ALLM (connector->display_info.hdmi.allm, parsed by
> DRM core from the HF-VSDB) and the content type is Game (content-type =
> Game is how userspace requests low-latency mode, HDMI GCTS HF1-56).
> - In update_freesync_state_on_stream(), also set ALLM_Mode when
> Gaming-VRR is active (VRR_EN=1, HDMI GCTS HF1-58 step 8.3.1), and push
> the updated HF-VSIF (vsp_infopacket) as a stream update.
>
> Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Harry
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++-
> .../display/amdgpu_dm/amdgpu_dm_connector.c | 18 +++++++++--
> .../display/amdgpu_dm/amdgpu_dm_freesync.c | 31 +++++++++++++++++++
> 3 files changed, 51 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index 567bf04979ee..ff0db0cb9880 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -4029,9 +4029,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
> }
>
> if (acrtc_state->stream) {
> - if (acrtc_state->freesync_vrr_info_changed)
> + if (acrtc_state->freesync_vrr_info_changed) {
> bundle->stream_update.vrr_infopacket =
> &acrtc_state->stream->vrr_infopacket;
> + bundle->stream_update.vsp_infopacket =
> + &acrtc_state->stream->vsp_infopacket;
> + }
> }
> }
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index df39bc70ec6c..6cfd7526ab56 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> @@ -1572,8 +1572,22 @@ create_stream_for_sink(struct drm_connector *connector,
> update_stream_signal(stream, sink);
>
> if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
> - stream->signal == SIGNAL_TYPE_HDMI_FRL)
> - mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
> + stream->signal == SIGNAL_TYPE_HDMI_FRL) {
> + /*
> + * Enable HDMI ALLM (Auto Low-Latency Mode) when the sink
> + * advertises ALLM in the SCDS and the content type is Game.
> + * Setting content-type = Game is how userspace requests the
> + * Sink's low-latency mode (HDMI GCTS HF1-56).
> + */
> + bool allm = connector->display_info.hdmi.allm &&
> + stream->content_type == DISPLAY_CONTENT_TYPE_GAME;
> +
> + drm_dbg_driver(dev,
> + "ALLM: set mode: sink_allm=%d content_type=%d -> ALLM_Mode=%d\n",
> + connector->display_info.hdmi.allm, stream->content_type, allm);
> +
> + mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, allm, allm);
> + }
>
> if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
> stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> index cb49184813de..c4bc6e717df9 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> @@ -252,6 +252,37 @@ void amdgpu_dm_update_freesync_state_on_stream(
> new_stream->vrr_infopacket = vrr_infopacket;
> new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
>
> + /*
> + * HDMI ALLM: transmit the HF-VSIF with ALLM_Mode=1 when the sink
> + * advertises ALLM in the SCDS and either the content type is Game
> + * (HF1-56) or Gaming-VRR is active (VRR_EN=1, HF1-58 step 8.3.1).
> + * HDMI 2.1 7.6.6.
> + */
> + if (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
> + new_stream->signal == SIGNAL_TYPE_HDMI_FRL) {
> + struct dc_info_packet vsp_infopacket = {0};
> + bool sink_allm = aconn && aconn->base.display_info.hdmi.allm;
> + bool allm = sink_allm &&
> + (new_stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
> + vrr_params.state == VRR_STATE_ACTIVE_VARIABLE ||
> + vrr_params.state == VRR_STATE_ACTIVE_FIXED);
> + bool allm_changed;
> +
> + mod_build_hf_vsif_infopacket(new_stream, &vsp_infopacket, allm, allm);
> +
> + allm_changed = memcmp(&new_stream->vsp_infopacket, &vsp_infopacket,
> + sizeof(vsp_infopacket)) != 0;
> + new_crtc_state->freesync_vrr_info_changed |= allm_changed;
> + new_stream->vsp_infopacket = vsp_infopacket;
> +
> + if (allm_changed)
> + drm_dbg_driver(adev_to_drm(adev),
> + "ALLM: flip on crtc=%u: sink_allm=%d content_type=%d vrr_state=%d -> ALLM_Mode=%d\n",
> + new_crtc_state->base.crtc->base.id,
> + sink_allm,
> + new_stream->content_type, vrr_params.state, allm);
> + }
> +
> if (new_crtc_state->freesync_vrr_info_changed)
> drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
> new_crtc_state->base.crtc->base.id,
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 0/4] HDMI 2.1 VRR and ALLM support
2026-08-06 20:54 ` [PATCH v2 0/4] HDMI 2.1 VRR and ALLM support Fangzhi Zuo
` (3 preceding siblings ...)
2026-08-06 20:54 ` [PATCH v2 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
@ 2026-08-11 0:39 ` Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
` (3 more replies)
4 siblings, 4 replies; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-11 0:39 UTC (permalink / raw)
To: amd-gfx; +Cc: dri-devel, Harry Wentland, Tomasz Pakuła, Fangzhi Zuo
This series adds HDMI 2.1 gaming support to amdgpu: Variable Refresh Rate
(VRR) derived from the HDMI Forum VSDB (HF-VSDB), and Auto Low-Latency
Mode (ALLM). It builds on a drm/edid patch that parses the HF-VSDB gaming
capabilities into struct drm_hdmi_info.
- Patch 1 reports FreeSync from the AMD VSDB (existing mechanism).
- Patch 2 (drm/edid) parses the HF-VSDB VRR range and ALLM bit.
- Patch 3 enables VRR from the HF-VSDB when the AMD VSDB has no range.
- Patch 4 signals ALLM_Mode in the HF-VSIF for Game content / active VRR.
v1: https://lore.kernel.org/amd-gfx/20260730171754.704049-1-jerry.zuo@amd.com/
v2: https://lore.kernel.org/amd-gfx/20260806205449.16806-1-jerry.zuo@amd.com/
Changes since v2:
- Fix coding-style issues in the VTEM info-packet code.
Fangzhi Zuo (3):
drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block
drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB
drm/amd/display: Add HDMI ALLM support
Tomasz Pakuła (1):
drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +-
.../display/amdgpu_dm/amdgpu_dm_connector.c | 89 +++++++++++++-
.../display/amdgpu_dm/amdgpu_dm_freesync.c | 43 +++++++
.../amd/display/modules/inc/mod_info_packet.h | 4 +
.../display/modules/info_packet/info_packet.c | 109 ++++++++++++++++++
drivers/gpu/drm/drm_edid.c | 42 +++++++
include/drm/drm_connector.h | 47 ++++++++
7 files changed, 335 insertions(+), 4 deletions(-)
base-commit: de2622bbc20276eaaaafa8fdbd374ace1ced28dc
--
2.53.0
^ permalink raw reply [flat|nested] 26+ messages in thread* [PATCH v3 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block
2026-08-11 0:39 ` [PATCH v3 0/4] HDMI 2.1 VRR and " Fangzhi Zuo
@ 2026-08-11 0:39 ` Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
` (2 subsequent siblings)
3 siblings, 0 replies; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-11 0:39 UTC (permalink / raw)
To: amd-gfx; +Cc: dri-devel, Harry Wentland, Tomasz Pakuła, Fangzhi Zuo
From: Fangzhi Zuo <Jerry.Zuo@amd.com>
why:
HDMI FRL sinks were not parsed for the AMD VSDB and no VTEM info packet
was emitted for them, so 2.1 FreeSync over HDMI FRL did not work. It is
backward-compatible with 2.0 FreeSync.
how:
- Accept SIGNAL_TYPE_HDMI_FRL alongside SIGNAL_TYPE_HDMI_TYPE_A when
parsing the AMD VSDB in amdgpu_dm_update_freesync_caps().
- Build and send the VTEM info packet via mod_build_infopacket_vtem()
when the stream signal is HDMI FRL during the freesync state update.
- Set the VTEM Data_Set_Length to 0 when no VTEM feature is enabled.
build_infopacket_header_vtem() hardcodes Data_Set_Length = 4, so a VTEM
with Data_Set_Length = 4 would be transmitted even when no VTEM feature
is enabled (VRR_EN = 0 and no FVA), e.g. when the sink advertises
VRRMIN = 0 and vrr_capable is false. This fails HDMI GCTS HF1-58 step
6.2.
The VTEM must keep being transmitted every MTW while VRR is enabled
(HF1-58 steps 8.1 and 8.3), so it cannot simply be suppressed per
frame. Instead, follow the MLDS option in HDMI 2.1 10.10.2.4: keep
transmitting the VTEM but set Data_Set_Length = 0 when no feature is
enabled. When VRR becomes active the full Data_Set_Length = 4 payload
with VRR_EN = 1 is sent as before.
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 4 +-
.../display/amdgpu_dm/amdgpu_dm_freesync.c | 4 +
.../amd/display/modules/inc/mod_info_packet.h | 4 +
.../display/modules/info_packet/info_packet.c | 109 ++++++++++++++++++
4 files changed, 120 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 2cc3734c992b..9eaa20ec528e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3838,7 +3838,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
}
- } else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
+ } else if (drm_edid &&
+ (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+ sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)) {
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
if (i >= 0) {
amdgpu_dm_connector->vsdb_info = vsdb_info;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
index 46674b83183c..035d7e88c3ed 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
@@ -37,6 +37,7 @@
#include "amdgpu_dm_freesync.h"
#include "dm_helpers.h"
#include "modules/inc/mod_freesync.h"
+#include "modules/inc/mod_info_packet.h"
bool amdgpu_dm_is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
struct dm_crtc_state *new_state)
@@ -229,6 +230,9 @@ void amdgpu_dm_update_freesync_state_on_stream(
&vrr_infopacket,
pack_sdp_v1_3);
+ if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)
+ mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket);
+
new_crtc_state->freesync_vrr_info_changed |=
(memcmp(&new_crtc_state->vrr_infopacket,
&vrr_infopacket,
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
index eee8206bc531..5181d889fe7f 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
@@ -67,6 +67,10 @@ struct AS_Df_params {
struct frame_duration_op decrease;
};
+void mod_build_infopacket_vtem(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr, int fva_factor,
+ struct dc_info_packet *infopacket);
+
void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
enum adaptive_sync_type asType, const struct AS_Df_params *param,
struct dc_info_packet *info_packet);
diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
index f5ac4bf32a78..32b697f46788 100644
--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
@@ -291,6 +291,21 @@ void set_vsc_packet_colorimetry_data(
info_packet->sb[18] = 0;
}
+static void set_field_with_mask(unsigned char *dest, unsigned int mask, unsigned int value)
+{
+ unsigned int shift = 0;
+
+ if (!mask || !dest)
+ return;
+
+ while (!((mask >> shift) & 1))
+ shift++;
+
+ *dest = *dest & ~mask;
+ value = value & (mask >> shift);
+ *dest = *dest | (value << shift);
+}
+
void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet,
enum dc_color_space cs,
@@ -644,6 +659,100 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
info_packet->valid = true;
}
+static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr, int fva_factor,
+ struct dc_info_packet *infopacket)
+{
+ unsigned int field_rate_in_hz;
+
+ /* FVA Factor setting */
+ set_field_with_mask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__FVA_FACTOR_M1,
+ (fva_factor > 0) ? (fva_factor - 1) : 0);
+ /* VRR Parameters */
+ if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
+ vrr->state == VRR_STATE_ACTIVE_FIXED) {
+ set_field_with_mask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__VRR_EN, 1);
+ } else {
+ set_field_with_mask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__VRR_EN, 0);
+ }
+
+ if (vrr->state == VRR_STATE_ACTIVE_FIXED)
+ set_field_with_mask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__M_CONST, vrr->m_const);
+
+ if (!stream->timing.vic) {
+ set_field_with_mask(&infopacket->sb[VTEM_MD1], MASK_VTEM_MD1__BASE_VFRONT,
+ stream->timing.v_front_porch);
+
+
+ /* TODO: In dal2, we check mode flags for a reduced blanking timing.
+ * Need a way to relay that information to this function.
+ * if("ReducedBlanking")
+ * {
+ * set_field_with_mask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__RB, 1;
+ * }
+ */
+
+ field_rate_in_hz = stream->timing.pix_clk_100hz * 100;
+ field_rate_in_hz /= stream->timing.h_total;
+ field_rate_in_hz = (field_rate_in_hz + stream->timing.v_total / 2)
+ / stream->timing.v_total;
+
+ set_field_with_mask(&infopacket->sb[VTEM_MD2], MASK_VTEM_MD2__BASE_REFRESH_RATE_98,
+ field_rate_in_hz >> 8);
+ set_field_with_mask(&infopacket->sb[VTEM_MD3], MASK_VTEM_MD3__BASE_REFRESH_RATE_07,
+ field_rate_in_hz);
+
+ }
+
+ /*
+ * When no VTEM feature is enabled (neither VRR nor FVA), signal a
+ * zero-length data set (MLDS) by clearing Data_Set_Length. HDMI 2.1
+ * 10.10.2.4 requires the Source to either stop transmitting the VTEM
+ * or set Data_Set_Length = 0 when no feature is enabled; keeping the
+ * VTEM with Data_Set_Length = 0 preserves the every-MTW cadence while
+ * staying compliant (e.g. HDMI GCTS HF1-58 step 6.2).
+ */
+ if (vrr->state != VRR_STATE_ACTIVE_VARIABLE &&
+ vrr->state != VRR_STATE_ACTIVE_FIXED && fva_factor == 0)
+ set_field_with_mask(&infopacket->sb[VTEM_PB6],
+ MASK_VTEM_PB6__DATA_SET_LENGTH_LSB, 0);
+
+ infopacket->valid = true;
+}
+
+static void build_infopacket_header_vtem(enum signal_type signal,
+ struct dc_info_packet *infopacket)
+{
+ /* HEADER */
+
+ /* HB0, HB1, HB2 indicates PacketType VTEMPacket */
+ infopacket->hb0 = 0x7F;
+ infopacket->hb1 = 0xC0;
+ infopacket->hb2 = 0x00; /* sequence_index */
+
+ set_field_with_mask(&infopacket->sb[VTEM_PB0], MASK_VTEM_PB0__VFR, 1);
+ set_field_with_mask(&infopacket->sb[VTEM_PB2], MASK_VTEM_PB2__ORGANIZATION_ID, 1);
+ set_field_with_mask(&infopacket->sb[VTEM_PB3], MASK_VTEM_PB3__DATA_SET_TAG_MSB, 0);
+ set_field_with_mask(&infopacket->sb[VTEM_PB4], MASK_VTEM_PB4__DATA_SET_TAG_LSB, 1);
+ set_field_with_mask(&infopacket->sb[VTEM_PB5], MASK_VTEM_PB5__DATA_SET_LENGTH_MSB, 0);
+ set_field_with_mask(&infopacket->sb[VTEM_PB6], MASK_VTEM_PB6__DATA_SET_LENGTH_LSB, 4);
+}
+
+void mod_build_infopacket_vtem(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr, int fva_factor,
+ struct dc_info_packet *infopacket)
+{
+ /* VTEM info packet for HdmiVrr */
+
+ memset(infopacket, 0, sizeof(struct dc_info_packet));
+
+ /* VTEM Packet is structured differently */
+ build_infopacket_header_vtem(stream->signal, infopacket);
+ build_vtem_infopacket_data(stream, vrr, fva_factor, infopacket);
+
+ infopacket->valid = true;
+}
+
void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
enum adaptive_sync_type asType,
const struct AS_Df_params *param,
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH v3 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB
2026-08-11 0:39 ` [PATCH v3 0/4] HDMI 2.1 VRR and " Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
@ 2026-08-11 0:39 ` Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
3 siblings, 0 replies; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-11 0:39 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, Harry Wentland, Tomasz Pakuła, Fangzhi Zuo,
Bernhard Berger
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Parse the HDMI 2.1 gaming-related capabilities advertised in the HDMI
Forum VSDB (HF-VSDB) and expose them through struct drm_hdmi_info so
drivers can consume them.
Add struct drm_hdmi_vrr_cap describing the sink's VRR capabilities: Fast
VActive (Quick Frame Transport), Negative M VRR, Cinema VRR, MDelta, and
the VRRmin/VRRmax range, together with a "supported" flag derived from
that range. Add the fapa_start_location and allm (Auto Low Latency Mode)
flags to struct drm_hdmi_info.
drm_parse_hdmi_gaming_info() reads byte 8 of the HF-VSDB for the
FAPA/ALLM/FVA/CNMVRR/CinemaVRR/MDelta flags and bytes 9-10 for
VRRmin/VRRmax. Per HDMI 2.1, VRR is considered supported when VRRmin is
within 1-48 and VRRmax is either 0 (maximum based on the video mode) or
>= 100. It is invoked from drm_parse_hdmi_forum_scds(), and the parsed
values are logged for debugging.
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Tested-by: Bernhard Berger <bernhard.berger@gmail.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
---
drivers/gpu/drm/drm_edid.c | 42 +++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 47 +++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index ae26618a9a57..d508ec633c9b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -6182,6 +6182,33 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector,
hdmi->y420_dc_modes = dc_mask;
}
+static void drm_parse_hdmi_gaming_info(struct drm_hdmi_info *hdmi, const u8 *db)
+{
+ struct drm_hdmi_vrr_cap *vrr = &hdmi->vrr_cap;
+
+ if (cea_db_payload_len(db) < 8)
+ return;
+
+ hdmi->fapa_start_location = db[8] & DRM_EDID_FAPA_START_LOCATION;
+ hdmi->allm = db[8] & DRM_EDID_ALLM;
+ vrr->fva = db[8] & DRM_EDID_FVA;
+ vrr->cnmvrr = db[8] & DRM_EDID_CNMVRR;
+ vrr->cinema_vrr = db[8] & DRM_EDID_CINEMA_VRR;
+ vrr->mdelta = db[8] & DRM_EDID_MDELTA;
+
+ if (cea_db_payload_len(db) < 9)
+ return;
+
+ vrr->vrr_min = db[9] & DRM_EDID_VRR_MIN_MASK;
+ vrr->supported = (vrr->vrr_min > 0 && vrr->vrr_min <= 48);
+
+ if (cea_db_payload_len(db) < 10)
+ return;
+
+ vrr->vrr_max = (db[9] & DRM_EDID_VRR_MAX_UPPER_MASK) << 2 | db[10];
+ vrr->supported &= (vrr->vrr_max == 0 || vrr->vrr_max >= 100);
+}
+
static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc,
const u8 *hf_scds)
{
@@ -6308,6 +6335,8 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
drm_parse_ycbcr420_deep_color_info(connector, hf_scds);
+ drm_parse_hdmi_gaming_info(&connector->display_info.hdmi, hf_scds);
+
if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) {
drm_parse_dsc_info(hdmi_dsc, hf_scds);
dsc_support = true;
@@ -6317,6 +6346,19 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
"[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n",
connector->base.id, connector->name,
max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support));
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] FAPA in blanking: %s, ALLM support: %s, Fast Vactive support: %s\n",
+ connector->base.id, connector->name, str_yes_no(hdmi->fapa_start_location),
+ str_yes_no(hdmi->allm), str_yes_no(hdmi->vrr_cap.fva));
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Negative M VRR support: %s, CinemaVRR support: %s, Mdelta: %d\n",
+ connector->base.id, connector->name, str_yes_no(hdmi->vrr_cap.cnmvrr),
+ str_yes_no(hdmi->vrr_cap.cinema_vrr), hdmi->vrr_cap.mdelta);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] VRRmin: %u, VRRmax: %u, VRR supported: %s\n",
+ connector->base.id, connector->name, hdmi->vrr_cap.vrr_min,
+ hdmi->vrr_cap.vrr_max, str_yes_no(hdmi->vrr_cap.supported));
+
}
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index cd06a3b914a0..9f8f109c2dd1 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -254,6 +254,44 @@ struct drm_scdc {
struct drm_scrambling scrambling;
};
+/**
+ * struct drm_hdmi_vrr_cap - Information about VRR capabilities of a HDMI sink
+ *
+ * Describes the VRR support provided by HDMI 2.1 sink. The information is
+ * fetched fom additional HFVSDB blocks defined for HDMI 2.1.
+ */
+struct drm_hdmi_vrr_cap {
+ /** @fva: flag for Fast VActive (Quick Frame Transport) support */
+ bool fva;
+
+ /** @mcnmvrr: flag for Negative M VRR support */
+ bool cnmvrr;
+
+ /** @mcinema_vrr: flag for Cinema VRR support */
+ bool cinema_vrr;
+
+ /** @mdelta: flag for limited frame-to-frame compensation support */
+ bool mdelta;
+
+ /**
+ * @vrr_min : minimum supported variable refresh rate in Hz.
+ * Valid values only inide 1 - 48 range
+ */
+ u16 vrr_min;
+
+ /**
+ * @vrr_max : maximum supported variable refresh rate in Hz (optional).
+ * Valid values are either 0 (max based on video mode) or >= 100
+ */
+ u16 vrr_max;
+
+ /**
+ * @supported: flag for vrr support based on checking for VRRmin and
+ * VRRmax values having correct values.
+ */
+ bool supported;
+};
+
/**
* struct drm_hdmi_dsc_cap - DSC capabilities of HDMI sink
*
@@ -330,6 +368,15 @@ struct drm_hdmi_info {
/** @max_lanes: supported by sink */
u8 max_lanes;
+ /** @fapa_start_location: flag for the FAPA in blanking support */
+ bool fapa_start_location;
+
+ /** @allm: flag for Auto Low Latency Mode support by sink */
+ bool allm;
+
+ /** @vrr_cap: VRR capabilities of the sink */
+ struct drm_hdmi_vrr_cap vrr_cap;
+
/** @dsc_cap: DSC capabilities of the sink */
struct drm_hdmi_dsc_cap dsc_cap;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH v3 3/4] drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB
2026-08-11 0:39 ` [PATCH v3 0/4] HDMI 2.1 VRR and " Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
@ 2026-08-11 0:39 ` Fangzhi Zuo
2026-08-11 0:39 ` [PATCH v3 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
3 siblings, 0 replies; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-11 0:39 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, Harry Wentland, Tomasz Pakuła, Fangzhi Zuo,
Fangzhi Zuo
why:
HDMI 2.1 sinks advertise their VRR range in the HDMI Forum VSDB
(HF-VSDB), but amdgpu derived FreeSync capability only from the AMD
VSDB. Sinks that expose just the HDMI Forum VRR capability (e.g. HDMI
compliance EDIDs) were therefore reported as not VRR capable.
how:
- In amdgpu_dm_update_freesync_caps(), when the AMD VSDB does not
provide a valid FreeSync range, fall back to the HDMI 2.1 VRR range
parsed by DRM core from the HF-VSDB
(connector->display_info.hdmi.vrr_cap). VRRMAX = 0 means "up to the
Base Refresh Rate"; when the EDID provides no monitor range maximum
either, fall back to the Base Refresh Rate (the highest refresh-rate
mode of the preferred timing) so a valid VRR range is still reported
to userspace.
- Add VRR debug logging along the FreeSync capability and config paths.
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 67 +++++++++++++++++++
.../display/amdgpu_dm/amdgpu_dm_freesync.c | 8 +++
2 files changed, 75 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 9eaa20ec528e..2fe7bfb1e88f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3812,6 +3812,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version))
goto update;
+ drm_dbg_driver(adev_to_drm(adev),
+ "VRR: enter signal=%d hdmi_vrr=%d mrange[%d-%d] hdmi.vrr_cap[sup=%d min=%d max=%d]\n",
+ sink->sink_signal, connector->display_info.hdmi.vrr_cap.supported,
+ connector->display_info.monitor_range.min_vfreq,
+ connector->display_info.monitor_range.max_vfreq,
+ connector->display_info.hdmi.vrr_cap.supported,
+ connector->display_info.hdmi.vrr_cap.vrr_min,
+ connector->display_info.hdmi.vrr_cap.vrr_max);
+
/* FIXME: Get rid of drm_edid_raw() */
edid = drm_edid_raw(drm_edid);
@@ -3856,6 +3865,59 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
}
}
+
+ drm_dbg_driver(adev_to_drm(adev),
+ "VRR: amd_vsdb i=%d fs_sup=%d min=%d max=%d fs_capable=%d\n",
+ i, vsdb_info.freesync_supported,
+ vsdb_info.min_refresh_rate_hz,
+ vsdb_info.max_refresh_rate_hz, freesync_capable);
+
+ /*
+ * If AMD VSDB didn't provide a valid FreeSync range, fall back to
+ * the HDMI 2.1 VRR capability parsed from the HF-VSDB.
+ */
+ if (!freesync_capable && connector->display_info.hdmi.vrr_cap.supported) {
+ struct drm_hdmi_vrr_cap *vrr_cap =
+ &connector->display_info.hdmi.vrr_cap;
+
+ drm_dbg_driver(adev_to_drm(adev),
+ "VRR: HF-VSDB fallback: hdmi_vrr=1 vrr_cap[sup=%d min=%d max=%d] mrange_max=%d\n",
+ vrr_cap->supported, vrr_cap->vrr_min, vrr_cap->vrr_max,
+ connector->display_info.monitor_range.max_vfreq);
+
+ if (vrr_cap->supported && vrr_cap->vrr_min > 0) {
+ amdgpu_dm_connector->min_vfreq = vrr_cap->vrr_min;
+ amdgpu_dm_connector->max_vfreq = vrr_cap->vrr_max ?
+ vrr_cap->vrr_max :
+ connector->display_info.monitor_range.max_vfreq;
+
+ /*
+ * VRRMAX = 0 in the HF-VSDB means "up to the Base
+ * Refresh Rate". If the EDID also did not provide a
+ * monitor range max, fall back to the Base Refresh
+ * Rate (the highest refresh rate of the preferred
+ * timing) so a valid VRR range is still reported to
+ * userspace.
+ */
+ if (!amdgpu_dm_connector->max_vfreq) {
+ struct drm_display_mode *brr_mode =
+ amdgpu_dm_get_highest_refresh_rate_mode(amdgpu_dm_connector, true);
+
+ if (brr_mode)
+ amdgpu_dm_connector->max_vfreq =
+ drm_mode_vrefresh(brr_mode);
+ }
+
+ if (amdgpu_dm_connector->max_vfreq -
+ amdgpu_dm_connector->min_vfreq > 10)
+ freesync_capable = true;
+
+ connector->display_info.monitor_range.min_vfreq =
+ amdgpu_dm_connector->min_vfreq;
+ connector->display_info.monitor_range.max_vfreq =
+ amdgpu_dm_connector->max_vfreq;
+ }
+ }
}
if (amdgpu_dm_connector->dc_link)
@@ -3911,6 +3973,11 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (dm_con_state)
dm_con_state->freesync_capable = freesync_capable;
+ drm_dbg_driver(adev_to_drm(adev),
+ "VRR: caps result: freesync_capable=%d min_vfreq=%d max_vfreq=%d\n",
+ freesync_capable, amdgpu_dm_connector->min_vfreq,
+ amdgpu_dm_connector->max_vfreq);
+
if (connector->state && amdgpu_dm_connector->dc_link && !freesync_capable &&
amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported) {
amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported = false;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
index 035d7e88c3ed..382c339b67b1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
@@ -152,6 +152,14 @@ void amdgpu_dm_get_freesync_config_for_crtc(
}
out:
new_crtc_state->freesync_config = config;
+
+ drm_dbg_driver(new_con_state->base.connector->dev,
+ "VRR: cfg vrr_enabled=%d vrr_supported=%d fs_capable=%d vrefresh=%d min=%d max=%d state=%d\n",
+ new_crtc_state->base.vrr_enabled,
+ new_crtc_state->vrr_supported,
+ new_con_state->freesync_capable, vrefresh,
+ aconnector->min_vfreq, aconnector->max_vfreq,
+ config.state);
}
EXPORT_IF_KUNIT(amdgpu_dm_get_freesync_config_for_crtc);
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH v3 4/4] drm/amd/display: Add HDMI ALLM support
2026-08-11 0:39 ` [PATCH v3 0/4] HDMI 2.1 VRR and " Fangzhi Zuo
` (2 preceding siblings ...)
2026-08-11 0:39 ` [PATCH v3 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
@ 2026-08-11 0:39 ` Fangzhi Zuo
2026-08-11 13:48 ` Derek Foreman
3 siblings, 1 reply; 26+ messages in thread
From: Fangzhi Zuo @ 2026-08-11 0:39 UTC (permalink / raw)
To: amd-gfx
Cc: dri-devel, Harry Wentland, Tomasz Pakuła, Fangzhi Zuo,
Fangzhi Zuo
why:
HDMI 2.1 Auto Low-Latency Mode (ALLM) lets a Source request the Sink's
low-latency mode through the HF-VSIF. amdgpu never set ALLM_Mode in the
HF-VSIF, so ALLM was never signalled to the sink.
how:
- In create_stream_for_sink(), build the HF-VSIF with ALLM_Mode set when
the sink advertises ALLM (connector->display_info.hdmi.allm, parsed by
DRM core from the HF-VSDB) and the content type is Game (content-type =
Game is how userspace requests low-latency mode, HDMI GCTS HF1-56).
- In update_freesync_state_on_stream(), also set ALLM_Mode when
Gaming-VRR is active (VRR_EN=1, HDMI GCTS HF1-58 step 8.3.1), and push
the updated HF-VSIF (vsp_infopacket) as a stream update.
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++-
.../display/amdgpu_dm/amdgpu_dm_connector.c | 18 +++++++++--
.../display/amdgpu_dm/amdgpu_dm_freesync.c | 31 +++++++++++++++++++
3 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 567bf04979ee..ff0db0cb9880 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4029,9 +4029,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
}
if (acrtc_state->stream) {
- if (acrtc_state->freesync_vrr_info_changed)
+ if (acrtc_state->freesync_vrr_info_changed) {
bundle->stream_update.vrr_infopacket =
&acrtc_state->stream->vrr_infopacket;
+ bundle->stream_update.vsp_infopacket =
+ &acrtc_state->stream->vsp_infopacket;
+ }
}
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 2fe7bfb1e88f..953b2a470734 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1572,8 +1572,22 @@ create_stream_for_sink(struct drm_connector *connector,
update_stream_signal(stream, sink);
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- stream->signal == SIGNAL_TYPE_HDMI_FRL)
- mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
+ stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+ /*
+ * Enable HDMI ALLM (Auto Low-Latency Mode) when the sink
+ * advertises ALLM in the SCDS and the content type is Game.
+ * Setting content-type = Game is how userspace requests the
+ * Sink's low-latency mode (HDMI GCTS HF1-56).
+ */
+ bool allm = connector->display_info.hdmi.allm &&
+ stream->content_type == DISPLAY_CONTENT_TYPE_GAME;
+
+ drm_dbg_driver(dev,
+ "ALLM: set mode: sink_allm=%d content_type=%d -> ALLM_Mode=%d\n",
+ connector->display_info.hdmi.allm, stream->content_type, allm);
+
+ mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, allm, allm);
+ }
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
index 382c339b67b1..0fa72c77415e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
@@ -252,6 +252,37 @@ void amdgpu_dm_update_freesync_state_on_stream(
new_stream->vrr_infopacket = vrr_infopacket;
new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
+ /*
+ * HDMI ALLM: transmit the HF-VSIF with ALLM_Mode=1 when the sink
+ * advertises ALLM in the SCDS and either the content type is Game
+ * (HF1-56) or Gaming-VRR is active (VRR_EN=1, HF1-58 step 8.3.1).
+ * HDMI 2.1 7.6.6.
+ */
+ if (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+ new_stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+ struct dc_info_packet vsp_infopacket = {0};
+ bool sink_allm = aconn && aconn->base.display_info.hdmi.allm;
+ bool allm = sink_allm &&
+ (new_stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
+ vrr_params.state == VRR_STATE_ACTIVE_VARIABLE ||
+ vrr_params.state == VRR_STATE_ACTIVE_FIXED);
+ bool allm_changed;
+
+ mod_build_hf_vsif_infopacket(new_stream, &vsp_infopacket, allm, allm);
+
+ allm_changed = memcmp(&new_stream->vsp_infopacket, &vsp_infopacket,
+ sizeof(vsp_infopacket)) != 0;
+ new_crtc_state->freesync_vrr_info_changed |= allm_changed;
+ new_stream->vsp_infopacket = vsp_infopacket;
+
+ if (allm_changed)
+ drm_dbg_driver(adev_to_drm(adev),
+ "ALLM: flip on crtc=%u: sink_allm=%d content_type=%d vrr_state=%d -> ALLM_Mode=%d\n",
+ new_crtc_state->base.crtc->base.id,
+ sink_allm,
+ new_stream->content_type, vrr_params.state, allm);
+ }
+
if (new_crtc_state->freesync_vrr_info_changed)
drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
new_crtc_state->base.crtc->base.id,
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v3 4/4] drm/amd/display: Add HDMI ALLM support
2026-08-11 0:39 ` [PATCH v3 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
@ 2026-08-11 13:48 ` Derek Foreman
2026-08-11 15:23 ` Daniel Stone
0 siblings, 1 reply; 26+ messages in thread
From: Derek Foreman @ 2026-08-11 13:48 UTC (permalink / raw)
To: Fangzhi Zuo, amd-gfx; +Cc: dri-devel, Harry Wentland, Tomasz Pakuła
On 8/10/26 7:39 PM, Fangzhi Zuo wrote:
> why:
> HDMI 2.1 Auto Low-Latency Mode (ALLM) lets a Source request the Sink's
> low-latency mode through the HF-VSIF. amdgpu never set ALLM_Mode in the
> HF-VSIF, so ALLM was never signalled to the sink.
>
> how:
> - In create_stream_for_sink(), build the HF-VSIF with ALLM_Mode set when
> the sink advertises ALLM (connector->display_info.hdmi.allm, parsed by
> DRM core from the HF-VSDB) and the content type is Game (content-type =
> Game is how userspace requests low-latency mode, HDMI GCTS HF1-56).
> - In update_freesync_state_on_stream(), also set ALLM_Mode when
> Gaming-VRR is active (VRR_EN=1, HDMI GCTS HF1-58 step 8.3.1), and push
> the updated HF-VSIF (vsp_infopacket) as a stream update.
>
> Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
> Reviewed-by: Harry Wentland <harry.wentland@amd.com>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++-
> .../display/amdgpu_dm/amdgpu_dm_connector.c | 18 +++++++++--
> .../display/amdgpu_dm/amdgpu_dm_freesync.c | 31 +++++++++++++++++++
> 3 files changed, 51 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index 567bf04979ee..ff0db0cb9880 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -4029,9 +4029,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
> }
>
> if (acrtc_state->stream) {
> - if (acrtc_state->freesync_vrr_info_changed)
> + if (acrtc_state->freesync_vrr_info_changed) {
> bundle->stream_update.vrr_infopacket =
> &acrtc_state->stream->vrr_infopacket;
> + bundle->stream_update.vsp_infopacket =
> + &acrtc_state->stream->vsp_infopacket;
> + }
> }
> }
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index 2fe7bfb1e88f..953b2a470734 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> @@ -1572,8 +1572,22 @@ create_stream_for_sink(struct drm_connector *connector,
> update_stream_signal(stream, sink);
>
> if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
> - stream->signal == SIGNAL_TYPE_HDMI_FRL)
> - mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
> + stream->signal == SIGNAL_TYPE_HDMI_FRL) {
> + /*
> + * Enable HDMI ALLM (Auto Low-Latency Mode) when the sink
> + * advertises ALLM in the SCDS and the content type is Game.
> + * Setting content-type = Game is how userspace requests the
> + * Sink's low-latency mode (HDMI GCTS HF1-56).
> + */
> + bool allm = connector->display_info.hdmi.allm &&
> + stream->content_type == DISPLAY_CONTENT_TYPE_GAME;
> +
> + drm_dbg_driver(dev,
> + "ALLM: set mode: sink_allm=%d content_type=%d -> ALLM_Mode=%d\n",
> + connector->display_info.hdmi.allm, stream->content_type, allm);
> +
> + mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, allm, allm);
> + }
>
> if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
> stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> index 382c339b67b1..0fa72c77415e 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
> @@ -252,6 +252,37 @@ void amdgpu_dm_update_freesync_state_on_stream(
> new_stream->vrr_infopacket = vrr_infopacket;
> new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
>
> + /*
> + * HDMI ALLM: transmit the HF-VSIF with ALLM_Mode=1 when the sink
> + * advertises ALLM in the SCDS and either the content type is Game
> + * (HF1-56) or Gaming-VRR is active (VRR_EN=1, HF1-58 step 8.3.1).
> + * HDMI 2.1 7.6.6.
> + */
Tying this to Gaming-VRR seems potentially surprising. Gaming-VRR
doesn't mean we're playing a game. We might be using it to play back
judder free video (where we'd like ALLM off to preserve the sink's image
enhancement), or we might be at the desktop.
I'd imagine some users would still want their sink to use all the image
enhancements they saw in the showroom even when playing a game, so I'm
not sure any kind of "auto" decision making in the kernel makes sense at
all, even based on content type. It's a very subjective trade-off.
To me, this seems like something a compositor would want control of with
a simple boolean property.
Thanks,
Derek
> + if (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
> + new_stream->signal == SIGNAL_TYPE_HDMI_FRL) {
> + struct dc_info_packet vsp_infopacket = {0};
> + bool sink_allm = aconn && aconn->base.display_info.hdmi.allm;
> + bool allm = sink_allm &&
> + (new_stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
> + vrr_params.state == VRR_STATE_ACTIVE_VARIABLE ||
> + vrr_params.state == VRR_STATE_ACTIVE_FIXED);
> + bool allm_changed;
> +
> + mod_build_hf_vsif_infopacket(new_stream, &vsp_infopacket, allm, allm);
> +
> + allm_changed = memcmp(&new_stream->vsp_infopacket, &vsp_infopacket,
> + sizeof(vsp_infopacket)) != 0;
> + new_crtc_state->freesync_vrr_info_changed |= allm_changed;
> + new_stream->vsp_infopacket = vsp_infopacket;
> +
> + if (allm_changed)
> + drm_dbg_driver(adev_to_drm(adev),
> + "ALLM: flip on crtc=%u: sink_allm=%d content_type=%d vrr_state=%d -> ALLM_Mode=%d\n",
> + new_crtc_state->base.crtc->base.id,
> + sink_allm,
> + new_stream->content_type, vrr_params.state, allm);
> + }
> +
> if (new_crtc_state->freesync_vrr_info_changed)
> drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
> new_crtc_state->base.crtc->base.id,
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v3 4/4] drm/amd/display: Add HDMI ALLM support
2026-08-11 13:48 ` Derek Foreman
@ 2026-08-11 15:23 ` Daniel Stone
0 siblings, 0 replies; 26+ messages in thread
From: Daniel Stone @ 2026-08-11 15:23 UTC (permalink / raw)
To: Derek Foreman
Cc: Fangzhi Zuo, amd-gfx, dri-devel, Harry Wentland,
Tomasz Pakuła
Hi,
On Tue, 11 Aug 2026 at 14:54, Derek Foreman <derek.foreman@collabora.com> wrote:
> On 8/10/26 7:39 PM, Fangzhi Zuo wrote:
> > + /*
> > + * Enable HDMI ALLM (Auto Low-Latency Mode) when the sink
> > + * advertises ALLM in the SCDS and the content type is Game.
> > + * Setting content-type = Game is how userspace requests the
> > + * Sink's low-latency mode (HDMI GCTS HF1-56).
> > + */
Is it mandatory for the source to set ALLM when the sink advertises
ALLM support, and content-type == game?
Is it allowable for the source to set ALLM when the sink advertises
ALLM support, and content-type != game?
> > + /*
> > + * HDMI ALLM: transmit the HF-VSIF with ALLM_Mode=1 when the sink
> > + * advertises ALLM in the SCDS and either the content type is Game
> > + * (HF1-56) or Gaming-VRR is active (VRR_EN=1, HF1-58 step 8.3.1).
> > + * HDMI 2.1 7.6.6.
> > + */
Is it mandatory for the source to set ALLM when the sink advertises
ALLM support, and game-VRR is active?
Is it allowable for the source to set ALLM when the sink advertises
ALLM support, and non-game-VRR is active?
> Tying this to Gaming-VRR seems potentially surprising. Gaming-VRR
> doesn't mean we're playing a game. We might be using it to play back
> judder free video (where we'd like ALLM off to preserve the sink's image
> enhancement), or we might be at the desktop.
>
> I'd imagine some users would still want their sink to use all the image
> enhancements they saw in the showroom even when playing a game, so I'm
> not sure any kind of "auto" decision making in the kernel makes sense at
> all, even based on content type. It's a very subjective trade-off.
>
> To me, this seems like something a compositor would want control of with
> a simple boolean property.
I strongly agree. I really don't want to see more magic implicit
semantics unless they're completely necessary for some reason.
Someone passed on second-hand that one of the reasons to do this was
to make it easier to support X11 - however, if X11 needs better ALLM
control, then it can be exposed as a connector property via RandR,
just like content-type.
Cheers,
Daniel
^ permalink raw reply [flat|nested] 26+ messages in thread