* [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block
@ 2026-07-30 17:17 Fangzhi Zuo
2026-07-30 17:17 ` [PATCH 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
` (4 more replies)
0 siblings, 5 replies; 24+ messages in thread
From: Fangzhi Zuo @ 2026-07-30 17:17 UTC (permalink / raw)
To: amd-gfx, harry.wentland; +Cc: 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>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +
.../display/amdgpu_dm/amdgpu_dm_connector.c | 4 +-
.../amd/display/modules/inc/mod_info_packet.h | 4 +
.../display/modules/info_packet/info_packet.c | 109 ++++++++++++++++++
4 files changed, 119 insertions(+), 1 deletion(-)
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 5a9afc0607b2..ccf882a22a57 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3881,6 +3881,9 @@ static void 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/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 5e3dfeaed76b..2deb5abae264 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
@@ -3631,7 +3631,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/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] 24+ messages in thread
* [PATCH 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB
2026-07-30 17:17 [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
@ 2026-07-30 17:17 ` Fangzhi Zuo
2026-07-31 19:55 ` Harry Wentland
2026-07-30 17:17 ` [PATCH 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
` (3 subsequent siblings)
4 siblings, 1 reply; 24+ messages in thread
From: Fangzhi Zuo @ 2026-07-30 17:17 UTC (permalink / raw)
To: amd-gfx, harry.wentland; +Cc: 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: Fangzhi Zuo <Jerry.Zuo@amd.com>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.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 a9d480981c8f..7f810b08a091 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 745cd917fe40..61ea6e866ea0 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] 24+ messages in thread
* [PATCH 3/4] drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB
2026-07-30 17:17 [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
2026-07-30 17:17 ` [PATCH 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
@ 2026-07-30 17:17 ` Fangzhi Zuo
2026-07-31 19:57 ` Harry Wentland
2026-07-30 17:17 ` [PATCH 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
` (2 subsequent siblings)
4 siblings, 1 reply; 24+ messages in thread
From: Fangzhi Zuo @ 2026-07-30 17:17 UTC (permalink / raw)
To: amd-gfx, harry.wentland; +Cc: 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>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 +++
.../display/amdgpu_dm/amdgpu_dm_connector.c | 67 +++++++++++++++++++
2 files changed, 75 insertions(+)
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 ccf882a22a57..223b562f7005 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -5781,6 +5781,14 @@ STATIC_IFN_KUNIT void 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(get_freesync_config_for_crtc);
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 2deb5abae264..ebead39939a6 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
@@ -3605,6 +3605,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);
@@ -3649,6 +3658,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)
@@ -3692,6 +3754,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;
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 4/4] drm/amd/display: Add HDMI ALLM support
2026-07-30 17:17 [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
2026-07-30 17:17 ` [PATCH 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
2026-07-30 17:17 ` [PATCH 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
@ 2026-07-30 17:17 ` Fangzhi Zuo
2026-07-31 20:11 ` Harry Wentland
2026-07-31 19:37 ` [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Harry Wentland
2026-08-06 20:54 ` [PATCH v2 0/4] HDMI 2.1 VRR and ALLM support Fangzhi Zuo
4 siblings, 1 reply; 24+ messages in thread
From: Fangzhi Zuo @ 2026-07-30 17:17 UTC (permalink / raw)
To: amd-gfx, harry.wentland; +Cc: 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:
- Add an allm capability flag to struct dc_edid_caps and populate it in
dm_helpers_parse_edid_caps() from the HF-VSDB ALLM bit parsed by DRM
core (connector->display_info.hdmi.allm).
- In create_stream_for_sink(), build the HF-VSIF with ALLM_Mode set when
the sink advertises ALLM 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 | 35 ++++++++++++++++++-
.../display/amdgpu_dm/amdgpu_dm_connector.c | 18 ++++++++--
.../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 5 ++-
drivers/gpu/drm/amd/display/dc/dc_types.h | 3 ++
4 files changed, 57 insertions(+), 4 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 223b562f7005..fc3005ecc681 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3895,6 +3895,36 @@ static void 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 allm = new_stream->sink->edid_caps.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,
+ new_stream->sink->edid_caps.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,
@@ -4429,9 +4459,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *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 ebead39939a6..430f1628ced0 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
@@ -1511,8 +1511,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 = sink->edid_caps.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",
+ sink->edid_caps.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_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 42f5673acb4d..e69ce0a1b4b4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -197,7 +197,10 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->display_name,
AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
- edid_caps->edid_hdmi = connector->display_info.is_hdmi;
+ if (connector->display_info.is_hdmi) {
+ edid_caps->edid_hdmi = true;
+ edid_caps->allm = connector->display_info.hdmi.allm;
+ }
if (edid_caps->edid_hdmi) {
populate_hdmi_info_from_connector(link->dc->config.enable_frl, &connector->display_info.hdmi, edid_caps);
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index 3edeb94fba23..ae409cc59ae4 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -226,6 +226,9 @@ struct dc_edid_caps {
/*HDMI 2.0 caps*/
bool lte_340mcsc_scramble;
+ /* HDMI 2.1 caps */
+ bool allm;
+
bool edid_hdmi;
bool hdr_supported;
bool rr_capable;
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block
2026-07-30 17:17 [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
` (2 preceding siblings ...)
2026-07-30 17:17 ` [PATCH 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
@ 2026-07-31 19:37 ` Harry Wentland
2026-08-06 20:54 ` [PATCH v2 0/4] HDMI 2.1 VRR and ALLM support Fangzhi Zuo
4 siblings, 0 replies; 24+ messages in thread
From: Harry Wentland @ 2026-07-31 19:37 UTC (permalink / raw)
To: Fangzhi Zuo, amd-gfx
On 2026-07-30 13:17, Fangzhi Zuo wrote:
> 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>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +
> .../display/amdgpu_dm/amdgpu_dm_connector.c | 4 +-
> .../amd/display/modules/inc/mod_info_packet.h | 4 +
> .../display/modules/info_packet/info_packet.c | 109 ++++++++++++++++++
> 4 files changed, 119 insertions(+), 1 deletion(-)
>
> 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 5a9afc0607b2..ccf882a22a57 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -3881,6 +3881,9 @@ static void 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/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index 5e3dfeaed76b..2deb5abae264 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
> @@ -3631,7 +3631,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/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)
Don't use camel-case. We should rename it to set_field_with_mask(...).
> +{
> + 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;
Same here: field_rate_in_hz
> +
> + /* FVA Factor setting */
> + setFieldWithMask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__FVA_FACTOR_M1,
> + (fva_factor > 0)?(fva_factor-1):0);
Formatting. There should be whitespace around the `?`, `-`, and `:`.
> + /* VRR Parameters */
> + if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
> + vrr->state == VRR_STATE_ACTIVE_FIXED) {
Formatting. The vrr->state on the second line should align with
the vrr->state on the prior line.
> + 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
Formatting: convert these C++-style comments to C-style.
> + 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
> +
C++-style comment
> + memset(infopacket, 0, sizeof(struct dc_info_packet));
> +
> + //VTEM Packet is structured differently
C++-style comment
Happy to have all these style comments fixed separately in an amd-dal commit
or a new asdn commit.
Either way, this is
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Harry
> + 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,
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB
2026-07-30 17:17 ` [PATCH 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
@ 2026-07-31 19:55 ` Harry Wentland
0 siblings, 0 replies; 24+ messages in thread
From: Harry Wentland @ 2026-07-31 19:55 UTC (permalink / raw)
To: Fangzhi Zuo, amd-gfx; +Cc: Tomasz Pakuła, Bernhard Berger
This is a core DRM patch and needs to be sent to dri-devel in
addition to amd-gfx.
On 2026-07-30 13:17, Fangzhi Zuo wrote:
> 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: Fangzhi Zuo <Jerry.Zuo@amd.com>
> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> Tested-by: Bernhard Berger <bernhard.berger@gmail.com>
I didn't look at the HDMI spec myself, so can't vouch for the
correctness of the parser, but everything looks sane to me.
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Harry
> ---
> 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 a9d480981c8f..7f810b08a091 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 745cd917fe40..61ea6e866ea0 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;
> };
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 3/4] drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB
2026-07-30 17:17 ` [PATCH 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
@ 2026-07-31 19:57 ` Harry Wentland
2026-08-06 20:17 ` Zuo, Jerry
0 siblings, 1 reply; 24+ messages in thread
From: Harry Wentland @ 2026-07-31 19:57 UTC (permalink / raw)
To: Fangzhi Zuo, amd-gfx
On 2026-07-30 13:17, Fangzhi Zuo wrote:
> 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>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 +++
> .../display/amdgpu_dm/amdgpu_dm_connector.c | 67 +++++++++++++++++++
> 2 files changed, 75 insertions(+)
>
> 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 ccf882a22a57..223b562f7005 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -5781,6 +5781,14 @@ STATIC_IFN_KUNIT void 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(get_freesync_config_for_crtc);
>
> 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 2deb5abae264..ebead39939a6 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
> @@ -3605,6 +3605,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);
>
> @@ -3649,6 +3658,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 =
Should this be `vrr_mode`?
With that fixed this is
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Harry
> + 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)
> @@ -3692,6 +3754,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;
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 4/4] drm/amd/display: Add HDMI ALLM support
2026-07-30 17:17 ` [PATCH 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
@ 2026-07-31 20:11 ` Harry Wentland
2026-08-06 20:20 ` Zuo, Jerry
0 siblings, 1 reply; 24+ messages in thread
From: Harry Wentland @ 2026-07-31 20:11 UTC (permalink / raw)
To: Fangzhi Zuo, amd-gfx
On 2026-07-30 13:17, 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:
> - Add an allm capability flag to struct dc_edid_caps and populate it in
> dm_helpers_parse_edid_caps() from the HF-VSDB ALLM bit parsed by DRM
> core (connector->display_info.hdmi.allm).
> - In create_stream_for_sink(), build the HF-VSIF with ALLM_Mode set when
> the sink advertises ALLM 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 | 35 ++++++++++++++++++-
> .../display/amdgpu_dm/amdgpu_dm_connector.c | 18 ++++++++--
> .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 5 ++-
> drivers/gpu/drm/amd/display/dc/dc_types.h | 3 ++
> 4 files changed, 57 insertions(+), 4 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 223b562f7005..fc3005ecc681 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -3895,6 +3895,36 @@ static void 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 allm = new_stream->sink->edid_caps.allm &&
We have an `aconn` in this function above, so we can simply get the allm
bit from the connector:
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);
Then we don't need to add a new allm bool to edid_caps.
Harry
> + (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,
> + new_stream->sink->edid_caps.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,
> @@ -4429,9 +4459,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *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 ebead39939a6..430f1628ced0 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
> @@ -1511,8 +1511,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 = sink->edid_caps.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",
> + sink->edid_caps.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_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> index 42f5673acb4d..e69ce0a1b4b4 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> @@ -197,7 +197,10 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
> edid_caps->display_name,
> AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
>
> - edid_caps->edid_hdmi = connector->display_info.is_hdmi;
> + if (connector->display_info.is_hdmi) {
> + edid_caps->edid_hdmi = true;
> + edid_caps->allm = connector->display_info.hdmi.allm;
> + }
>
> if (edid_caps->edid_hdmi) {
> populate_hdmi_info_from_connector(link->dc->config.enable_frl, &connector->display_info.hdmi, edid_caps);
> diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
> index 3edeb94fba23..ae409cc59ae4 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc_types.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
> @@ -226,6 +226,9 @@ struct dc_edid_caps {
> /*HDMI 2.0 caps*/
> bool lte_340mcsc_scramble;
>
> + /* HDMI 2.1 caps */
> + bool allm;
> +
> bool edid_hdmi;
> bool hdr_supported;
> bool rr_capable;
^ permalink raw reply [flat|nested] 24+ messages in thread
* RE: [PATCH 3/4] drm/amd/display: Add HDMI 2.1 VRR support from HF-VSDB
2026-07-31 19:57 ` Harry Wentland
@ 2026-08-06 20:17 ` Zuo, Jerry
0 siblings, 0 replies; 24+ messages in thread
From: Zuo, Jerry @ 2026-08-06 20:17 UTC (permalink / raw)
To: Wentland, Harry, amd-gfx@lists.freedesktop.org
AMD General
> -----Original Message-----
> From: Wentland, Harry <Harry.Wentland@amd.com>
> Sent: Friday, July 31, 2026 15:57
> To: Zuo, Jerry <Jerry.Zuo@amd.com>; amd-gfx@lists.freedesktop.org
> Subject: Re: [PATCH 3/4] drm/amd/display: Add HDMI 2.1 VRR support from
> HF-VSDB
>
>
>
> On 2026-07-30 13:17, Fangzhi Zuo wrote:
> > 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>
> > ---
> > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 +++
> > .../display/amdgpu_dm/amdgpu_dm_connector.c | 67
> +++++++++++++++++++
> > 2 files changed, 75 insertions(+)
> >
> > 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 ccf882a22a57..223b562f7005 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > @@ -5781,6 +5781,14 @@ STATIC_IFN_KUNIT void
> 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(get_freesync_config_for_crtc);
> >
> > 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 2deb5abae264..ebead39939a6 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
> > @@ -3605,6 +3605,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);
> >
> > @@ -3649,6 +3658,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
> =
>
> Should this be `vrr_mode`?
>
> With that fixed this is
> Reviewed-by: Harry Wentland <harry.wentland@amd.com>
>
> Harry
It stands for "Base Refresh Rate". So it is the right phrase here.
>
> > +
> amdgpu_dm_get_highest_refresh_rate_mode(amdgpu_dm_connect
> or,
> > +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)
> > @@ -3692,6 +3754,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;
^ permalink raw reply [flat|nested] 24+ messages in thread
* RE: [PATCH 4/4] drm/amd/display: Add HDMI ALLM support
2026-07-31 20:11 ` Harry Wentland
@ 2026-08-06 20:20 ` Zuo, Jerry
0 siblings, 0 replies; 24+ messages in thread
From: Zuo, Jerry @ 2026-08-06 20:20 UTC (permalink / raw)
To: Wentland, Harry, amd-gfx@lists.freedesktop.org
AMD General
> -----Original Message-----
> From: Wentland, Harry <Harry.Wentland@amd.com>
> Sent: Friday, July 31, 2026 16:11
> To: Zuo, Jerry <Jerry.Zuo@amd.com>; amd-gfx@lists.freedesktop.org
> Subject: Re: [PATCH 4/4] drm/amd/display: Add HDMI ALLM support
>
>
>
> On 2026-07-30 13:17, 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:
> > - Add an allm capability flag to struct dc_edid_caps and populate it in
> > dm_helpers_parse_edid_caps() from the HF-VSDB ALLM bit parsed by
> DRM
> > core (connector->display_info.hdmi.allm).
> > - In create_stream_for_sink(), build the HF-VSIF with ALLM_Mode set when
> > the sink advertises ALLM 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 | 35
> ++++++++++++++++++-
> > .../display/amdgpu_dm/amdgpu_dm_connector.c | 18 ++++++++--
> > .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 5 ++-
> > drivers/gpu/drm/amd/display/dc/dc_types.h | 3 ++
> > 4 files changed, 57 insertions(+), 4 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 223b562f7005..fc3005ecc681 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > @@ -3895,6 +3895,36 @@ static void 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 allm = new_stream->sink->edid_caps.allm &&
>
> We have an `aconn` in this function above, so we can simply get the allm bit
> from the connector:
>
> 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);
>
> Then we don't need to add a new allm bool to edid_caps.
>
> Harry
>
Noted. Will be changed in v2.
> > + (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,
> > + new_stream->sink->edid_caps.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,
> > @@ -4429,9 +4459,12 @@ static void amdgpu_dm_commit_planes(struct
> drm_atomic_state *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 ebead39939a6..430f1628ced0 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
> > @@ -1511,8 +1511,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 = sink->edid_caps.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",
> > + sink->edid_caps.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_helpers.c
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> > index 42f5673acb4d..e69ce0a1b4b4 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> > @@ -197,7 +197,10 @@ enum dc_edid_status
> dm_helpers_parse_edid_caps(
> > edid_caps->display_name,
> >
> AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
> >
> > - edid_caps->edid_hdmi = connector->display_info.is_hdmi;
> > + if (connector->display_info.is_hdmi) {
> > + edid_caps->edid_hdmi = true;
> > + edid_caps->allm = connector->display_info.hdmi.allm;
> > + }
> >
> > if (edid_caps->edid_hdmi) {
> > populate_hdmi_info_from_connector(link->dc-
> >config.enable_frl,
> > &connector->display_info.hdmi, edid_caps); diff --git
> > a/drivers/gpu/drm/amd/display/dc/dc_types.h
> > b/drivers/gpu/drm/amd/display/dc/dc_types.h
> > index 3edeb94fba23..ae409cc59ae4 100644
> > --- a/drivers/gpu/drm/amd/display/dc/dc_types.h
> > +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
> > @@ -226,6 +226,9 @@ struct dc_edid_caps {
> > /*HDMI 2.0 caps*/
> > bool lte_340mcsc_scramble;
> >
> > + /* HDMI 2.1 caps */
> > + bool allm;
> > +
> > bool edid_hdmi;
> > bool hdr_supported;
> > bool rr_capable;
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 0/4] HDMI 2.1 VRR and ALLM support
2026-07-30 17:17 [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
` (3 preceding siblings ...)
2026-07-31 19:37 ` [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Harry Wentland
@ 2026-08-06 20:54 ` 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
` (4 more replies)
4 siblings, 5 replies; 24+ messages in thread
From: Fangzhi Zuo @ 2026-08-06 20:54 UTC (permalink / raw)
To: amd-gfx; +Cc: dri-devel, 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/
Changes in v2:
- Read HF-VSDB caps directly from connector->display_info.hdmi.vrr_cap
and .allm instead of mirroring redundant fva/hdmi_vrr/allm flags into
struct dc_edid_caps.
- VRRMAX=0 now falls back to the Base Refresh Rate (highest refresh-rate
mode of the preferred timing) instead of a hardcoded 240 Hz.
- Rebased onto amd-staging-drm-next; the FreeSync code now lives in
amdgpu_dm_freesync.c.
- Reordered Signed-off-by on the drm/edid patch (author first).
- Reworded commit messages.
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: c4f76bf5e107bcda6e496f1c4060c55af091fa79
--
2.53.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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; 24+ 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] 24+ 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
3 siblings, 0 replies; 24+ 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] 24+ messages in thread
end of thread, other threads:[~2026-08-11 0:38 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 17:17 [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Fangzhi Zuo
2026-07-30 17:17 ` [PATCH 2/4] drm/edid: parse HDMI 2.1 gaming (ALLM/VRR) capabilities from HF-VSDB Fangzhi Zuo
2026-07-31 19:55 ` Harry Wentland
2026-07-30 17:17 ` [PATCH 3/4] drm/amd/display: Add HDMI 2.1 VRR support " Fangzhi Zuo
2026-07-31 19:57 ` Harry Wentland
2026-08-06 20:17 ` Zuo, Jerry
2026-07-30 17:17 ` [PATCH 4/4] drm/amd/display: Add HDMI ALLM support Fangzhi Zuo
2026-07-31 20:11 ` Harry Wentland
2026-08-06 20:20 ` Zuo, Jerry
2026-07-31 19:37 ` [PATCH 1/4] drm/amd/display: Add 2.1 FreeSync support for AMD VSDB EDID Block Harry Wentland
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 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
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
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
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 ` [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
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.