mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features
@ 2026-02-03 18:56 Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 01/19] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
                   ` (19 more replies)
  0 siblings, 20 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

This patch series tackles a few things:
- Fixes VRR not detected if monitor uses GTF flag for ranges
  instead of Range Limits Only
- Detects if AMD vsdb carries a wider VRR range and uses it instead
- DP->HDMI PCON changes which includes a module property to override
  PCON ID check
- Parses HDMI gaming features in generic drm
- Reintroduces proper HF-VSIF and VTEM info packets
- Adds support for Auto Low Latency Mode
- Adds support for HDMI VRR

VRR range fixes are simple and fix VRR support for many monitors. They
close about 5 issues on the amdgpu issue tracker.

Adaptive Sync over PCON is only available as FreeSync over HDMI. TVs which
do not support FreeSync, do not have working VRR with DP -> HDMI 2.1
adapters even though adapters will take care of HDMI VRR info packets.

I myself validated these changes with my Samsung S95B + Bernhard validated
on LG C4 + FreeSync-less Sony Bravia 8. I used Alienware AW3423DWF that
only has HDMI 2.0 to check that FreeSync still triggers properly for
"older" hardware,

For missing VRRmax or VRRmax == 0, the upper boundary is the currently
selected video mode refresh rate. I wasn't sure how best to implement it
but ended up on a great solution. We first check if maybe there is a VRR
range in AMD vsdb. If not, rely on limitation of base refresh rate in
VTEM vsif.

More history on previous shape of HF-VSIF and VTEM in their respective
patches but the info packets were previously included in the driver code.
HF-VSIF was improperly handled and VTEM doesn't seem to have been plumbed
as it had no use before. I recoded these and this code should be much
easier to understand and maintain.

ALLM support uses the info from EDID to determine if ALLM is supported by
sink and if that's the case, always signals for ALLM to be enabled. In PC
use, be it for gaming, desktop use, work etc. we always want the lowest
latency and less processing + possibly higher available refresh rates when
gaming mode is turned on.

HDMI VRR support relies on sending VTEM info packet in place of FreeSync
info packets. Though VTEM has it's own place in the info packet pipeline,
I didn't touch it as it already replaces FreeSync info packets. If there's
a need to change this, please let me know for v2.

Both features were tested and work just like they were intended to. Gaming
mode is automatically triggered and HDMI VRR is used in place of FreeSync
(if available). This HDMI VRR preference actually fixes VRR-induced
flickering on many TVs (S95B in my case) with somehow subpar
FreeSync implementation.

I still think it's better to not force users to search for solutions
manually especially since it seems like DP and eDP don't save info about
FreeSync version and completely rely on basic VRR support.
This would then be mirrored.

There's still an issue with some TVs behaving like a mode change is
happening when VRR is triggered and I'd like to maybe tackle this too. When
using HDMI through PCON, VRR is always active, like it's in
VRR_STATE_ACTIVE_FIXED mode. This makes my TV much nicer to use and
replication this behavior would be worthwhile IMO.

Everything in this patch series has been based on already public
code/knowledge or trying things out until they work/break.

This patch series supersedes previous patches/series:
https://lore.kernel.org/amd-gfx/20251209231107.1968472-1-tomasz.pakula.oficjalny@gmail.com/
https://lore.kernel.org/amd-gfx/20260113214104.146856-1-tomasz.pakula.oficjalny@gmail.com/
https://lore.kernel.org/amd-gfx/20260113183540.86266-1-tomasz.pakula.oficjalny@gmail.com/

Built on top of amd-staging-drm-next

Changes in v2:
- Updated BRR max value to 1023 after testing one by one. This should've
  been obvious since 1023 is the max value for a 10-bit field
- Fixed some comments, to silence "not a kernel doc" warning
- Considered ALLM comments from Michel Dänzer, Daniel Stone and
  Jani Nikula. ALLM is now triggered if either VRR is active or Content
  Type Hint is set to "Game". Content type hint is already supported by
  amdgpu and fully plumbed.
- Added module parameter for controlling ALLM trigger behavior. Now it can
  be configured to never trigger ALLM, trigger with VRR/Game (default) or
  be always forced on.
- Added HDMI VRR desktop mode module parameter, which is on by default.
  This mimics how FreeSync is handeled on Windows and this fixes a lot of
  issues with unwanted screen blanking and glitches around entering/exiting
  VRR mode.
- Moved hdmi vic mode check to one central function to avoid checking for
  3D and ALLM in different places which could sometimes break the logic for
  translating HDMI VIC modes into CTA vic modes (when such translation 
  is needed).
  
Changes in v3:
- Fixed wonky English
- Less struct traversal in helper functions
- Fixed possible NULL pointer dereference while checking if ALLM support is
  indicated in edid_caps of local_sink
- Fixed ALLM bit assignment overriding 3D bit data in HF-VSIF
- Fixed assignment of the upper 2 bits of BRR in VTEM

Tomasz Pakuła (19):
  drm/amd/display: Return if DisplayID not found in parse_amd_vsdb()
  drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
  drm/amd/display: Check for VRR range in CEA AMD vsdb
  drm/amd/display: Use bigger VRR range if found in AMD vsdb
  drm/amd/display: Refactor PCON VRR compatibility check
  drm/amd/display: Add PCON VRR ID check override
  drm/amd/display: Add CH7218 PCON ID
  drm/edid: Parse more info from HDMI Forum vsdb
  drm/amd/display: Rename PCON adaptive sync types
  drm/amd/display: Enable HDMI VRR over PCON
  drm/amd/display: Support HDMI VRRmax=0
  drm/amd/display: Build HDMI vsif in correct slot
  drm/amd/display: Save HDMI gaming info to edid caps
  drm/amd/display: Restore ALLM support in HDMI vsif
  drm/amd/display: Trigger ALLM if it's available
  drm/amd/display: Add parameter to control ALLM behavior
  drm/amd/display: Reintroduce VTEM info frame
  drm/amd/display: Enable HDMI VRR
  drm/amd/display: Add HDMI VRR desktop mode

 drivers/gpu/drm/amd/amdgpu/amdgpu.h           |   2 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c       |  27 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 207 ++++++++---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  49 ++-
 .../gpu/drm/amd/display/dc/core/dc_resource.c |   5 +-
 drivers/gpu/drm/amd/display/dc/dc.h           |   1 +
 drivers/gpu/drm/amd/display/dc/dc_types.h     |   7 +-
 drivers/gpu/drm/amd/display/dc/dm_helpers.h   |   2 +-
 .../amd/display/include/ddc_service_types.h   |   1 +
 .../amd/display/modules/freesync/freesync.c   |   4 +
 .../amd/display/modules/inc/mod_info_packet.h |  18 +-
 .../display/modules/info_packet/info_packet.c | 342 ++++++++++++------
 drivers/gpu/drm/amd/include/amd_shared.h      |   6 +
 drivers/gpu/drm/drm_edid.c                    |  41 ++-
 include/drm/drm_connector.h                   |  47 +++
 15 files changed, 559 insertions(+), 200 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 01/19] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb()
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 02/19] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
The function would continue to try to parse EDID even if DisplayID
extension block wasn't found. Sometimes it got lucky and found AMD vsdb
in CEA extension block which made debugging harder.

[How]
Add a return if DisplayID extension block wasn't found

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++
 1 file changed, 3 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 d8fac7e69181..29e4a047b455 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13136,6 +13136,9 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 			break;
 	}
 
+	if (i == edid->extensions)
+		return false;
+
 	while (j < EDID_LENGTH - sizeof(struct amd_vsdb_block)) {
 		struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j];
 		unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) | (amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]);
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 02/19] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 01/19] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-06 18:22   ` Harry Wentland
  2026-02-03 18:56 ` [PATCH v3 03/19] drm/amd/display: Check for VRR range in CEA AMD vsdb Tomasz Pakuła
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
This function started to get very messy and hard to follow.

[How]
Eject some functionality to separate functions and simplify greatly.

Changes in v3:
- Less struct traversal in helper functions

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 123 +++++++++++-------
 1 file changed, 73 insertions(+), 50 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 29e4a047b455..2c5877ed5f32 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13119,8 +13119,8 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
 	}
 }
 
-static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
-			  const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
+static int parse_amd_vsdb_did(struct amdgpu_dm_connector *aconnector,
+			      const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
 {
 	u8 *edid_ext = NULL;
 	int i;
@@ -13172,13 +13172,13 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 	return false;
 }
 
-static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
-			       const struct edid *edid,
-			       struct amdgpu_hdmi_vsdb_info *vsdb_info)
+static int parse_amd_vsdb_cea(struct amdgpu_dm_connector *aconnector,
+			      const struct edid *edid,
+			      struct amdgpu_hdmi_vsdb_info *vsdb_info)
 {
+	struct amdgpu_hdmi_vsdb_info vsdb_local = {0};
 	u8 *edid_ext = NULL;
 	int i;
-	bool valid_vsdb_found = false;
 
 	/*----- drm_find_cea_extension() -----*/
 	/* No EDID or EDID extensions */
@@ -13199,9 +13199,47 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 	if (edid_ext[0] != CEA_EXT)
 		return -ENODEV;
 
-	valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
+	if (!parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, &vsdb_local))
+		return -ENODEV;
 
-	return valid_vsdb_found ? i : -ENODEV;
+	*vsdb_info = vsdb_local;
+	return i;
+}
+
+static bool is_monitor_range_invalid(const struct drm_connector *conn)
+{
+	return conn->display_info.monitor_range.min_vfreq == 0 ||
+	       conn->display_info.monitor_range.max_vfreq == 0;
+}
+
+/*
+ * Returns true if (max_vfreq - min_vfreq) > 10
+ */
+static bool is_freesync_capable(const struct drm_monitor_range_info *range)
+{
+	return (range->max_vfreq - range->min_vfreq) > 10;
+}
+
+static void monitor_range_from_vsdb(struct drm_display_info *display,
+				    const struct amdgpu_hdmi_vsdb_info *vsdb)
+{
+	display->monitor_range.min_vfreq = vsdb->min_refresh_rate_hz;
+	display->monitor_range.max_vfreq = vsdb->max_refresh_rate_hz;
+}
+
+/*
+ * Returns true if connector is capable of freesync
+ * Optionally, can fetch the range from AMD vsdb
+ */
+static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
+{
+	struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
+	struct drm_monitor_range_info *range = &conn->display_info.monitor_range;
+
+	aconn->min_vfreq = range->min_vfreq;
+	aconn->max_vfreq = range->max_vfreq;
+
+	return is_freesync_capable(range);
 }
 
 /**
@@ -13218,13 +13256,14 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 				    const struct drm_edid *drm_edid)
 {
-	int i = 0;
 	struct amdgpu_dm_connector *amdgpu_dm_connector =
 			to_amdgpu_dm_connector(connector);
 	struct dm_connector_state *dm_con_state = NULL;
 	struct dc_sink *sink;
 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
 	struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
+	struct amdgpu_hdmi_vsdb_info vsdb_did = {0};
+	struct dpcd_caps dpcd_caps = {0};
 	const struct edid *edid;
 	bool freesync_capable = false;
 	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
@@ -13256,62 +13295,46 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 		goto update;
 
 	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
+	parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
+
+	if (amdgpu_dm_connector->dc_link)
+		dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
 
 	/* Some eDP panels only have the refresh rate range info in DisplayID */
-	if ((connector->display_info.monitor_range.min_vfreq == 0 ||
-	     connector->display_info.monitor_range.max_vfreq == 0))
+	if (is_monitor_range_invalid(connector))
 		parse_edid_displayid_vrr(connector, edid);
 
-	if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
-		     sink->sink_signal == SIGNAL_TYPE_EDP)) {
-		if (amdgpu_dm_connector->dc_link &&
-		    amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
-			amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
-			amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
-			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
-				freesync_capable = true;
-		}
+	if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
+	    sink->sink_signal == SIGNAL_TYPE_EDP) {
 
-		parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
+		if (dpcd_caps.allow_invalid_MSA_timing_param)
+			freesync_capable = copy_range_to_amdgpu_connector(connector);
 
-		if (vsdb_info.replay_mode) {
-			amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
-			amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version;
+		/* eDP */
+		if (edid)
+			parse_amd_vsdb_did(amdgpu_dm_connector, edid, &vsdb_did);
+
+		if (vsdb_did.replay_mode) {
+			amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_did.replay_mode;
+			amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_did.amd_vsdb_version;
 			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
 		}
 
-	} else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
-		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
-		if (i >= 0 && vsdb_info.freesync_supported) {
-			amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
-			amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
-			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
-				freesync_capable = true;
-
-			connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
-			connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
-		}
+	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_info.freesync_supported) {
+		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+		freesync_capable = copy_range_to_amdgpu_connector(connector);
 	}
 
 	if (amdgpu_dm_connector->dc_link)
 		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
 
-	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
-		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
-		if (i >= 0 && vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
+	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST && vsdb_info.freesync_supported) {
+		amdgpu_dm_connector->pack_sdp_v1_3 = true;
+		amdgpu_dm_connector->as_type = as_type;
+		amdgpu_dm_connector->vsdb_info = vsdb_info;
 
-			amdgpu_dm_connector->pack_sdp_v1_3 = true;
-			amdgpu_dm_connector->as_type = as_type;
-			amdgpu_dm_connector->vsdb_info = vsdb_info;
-
-			amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
-			amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
-			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
-				freesync_capable = true;
-
-			connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
-			connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
-		}
+		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+		freesync_capable = copy_range_to_amdgpu_connector(connector);
 	}
 
 update:
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 03/19] drm/amd/display: Check for VRR range in CEA AMD vsdb
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 01/19] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 02/19] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 04/19] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
Some monitors only expose GTF ranges (or others, without Range Limits
Only flag). This breaks VRR even though they have explicit FreeSync
support.

Currently, if monitor ranges were missing, amdgpu only searched for AMD
vsdb in DisplayID but many monitors have it in CEA, just like HDMI.

[How]
For DP and eDP connections, check for VRR ranges provided in AMD vendor-
specific data block if VRR range wasn't detected.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3894
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4457
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4747
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4856
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++++++
 1 file changed, 6 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 2c5877ed5f32..856007bba4d9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13306,6 +13306,12 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 
 	if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
 	    sink->sink_signal == SIGNAL_TYPE_EDP) {
+		/*
+		 * Many monitors expose AMD vsdb in CAE even for DP and their
+		 * monitor ranges do not contain Range Limits Only flag
+		 */
+		if (is_monitor_range_invalid(connector))
+			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
 
 		if (dpcd_caps.allow_invalid_MSA_timing_param)
 			freesync_capable = copy_range_to_amdgpu_connector(connector);
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 04/19] drm/amd/display: Use bigger VRR range if found in AMD vsdb
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (2 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 03/19] drm/amd/display: Check for VRR range in CEA AMD vsdb Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 05/19] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
Some monitors only expose their full VRR range in AMD vsdb for some
reason.

[How]
Compare exposed ranges and use the bigger one.

This check could be merged with the previous one but it's better to keep
them separate to easily convey their meaning.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4177
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c    | 16 ++++++++++++++++
 1 file changed, 16 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 856007bba4d9..284f5b326c18 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13242,6 +13242,18 @@ static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
 	return is_freesync_capable(range);
 }
 
+/*
+ * Returns true if range from AMD vsdb is bigger
+ */
+static bool compare_ranges(struct drm_connector *conn,
+			   struct amdgpu_hdmi_vsdb_info *vsdb)
+{
+	struct drm_monitor_range_info *range = &conn->display_info.monitor_range;
+
+	return (vsdb->max_refresh_rate_hz - vsdb->min_refresh_rate_hz) >
+	       (range->max_vfreq - range->min_vfreq);
+}
+
 /**
  * amdgpu_dm_update_freesync_caps - Update Freesync capabilities
  *
@@ -13313,6 +13325,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 		if (is_monitor_range_invalid(connector))
 			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
 
+		/* Use bigger range if found in AMD vsdb */
+		if (compare_ranges(connector, &vsdb_info))
+			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+
 		if (dpcd_caps.allow_invalid_MSA_timing_param)
 			freesync_capable = copy_range_to_amdgpu_connector(connector);
 
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 05/19] drm/amd/display: Refactor PCON VRR compatibility check
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (3 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 04/19] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-06 18:39   ` Harry Wentland
  2026-02-03 18:56 ` [PATCH v3 06/19] drm/amd/display: Add PCON VRR ID check override Tomasz Pakuła
                   ` (14 subsequent siblings)
  19 siblings, 1 reply; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
DP->HDMI PCONs prevously entered the DP path

[How]
Restructure amdgpu_dm_update_freesync_caps() and move
dm_get_adaptive_sync_support_type() to dm_helpers_is_vrr_pcon_allowed()
to better reflect what this function does. It never actually gave us any
other info.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 24 +++++++-----
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 39 ++++++-------------
 drivers/gpu/drm/amd/display/dc/dm_helpers.h   |  2 +-
 3 files changed, 27 insertions(+), 38 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 284f5b326c18..9346b62d981b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13278,7 +13278,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	struct dpcd_caps dpcd_caps = {0};
 	const struct edid *edid;
 	bool freesync_capable = false;
-	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
+	bool pcon_allowed = false;
+	bool is_pcon = false;
 
 	if (!connector->state) {
 		drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__);
@@ -13306,18 +13307,23 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version))
 		goto update;
 
+	/* Gather all data */
 	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
 	parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
 
-	if (amdgpu_dm_connector->dc_link)
+	if (amdgpu_dm_connector->dc_link) {
 		dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
+		is_pcon = dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+		pcon_allowed = dm_helpers_is_vrr_pcon_allowed(amdgpu_dm_connector->dc_link);
+	}
 
 	/* Some eDP panels only have the refresh rate range info in DisplayID */
 	if (is_monitor_range_invalid(connector))
 		parse_edid_displayid_vrr(connector, edid);
 
-	if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
-	    sink->sink_signal == SIGNAL_TYPE_EDP) {
+	/* DP & eDP excluding PCONs */
+	if ((sink->sink_signal == SIGNAL_TYPE_EDP ||
+	     sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) && !is_pcon) {
 		/*
 		 * Many monitors expose AMD vsdb in CAE even for DP and their
 		 * monitor ranges do not contain Range Limits Only flag
@@ -13342,17 +13348,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
 		}
 
+	/* HDMI */
 	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_info.freesync_supported) {
 		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
 		freesync_capable = copy_range_to_amdgpu_connector(connector);
-	}
 
-	if (amdgpu_dm_connector->dc_link)
-		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
-
-	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST && vsdb_info.freesync_supported) {
+	/* DP -> HDMI PCON */
+	} else if (pcon_allowed && vsdb_info.freesync_supported) {
+		amdgpu_dm_connector->as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
 		amdgpu_dm_connector->pack_sdp_v1_3 = true;
-		amdgpu_dm_connector->as_type = as_type;
 		amdgpu_dm_connector->vsdb_info = vsdb_info;
 
 		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
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 1f41d6540b83..45a91df619d9 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
@@ -1381,40 +1381,25 @@ void dm_helpers_dp_mst_update_branch_bandwidth(
 	// TODO
 }
 
-static bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id)
+bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link)
 {
-	bool ret_val = false;
+	if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER)
+		return false;
 
-	switch (branch_dev_id) {
+	if (!link->dpcd_caps.allow_invalid_MSA_timing_param)
+		return false;
+
+	if (!link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT)
+		return false;
+
+	switch (link->dpcd_caps.branch_dev_id) {
 	case DP_BRANCH_DEVICE_ID_0060AD:
 	case DP_BRANCH_DEVICE_ID_00E04C:
 	case DP_BRANCH_DEVICE_ID_90CC24:
-		ret_val = true;
-		break;
-	default:
-		break;
+		return true;
 	}
 
-	return ret_val;
-}
-
-enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link)
-{
-	struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
-	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
-
-	switch (dpcd_caps->dongle_type) {
-	case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
-		if (dpcd_caps->adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT == true &&
-			dpcd_caps->allow_invalid_MSA_timing_param == true &&
-			dm_is_freesync_pcon_whitelist(dpcd_caps->branch_dev_id))
-			as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
-		break;
-	default:
-		break;
-	}
-
-	return as_type;
+	return false;
 }
 
 bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state *stream)
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index 7014b8c2c956..e51f1e489129 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -220,10 +220,10 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
 		const struct dc_link *link,
 		struct set_config_cmd_payload *payload,
 		enum set_config_status *operation_result);
-enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link);
 
 enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid);
 
+bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link);
 bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state *stream);
 bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream);
 
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 06/19] drm/amd/display: Add PCON VRR ID check override
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (4 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 05/19] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 07/19] drm/amd/display: Add CH7218 PCON ID Tomasz Pakuła
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
It's currently very hard to test if a random PCON supports VRR and
report it's ID.

[How]
Adds override as part of dc debug mask. Allows faster testing and
reporting of VRR-compatible DP->HDMI adapters.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c         | 6 +++++-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +++++++-
 drivers/gpu/drm/amd/display/dc/dc.h                       | 1 +
 drivers/gpu/drm/amd/display/dc/dm_helpers.h               | 2 +-
 drivers/gpu/drm/amd/include/amd_shared.h                  | 6 ++++++
 5 files changed, 20 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 9346b62d981b..306c29ff38f0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2062,6 +2062,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
 	if (amdgpu_dc_debug_mask & DC_SKIP_DETECTION_LT)
 		adev->dm.dc->debug.skip_detection_link_training = true;
 
+	if (amdgpu_dc_debug_mask & DC_OVERRIDE_PCON_VRR_ID_CHECK)
+		adev->dm.dc->debug.override_pcon_vrr_id_check = true;
+
 	adev->dm.dc->debug.visual_confirm = amdgpu_dc_visual_confirm;
 
 	/* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */
@@ -13314,7 +13317,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	if (amdgpu_dm_connector->dc_link) {
 		dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
 		is_pcon = dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER;
-		pcon_allowed = dm_helpers_is_vrr_pcon_allowed(amdgpu_dm_connector->dc_link);
+		pcon_allowed = dm_helpers_is_vrr_pcon_allowed(
+			amdgpu_dm_connector->dc_link, connector->dev);
 	}
 
 	/* Some eDP panels only have the refresh rate range info in DisplayID */
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 45a91df619d9..cb8a2855ac10 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
@@ -1381,7 +1381,7 @@ void dm_helpers_dp_mst_update_branch_bandwidth(
 	// TODO
 }
 
-bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link)
+bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link, const struct drm_device *dev)
 {
 	if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER)
 		return false;
@@ -1399,6 +1399,12 @@ bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link)
 		return true;
 	}
 
+	if (link->dc->debug.override_pcon_vrr_id_check) {
+		drm_info(dev, "Overriding VRR PCON check for ID: 0x%06x\n",
+			 link->dpcd_caps.branch_dev_id);
+		return true;
+	}
+
 	return false;
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index ab19b6230945..7b22575ff638 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1057,6 +1057,7 @@ struct dc_debug_options {
 	bool scl_reset_length10;
 	bool hdmi20_disable;
 	bool skip_detection_link_training;
+	bool override_pcon_vrr_id_check;
 	uint32_t edid_read_retry_times;
 	unsigned int force_odm_combine; //bit vector based on otg inst
 	unsigned int seamless_boot_odm_combine;
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index e51f1e489129..5e77deb09200 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -223,7 +223,7 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
 
 enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid);
 
-bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link);
+bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link, const struct drm_device *dev);
 bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state *stream);
 bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream);
 
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index ac2d3701e2bd..894e1e738ce0 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -412,6 +412,12 @@ enum DC_DEBUG_MASK {
 	 * @DC_SKIP_DETECTION_LT: (0x200000) If set, skip detection link training
 	 */
 	DC_SKIP_DETECTION_LT = 0x200000,
+
+	/**
+	 * @DC_OVERRIDE_PCON_VRR_ID_CHECK: (0x400000) If set, always return true if checking for
+	 * PCON VRR compatibility and print it's ID in kernel log.
+	 */
+	DC_OVERRIDE_PCON_VRR_ID_CHECK = 0x400000,
 };
 
 enum amd_dpm_forced_level;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 07/19] drm/amd/display: Add CH7218 PCON ID
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (5 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 06/19] drm/amd/display: Add PCON VRR ID check override Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 08/19] drm/edid: Parse more info from HDMI Forum vsdb Tomasz Pakuła
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
Chrontel CH7218 found in Ugreen DP -> HDMI 2.1 adapter (model 85564)
works perfectly with VRR after testing. VRR and FreeSync compatibility
is explicitly advertised as a feature so it's addition is a formality.

Support FreeSync info packet passthrough and "generic" HDMI VRR.

[How]
Add CH7218's ID to dm_helpers_is_vrr_pcon_allowed()

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4773

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 1 +
 drivers/gpu/drm/amd/display/include/ddc_service_types.h   | 1 +
 2 files changed, 2 insertions(+)

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 cb8a2855ac10..690558584a0f 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
@@ -1396,6 +1396,7 @@ bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link, const struct drm
 	case DP_BRANCH_DEVICE_ID_0060AD:
 	case DP_BRANCH_DEVICE_ID_00E04C:
 	case DP_BRANCH_DEVICE_ID_90CC24:
+	case DP_BRANCH_DEVICE_ID_2B02F0:
 		return true;
 	}
 
diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
index 1c603b12957f..e838f7c1269c 100644
--- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
@@ -36,6 +36,7 @@
 #define DP_BRANCH_DEVICE_ID_006037 0x006037
 #define DP_BRANCH_DEVICE_ID_001CF8 0x001CF8
 #define DP_BRANCH_DEVICE_ID_0060AD 0x0060AD
+#define DP_BRANCH_DEVICE_ID_2B02F0 0x2B02F0 /* Chrontel CH7218 */
 #define DP_BRANCH_HW_REV_10 0x10
 #define DP_BRANCH_HW_REV_20 0x20
 
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 08/19] drm/edid: Parse more info from HDMI Forum vsdb
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (6 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 07/19] drm/amd/display: Add CH7218 PCON ID Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 09/19] drm/amd/display: Rename PCON adaptive sync types Tomasz Pakuła
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
Drivers may need info about gaming features exposed by HDMI sinks. Add
a central way of storing this information.

[How]
Adds flags and a struct to hold HDMI VRR information. `supported` here
is an additional property which allows easier parsing in consumers and
adds a bit of logic used to detect malformed VRRmin/VRRmax values.

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  | 41 +++++++++++++++++++++++++++++++-
 include/drm/drm_connector.h | 47 +++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 26bb7710a462..056eff8cbd1a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -6152,6 +6152,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)
 {
@@ -6277,7 +6304,7 @@ 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;
@@ -6287,6 +6314,18 @@ 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 8f34f4b8183d..dab9d5521f41 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.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 09/19] drm/amd/display: Rename PCON adaptive sync types
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (7 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 08/19] drm/edid: Parse more info from HDMI Forum vsdb Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 10/19] drm/amd/display: Enable HDMI VRR over PCON Tomasz Pakuła
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
PCONs support sending out HDMI VRR infopackets on their own and this
makes this types not specific to FreeSync

[How]
Make the name more generic for the upcoming HDMI VRR over PCON
implementation

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Tested-by: Bernhard Berger <bernhard.berger@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c      |  5 +++--
 .../gpu/drm/amd/display/modules/inc/mod_info_packet.h  | 10 +++++-----
 .../drm/amd/display/modules/info_packet/info_packet.c  |  4 ++--
 3 files changed, 10 insertions(+), 9 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 306c29ff38f0..92e571e687e9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9620,7 +9620,8 @@ static void update_freesync_state_on_stream(
 
 	aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context;
 
-	if (aconn && (aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST || aconn->vsdb_info.replay_mode)) {
+	if (aconn && (aconn->as_type == ADAPTIVE_SYNC_TYPE_PCON_ALLOWED ||
+		      aconn->vsdb_info.replay_mode)) {
 		pack_sdp_v1_3 = aconn->pack_sdp_v1_3;
 
 		if (aconn->vsdb_info.amd_vsdb_version == 1)
@@ -13359,7 +13360,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 
 	/* DP -> HDMI PCON */
 	} else if (pcon_allowed && vsdb_info.freesync_supported) {
-		amdgpu_dm_connector->as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
+		amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_PCON_ALLOWED;
 		amdgpu_dm_connector->pack_sdp_v1_3 = true;
 		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 ddd64b7e4c04..5de8a6918e6a 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
@@ -48,11 +48,11 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
 		struct dc_info_packet *info_packet);
 
 enum adaptive_sync_type {
-	ADAPTIVE_SYNC_TYPE_NONE                  = 0,
-	ADAPTIVE_SYNC_TYPE_DP                    = 1,
-	FREESYNC_TYPE_PCON_IN_WHITELIST          = 2,
-	FREESYNC_TYPE_PCON_NOT_IN_WHITELIST      = 3,
-	ADAPTIVE_SYNC_TYPE_EDP                   = 4,
+	ADAPTIVE_SYNC_TYPE_NONE             = 0,
+	ADAPTIVE_SYNC_TYPE_DP               = 1,
+	ADAPTIVE_SYNC_TYPE_PCON_ALLOWED     = 2,
+	ADAPTIVE_SYNC_TYPE_PCON_NOT_ALLOWED = 3,
+	ADAPTIVE_SYNC_TYPE_EDP              = 4,
 };
 
 enum adaptive_sync_sdp_version {
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 00473c6284d5..294f56d20062 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
@@ -590,7 +590,7 @@ void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
 		if (stream != NULL)
 			mod_build_adaptive_sync_infopacket_v2(stream, param, info_packet);
 		break;
-	case FREESYNC_TYPE_PCON_IN_WHITELIST:
+	case ADAPTIVE_SYNC_TYPE_PCON_ALLOWED:
 	case ADAPTIVE_SYNC_TYPE_EDP:
 		if (stream && stream->link->replay_settings.config.replay_supported &&
 			stream->link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY)
@@ -599,7 +599,7 @@ void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
 			mod_build_adaptive_sync_infopacket_v1(info_packet);
 		break;
 	case ADAPTIVE_SYNC_TYPE_NONE:
-	case FREESYNC_TYPE_PCON_NOT_IN_WHITELIST:
+	case ADAPTIVE_SYNC_TYPE_PCON_NOT_ALLOWED:
 	default:
 		break;
 	}
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 10/19] drm/amd/display: Enable HDMI VRR over PCON
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (8 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 09/19] drm/amd/display: Rename PCON adaptive sync types Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 11/19] drm/amd/display: Support HDMI VRRmax=0 Tomasz Pakuła
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
Not all TVs support FreeSync and many TVs suffer from VRR flickering
while Freesync is activated.

[How]
This works the same as FreeSync over PCON just without sending FreeSync
info packets (we're sending standard DisplayPort info packets) + reading
the VRR range from the HDMI Forum vendor specific data block. PCONs take
over HDMI VRR triggering.

Prefer HDMI VRR over FreeSync to reduce VRR flickering on many TVs.
FreeSync over HDMI seems to be a fallback solution and not a first-class
citizen. This especially helps VMM7100.

Tested with VMM7100 and CH7218 based adapters on multiple HDMI 2.1 and
HDMI 2.0 devices. (Samsung S95B, LG C4, Sony Bravia 8, Dell AW3423DWF)

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4805

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Tested-by: Bernhard Berger <bernhard.berger@gmail.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 28 +++++++++++++++----
 1 file changed, 23 insertions(+), 5 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 92e571e687e9..6fb23d59fcc9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13231,6 +13231,17 @@ static void monitor_range_from_vsdb(struct drm_display_info *display,
 	display->monitor_range.max_vfreq = vsdb->max_refresh_rate_hz;
 }
 
+/**
+ * Get VRR range from HDMI VRR info in EDID.
+ *
+ * @conn: drm_connector with HDMI VRR info
+ */
+static void monitor_range_from_hdmi(struct drm_display_info *display)
+{
+	display->monitor_range.min_vfreq = display->hdmi.vrr_cap.vrr_min;
+	display->monitor_range.max_vfreq = display->hdmi.vrr_cap.vrr_max;
+}
+
 /*
  * Returns true if connector is capable of freesync
  * Optionally, can fetch the range from AMD vsdb
@@ -13279,6 +13290,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
 	struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
 	struct amdgpu_hdmi_vsdb_info vsdb_did = {0};
+	struct drm_hdmi_vrr_cap hdmi_vrr = {0};
 	struct dpcd_caps dpcd_caps = {0};
 	const struct edid *edid;
 	bool freesync_capable = false;
@@ -13314,6 +13326,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	/* Gather all data */
 	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
 	parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
+	hdmi_vrr = connector->display_info.hdmi.vrr_cap;
 
 	if (amdgpu_dm_connector->dc_link) {
 		dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
@@ -13359,12 +13372,17 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 		freesync_capable = copy_range_to_amdgpu_connector(connector);
 
 	/* DP -> HDMI PCON */
-	} else if (pcon_allowed && vsdb_info.freesync_supported) {
-		amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_PCON_ALLOWED;
-		amdgpu_dm_connector->pack_sdp_v1_3 = true;
-		amdgpu_dm_connector->vsdb_info = vsdb_info;
+	} else if (pcon_allowed) {
+		/* Prefer HDMI VRR */
+		if (hdmi_vrr.supported && hdmi_vrr.vrr_max > 0)
+			monitor_range_from_hdmi(&connector->display_info);
+		else if (vsdb_info.freesync_supported) {
+			amdgpu_dm_connector->vsdb_info = vsdb_info;
+			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+		}
 
-		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+		amdgpu_dm_connector->pack_sdp_v1_3 = true;
+		amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_PCON_ALLOWED;
 		freesync_capable = copy_range_to_amdgpu_connector(connector);
 	}
 
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 11/19] drm/amd/display: Support HDMI VRRmax=0
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (9 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 10/19] drm/amd/display: Enable HDMI VRR over PCON Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 12/19] drm/amd/display: Build HDMI vsif in correct slot Tomasz Pakuła
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
VRRmax=0 is a valid value and means that the upper bound is guared by
the selected video mode.

[How]
In this context, saved vrr max is the max possible refresh rate ever.
Try getting upper VRR bound from AMD vsdbif it exists or rely on the
limitations of BRR in VTEM info frames.

I found through testing, that TVs seem to reject VTEM when BRR is set
to over 1023 Hz. Use this as the last resort VRRmax. 1023 is the max
value for a 10-bit field as well.

v2:
- Update max BRR value to 1023

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 +++++++++++++++----
 .../amd/display/modules/inc/mod_info_packet.h |  2 ++
 2 files changed, 20 insertions(+), 5 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 6fb23d59fcc9..2200161da71b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13232,14 +13232,27 @@ static void monitor_range_from_vsdb(struct drm_display_info *display,
 }
 
 /**
- * Get VRR range from HDMI VRR info in EDID.
+ * Get VRR range from HDMI VRR info in EDID. If VRRmax == 0,
+ * try getting upper bound from AMD vsdb.
  *
  * @conn: drm_connector with HDMI VRR info
+ * @vsdb: AMD vsdb from CAE
  */
-static void monitor_range_from_hdmi(struct drm_display_info *display)
+static void monitor_range_from_hdmi(struct drm_display_info *display,
+				    const struct amdgpu_hdmi_vsdb_info *vsdb)
 {
+	u16 vrr_max = display->hdmi.vrr_cap.vrr_max;
+
+	/* Try getting upper vrr bound from AMD vsdb */
+	if (vrr_max == 0)
+		vrr_max = vsdb->max_refresh_rate_hz;
+
+	/* Use max possible BRR value as a last resort */
+	if (vrr_max == 0)
+		vrr_max = VTEM_BRR_MAX;
+
 	display->monitor_range.min_vfreq = display->hdmi.vrr_cap.vrr_min;
-	display->monitor_range.max_vfreq = display->hdmi.vrr_cap.vrr_max;
+	display->monitor_range.max_vfreq = vrr_max;
 }
 
 /*
@@ -13374,8 +13387,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	/* DP -> HDMI PCON */
 	} else if (pcon_allowed) {
 		/* Prefer HDMI VRR */
-		if (hdmi_vrr.supported && hdmi_vrr.vrr_max > 0)
-			monitor_range_from_hdmi(&connector->display_info);
+		if (hdmi_vrr.supported)
+			monitor_range_from_hdmi(&connector->display_info, &vsdb_info);
 		else if (vsdb_info.freesync_supported) {
 			amdgpu_dm_connector->vsdb_info = vsdb_info;
 			monitor_range_from_vsdb(&connector->display_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 5de8a6918e6a..306eb7355c25 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
@@ -33,6 +33,8 @@ struct dc_stream_state;
 struct dc_info_packet;
 struct mod_vrr_params;
 
+#define VTEM_BRR_MAX 1023
+
 void set_vsc_packet_colorimetry_data(
 		const struct dc_stream_state *stream,
 		struct dc_info_packet *info_packet,
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 12/19] drm/amd/display: Build HDMI vsif in correct slot
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (10 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 11/19] drm/amd/display: Support HDMI VRRmax=0 Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 13/19] drm/amd/display: Save HDMI gaming info to edid caps Tomasz Pakuła
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
HDMI vsif was assigned to vsp_infopacket (FreeSync) field

[How]
Build HDMI vsif in the correct hfvsif_infopacket field

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
 1 file changed, 1 insertion(+), 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 2200161da71b..ab01a45aef1c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7383,7 +7383,7 @@ create_stream_for_sink(struct drm_connector *connector,
 	update_stream_signal(stream, sink);
 
 	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
-		mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket);
+		mod_build_hf_vsif_infopacket(stream, &stream->hfvsif_infopacket);
 
 	if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
 	    stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 13/19] drm/amd/display: Save HDMI gaming info to edid caps
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (11 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 12/19] drm/amd/display: Build HDMI vsif in correct slot Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 14/19] drm/amd/display: Restore ALLM support in HDMI vsif Tomasz Pakuła
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
We need info about these features in parts of the driver where fishing
for drm_connector struct is infeasible.

[How]
Add three new fields to dc_edid_caps and fill them if connected device
is HDMI based on it's EDID

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 7 ++++++-
 drivers/gpu/drm/amd/display/dc/dc_types.h                 | 7 ++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

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 690558584a0f..c24476182fdf 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
@@ -137,7 +137,12 @@ 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;
+		edid_caps->fva = connector->display_info.hdmi.vrr_cap.fva;
+		edid_caps->hdmi_vrr = connector->display_info.hdmi.vrr_cap.supported;
+	}
 
 	if (edid_caps->edid_hdmi)
 		populate_hdmi_info_from_connector(&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 0e953059ff6d..f9f108db1734 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -210,9 +210,14 @@ struct dc_edid_caps {
 
 	uint32_t max_tmds_clk_mhz;
 
-	/*HDMI 2.0 caps*/
+	/* HDMI 2.0 caps */
 	bool lte_340mcsc_scramble;
 
+	/* HDMI 2.1 caps */
+	bool allm;
+	bool fva;
+	bool hdmi_vrr;
+
 	bool edid_hdmi;
 	bool hdr_supported;
 	bool rr_capable;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 14/19] drm/amd/display: Restore ALLM support in HDMI vsif
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (12 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 13/19] drm/amd/display: Save HDMI gaming info to edid caps Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 15/19] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
Support for triggering ALLM in modern TVs is missing.

When HDMI vsif was added in 2019:
commit 3c2381b92cba ("drm/amd/display: add support for VSIP info packet")
it was improperly handeled as HDMI actually has two separate vsifs. The
implementation was based on H14b-vsif and ALLM bit was messing it up
because H14b-vsif doesn't support ALLM. It was later removed in:
commit 75f77aafe281 ("drm/amd/display: Send H14b-VSIF specified in HDMI")

ALLM is supported by hf-vsif (HDMI Forum) instead.

[How]
Add proper logic to construct either h14b-vsif or hf-vsif based on
required capabilities. Currently, only ALLM from hf-vsif is supported.

Turns out, hf-vsif is almost identical to h14b-vsif, BUT has additional
two bytes of data after OUI. First byte is static and seems like
a version supported by leftover define. Second byte consists of 3D and
ALLM bits.

Implement logic to offset 3D data if building hf-vsif.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 .../display/modules/info_packet/info_packet.c | 113 ++++++++++++------
 1 file changed, 74 insertions(+), 39 deletions(-)

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 294f56d20062..8e110c86bdd4 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
@@ -49,7 +49,10 @@ enum vsc_packet_revision {
 };
 
 #define HDMI_INFOFRAME_TYPE_VENDOR 0x81
-#define HF_VSIF_VERSION 1
+#define HDMI_INFOFRAME_LENGTH_MASK 0x1F
+#define HF_VSIF_VERSION  1
+#define HF_VSIF_3D_BIT   0
+#define HF_VSIF_ALLM_BIT 1
 
 // VTEM Byte Offset
 #define VTEM_PB0		0
@@ -496,9 +499,29 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
 	}
 }
 
+static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
+{
+	if (stream->timing.hdmi_vic == 0)
+		return false;
+
+	if (stream->timing.h_total < 3840 ||
+	    stream->timing.v_total < 2160)
+		return false;
+
+	/* 3D/ALLM forces HDMI VIC -> CTA VIC translation */
+	if (stream->view_format != VIEW_3D_FORMAT_NONE)
+		return false;
+
+	if (stream->link->local_sink->edid_caps.allm)
+		return false;
+
+	return true;
+}
+
 /**
  *  mod_build_hf_vsif_infopacket - Prepare HDMI Vendor Specific info frame.
  *                                 Follows HDMI Spec to build up Vendor Specific info frame
+ *                                 Conforms to h14b-vsif or hf-vsif based on the capabilities
  *
  *  @stream:      contains data we may need to construct VSIF (i.e. timing_3d_format, etc.)
  *  @info_packet: output structure where to store VSIF
@@ -506,63 +529,75 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
 void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
 		struct dc_info_packet *info_packet)
 {
-		unsigned int length = 5;
 		bool hdmi_vic_mode = false;
+		bool allm = false;
+		bool stereo = false;
 		uint8_t checksum = 0;
-		uint32_t i = 0;
+		uint8_t offset = 0;
+		uint8_t i = 0;
+		uint8_t length = 5;
+		uint32_t oui = HDMI_IEEE_OUI;
 		enum dc_timing_3d_format format;
 
 		info_packet->valid = false;
+
 		format = stream->timing.timing_3d_format;
 		if (stream->view_format == VIEW_3D_FORMAT_NONE)
 			format = TIMING_3D_FORMAT_NONE;
+		stereo = format != TIMING_3D_FORMAT_NONE;
+		hdmi_vic_mode = is_hdmi_vic_mode(stream);
 
-		if (stream->timing.hdmi_vic != 0
-				&& stream->timing.h_total >= 3840
-				&& stream->timing.v_total >= 2160
-				&& format == TIMING_3D_FORMAT_NONE)
-			hdmi_vic_mode = true;
-
-		if ((format == TIMING_3D_FORMAT_NONE) && !hdmi_vic_mode)
+		if (!stereo && !hdmi_vic_mode && !allm)
 			return;
 
-		info_packet->sb[1] = 0x03;
-		info_packet->sb[2] = 0x0C;
-		info_packet->sb[3] = 0x00;
+		if (allm)
+			oui = HDMI_FORUM_IEEE_OUI;
 
-		if (format != TIMING_3D_FORMAT_NONE)
-			info_packet->sb[4] = (2 << 5);
+		info_packet->sb[1] = oui & 0xFF;
+		info_packet->sb[2] = (oui >> 8) & 0xFF;
+		info_packet->sb[3] = (oui >> 16) & 0xFF;
 
-		else if (hdmi_vic_mode)
-			info_packet->sb[4] = (1 << 5);
-
-		switch (format) {
-		case TIMING_3D_FORMAT_HW_FRAME_PACKING:
-		case TIMING_3D_FORMAT_SW_FRAME_PACKING:
-			info_packet->sb[5] = (0x0 << 4);
-			break;
-
-		case TIMING_3D_FORMAT_SIDE_BY_SIDE:
-		case TIMING_3D_FORMAT_SBS_SW_PACKED:
-			info_packet->sb[5] = (0x8 << 4);
-			length = 6;
-			break;
-
-		case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
-		case TIMING_3D_FORMAT_TB_SW_PACKED:
-			info_packet->sb[5] = (0x6 << 4);
-			break;
-
-		default:
-			break;
+		if (oui == HDMI_FORUM_IEEE_OUI) {
+			offset = 2;
+			length += 2;
+			info_packet->sb[4] = HF_VSIF_VERSION;
+			info_packet->sb[5] = stereo << HF_VSIF_3D_BIT;
+			info_packet->sb[5] |= allm << HF_VSIF_ALLM_BIT;
 		}
 
-		if (hdmi_vic_mode)
+		if (stereo) {
+			info_packet->sb[4 + offset] = (2 << 5);
+
+			switch (format) {
+			case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+			case TIMING_3D_FORMAT_SW_FRAME_PACKING:
+				info_packet->sb[5 + offset] = (0x0 << 4);
+				break;
+
+			case TIMING_3D_FORMAT_SIDE_BY_SIDE:
+			case TIMING_3D_FORMAT_SBS_SW_PACKED:
+				info_packet->sb[5 + offset] = (0x8 << 4);
+				++length;
+				break;
+
+			case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
+			case TIMING_3D_FORMAT_TB_SW_PACKED:
+				info_packet->sb[5 + offset] = (0x6 << 4);
+				break;
+
+			default:
+				break;
+			}
+
+		/* Doesn't need the offset as it can't be used with hf-vsif */
+		} else if (hdmi_vic_mode) {
+			info_packet->sb[4] = (1 << 5);
 			info_packet->sb[5] = stream->timing.hdmi_vic;
+		}
 
 		info_packet->hb0 = HDMI_INFOFRAME_TYPE_VENDOR;
 		info_packet->hb1 = 0x01;
-		info_packet->hb2 = (uint8_t) (length);
+		info_packet->hb2 = length & HDMI_INFOFRAME_LENGTH_MASK;
 
 		checksum += info_packet->hb0;
 		checksum += info_packet->hb1;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 15/19] drm/amd/display: Trigger ALLM if it's available
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (13 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 14/19] drm/amd/display: Restore ALLM support in HDMI vsif Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior Tomasz Pakuła
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
ALLM automatically puts TVs into low latency modes (gaming modes) which
we basically always want for PC use, be it gaming, or using precise
inputs like mice and keyboards.

[How]
Read the ALLM info from HDMI caps and use it to determine if ALLM should
be indicated in HDMI Forum vsif. Additionally, make sure VIC modes are
translated in case of ALLM active as VIC cannot be used in conjunction
with hf-vsif. I learned this the hard way...

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc_resource.c          | 4 +++-
 .../gpu/drm/amd/display/modules/info_packet/info_packet.c  | 7 ++++---
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 848c267ef11e..4a7c9f810e35 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -4504,6 +4504,7 @@ static void set_avi_info_frame(
 	unsigned int rid = pipe_ctx->stream->timing.rid;
 	unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
 	enum dc_timing_3d_format format;
+	bool allm;
 
 	if (stream->avi_infopacket.valid) {
 		*info_packet = stream->avi_infopacket;
@@ -4658,8 +4659,9 @@ static void set_avi_info_frame(
 	if (pipe_ctx->stream->timing.hdmi_vic != 0)
 		vic = 0;
 	format = stream->timing.timing_3d_format;
+	allm = stream->link->local_sink->edid_caps.allm;
 	/*todo, add 3DStereo support*/
-	if (format != TIMING_3D_FORMAT_NONE) {
+	if ((format != TIMING_3D_FORMAT_NONE) || allm) {
 		// Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
 		switch (pipe_ctx->stream->timing.hdmi_vic) {
 		case 1:
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 8e110c86bdd4..53e488fdb4ea 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
@@ -541,9 +541,10 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
 
 		info_packet->valid = false;
 
-		format = stream->timing.timing_3d_format;
-		if (stream->view_format == VIEW_3D_FORMAT_NONE)
-			format = TIMING_3D_FORMAT_NONE;
+		allm = stream->link->local_sink->edid_caps.allm;
+		format = stream->view_format == VIEW_3D_FORMAT_NONE ?
+			 TIMING_3D_FORMAT_NONE :
+			 stream->timing.timing_3d_format;
 		stereo = format != TIMING_3D_FORMAT_NONE;
 		hdmi_vic_mode = is_hdmi_vic_mode(stream);
 
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (14 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 15/19] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-06 18:52   ` Harry Wentland
  2026-02-03 18:56 ` [PATCH v3 17/19] drm/amd/display: Reintroduce VTEM info frame Tomasz Pakuła
                   ` (3 subsequent siblings)
  19 siblings, 1 reply; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
Some users prefer to always manually control ALLM/Gaming mode while
others might want it permanently forced on.

[How]
Since there isn't yet an API to control this, expose module parameter

Changes in v3:
- Include a fix for possible NULL pointer dereference by Peter

Closes: https://github.com/CachyOS/linux-cachyos/issues/680

Co-developed-by: Peter Jung <admin@ptr1337.dev>
Signed-off-by: Peter Jung <admin@ptr1337.dev>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h           |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c       | 14 +++++-
 .../gpu/drm/amd/display/dc/core/dc_resource.c |  7 +--
 .../amd/display/modules/inc/mod_info_packet.h |  1 +
 .../display/modules/info_packet/info_packet.c | 46 ++++++++++++++++---
 5 files changed, 56 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 447e734c362b..312aa32064d5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -268,6 +268,7 @@ extern int amdgpu_rebar;
 
 extern int amdgpu_wbrf;
 extern int amdgpu_user_queue;
+extern uint amdgpu_allm_mode;
 
 extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index d6d0a6e34c6b..4b038c8bbf9f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -248,6 +248,7 @@ int amdgpu_umsch_mm_fwlog;
 int amdgpu_rebar = -1; /* auto */
 int amdgpu_user_queue = -1;
 uint amdgpu_hdmi_hpd_debounce_delay_ms;
+uint amdgpu_allm_mode = 1;
 
 DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
 			"DRM_UT_CORE",
@@ -1124,7 +1125,7 @@ module_param_named(rebar, amdgpu_rebar, int, 0444);
 MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disable, 1 = enable, 2 = enable UQs and disable KQs)");
 module_param_named(user_queue, amdgpu_user_queue, int, 0444);
 
-/*
+/**
  * DOC: hdmi_hpd_debounce_delay_ms (uint)
  * HDMI HPD disconnect debounce delay in milliseconds.
  *
@@ -1134,6 +1135,17 @@ module_param_named(user_queue, amdgpu_user_queue, int, 0444);
 MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
 module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
 
+/**
+ * DOC: allm_mode (int)
+ * Changes ALLM triggering mode (if sink supports ALLM). Possible values:
+ *
+ * - 0 = ALLM disabled
+ * - 1 = ALLM dynamically triggered based on VRR state / Game Content Type Hint
+ * - 2 = ALLM forced always on
+ */
+MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
+module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);
+
 /* These devices are not supported by amdgpu.
  * They are supported by the mach64, r128, radeon drivers
  */
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 4a7c9f810e35..b779aac28dfa 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -44,6 +44,7 @@
 #include "clk_mgr.h"
 #include "dc_state_priv.h"
 #include "dc_stream_priv.h"
+#include "modules/inc/mod_info_packet.h"
 
 #include "virtual/virtual_link_hwss.h"
 #include "link/hwss/link_hwss_dio.h"
@@ -4503,8 +4504,6 @@ static void set_avi_info_frame(
 	unsigned int vic = pipe_ctx->stream->timing.vic;
 	unsigned int rid = pipe_ctx->stream->timing.rid;
 	unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
-	enum dc_timing_3d_format format;
-	bool allm;
 
 	if (stream->avi_infopacket.valid) {
 		*info_packet = stream->avi_infopacket;
@@ -4658,10 +4657,8 @@ static void set_avi_info_frame(
 	///VIC
 	if (pipe_ctx->stream->timing.hdmi_vic != 0)
 		vic = 0;
-	format = stream->timing.timing_3d_format;
-	allm = stream->link->local_sink->edid_caps.allm;
 	/*todo, add 3DStereo support*/
-	if ((format != TIMING_3D_FORMAT_NONE) || allm) {
+	if (!is_hdmi_vic_mode(pipe_ctx->stream)) {
 		// Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
 		switch (pipe_ctx->stream->timing.hdmi_vic) {
 		case 1:
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 306eb7355c25..9ec123ecc7c4 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
@@ -41,6 +41,7 @@ void set_vsc_packet_colorimetry_data(
 		enum dc_color_space cs,
 		enum color_transfer_func tf);
 
+bool is_hdmi_vic_mode(const struct dc_stream_state *stream);
 void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
 		struct dc_info_packet *info_packet,
 		enum dc_color_space cs,
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 53e488fdb4ea..829cce9455db 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
@@ -23,12 +23,13 @@
  *
  */
 
-#include "mod_info_packet.h"
+#include "amdgpu.h"
 #include "core_types.h"
-#include "dc_types.h"
-#include "mod_shared.h"
-#include "mod_freesync.h"
 #include "dc.h"
+#include "dc_types.h"
+#include "mod_freesync.h"
+#include "mod_info_packet.h"
+#include "mod_shared.h"
 
 enum vsc_packet_revision {
 	vsc_packet_undefined = 0,
@@ -54,6 +55,12 @@ enum vsc_packet_revision {
 #define HF_VSIF_3D_BIT   0
 #define HF_VSIF_ALLM_BIT 1
 
+enum allm_trigger_mode {
+	ALLM_MODE_DISABLED        = 0,
+	ALLM_MODE_ENABLED_DYNAMIC = 1,
+	ALLM_MODE_ENABLED_FORCED  = 2,
+};
+
 // VTEM Byte Offset
 #define VTEM_PB0		0
 #define VTEM_PB1		1
@@ -499,7 +506,32 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
 	}
 }
 
-static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
+static bool is_hdmi_allm_mode(const struct dc_stream_state *stream)
+{
+	/* No local sink */
+	if (!stream->link->local_sink)
+		return false;
+
+	/* Sink doesn't expose ALLM support in edid */
+	if (!stream->link->local_sink->edid_caps.allm)
+		return false;
+
+	switch (amdgpu_allm_mode) {
+	case ALLM_MODE_DISABLED:
+		return false;
+
+	case ALLM_MODE_ENABLED_DYNAMIC:
+		break;
+
+	case ALLM_MODE_ENABLED_FORCED:
+		return true;
+	}
+
+	return stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
+	       stream->vrr_active_variable;
+}
+
+bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
 {
 	if (stream->timing.hdmi_vic == 0)
 		return false;
@@ -512,7 +544,7 @@ static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
 	if (stream->view_format != VIEW_3D_FORMAT_NONE)
 		return false;
 
-	if (stream->link->local_sink->edid_caps.allm)
+	if (is_hdmi_allm_mode(stream))
 		return false;
 
 	return true;
@@ -541,7 +573,7 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
 
 		info_packet->valid = false;
 
-		allm = stream->link->local_sink->edid_caps.allm;
+		allm = is_hdmi_allm_mode(stream);
 		format = stream->view_format == VIEW_3D_FORMAT_NONE ?
 			 TIMING_3D_FORMAT_NONE :
 			 stream->timing.timing_3d_format;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 17/19] drm/amd/display: Reintroduce VTEM info frame
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (15 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 18/19] drm/amd/display: Enable HDMI VRR Tomasz Pakuła
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
VTEM info fram building was removed back in: commit a9f54ce3c603
("drm/amd/display: Refactoring VTEM"), but it's needed to support
HDMI VRR signalling.

[How]
Build completely new and more robust functions to build out the VTEM
infopacket. Many values are defined but could have added logic in the
future, that's shy they are not static values but already value + bit
position in it's byte.

Reduced blanking detection was previously missing. Use possible hblank
periods defined for RB1 (from CVT 1.2), RB2 and RB3 (from CVT 2.1).

Changes in v3:
- Use div_u64() instead of division operator

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 .../amd/display/modules/inc/mod_info_packet.h |   4 +
 .../display/modules/info_packet/info_packet.c | 176 ++++++++++++------
 2 files changed, 119 insertions(+), 61 deletions(-)

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 9ec123ecc7c4..07e86b16ef77 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
@@ -50,6 +50,10 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
 void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
 		struct dc_info_packet *info_packet);
 
+void mod_build_vtem_infopacket(const struct dc_stream_state *stream,
+		const struct mod_vrr_params *vrr,
+		struct dc_info_packet *infopacket);
+
 enum adaptive_sync_type {
 	ADAPTIVE_SYNC_TYPE_NONE             = 0,
 	ADAPTIVE_SYNC_TYPE_DP               = 1,
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 829cce9455db..b08b52bba574 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
@@ -49,6 +49,7 @@ enum vsc_packet_revision {
 	vsc_packet_rev7 = 7,
 };
 
+#define HDMI_INFOFRAME_TYPE_EMP    0x7F
 #define HDMI_INFOFRAME_TYPE_VENDOR 0x81
 #define HDMI_INFOFRAME_LENGTH_MASK 0x1F
 #define HF_VSIF_VERSION  1
@@ -61,74 +62,52 @@ enum allm_trigger_mode {
 	ALLM_MODE_ENABLED_FORCED  = 2,
 };
 
-// VTEM Byte Offset
-#define VTEM_PB0		0
-#define VTEM_PB1		1
-#define VTEM_PB2		2
-#define VTEM_PB3		3
-#define VTEM_PB4		4
-#define VTEM_PB5		5
-#define VTEM_PB6		6
+#define VTEM_ORG_ID          1
+#define VTEM_DATA_SET_TAG    1
+#define VTEM_DATA_SET_LENGTH 4
 
-#define VTEM_MD0		7
-#define VTEM_MD1		8
-#define VTEM_MD2		9
-#define VTEM_MD3		10
+#define VTEM_M_CONST    0
+#define VTEM_FVA_FACTOR 0
 
+#define VTEM_BRR_MASK_UPPER 0x03
+#define VTEM_BRR_MASK_LOWER 0xFF
 
-// VTEM Byte Masks
-//PB0
-#define MASK_VTEM_PB0__RESERVED0  0x01
-#define MASK_VTEM_PB0__SYNC       0x02
-#define MASK_VTEM_PB0__VFR        0x04
-#define MASK_VTEM_PB0__AFR        0x08
-#define MASK_VTEM_PB0__DS_TYPE    0x30
-	//0: Periodic pseudo-static EM Data Set
-	//1: Periodic dynamic EM Data Set
-	//2: Unique EM Data Set
-	//3: Reserved
-#define MASK_VTEM_PB0__END        0x40
-#define MASK_VTEM_PB0__NEW        0x80
+/* VTEM Byte Offset */
+#define VTEM_PB0 0
+#define VTEM_PB1 1
+#define VTEM_PB2 2
+#define VTEM_PB3 3
+#define VTEM_PB4 4
+#define VTEM_PB5 5
+#define VTEM_PB6 6
 
-//PB1
-#define MASK_VTEM_PB1__RESERVED1 0xFF
+#define VTEM_MD0 7
+#define VTEM_MD1 8
+#define VTEM_MD2 9
+#define VTEM_MD3 10
 
-//PB2
-#define MASK_VTEM_PB2__ORGANIZATION_ID 0xFF
-	//0: This is a Vendor Specific EM Data Set
-	//1: This EM Data Set is defined by This Specification (HDMI 2.1 r102.clean)
-	//2: This EM Data Set is defined by CTA-861-G
-	//3: This EM Data Set is defined by VESA
-//PB3
-#define MASK_VTEM_PB3__DATA_SET_TAG_MSB    0xFF
-//PB4
-#define MASK_VTEM_PB4__DATA_SET_TAG_LSB    0xFF
-//PB5
-#define MASK_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF
-//PB6
-#define MASK_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF
+/* Extended Metadata Packet */
+/* Header */
+#define EMP_LAST_BIT  6
+#define EMP_FIRST_BIT 7
+/* PB0 */
+#define EMP_SNC_BIT 1
+#define EMP_VFR_BIT 2
+#define EMP_AFR_BIT 3
+#define EMP_DST_BIT 4
+#define EMP_END_BIT 6
+#define EMP_NEW_BIT 7
+/* PB7 = MD0 */
+#define VTEM_VRR_BIT     0
+#define VTEM_M_CONST_BIT 1
+#define VTEM_FVA_BIT     4
+/* MD1 Base_Vfront */
+/* MD2 */
+#define VTEM_BRR_UPPER_BIT 0
+#define VTEM_RB_BIT        2
+/* MD3 BRR Lower */
 
 
-
-//PB7-27 (20 bytes):
-//PB7 = MD0
-#define MASK_VTEM_MD0__VRR_EN         0x01
-#define MASK_VTEM_MD0__M_CONST        0x02
-#define MASK_VTEM_MD0__QMS_EN         0x04
-#define MASK_VTEM_MD0__RESERVED2      0x08
-#define MASK_VTEM_MD0__FVA_FACTOR_M1  0xF0
-
-//MD1
-#define MASK_VTEM_MD1__BASE_VFRONT    0xFF
-
-//MD2
-#define MASK_VTEM_MD2__BASE_REFRESH_RATE_98  0x03
-#define MASK_VTEM_MD2__RB                    0x04
-#define MASK_VTEM_MD2__NEXT_TFR              0xF8
-
-//MD3
-#define MASK_VTEM_MD3__BASE_REFRESH_RATE_07  0xFF
-
 enum ColorimetryRGBDP {
 	ColorimetryRGB_DP_sRGB               = 0,
 	ColorimetryRGB_DP_AdobeRGB           = 3,
@@ -644,6 +623,81 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
 		info_packet->valid = true;
 }
 
+static void build_vtem_infopacket_header(struct dc_info_packet *infopacket)
+{
+	uint8_t pb0 = 0;
+
+	/* might need logic in the future */
+	pb0 |= 0 << EMP_SNC_BIT;
+	pb0 |= 1 << EMP_VFR_BIT;
+	pb0 |= 0 << EMP_AFR_BIT;
+	pb0 |= 0 << EMP_DST_BIT;
+	pb0 |= 0 << EMP_END_BIT;
+	pb0 |= 1 << EMP_NEW_BIT;
+
+	infopacket->hb0 = HDMI_INFOFRAME_TYPE_EMP;
+	infopacket->hb1 = (1 << EMP_FIRST_BIT) | (1 << EMP_LAST_BIT);
+	infopacket->hb2 = 0; // sequence
+
+	infopacket->sb[VTEM_PB0] = pb0;
+	infopacket->sb[VTEM_PB2] = VTEM_ORG_ID;
+	infopacket->sb[VTEM_PB4] = VTEM_DATA_SET_TAG;
+	infopacket->sb[VTEM_PB6] = VTEM_DATA_SET_LENGTH;
+}
+
+static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
+		const struct mod_vrr_params *vrr,
+		struct dc_info_packet *infopacket)
+{
+	unsigned int hblank = 0;
+	unsigned int brr = 0;
+	bool vrr_active = false;
+	bool rb = false;
+
+	vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
+		     vrr->state == VRR_STATE_ACTIVE_FIXED;
+
+	infopacket->sb[VTEM_MD0] = VTEM_M_CONST << VTEM_M_CONST_BIT;
+	infopacket->sb[VTEM_MD0] |= VTEM_FVA_FACTOR << VTEM_FVA_BIT;
+	infopacket->sb[VTEM_MD0] |= vrr_active << VTEM_VRR_BIT;
+
+	infopacket->sb[VTEM_MD1] = 0;
+	infopacket->sb[VTEM_MD2] = 0;
+	infopacket->sb[VTEM_MD3] = 0;
+
+	if (!vrr_active || is_hdmi_vic_mode(stream))
+		return;
+	/*
+	 * In accordance with CVT 1.2 and CVT 2.1:
+	 * Reduced Blanking standard defines a fixed value of
+	 * 160 for hblank, further reduced to 80 in RB2. RB3 uses
+	 * fixed hblank of 80 pixels + up to 120 additional pixels
+	 * in 8-pixel steps.
+	 */
+	hblank = stream->timing.h_total - stream->timing.h_addressable;
+	rb = (hblank >= 80 && hblank <= 200 && hblank % 8 == 0);
+	brr = div_u64(mod_freesync_calc_nominal_field_rate(stream), 1000000);
+
+	if (brr > VTEM_BRR_MAX) {
+		infopacket->valid = false;
+		return;
+	}
+
+	infopacket->sb[VTEM_MD1] = (uint8_t) stream->timing.v_front_porch;
+	infopacket->sb[VTEM_MD2] = rb << VTEM_RB_BIT;
+	infopacket->sb[VTEM_MD2] |= (brr >> 8) & VTEM_BRR_MASK_UPPER;
+	infopacket->sb[VTEM_MD3] = brr & VTEM_BRR_MASK_LOWER;
+}
+
+void mod_build_vtem_infopacket(const struct dc_stream_state *stream,
+		const struct mod_vrr_params *vrr,
+		struct dc_info_packet *infopacket)
+{
+	infopacket->valid = true;
+	build_vtem_infopacket_header(infopacket);
+	build_vtem_infopacket_data(stream, vrr, infopacket);
+}
+
 void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
 		enum adaptive_sync_type asType,
 		const struct AS_Df_params *param,
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 18/19] drm/amd/display: Enable HDMI VRR
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (16 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 17/19] drm/amd/display: Reintroduce VTEM info frame Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-03 18:56 ` [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode Tomasz Pakuła
  2026-02-06 19:00 ` [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Harry Wentland
  19 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
We'd like to expose VRR functionality to end user if HDMI sink is
advertising it's support.

[How]
VTEM info frame is used to signal HDMI sink that VRR is active.
Use VTEM info packet as vrr_infopacket

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 ++++++++++++---
 .../drm/amd/display/modules/freesync/freesync.c   |  4 ++++
 .../drm/amd/display/modules/inc/mod_info_packet.h |  1 +
 .../amd/display/modules/info_packet/info_packet.c |  1 +
 4 files changed, 18 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 ab01a45aef1c..6f841c84d114 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9620,7 +9620,10 @@ static void update_freesync_state_on_stream(
 
 	aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context;
 
-	if (aconn && (aconn->as_type == ADAPTIVE_SYNC_TYPE_PCON_ALLOWED ||
+	if (aconn && aconn->as_type == ADAPTIVE_SYNC_TYPE_HDMI)
+		packet_type = PACKET_TYPE_VTEM;
+
+	else if (aconn && (aconn->as_type == ADAPTIVE_SYNC_TYPE_PCON_ALLOWED ||
 		      aconn->vsdb_info.replay_mode)) {
 		pack_sdp_v1_3 = aconn->pack_sdp_v1_3;
 
@@ -13380,8 +13383,14 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 		}
 
 	/* HDMI */
-	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_info.freesync_supported) {
-		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
+		/* Prefer HDMI VRR */
+		if (hdmi_vrr.supported) {
+			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_HDMI;
+			monitor_range_from_hdmi(&connector->display_info, &vsdb_info);
+		} else if (vsdb_info.freesync_supported)
+			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+
 		freesync_capable = copy_range_to_amdgpu_connector(connector);
 
 	/* DP -> HDMI PCON */
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
index 1aae46d703ba..db197cf048e1 100644
--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -27,6 +27,7 @@
 #include "dc.h"
 #include "mod_freesync.h"
 #include "core_types.h"
+#include "mod_info_packet.h"
 
 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS  32
 
@@ -955,6 +956,9 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
 		return;
 
 	switch (packet_type) {
+	case PACKET_TYPE_VTEM:
+		mod_build_vtem_infopacket(stream, vrr, infopacket);
+		break;
 	case PACKET_TYPE_FS_V3:
 		build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop);
 		break;
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 07e86b16ef77..ca7c5542620d 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
@@ -60,6 +60,7 @@ enum adaptive_sync_type {
 	ADAPTIVE_SYNC_TYPE_PCON_ALLOWED     = 2,
 	ADAPTIVE_SYNC_TYPE_PCON_NOT_ALLOWED = 3,
 	ADAPTIVE_SYNC_TYPE_EDP              = 4,
+	ADAPTIVE_SYNC_TYPE_HDMI             = 5,
 };
 
 enum adaptive_sync_sdp_version {
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 b08b52bba574..5fd9e8aadc98 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
@@ -722,6 +722,7 @@ void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
 		break;
 	case ADAPTIVE_SYNC_TYPE_NONE:
 	case ADAPTIVE_SYNC_TYPE_PCON_NOT_ALLOWED:
+	case ADAPTIVE_SYNC_TYPE_HDMI:
 	default:
 		break;
 	}
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (17 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 18/19] drm/amd/display: Enable HDMI VRR Tomasz Pakuła
@ 2026-02-03 18:56 ` Tomasz Pakuła
  2026-02-06 18:58   ` Harry Wentland
  2026-02-06 22:06   ` Alex Deucher
  2026-02-06 19:00 ` [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Harry Wentland
  19 siblings, 2 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-03 18:56 UTC (permalink / raw)
  To: alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel,
	tomasz.pakula.oficjalny, bernhard.berger, michel.daenzer, daniel,
	admin

[Why]
Many TVs and other HDMI sinks suffer from blanking and possibly other
glitches when VRR is toggled. With FreeSync present on such sinks, they
behave like the signal is always variable, even in fixed refresh rate
situations.

[How]
Keep HDMI VRR toggled if it's supported and not explicitly disabled.
Additionnally, add module parameter which allows users to configure HDMI
VRR triggering to only happen when the signal is truly asking for
variable state. This is useful if end user has a TV that automatically
toggles ALLM/Game mode when VRR is active and such user doesn't want
gaming mode in normal desktop usage.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h                 |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c             | 13 +++++++++++++
 .../amd/display/modules/info_packet/info_packet.c   |  9 +++++++--
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 312aa32064d5..d49cd55e0f35 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -269,6 +269,7 @@ extern int amdgpu_rebar;
 extern int amdgpu_wbrf;
 extern int amdgpu_user_queue;
 extern uint amdgpu_allm_mode;
+extern bool amdgpu_hdmi_vrr_desktop_mode;
 
 extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 4b038c8bbf9f..f53c2ffeffa2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -249,6 +249,7 @@ int amdgpu_rebar = -1; /* auto */
 int amdgpu_user_queue = -1;
 uint amdgpu_hdmi_hpd_debounce_delay_ms;
 uint amdgpu_allm_mode = 1;
+bool amdgpu_hdmi_vrr_desktop_mode = true;
 
 DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
 			"DRM_UT_CORE",
@@ -1146,6 +1147,18 @@ module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms
 MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
 module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);
 
+/**
+ * DOC: hdmi_vrr_on_dekstop (bool)
+ * Enables FreeSync behavior mimicking by keeping HDMI VRR signalling active in
+ * fixed refresh rate conditions like normal desktop work/web browsing.
+ * Possible values:
+ *
+ * - false = HDMI VRR is only enabled if refresh rate is truly variable
+ * - true  = Mimics FreeSync behavior and keeps HDMI VRR always active
+ */
+MODULE_PARM_DESC(hdmi_vrr_desktop_mode, "Changes HDMI VRR desktop mode (false = disable, true = enable (default))");
+module_param_named(hdmi_vrr_desktop_mode, amdgpu_hdmi_vrr_desktop_mode, bool, 0644);
+
 /* These devices are not supported by amdgpu.
  * They are supported by the mach64, r128, radeon drivers
  */
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 5fd9e8aadc98..b41e2240e1ae 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
@@ -654,8 +654,13 @@ static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
 	bool vrr_active = false;
 	bool rb = false;
 
-	vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
-		     vrr->state == VRR_STATE_ACTIVE_FIXED;
+	if (amdgpu_hdmi_vrr_desktop_mode) {
+		vrr_active = vrr->state != VRR_STATE_UNSUPPORTED &&
+			     vrr->state != VRR_STATE_DISABLED;
+	} else {
+		vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
+			     vrr->state == VRR_STATE_ACTIVE_FIXED;
+	}
 
 	infopacket->sb[VTEM_MD0] = VTEM_M_CONST << VTEM_M_CONST_BIT;
 	infopacket->sb[VTEM_MD0] |= VTEM_FVA_FACTOR << VTEM_FVA_BIT;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 02/19] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
  2026-02-03 18:56 ` [PATCH v3 02/19] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
@ 2026-02-06 18:22   ` Harry Wentland
  2026-02-06 20:46     ` Tomasz Pakuła
  0 siblings, 1 reply; 33+ messages in thread
From: Harry Wentland @ 2026-02-06 18:22 UTC (permalink / raw)
  To: Tomasz Pakuła, alexander.deucher, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel, admin



On 2026-02-03 13:56, Tomasz Pakuła wrote:
> [Why]
> This function started to get very messy and hard to follow.
> 
> [How]
> Eject some functionality to separate functions and simplify greatly.
> 
> Changes in v3:
> - Less struct traversal in helper functions
> 
> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> ---
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 123 +++++++++++-------
>  1 file changed, 73 insertions(+), 50 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 29e4a047b455..2c5877ed5f32 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -13119,8 +13119,8 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
>  	}
>  }
>  
> -static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
> -			  const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
> +static int parse_amd_vsdb_did(struct amdgpu_dm_connector *aconnector,
> +			      const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
>  {
>  	u8 *edid_ext = NULL;
>  	int i;
> @@ -13172,13 +13172,13 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
>  	return false;
>  }
>  
> -static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
> -			       const struct edid *edid,
> -			       struct amdgpu_hdmi_vsdb_info *vsdb_info)
> +static int parse_amd_vsdb_cea(struct amdgpu_dm_connector *aconnector,
> +			      const struct edid *edid,
> +			      struct amdgpu_hdmi_vsdb_info *vsdb_info)
>  {
> +	struct amdgpu_hdmi_vsdb_info vsdb_local = {0};
>  	u8 *edid_ext = NULL;
>  	int i;
> -	bool valid_vsdb_found = false;
>  
>  	/*----- drm_find_cea_extension() -----*/
>  	/* No EDID or EDID extensions */
> @@ -13199,9 +13199,47 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
>  	if (edid_ext[0] != CEA_EXT)
>  		return -ENODEV;
>  
> -	valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
> +	if (!parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, &vsdb_local))
> +		return -ENODEV;
>  
> -	return valid_vsdb_found ? i : -ENODEV;
> +	*vsdb_info = vsdb_local;
> +	return i;
> +}
> +
> +static bool is_monitor_range_invalid(const struct drm_connector *conn)
> +{
> +	return conn->display_info.monitor_range.min_vfreq == 0 ||
> +	       conn->display_info.monitor_range.max_vfreq == 0;
> +}
> +
> +/*
> + * Returns true if (max_vfreq - min_vfreq) > 10
> + */
> +static bool is_freesync_capable(const struct drm_monitor_range_info *range)
> +{
> +	return (range->max_vfreq - range->min_vfreq) > 10;
> +}
> +
> +static void monitor_range_from_vsdb(struct drm_display_info *display,
> +				    const struct amdgpu_hdmi_vsdb_info *vsdb)
> +{
> +	display->monitor_range.min_vfreq = vsdb->min_refresh_rate_hz;
> +	display->monitor_range.max_vfreq = vsdb->max_refresh_rate_hz;
> +}
> +
> +/*
> + * Returns true if connector is capable of freesync
> + * Optionally, can fetch the range from AMD vsdb
> + */
> +static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
> +{
> +	struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
> +	struct drm_monitor_range_info *range = &conn->display_info.monitor_range;
> +
> +	aconn->min_vfreq = range->min_vfreq;
> +	aconn->max_vfreq = range->max_vfreq;
> +
> +	return is_freesync_capable(range);
>  }
>  
>  /**
> @@ -13218,13 +13256,14 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
>  void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
>  				    const struct drm_edid *drm_edid)
>  {
> -	int i = 0;
>  	struct amdgpu_dm_connector *amdgpu_dm_connector =
>  			to_amdgpu_dm_connector(connector);
>  	struct dm_connector_state *dm_con_state = NULL;
>  	struct dc_sink *sink;
>  	struct amdgpu_device *adev = drm_to_adev(connector->dev);
>  	struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
> +	struct amdgpu_hdmi_vsdb_info vsdb_did = {0};
> +	struct dpcd_caps dpcd_caps = {0};
>  	const struct edid *edid;
>  	bool freesync_capable = false;
>  	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
> @@ -13256,62 +13295,46 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
>  		goto update;
>  
>  	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
> +	parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);

This change says it's a refactor, which in my book should
never include a (subtle) functional change. But we're now
calling this function for all sink_signal types, whereas
before it was only called for HDMI_TYPE_A.

> +
> +	if (amdgpu_dm_connector->dc_link)
> +		dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
>  
>  	/* Some eDP panels only have the refresh rate range info in DisplayID */
> -	if ((connector->display_info.monitor_range.min_vfreq == 0 ||
> -	     connector->display_info.monitor_range.max_vfreq == 0))
> +	if (is_monitor_range_invalid(connector))
>  		parse_edid_displayid_vrr(connector, edid);
>  
> -	if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
> -		     sink->sink_signal == SIGNAL_TYPE_EDP)) {
> -		if (amdgpu_dm_connector->dc_link &&
> -		    amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
> -			amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
> -			amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
> -			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
> -				freesync_capable = true;
> -		}
> +	if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
> +	    sink->sink_signal == SIGNAL_TYPE_EDP) {
>  
> -		parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
> +		if (dpcd_caps.allow_invalid_MSA_timing_param)
> +			freesync_capable = copy_range_to_amdgpu_connector(connector);
>  
> -		if (vsdb_info.replay_mode) {
> -			amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
> -			amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version;
> +		/* eDP */
> +		if (edid)

Same here, I'm not entirely sure whether moving the edid
check down here won't have a subtle behavior change.

I'd like to be either convinced that these things cannot
change behavior, or I'd like to see this broken out into
two patches, (1) a true refactor patch, without possible
behavior changes, and (2) another patch that might affect
behavior.

Overall I'm in favor of the changes and thank you for
cleaning this up. I'm just worried about subtle bugs.

Harry

> +			parse_amd_vsdb_did(amdgpu_dm_connector, edid, &vsdb_did);
> +
> +		if (vsdb_did.replay_mode) {
> +			amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_did.replay_mode;
> +			amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_did.amd_vsdb_version;
>  			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
>  		}
>  
> -	} else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
> -		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
> -		if (i >= 0 && vsdb_info.freesync_supported) {
> -			amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
> -			amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
> -			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
> -				freesync_capable = true;
> -
> -			connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
> -			connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
> -		}
> +	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_info.freesync_supported) {
> +		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
> +		freesync_capable = copy_range_to_amdgpu_connector(connector);
>  	}
>  
>  	if (amdgpu_dm_connector->dc_link)
>  		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
>  
> -	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
> -		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
> -		if (i >= 0 && vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
> +	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST && vsdb_info.freesync_supported) {
> +		amdgpu_dm_connector->pack_sdp_v1_3 = true;
> +		amdgpu_dm_connector->as_type = as_type;
> +		amdgpu_dm_connector->vsdb_info = vsdb_info;
>  
> -			amdgpu_dm_connector->pack_sdp_v1_3 = true;
> -			amdgpu_dm_connector->as_type = as_type;
> -			amdgpu_dm_connector->vsdb_info = vsdb_info;
> -
> -			amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
> -			amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
> -			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
> -				freesync_capable = true;
> -
> -			connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
> -			connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
> -		}
> +		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
> +		freesync_capable = copy_range_to_amdgpu_connector(connector);
>  	}
>  
>  update:



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 05/19] drm/amd/display: Refactor PCON VRR compatibility check
  2026-02-03 18:56 ` [PATCH v3 05/19] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
@ 2026-02-06 18:39   ` Harry Wentland
  0 siblings, 0 replies; 33+ messages in thread
From: Harry Wentland @ 2026-02-06 18:39 UTC (permalink / raw)
  To: Tomasz Pakuła, alexander.deucher, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel, admin

On 2026-02-03 13:56, Tomasz Pakuła wrote:
> [Why]
> DP->HDMI PCONs prevously entered the DP path

Again, not a fan of changing behavior in a "Refactor" commit.
Maybe drop refactor and put the functional change in the title
instead? And/or disentangle the non-functional and functional
portions of the change into two separate commits. Though I'm not
set on separating this into two commits.

Otherwise the change looks good.

Harry

> 
> [How]
> Restructure amdgpu_dm_update_freesync_caps() and move
> dm_get_adaptive_sync_support_type() to dm_helpers_is_vrr_pcon_allowed()
> to better reflect what this function does. It never actually gave us any
> other info.
> 
> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> ---
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 24 +++++++-----
>  .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 39 ++++++-------------
>  drivers/gpu/drm/amd/display/dc/dm_helpers.h   |  2 +-
>  3 files changed, 27 insertions(+), 38 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 284f5b326c18..9346b62d981b 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -13278,7 +13278,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
>  	struct dpcd_caps dpcd_caps = {0};
>  	const struct edid *edid;
>  	bool freesync_capable = false;
> -	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
> +	bool pcon_allowed = false;
> +	bool is_pcon = false;
>  
>  	if (!connector->state) {
>  		drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__);
> @@ -13306,18 +13307,23 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
>  	if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version))
>  		goto update;
>  
> +	/* Gather all data */
>  	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
>  	parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
>  
> -	if (amdgpu_dm_connector->dc_link)
> +	if (amdgpu_dm_connector->dc_link) {
>  		dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
> +		is_pcon = dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER;
> +		pcon_allowed = dm_helpers_is_vrr_pcon_allowed(amdgpu_dm_connector->dc_link);
> +	}
>  
>  	/* Some eDP panels only have the refresh rate range info in DisplayID */
>  	if (is_monitor_range_invalid(connector))
>  		parse_edid_displayid_vrr(connector, edid);
>  
> -	if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
> -	    sink->sink_signal == SIGNAL_TYPE_EDP) {
> +	/* DP & eDP excluding PCONs */
> +	if ((sink->sink_signal == SIGNAL_TYPE_EDP ||
> +	     sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) && !is_pcon) {
>  		/*
>  		 * Many monitors expose AMD vsdb in CAE even for DP and their
>  		 * monitor ranges do not contain Range Limits Only flag
> @@ -13342,17 +13348,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
>  			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
>  		}
>  
> +	/* HDMI */
>  	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_info.freesync_supported) {
>  		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
>  		freesync_capable = copy_range_to_amdgpu_connector(connector);
> -	}
>  
> -	if (amdgpu_dm_connector->dc_link)
> -		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
> -
> -	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST && vsdb_info.freesync_supported) {
> +	/* DP -> HDMI PCON */
> +	} else if (pcon_allowed && vsdb_info.freesync_supported) {
> +		amdgpu_dm_connector->as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
>  		amdgpu_dm_connector->pack_sdp_v1_3 = true;
> -		amdgpu_dm_connector->as_type = as_type;
>  		amdgpu_dm_connector->vsdb_info = vsdb_info;
>  
>  		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
> 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 1f41d6540b83..45a91df619d9 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
> @@ -1381,40 +1381,25 @@ void dm_helpers_dp_mst_update_branch_bandwidth(
>  	// TODO
>  }
>  
> -static bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id)
> +bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link)
>  {
> -	bool ret_val = false;
> +	if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER)
> +		return false;
>  
> -	switch (branch_dev_id) {
> +	if (!link->dpcd_caps.allow_invalid_MSA_timing_param)
> +		return false;
> +
> +	if (!link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT)
> +		return false;
> +
> +	switch (link->dpcd_caps.branch_dev_id) {
>  	case DP_BRANCH_DEVICE_ID_0060AD:
>  	case DP_BRANCH_DEVICE_ID_00E04C:
>  	case DP_BRANCH_DEVICE_ID_90CC24:
> -		ret_val = true;
> -		break;
> -	default:
> -		break;
> +		return true;
>  	}
>  
> -	return ret_val;
> -}
> -
> -enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link)
> -{
> -	struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
> -	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
> -
> -	switch (dpcd_caps->dongle_type) {
> -	case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
> -		if (dpcd_caps->adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT == true &&
> -			dpcd_caps->allow_invalid_MSA_timing_param == true &&
> -			dm_is_freesync_pcon_whitelist(dpcd_caps->branch_dev_id))
> -			as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
> -		break;
> -	default:
> -		break;
> -	}
> -
> -	return as_type;
> +	return false;
>  }
>  
>  bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state *stream)
> diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
> index 7014b8c2c956..e51f1e489129 100644
> --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
> +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
> @@ -220,10 +220,10 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
>  		const struct dc_link *link,
>  		struct set_config_cmd_payload *payload,
>  		enum set_config_status *operation_result);
> -enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link);
>  
>  enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid);
>  
> +bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link);
>  bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state *stream);
>  bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream);
>  


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior
  2026-02-03 18:56 ` [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior Tomasz Pakuła
@ 2026-02-06 18:52   ` Harry Wentland
  2026-02-06 20:52     ` Tomasz Pakuła
  0 siblings, 1 reply; 33+ messages in thread
From: Harry Wentland @ 2026-02-06 18:52 UTC (permalink / raw)
  To: Tomasz Pakuła, alexander.deucher, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel, admin

On 2026-02-03 13:56, Tomasz Pakuła wrote:
> [Why]
> Some users prefer to always manually control ALLM/Gaming mode while
> others might want it permanently forced on.
> 
> [How]
> Since there isn't yet an API to control this, expose module parameter
> 
> Changes in v3:
> - Include a fix for possible NULL pointer dereference by Peter
> 
> Closes: https://github.com/CachyOS/linux-cachyos/issues/680
> 
> Co-developed-by: Peter Jung <admin@ptr1337.dev>
> Signed-off-by: Peter Jung <admin@ptr1337.dev>
> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h           |  1 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c       | 14 +++++-
>  .../gpu/drm/amd/display/dc/core/dc_resource.c |  7 +--
>  .../amd/display/modules/inc/mod_info_packet.h |  1 +
>  .../display/modules/info_packet/info_packet.c | 46 ++++++++++++++++---
>  5 files changed, 56 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 447e734c362b..312aa32064d5 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -268,6 +268,7 @@ extern int amdgpu_rebar;
>  
>  extern int amdgpu_wbrf;
>  extern int amdgpu_user_queue;
> +extern uint amdgpu_allm_mode;
>  
>  extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
>  
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index d6d0a6e34c6b..4b038c8bbf9f 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -248,6 +248,7 @@ int amdgpu_umsch_mm_fwlog;
>  int amdgpu_rebar = -1; /* auto */
>  int amdgpu_user_queue = -1;
>  uint amdgpu_hdmi_hpd_debounce_delay_ms;
> +uint amdgpu_allm_mode = 1;
>  
>  DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
>  			"DRM_UT_CORE",
> @@ -1124,7 +1125,7 @@ module_param_named(rebar, amdgpu_rebar, int, 0444);
>  MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disable, 1 = enable, 2 = enable UQs and disable KQs)");
>  module_param_named(user_queue, amdgpu_user_queue, int, 0444);
>  
> -/*
> +/**
>   * DOC: hdmi_hpd_debounce_delay_ms (uint)
>   * HDMI HPD disconnect debounce delay in milliseconds.
>   *
> @@ -1134,6 +1135,17 @@ module_param_named(user_queue, amdgpu_user_queue, int, 0444);
>  MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
>  module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
>  
> +/**
> + * DOC: allm_mode (int)
> + * Changes ALLM triggering mode (if sink supports ALLM). Possible values:
> + *
> + * - 0 = ALLM disabled
> + * - 1 = ALLM dynamically triggered based on VRR state / Game Content Type Hint
> + * - 2 = ALLM forced always on
> + */
> +MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
> +module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);
> +
>  /* These devices are not supported by amdgpu.
>   * They are supported by the mach64, r128, radeon drivers
>   */
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> index 4a7c9f810e35..b779aac28dfa 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> @@ -44,6 +44,7 @@
>  #include "clk_mgr.h"
>  #include "dc_state_priv.h"
>  #include "dc_stream_priv.h"
> +#include "modules/inc/mod_info_packet.h"

Architecturally DC can't have a dependency on modules.
Is there a different way we can handle this?

Could we do the determination in amdgpu_dm (with help of
the module) and then set a flag on the stream?

Harry

>  
>  #include "virtual/virtual_link_hwss.h"
>  #include "link/hwss/link_hwss_dio.h"
> @@ -4503,8 +4504,6 @@ static void set_avi_info_frame(
>  	unsigned int vic = pipe_ctx->stream->timing.vic;
>  	unsigned int rid = pipe_ctx->stream->timing.rid;
>  	unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
> -	enum dc_timing_3d_format format;
> -	bool allm;
>  
>  	if (stream->avi_infopacket.valid) {
>  		*info_packet = stream->avi_infopacket;
> @@ -4658,10 +4657,8 @@ static void set_avi_info_frame(
>  	///VIC
>  	if (pipe_ctx->stream->timing.hdmi_vic != 0)
>  		vic = 0;
> -	format = stream->timing.timing_3d_format;
> -	allm = stream->link->local_sink->edid_caps.allm;
>  	/*todo, add 3DStereo support*/
> -	if ((format != TIMING_3D_FORMAT_NONE) || allm) {
> +	if (!is_hdmi_vic_mode(pipe_ctx->stream)) {
>  		// Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
>  		switch (pipe_ctx->stream->timing.hdmi_vic) {
>  		case 1:
> 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 306eb7355c25..9ec123ecc7c4 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
> @@ -41,6 +41,7 @@ void set_vsc_packet_colorimetry_data(
>  		enum dc_color_space cs,
>  		enum color_transfer_func tf);
>  
> +bool is_hdmi_vic_mode(const struct dc_stream_state *stream);
>  void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
>  		struct dc_info_packet *info_packet,
>  		enum dc_color_space cs,
> 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 53e488fdb4ea..829cce9455db 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
> @@ -23,12 +23,13 @@
>   *
>   */
>  
> -#include "mod_info_packet.h"
> +#include "amdgpu.h"
>  #include "core_types.h"
> -#include "dc_types.h"
> -#include "mod_shared.h"
> -#include "mod_freesync.h"
>  #include "dc.h"
> +#include "dc_types.h"
> +#include "mod_freesync.h"
> +#include "mod_info_packet.h"
> +#include "mod_shared.h"
>  
>  enum vsc_packet_revision {
>  	vsc_packet_undefined = 0,
> @@ -54,6 +55,12 @@ enum vsc_packet_revision {
>  #define HF_VSIF_3D_BIT   0
>  #define HF_VSIF_ALLM_BIT 1
>  
> +enum allm_trigger_mode {
> +	ALLM_MODE_DISABLED        = 0,
> +	ALLM_MODE_ENABLED_DYNAMIC = 1,
> +	ALLM_MODE_ENABLED_FORCED  = 2,
> +};
> +
>  // VTEM Byte Offset
>  #define VTEM_PB0		0
>  #define VTEM_PB1		1
> @@ -499,7 +506,32 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
>  	}
>  }
>  
> -static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
> +static bool is_hdmi_allm_mode(const struct dc_stream_state *stream)
> +{
> +	/* No local sink */
> +	if (!stream->link->local_sink)
> +		return false;
> +
> +	/* Sink doesn't expose ALLM support in edid */
> +	if (!stream->link->local_sink->edid_caps.allm)
> +		return false;
> +
> +	switch (amdgpu_allm_mode) {
> +	case ALLM_MODE_DISABLED:
> +		return false;
> +
> +	case ALLM_MODE_ENABLED_DYNAMIC:
> +		break;
> +
> +	case ALLM_MODE_ENABLED_FORCED:
> +		return true;
> +	}
> +
> +	return stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
> +	       stream->vrr_active_variable;
> +}
> +
> +bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
>  {
>  	if (stream->timing.hdmi_vic == 0)
>  		return false;
> @@ -512,7 +544,7 @@ static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
>  	if (stream->view_format != VIEW_3D_FORMAT_NONE)
>  		return false;
>  
> -	if (stream->link->local_sink->edid_caps.allm)
> +	if (is_hdmi_allm_mode(stream))
>  		return false;
>  
>  	return true;
> @@ -541,7 +573,7 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
>  
>  		info_packet->valid = false;
>  
> -		allm = stream->link->local_sink->edid_caps.allm;
> +		allm = is_hdmi_allm_mode(stream);
>  		format = stream->view_format == VIEW_3D_FORMAT_NONE ?
>  			 TIMING_3D_FORMAT_NONE :
>  			 stream->timing.timing_3d_format;


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode
  2026-02-03 18:56 ` [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode Tomasz Pakuła
@ 2026-02-06 18:58   ` Harry Wentland
  2026-02-06 21:08     ` Tomasz Pakuła
  2026-02-06 22:06   ` Alex Deucher
  1 sibling, 1 reply; 33+ messages in thread
From: Harry Wentland @ 2026-02-06 18:58 UTC (permalink / raw)
  To: Tomasz Pakuła, alexander.deucher, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel, admin

On 2026-02-03 13:56, Tomasz Pakuła wrote:
> [Why]
> Many TVs and other HDMI sinks suffer from blanking and possibly other
> glitches when VRR is toggled. With FreeSync present on such sinks, they
> behave like the signal is always variable, even in fixed refresh rate
> situations.
> 
> [How]
> Keep HDMI VRR toggled if it's supported and not explicitly disabled.
> Additionnally, add module parameter which allows users to configure HDMI
> VRR triggering to only happen when the signal is truly asking for
> variable state. This is useful if end user has a TV that automatically
> toggles ALLM/Game mode when VRR is active and such user doesn't want
> gaming mode in normal desktop usage.
> 

Can't this already be done by the compositor by simply setting the
VRR_ENABLED property on a crtc?

I don't like doing behavior behind the backs of compositors that
they might not be expecting.

Harry

> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h                 |  1 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c             | 13 +++++++++++++
>  .../amd/display/modules/info_packet/info_packet.c   |  9 +++++++--
>  3 files changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 312aa32064d5..d49cd55e0f35 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -269,6 +269,7 @@ extern int amdgpu_rebar;
>  extern int amdgpu_wbrf;
>  extern int amdgpu_user_queue;
>  extern uint amdgpu_allm_mode;
> +extern bool amdgpu_hdmi_vrr_desktop_mode;
>  
>  extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
>  
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 4b038c8bbf9f..f53c2ffeffa2 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -249,6 +249,7 @@ int amdgpu_rebar = -1; /* auto */
>  int amdgpu_user_queue = -1;
>  uint amdgpu_hdmi_hpd_debounce_delay_ms;
>  uint amdgpu_allm_mode = 1;
> +bool amdgpu_hdmi_vrr_desktop_mode = true;
>  
>  DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
>  			"DRM_UT_CORE",
> @@ -1146,6 +1147,18 @@ module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms
>  MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
>  module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);
>  
> +/**
> + * DOC: hdmi_vrr_on_dekstop (bool)
> + * Enables FreeSync behavior mimicking by keeping HDMI VRR signalling active in
> + * fixed refresh rate conditions like normal desktop work/web browsing.
> + * Possible values:
> + *
> + * - false = HDMI VRR is only enabled if refresh rate is truly variable
> + * - true  = Mimics FreeSync behavior and keeps HDMI VRR always active
> + */
> +MODULE_PARM_DESC(hdmi_vrr_desktop_mode, "Changes HDMI VRR desktop mode (false = disable, true = enable (default))");
> +module_param_named(hdmi_vrr_desktop_mode, amdgpu_hdmi_vrr_desktop_mode, bool, 0644);
> +
>  /* These devices are not supported by amdgpu.
>   * They are supported by the mach64, r128, radeon drivers
>   */
> 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 5fd9e8aadc98..b41e2240e1ae 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
> @@ -654,8 +654,13 @@ static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
>  	bool vrr_active = false;
>  	bool rb = false;
>  
> -	vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
> -		     vrr->state == VRR_STATE_ACTIVE_FIXED;
> +	if (amdgpu_hdmi_vrr_desktop_mode) {
> +		vrr_active = vrr->state != VRR_STATE_UNSUPPORTED &&
> +			     vrr->state != VRR_STATE_DISABLED;
> +	} else {
> +		vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
> +			     vrr->state == VRR_STATE_ACTIVE_FIXED;
> +	}
>  
>  	infopacket->sb[VTEM_MD0] = VTEM_M_CONST << VTEM_M_CONST_BIT;
>  	infopacket->sb[VTEM_MD0] |= VTEM_FVA_FACTOR << VTEM_FVA_BIT;


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features
  2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (18 preceding siblings ...)
  2026-02-03 18:56 ` [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode Tomasz Pakuła
@ 2026-02-06 19:00 ` Harry Wentland
  19 siblings, 0 replies; 33+ messages in thread
From: Harry Wentland @ 2026-02-06 19:00 UTC (permalink / raw)
  To: Tomasz Pakuła, alexander.deucher, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel, admin



On 2026-02-03 13:56, Tomasz Pakuła wrote:
> This patch series tackles a few things:
> - Fixes VRR not detected if monitor uses GTF flag for ranges
>   instead of Range Limits Only
> - Detects if AMD vsdb carries a wider VRR range and uses it instead
> - DP->HDMI PCON changes which includes a module property to override
>   PCON ID check
> - Parses HDMI gaming features in generic drm
> - Reintroduces proper HF-VSIF and VTEM info packets
> - Adds support for Auto Low Latency Mode
> - Adds support for HDMI VRR
> 
> VRR range fixes are simple and fix VRR support for many monitors. They
> close about 5 issues on the amdgpu issue tracker.
> 
> Adaptive Sync over PCON is only available as FreeSync over HDMI. TVs which
> do not support FreeSync, do not have working VRR with DP -> HDMI 2.1
> adapters even though adapters will take care of HDMI VRR info packets.
> 
> I myself validated these changes with my Samsung S95B + Bernhard validated
> on LG C4 + FreeSync-less Sony Bravia 8. I used Alienware AW3423DWF that
> only has HDMI 2.0 to check that FreeSync still triggers properly for
> "older" hardware,
> 
> For missing VRRmax or VRRmax == 0, the upper boundary is the currently
> selected video mode refresh rate. I wasn't sure how best to implement it
> but ended up on a great solution. We first check if maybe there is a VRR
> range in AMD vsdb. If not, rely on limitation of base refresh rate in
> VTEM vsif.
> 
> More history on previous shape of HF-VSIF and VTEM in their respective
> patches but the info packets were previously included in the driver code.
> HF-VSIF was improperly handled and VTEM doesn't seem to have been plumbed
> as it had no use before. I recoded these and this code should be much
> easier to understand and maintain.
> 
> ALLM support uses the info from EDID to determine if ALLM is supported by
> sink and if that's the case, always signals for ALLM to be enabled. In PC
> use, be it for gaming, desktop use, work etc. we always want the lowest
> latency and less processing + possibly higher available refresh rates when
> gaming mode is turned on.
> 
> HDMI VRR support relies on sending VTEM info packet in place of FreeSync
> info packets. Though VTEM has it's own place in the info packet pipeline,
> I didn't touch it as it already replaces FreeSync info packets. If there's
> a need to change this, please let me know for v2.
> 
> Both features were tested and work just like they were intended to. Gaming
> mode is automatically triggered and HDMI VRR is used in place of FreeSync
> (if available). This HDMI VRR preference actually fixes VRR-induced
> flickering on many TVs (S95B in my case) with somehow subpar
> FreeSync implementation.
> 
> I still think it's better to not force users to search for solutions
> manually especially since it seems like DP and eDP don't save info about
> FreeSync version and completely rely on basic VRR support.
> This would then be mirrored.
> 
> There's still an issue with some TVs behaving like a mode change is
> happening when VRR is triggered and I'd like to maybe tackle this too. When
> using HDMI through PCON, VRR is always active, like it's in
> VRR_STATE_ACTIVE_FIXED mode. This makes my TV much nicer to use and
> replication this behavior would be worthwhile IMO.
> 
> Everything in this patch series has been based on already public
> code/knowledge or trying things out until they work/break.
> 

Thanks for your thorough patch series. Really appreciate it.

I left comments on a few patches.

Patches 1, 3, 4, 6, 7, 9, 10, 12, 13, and 15 are
Reviewed-by: Harry Wentland <harry.wentland@amd.com>

I can't currently comment on patches 8, 11, 14, 17, 18.

Harry

> This patch series supersedes previous patches/series:
> https://lore.kernel.org/amd-gfx/20251209231107.1968472-1-tomasz.pakula.oficjalny@gmail.com/
> https://lore.kernel.org/amd-gfx/20260113214104.146856-1-tomasz.pakula.oficjalny@gmail.com/
> https://lore.kernel.org/amd-gfx/20260113183540.86266-1-tomasz.pakula.oficjalny@gmail.com/
> 
> Built on top of amd-staging-drm-next
> 
> Changes in v2:
> - Updated BRR max value to 1023 after testing one by one. This should've
>   been obvious since 1023 is the max value for a 10-bit field
> - Fixed some comments, to silence "not a kernel doc" warning
> - Considered ALLM comments from Michel Dänzer, Daniel Stone and
>   Jani Nikula. ALLM is now triggered if either VRR is active or Content
>   Type Hint is set to "Game". Content type hint is already supported by
>   amdgpu and fully plumbed.
> - Added module parameter for controlling ALLM trigger behavior. Now it can
>   be configured to never trigger ALLM, trigger with VRR/Game (default) or
>   be always forced on.
> - Added HDMI VRR desktop mode module parameter, which is on by default.
>   This mimics how FreeSync is handeled on Windows and this fixes a lot of
>   issues with unwanted screen blanking and glitches around entering/exiting
>   VRR mode.
> - Moved hdmi vic mode check to one central function to avoid checking for
>   3D and ALLM in different places which could sometimes break the logic for
>   translating HDMI VIC modes into CTA vic modes (when such translation 
>   is needed).
>   
> Changes in v3:
> - Fixed wonky English
> - Less struct traversal in helper functions
> - Fixed possible NULL pointer dereference while checking if ALLM support is
>   indicated in edid_caps of local_sink
> - Fixed ALLM bit assignment overriding 3D bit data in HF-VSIF
> - Fixed assignment of the upper 2 bits of BRR in VTEM
> 
> Tomasz Pakuła (19):
>   drm/amd/display: Return if DisplayID not found in parse_amd_vsdb()
>   drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
>   drm/amd/display: Check for VRR range in CEA AMD vsdb
>   drm/amd/display: Use bigger VRR range if found in AMD vsdb
>   drm/amd/display: Refactor PCON VRR compatibility check
>   drm/amd/display: Add PCON VRR ID check override
>   drm/amd/display: Add CH7218 PCON ID
>   drm/edid: Parse more info from HDMI Forum vsdb
>   drm/amd/display: Rename PCON adaptive sync types
>   drm/amd/display: Enable HDMI VRR over PCON
>   drm/amd/display: Support HDMI VRRmax=0
>   drm/amd/display: Build HDMI vsif in correct slot
>   drm/amd/display: Save HDMI gaming info to edid caps
>   drm/amd/display: Restore ALLM support in HDMI vsif
>   drm/amd/display: Trigger ALLM if it's available
>   drm/amd/display: Add parameter to control ALLM behavior
>   drm/amd/display: Reintroduce VTEM info frame
>   drm/amd/display: Enable HDMI VRR
>   drm/amd/display: Add HDMI VRR desktop mode
> 
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h           |   2 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c       |  27 +-
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 207 ++++++++---
>  .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  49 ++-
>  .../gpu/drm/amd/display/dc/core/dc_resource.c |   5 +-
>  drivers/gpu/drm/amd/display/dc/dc.h           |   1 +
>  drivers/gpu/drm/amd/display/dc/dc_types.h     |   7 +-
>  drivers/gpu/drm/amd/display/dc/dm_helpers.h   |   2 +-
>  .../amd/display/include/ddc_service_types.h   |   1 +
>  .../amd/display/modules/freesync/freesync.c   |   4 +
>  .../amd/display/modules/inc/mod_info_packet.h |  18 +-
>  .../display/modules/info_packet/info_packet.c | 342 ++++++++++++------
>  drivers/gpu/drm/amd/include/amd_shared.h      |   6 +
>  drivers/gpu/drm/drm_edid.c                    |  41 ++-
>  include/drm/drm_connector.h                   |  47 +++
>  15 files changed, 559 insertions(+), 200 deletions(-)
> 


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 02/19] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
  2026-02-06 18:22   ` Harry Wentland
@ 2026-02-06 20:46     ` Tomasz Pakuła
  0 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-06 20:46 UTC (permalink / raw)
  To: Harry Wentland, alexander.deucher, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel, admin

On Fri, 2026-02-06 at 13:22 -0500, Harry Wentland wrote:
> 
> On 2026-02-03 13:56, Tomasz Pakuła wrote:
> > [Why]
> > This function started to get very messy and hard to follow.
> > 
> > [How]
> > Eject some functionality to separate functions and simplify greatly.
> > 
> > Changes in v3:
> > - Less struct traversal in helper functions
> > 
> > Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> > ---
> >  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 123 +++++++++++-------
> >  1 file changed, 73 insertions(+), 50 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 29e4a047b455..2c5877ed5f32 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > @@ -13119,8 +13119,8 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
> >  	}
> >  }
> >  
> > -static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
> > -			  const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
> > +static int parse_amd_vsdb_did(struct amdgpu_dm_connector *aconnector,
> > +			      const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
> >  {
> >  	u8 *edid_ext = NULL;
> >  	int i;
> > @@ -13172,13 +13172,13 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
> >  	return false;
> >  }
> >  
> > -static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
> > -			       const struct edid *edid,
> > -			       struct amdgpu_hdmi_vsdb_info *vsdb_info)
> > +static int parse_amd_vsdb_cea(struct amdgpu_dm_connector *aconnector,
> > +			      const struct edid *edid,
> > +			      struct amdgpu_hdmi_vsdb_info *vsdb_info)
> >  {
> > +	struct amdgpu_hdmi_vsdb_info vsdb_local = {0};
> >  	u8 *edid_ext = NULL;
> >  	int i;
> > -	bool valid_vsdb_found = false;
> >  
> >  	/*----- drm_find_cea_extension() -----*/
> >  	/* No EDID or EDID extensions */
> > @@ -13199,9 +13199,47 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
> >  	if (edid_ext[0] != CEA_EXT)
> >  		return -ENODEV;
> >  
> > -	valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
> > +	if (!parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, &vsdb_local))
> > +		return -ENODEV;
> >  
> > -	return valid_vsdb_found ? i : -ENODEV;
> > +	*vsdb_info = vsdb_local;
> > +	return i;
> > +}
> > +
> > +static bool is_monitor_range_invalid(const struct drm_connector *conn)
> > +{
> > +	return conn->display_info.monitor_range.min_vfreq == 0 ||
> > +	       conn->display_info.monitor_range.max_vfreq == 0;
> > +}
> > +
> > +/*
> > + * Returns true if (max_vfreq - min_vfreq) > 10
> > + */
> > +static bool is_freesync_capable(const struct drm_monitor_range_info *range)
> > +{
> > +	return (range->max_vfreq - range->min_vfreq) > 10;
> > +}
> > +
> > +static void monitor_range_from_vsdb(struct drm_display_info *display,
> > +				    const struct amdgpu_hdmi_vsdb_info *vsdb)
> > +{
> > +	display->monitor_range.min_vfreq = vsdb->min_refresh_rate_hz;
> > +	display->monitor_range.max_vfreq = vsdb->max_refresh_rate_hz;
> > +}
> > +
> > +/*
> > + * Returns true if connector is capable of freesync
> > + * Optionally, can fetch the range from AMD vsdb
> > + */
> > +static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
> > +{
> > +	struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
> > +	struct drm_monitor_range_info *range = &conn->display_info.monitor_range;
> > +
> > +	aconn->min_vfreq = range->min_vfreq;
> > +	aconn->max_vfreq = range->max_vfreq;
> > +
> > +	return is_freesync_capable(range);
> >  }
> >  
> >  /**
> > @@ -13218,13 +13256,14 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
> >  void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
> >  				    const struct drm_edid *drm_edid)
> >  {
> > -	int i = 0;
> >  	struct amdgpu_dm_connector *amdgpu_dm_connector =
> >  			to_amdgpu_dm_connector(connector);
> >  	struct dm_connector_state *dm_con_state = NULL;
> >  	struct dc_sink *sink;
> >  	struct amdgpu_device *adev = drm_to_adev(connector->dev);
> >  	struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
> > +	struct amdgpu_hdmi_vsdb_info vsdb_did = {0};
> > +	struct dpcd_caps dpcd_caps = {0};
> >  	const struct edid *edid;
> >  	bool freesync_capable = false;
> >  	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
> > @@ -13256,62 +13295,46 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
> >  		goto update;
> >  
> >  	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
> > +	parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
> 
> This change says it's a refactor, which in my book should
> never include a (subtle) functional change. But we're now
> calling this function for all sink_signal types, whereas
> before it was only called for HDMI_TYPE_A.

Got it. I'll explain it better in the next version. I think the edid
check was there only to guard against parsing it in parse_amd_vsdb(). I
must say the code there was not the clearest but I can't think of a
reason to check for edid in case of DP. If it's missing, the
display_info won't have a valid range.

The parsing functions check for edid as well so this check is actually
redundant and could be entirely removed. vsdb structs are initialized to
0 either way so nothing will break and nothing will get enabled by
mistake.

Quite honestly, looking at (before changes) parse_edid_displayid_vrr(),
parse_amd_vsdb(), parse_hdmi_amd_vsdb() there's quite a bit of code
duplication and especially the former two are almost the same.

> > +
> > +	if (amdgpu_dm_connector->dc_link)
> > +		dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
> >  
> >  	/* Some eDP panels only have the refresh rate range info in DisplayID */
> > -	if ((connector->display_info.monitor_range.min_vfreq == 0 ||
> > -	     connector->display_info.monitor_range.max_vfreq == 0))
> > +	if (is_monitor_range_invalid(connector))
> >  		parse_edid_displayid_vrr(connector, edid);
> >  
> > -	if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
> > -		     sink->sink_signal == SIGNAL_TYPE_EDP)) {
> > -		if (amdgpu_dm_connector->dc_link &&
> > -		    amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
> > -			amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
> > -			amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
> > -			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
> > -				freesync_capable = true;
> > -		}
> > +	if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
> > +	    sink->sink_signal == SIGNAL_TYPE_EDP) {
> >  
> > -		parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
> > +		if (dpcd_caps.allow_invalid_MSA_timing_param)
> > +			freesync_capable = copy_range_to_amdgpu_connector(connector);
> >  
> > -		if (vsdb_info.replay_mode) {
> > -			amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
> > -			amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version;
> > +		/* eDP */
> > +		if (edid)
> 
> Same here, I'm not entirely sure whether moving the edid
> check down here won't have a subtle behavior change.
> 
> I'd like to be either convinced that these things cannot
> change behavior, or I'd like to see this broken out into
> two patches, (1) a true refactor patch, without possible
> behavior changes, and (2) another patch that might affect
> behavior.

Will do. Now that I'm looking at this with a clear head, it's too much
in one go even for me :) I think this will end up as 3-4 patches to
clean up the vsdb parsing functions as well.

> 
> Overall I'm in favor of the changes and thank you for
> cleaning this up. I'm just worried about subtle bugs.
> 
> Harry
> 
> > +			parse_amd_vsdb_did(amdgpu_dm_connector, edid, &vsdb_did);
> > +
> > +		if (vsdb_did.replay_mode) {
> > +			amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_did.replay_mode;
> > +			amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_did.amd_vsdb_version;
> >  			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
> >  		}
> >  
> > -	} else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
> > -		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
> > -		if (i >= 0 && vsdb_info.freesync_supported) {
> > -			amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
> > -			amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
> > -			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
> > -				freesync_capable = true;
> > -
> > -			connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
> > -			connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
> > -		}
> > +	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_info.freesync_supported) {
> > +		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
> > +		freesync_capable = copy_range_to_amdgpu_connector(connector);
> >  	}
> >  
> >  	if (amdgpu_dm_connector->dc_link)
> >  		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
> >  
> > -	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
> > -		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
> > -		if (i >= 0 && vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
> > +	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST && vsdb_info.freesync_supported) {
> > +		amdgpu_dm_connector->pack_sdp_v1_3 = true;
> > +		amdgpu_dm_connector->as_type = as_type;
> > +		amdgpu_dm_connector->vsdb_info = vsdb_info;
> >  
> > -			amdgpu_dm_connector->pack_sdp_v1_3 = true;
> > -			amdgpu_dm_connector->as_type = as_type;
> > -			amdgpu_dm_connector->vsdb_info = vsdb_info;
> > -
> > -			amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
> > -			amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
> > -			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
> > -				freesync_capable = true;
> > -
> > -			connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
> > -			connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
> > -		}
> > +		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
> > +		freesync_capable = copy_range_to_amdgpu_connector(connector);
> >  	}
> >  
> >  update:
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior
  2026-02-06 18:52   ` Harry Wentland
@ 2026-02-06 20:52     ` Tomasz Pakuła
  2026-02-06 22:04       ` Alex Deucher
  0 siblings, 1 reply; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-06 20:52 UTC (permalink / raw)
  To: Harry Wentland, alexander.deucher, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel, admin

On Fri, 2026-02-06 at 13:52 -0500, Harry Wentland wrote:
> On 2026-02-03 13:56, Tomasz Pakuła wrote:
> > [Why]
> > Some users prefer to always manually control ALLM/Gaming mode while
> > others might want it permanently forced on.
> > 
> > [How]
> > Since there isn't yet an API to control this, expose module parameter
> > 
> > Changes in v3:
> > - Include a fix for possible NULL pointer dereference by Peter
> > 
> > Closes: https://github.com/CachyOS/linux-cachyos/issues/680
> > 
> > Co-developed-by: Peter Jung <admin@ptr1337.dev>
> > Signed-off-by: Peter Jung <admin@ptr1337.dev>
> > Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> > ---
> >  drivers/gpu/drm/amd/amdgpu/amdgpu.h           |  1 +
> >  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c       | 14 +++++-
> >  .../gpu/drm/amd/display/dc/core/dc_resource.c |  7 +--
> >  .../amd/display/modules/inc/mod_info_packet.h |  1 +
> >  .../display/modules/info_packet/info_packet.c | 46 ++++++++++++++++---
> >  5 files changed, 56 insertions(+), 13 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > index 447e734c362b..312aa32064d5 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > @@ -268,6 +268,7 @@ extern int amdgpu_rebar;
> >  
> >  extern int amdgpu_wbrf;
> >  extern int amdgpu_user_queue;
> > +extern uint amdgpu_allm_mode;
> >  
> >  extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
> >  
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > index d6d0a6e34c6b..4b038c8bbf9f 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > @@ -248,6 +248,7 @@ int amdgpu_umsch_mm_fwlog;
> >  int amdgpu_rebar = -1; /* auto */
> >  int amdgpu_user_queue = -1;
> >  uint amdgpu_hdmi_hpd_debounce_delay_ms;
> > +uint amdgpu_allm_mode = 1;
> >  
> >  DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
> >  			"DRM_UT_CORE",
> > @@ -1124,7 +1125,7 @@ module_param_named(rebar, amdgpu_rebar, int, 0444);
> >  MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disable, 1 = enable, 2 = enable UQs and disable KQs)");
> >  module_param_named(user_queue, amdgpu_user_queue, int, 0444);
> >  
> > -/*
> > +/**
> >   * DOC: hdmi_hpd_debounce_delay_ms (uint)
> >   * HDMI HPD disconnect debounce delay in milliseconds.
> >   *
> > @@ -1134,6 +1135,17 @@ module_param_named(user_queue, amdgpu_user_queue, int, 0444);
> >  MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
> >  module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
> >  
> > +/**
> > + * DOC: allm_mode (int)
> > + * Changes ALLM triggering mode (if sink supports ALLM). Possible values:
> > + *
> > + * - 0 = ALLM disabled
> > + * - 1 = ALLM dynamically triggered based on VRR state / Game Content Type Hint
> > + * - 2 = ALLM forced always on
> > + */
> > +MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
> > +module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);
> > +
> >  /* These devices are not supported by amdgpu.
> >   * They are supported by the mach64, r128, radeon drivers
> >   */
> > diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> > index 4a7c9f810e35..b779aac28dfa 100644
> > --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> > +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> > @@ -44,6 +44,7 @@
> >  #include "clk_mgr.h"
> >  #include "dc_state_priv.h"
> >  #include "dc_stream_priv.h"
> > +#include "modules/inc/mod_info_packet.h"
> 
> Architecturally DC can't have a dependency on modules.
> Is there a different way we can handle this?
> 
> Could we do the determination in amdgpu_dm (with help of
> the module) and then set a flag on the stream?
> 
> Harry

Sure. I don't have any opinion on how it should be done. I think I only
did this like that because I wanted it to be easily changeable at
runtime, but the value of having this RW is next to none.

> 
> >  
> >  #include "virtual/virtual_link_hwss.h"
> >  #include "link/hwss/link_hwss_dio.h"
> > @@ -4503,8 +4504,6 @@ static void set_avi_info_frame(
> >  	unsigned int vic = pipe_ctx->stream->timing.vic;
> >  	unsigned int rid = pipe_ctx->stream->timing.rid;
> >  	unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
> > -	enum dc_timing_3d_format format;
> > -	bool allm;
> >  
> >  	if (stream->avi_infopacket.valid) {
> >  		*info_packet = stream->avi_infopacket;
> > @@ -4658,10 +4657,8 @@ static void set_avi_info_frame(
> >  	///VIC
> >  	if (pipe_ctx->stream->timing.hdmi_vic != 0)
> >  		vic = 0;
> > -	format = stream->timing.timing_3d_format;
> > -	allm = stream->link->local_sink->edid_caps.allm;
> >  	/*todo, add 3DStereo support*/
> > -	if ((format != TIMING_3D_FORMAT_NONE) || allm) {
> > +	if (!is_hdmi_vic_mode(pipe_ctx->stream)) {
> >  		// Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
> >  		switch (pipe_ctx->stream->timing.hdmi_vic) {
> >  		case 1:
> > 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 306eb7355c25..9ec123ecc7c4 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
> > @@ -41,6 +41,7 @@ void set_vsc_packet_colorimetry_data(
> >  		enum dc_color_space cs,
> >  		enum color_transfer_func tf);
> >  
> > +bool is_hdmi_vic_mode(const struct dc_stream_state *stream);
> >  void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
> >  		struct dc_info_packet *info_packet,
> >  		enum dc_color_space cs,
> > 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 53e488fdb4ea..829cce9455db 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
> > @@ -23,12 +23,13 @@
> >   *
> >   */
> >  
> > -#include "mod_info_packet.h"
> > +#include "amdgpu.h"
> >  #include "core_types.h"
> > -#include "dc_types.h"
> > -#include "mod_shared.h"
> > -#include "mod_freesync.h"
> >  #include "dc.h"
> > +#include "dc_types.h"
> > +#include "mod_freesync.h"
> > +#include "mod_info_packet.h"
> > +#include "mod_shared.h"
> >  
> >  enum vsc_packet_revision {
> >  	vsc_packet_undefined = 0,
> > @@ -54,6 +55,12 @@ enum vsc_packet_revision {
> >  #define HF_VSIF_3D_BIT   0
> >  #define HF_VSIF_ALLM_BIT 1
> >  
> > +enum allm_trigger_mode {
> > +	ALLM_MODE_DISABLED        = 0,
> > +	ALLM_MODE_ENABLED_DYNAMIC = 1,
> > +	ALLM_MODE_ENABLED_FORCED  = 2,
> > +};
> > +
> >  // VTEM Byte Offset
> >  #define VTEM_PB0		0
> >  #define VTEM_PB1		1
> > @@ -499,7 +506,32 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
> >  	}
> >  }
> >  
> > -static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
> > +static bool is_hdmi_allm_mode(const struct dc_stream_state *stream)
> > +{
> > +	/* No local sink */
> > +	if (!stream->link->local_sink)
> > +		return false;
> > +
> > +	/* Sink doesn't expose ALLM support in edid */
> > +	if (!stream->link->local_sink->edid_caps.allm)
> > +		return false;
> > +
> > +	switch (amdgpu_allm_mode) {
> > +	case ALLM_MODE_DISABLED:
> > +		return false;
> > +
> > +	case ALLM_MODE_ENABLED_DYNAMIC:
> > +		break;
> > +
> > +	case ALLM_MODE_ENABLED_FORCED:
> > +		return true;
> > +	}
> > +
> > +	return stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
> > +	       stream->vrr_active_variable;
> > +}
> > +
> > +bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
> >  {
> >  	if (stream->timing.hdmi_vic == 0)
> >  		return false;
> > @@ -512,7 +544,7 @@ static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
> >  	if (stream->view_format != VIEW_3D_FORMAT_NONE)
> >  		return false;
> >  
> > -	if (stream->link->local_sink->edid_caps.allm)
> > +	if (is_hdmi_allm_mode(stream))
> >  		return false;
> >  
> >  	return true;
> > @@ -541,7 +573,7 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
> >  
> >  		info_packet->valid = false;
> >  
> > -		allm = stream->link->local_sink->edid_caps.allm;
> > +		allm = is_hdmi_allm_mode(stream);
> >  		format = stream->view_format == VIEW_3D_FORMAT_NONE ?
> >  			 TIMING_3D_FORMAT_NONE :
> >  			 stream->timing.timing_3d_format;

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode
  2026-02-06 18:58   ` Harry Wentland
@ 2026-02-06 21:08     ` Tomasz Pakuła
  0 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-06 21:08 UTC (permalink / raw)
  To: Harry Wentland, alexander.deucher, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel, admin

On Fri, 2026-02-06 at 13:58 -0500, Harry Wentland wrote:
> On 2026-02-03 13:56, Tomasz Pakuła wrote:
> > [Why]
> > Many TVs and other HDMI sinks suffer from blanking and possibly other
> > glitches when VRR is toggled. With FreeSync present on such sinks, they
> > behave like the signal is always variable, even in fixed refresh rate
> > situations.
> > 
> > [How]
> > Keep HDMI VRR toggled if it's supported and not explicitly disabled.
> > Additionnally, add module parameter which allows users to configure HDMI
> > VRR triggering to only happen when the signal is truly asking for
> > variable state. This is useful if end user has a TV that automatically
> > toggles ALLM/Game mode when VRR is active and such user doesn't want
> > gaming mode in normal desktop usage.
> > 
> 
> Can't this already be done by the compositor by simply setting the
> VRR_ENABLED property on a crtc?
> 
> I don't like doing behavior behind the backs of compositors that
> they might not be expecting.
> 
> Harry

This actually mimics how FreeSync works on Windows. It keeps signaling
VRR or well, FreeSync mode, to the sink while keeping the signal fixed. 
Overall behavior is the same as with VRR completely disabled. Signal is
only variable if the compositor sets VRR_ENABLED.

It's a bit similar to freesync video or VRR_STATE_ACTIVE_FIXED.

FreeSync infopacket contains separate FreeSync on Desktop, and FreeSync
active fields and in this change, the check for VRR with
hdmi_vrr_on_desktop is the same as for FreeSync on Desktop field.

I could better show this by uploading a video to youtube, especially
with a comparison to the Windows driver.

Sadly, VRR_ENABLED is just a bool whereas compositors could give drivers
info in three steps: Disabled, Inactive, Active. This way, we could
still completely disable VRR signaling though again, the desired
behavior is preset even in the Windows driver or maybe it's baked into
FreeSync specification? I don't know if it's public, I know I haven't
seen it but it would be nice.

The need for this is due to the fact that, contrary to VESA Adaptive
Sync, HDMI doesn't seem to enforce that VRR mode toggling shouldn't
cause a mode change this A LOT of TVs will blank.

This is especially egregious with Windows' Dynamic Refresh rate setting
where the desktop becomes absolutely unusable. With constant blanking.


> > Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> > ---
> >  drivers/gpu/drm/amd/amdgpu/amdgpu.h                 |  1 +
> >  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c             | 13 +++++++++++++
> >  .../amd/display/modules/info_packet/info_packet.c   |  9 +++++++--
> >  3 files changed, 21 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > index 312aa32064d5..d49cd55e0f35 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > @@ -269,6 +269,7 @@ extern int amdgpu_rebar;
> >  extern int amdgpu_wbrf;
> >  extern int amdgpu_user_queue;
> >  extern uint amdgpu_allm_mode;
> > +extern bool amdgpu_hdmi_vrr_desktop_mode;
> >  
> >  extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
> >  
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > index 4b038c8bbf9f..f53c2ffeffa2 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > @@ -249,6 +249,7 @@ int amdgpu_rebar = -1; /* auto */
> >  int amdgpu_user_queue = -1;
> >  uint amdgpu_hdmi_hpd_debounce_delay_ms;
> >  uint amdgpu_allm_mode = 1;
> > +bool amdgpu_hdmi_vrr_desktop_mode = true;
> >  
> >  DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
> >  			"DRM_UT_CORE",
> > @@ -1146,6 +1147,18 @@ module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms
> >  MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
> >  module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);
> >  
> > +/**
> > + * DOC: hdmi_vrr_on_dekstop (bool)
> > + * Enables FreeSync behavior mimicking by keeping HDMI VRR signalling active in
> > + * fixed refresh rate conditions like normal desktop work/web browsing.
> > + * Possible values:
> > + *
> > + * - false = HDMI VRR is only enabled if refresh rate is truly variable
> > + * - true  = Mimics FreeSync behavior and keeps HDMI VRR always active
> > + */
> > +MODULE_PARM_DESC(hdmi_vrr_desktop_mode, "Changes HDMI VRR desktop mode (false = disable, true = enable (default))");
> > +module_param_named(hdmi_vrr_desktop_mode, amdgpu_hdmi_vrr_desktop_mode, bool, 0644);
> > +
> >  /* These devices are not supported by amdgpu.
> >   * They are supported by the mach64, r128, radeon drivers
> >   */
> > 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 5fd9e8aadc98..b41e2240e1ae 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
> > @@ -654,8 +654,13 @@ static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
> >  	bool vrr_active = false;
> >  	bool rb = false;
> >  
> > -	vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
> > -		     vrr->state == VRR_STATE_ACTIVE_FIXED;
> > +	if (amdgpu_hdmi_vrr_desktop_mode) {
> > +		vrr_active = vrr->state != VRR_STATE_UNSUPPORTED &&
> > +			     vrr->state != VRR_STATE_DISABLED;
> > +	} else {
> > +		vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
> > +			     vrr->state == VRR_STATE_ACTIVE_FIXED;
> > +	}
> >  
> >  	infopacket->sb[VTEM_MD0] = VTEM_M_CONST << VTEM_M_CONST_BIT;
> >  	infopacket->sb[VTEM_MD0] |= VTEM_FVA_FACTOR << VTEM_FVA_BIT;

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior
  2026-02-06 20:52     ` Tomasz Pakuła
@ 2026-02-06 22:04       ` Alex Deucher
  2026-02-10 18:44         ` Tomasz Pakuła
  0 siblings, 1 reply; 33+ messages in thread
From: Alex Deucher @ 2026-02-06 22:04 UTC (permalink / raw)
  To: Tomasz Pakuła
  Cc: Harry Wentland, alexander.deucher, sunpeng.li, maarten.lankhorst,
	mripard, tzimmermann, airlied, simona, siqueira, dri-devel,
	amd-gfx, linux-kernel, bernhard.berger, michel.daenzer, daniel,
	admin

On Fri, Feb 6, 2026 at 4:12 PM Tomasz Pakuła
<tomasz.pakula.oficjalny@gmail.com> wrote:
>
> On Fri, 2026-02-06 at 13:52 -0500, Harry Wentland wrote:
> > On 2026-02-03 13:56, Tomasz Pakuła wrote:
> > > [Why]
> > > Some users prefer to always manually control ALLM/Gaming mode while
> > > others might want it permanently forced on.
> > >
> > > [How]
> > > Since there isn't yet an API to control this, expose module parameter
> > >
> > > Changes in v3:
> > > - Include a fix for possible NULL pointer dereference by Peter
> > >
> > > Closes: https://github.com/CachyOS/linux-cachyos/issues/680
> > >
> > > Co-developed-by: Peter Jung <admin@ptr1337.dev>
> > > Signed-off-by: Peter Jung <admin@ptr1337.dev>
> > > Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> > > ---
> > >  drivers/gpu/drm/amd/amdgpu/amdgpu.h           |  1 +
> > >  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c       | 14 +++++-
> > >  .../gpu/drm/amd/display/dc/core/dc_resource.c |  7 +--
> > >  .../amd/display/modules/inc/mod_info_packet.h |  1 +
> > >  .../display/modules/info_packet/info_packet.c | 46 ++++++++++++++++---
> > >  5 files changed, 56 insertions(+), 13 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > > index 447e734c362b..312aa32064d5 100644
> > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> > > @@ -268,6 +268,7 @@ extern int amdgpu_rebar;
> > >
> > >  extern int amdgpu_wbrf;
> > >  extern int amdgpu_user_queue;
> > > +extern uint amdgpu_allm_mode;
> > >
> > >  extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
> > >
> > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > > index d6d0a6e34c6b..4b038c8bbf9f 100644
> > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> > > @@ -248,6 +248,7 @@ int amdgpu_umsch_mm_fwlog;
> > >  int amdgpu_rebar = -1; /* auto */
> > >  int amdgpu_user_queue = -1;
> > >  uint amdgpu_hdmi_hpd_debounce_delay_ms;
> > > +uint amdgpu_allm_mode = 1;
> > >
> > >  DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
> > >                     "DRM_UT_CORE",
> > > @@ -1124,7 +1125,7 @@ module_param_named(rebar, amdgpu_rebar, int, 0444);
> > >  MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disable, 1 = enable, 2 = enable UQs and disable KQs)");
> > >  module_param_named(user_queue, amdgpu_user_queue, int, 0444);
> > >
> > > -/*
> > > +/**
> > >   * DOC: hdmi_hpd_debounce_delay_ms (uint)
> > >   * HDMI HPD disconnect debounce delay in milliseconds.
> > >   *
> > > @@ -1134,6 +1135,17 @@ module_param_named(user_queue, amdgpu_user_queue, int, 0444);
> > >  MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
> > >  module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
> > >
> > > +/**
> > > + * DOC: allm_mode (int)

Would be good to define ALLM.

> > > + * Changes ALLM triggering mode (if sink supports ALLM). Possible values:
> > > + *
> > > + * - 0 = ALLM disabled
> > > + * - 1 = ALLM dynamically triggered based on VRR state / Game Content Type Hint
> > > + * - 2 = ALLM forced always on
> > > + */
> > > +MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
> > > +module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);

Also, maybe a per connector kms property would be preferable.  Then
you could change it per display.

Alex

> > > +
> > >  /* These devices are not supported by amdgpu.
> > >   * They are supported by the mach64, r128, radeon drivers
> > >   */
> > > diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> > > index 4a7c9f810e35..b779aac28dfa 100644
> > > --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> > > +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> > > @@ -44,6 +44,7 @@
> > >  #include "clk_mgr.h"
> > >  #include "dc_state_priv.h"
> > >  #include "dc_stream_priv.h"
> > > +#include "modules/inc/mod_info_packet.h"
> >
> > Architecturally DC can't have a dependency on modules.
> > Is there a different way we can handle this?
> >
> > Could we do the determination in amdgpu_dm (with help of
> > the module) and then set a flag on the stream?
> >
> > Harry
>
> Sure. I don't have any opinion on how it should be done. I think I only
> did this like that because I wanted it to be easily changeable at
> runtime, but the value of having this RW is next to none.
>
> >
> > >
> > >  #include "virtual/virtual_link_hwss.h"
> > >  #include "link/hwss/link_hwss_dio.h"
> > > @@ -4503,8 +4504,6 @@ static void set_avi_info_frame(
> > >     unsigned int vic = pipe_ctx->stream->timing.vic;
> > >     unsigned int rid = pipe_ctx->stream->timing.rid;
> > >     unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
> > > -   enum dc_timing_3d_format format;
> > > -   bool allm;
> > >
> > >     if (stream->avi_infopacket.valid) {
> > >             *info_packet = stream->avi_infopacket;
> > > @@ -4658,10 +4657,8 @@ static void set_avi_info_frame(
> > >     ///VIC
> > >     if (pipe_ctx->stream->timing.hdmi_vic != 0)
> > >             vic = 0;
> > > -   format = stream->timing.timing_3d_format;
> > > -   allm = stream->link->local_sink->edid_caps.allm;
> > >     /*todo, add 3DStereo support*/
> > > -   if ((format != TIMING_3D_FORMAT_NONE) || allm) {
> > > +   if (!is_hdmi_vic_mode(pipe_ctx->stream)) {
> > >             // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
> > >             switch (pipe_ctx->stream->timing.hdmi_vic) {
> > >             case 1:
> > > 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 306eb7355c25..9ec123ecc7c4 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
> > > @@ -41,6 +41,7 @@ void set_vsc_packet_colorimetry_data(
> > >             enum dc_color_space cs,
> > >             enum color_transfer_func tf);
> > >
> > > +bool is_hdmi_vic_mode(const struct dc_stream_state *stream);
> > >  void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
> > >             struct dc_info_packet *info_packet,
> > >             enum dc_color_space cs,
> > > 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 53e488fdb4ea..829cce9455db 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
> > > @@ -23,12 +23,13 @@
> > >   *
> > >   */
> > >
> > > -#include "mod_info_packet.h"
> > > +#include "amdgpu.h"
> > >  #include "core_types.h"
> > > -#include "dc_types.h"
> > > -#include "mod_shared.h"
> > > -#include "mod_freesync.h"
> > >  #include "dc.h"
> > > +#include "dc_types.h"
> > > +#include "mod_freesync.h"
> > > +#include "mod_info_packet.h"
> > > +#include "mod_shared.h"
> > >
> > >  enum vsc_packet_revision {
> > >     vsc_packet_undefined = 0,
> > > @@ -54,6 +55,12 @@ enum vsc_packet_revision {
> > >  #define HF_VSIF_3D_BIT   0
> > >  #define HF_VSIF_ALLM_BIT 1
> > >
> > > +enum allm_trigger_mode {
> > > +   ALLM_MODE_DISABLED        = 0,
> > > +   ALLM_MODE_ENABLED_DYNAMIC = 1,
> > > +   ALLM_MODE_ENABLED_FORCED  = 2,
> > > +};
> > > +
> > >  // VTEM Byte Offset
> > >  #define VTEM_PB0           0
> > >  #define VTEM_PB1           1
> > > @@ -499,7 +506,32 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
> > >     }
> > >  }
> > >
> > > -static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
> > > +static bool is_hdmi_allm_mode(const struct dc_stream_state *stream)
> > > +{
> > > +   /* No local sink */
> > > +   if (!stream->link->local_sink)
> > > +           return false;
> > > +
> > > +   /* Sink doesn't expose ALLM support in edid */
> > > +   if (!stream->link->local_sink->edid_caps.allm)
> > > +           return false;
> > > +
> > > +   switch (amdgpu_allm_mode) {
> > > +   case ALLM_MODE_DISABLED:
> > > +           return false;
> > > +
> > > +   case ALLM_MODE_ENABLED_DYNAMIC:
> > > +           break;
> > > +
> > > +   case ALLM_MODE_ENABLED_FORCED:
> > > +           return true;
> > > +   }
> > > +
> > > +   return stream->content_type == DISPLAY_CONTENT_TYPE_GAME ||
> > > +          stream->vrr_active_variable;
> > > +}
> > > +
> > > +bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
> > >  {
> > >     if (stream->timing.hdmi_vic == 0)
> > >             return false;
> > > @@ -512,7 +544,7 @@ static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
> > >     if (stream->view_format != VIEW_3D_FORMAT_NONE)
> > >             return false;
> > >
> > > -   if (stream->link->local_sink->edid_caps.allm)
> > > +   if (is_hdmi_allm_mode(stream))
> > >             return false;
> > >
> > >     return true;
> > > @@ -541,7 +573,7 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
> > >
> > >             info_packet->valid = false;
> > >
> > > -           allm = stream->link->local_sink->edid_caps.allm;
> > > +           allm = is_hdmi_allm_mode(stream);
> > >             format = stream->view_format == VIEW_3D_FORMAT_NONE ?
> > >                      TIMING_3D_FORMAT_NONE :
> > >                      stream->timing.timing_3d_format;

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode
  2026-02-03 18:56 ` [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode Tomasz Pakuła
  2026-02-06 18:58   ` Harry Wentland
@ 2026-02-06 22:06   ` Alex Deucher
  1 sibling, 0 replies; 33+ messages in thread
From: Alex Deucher @ 2026-02-06 22:06 UTC (permalink / raw)
  To: Tomasz Pakuła
  Cc: alexander.deucher, harry.wentland, sunpeng.li, maarten.lankhorst,
	mripard, tzimmermann, airlied, simona, siqueira, dri-devel,
	amd-gfx, linux-kernel, bernhard.berger, michel.daenzer, daniel,
	admin

On Tue, Feb 3, 2026 at 2:07 PM Tomasz Pakuła
<tomasz.pakula.oficjalny@gmail.com> wrote:
>
> [Why]
> Many TVs and other HDMI sinks suffer from blanking and possibly other
> glitches when VRR is toggled. With FreeSync present on such sinks, they
> behave like the signal is always variable, even in fixed refresh rate
> situations.
>
> [How]
> Keep HDMI VRR toggled if it's supported and not explicitly disabled.
> Additionnally, add module parameter which allows users to configure HDMI
> VRR triggering to only happen when the signal is truly asking for
> variable state. This is useful if end user has a TV that automatically
> toggles ALLM/Game mode when VRR is active and such user doesn't want
> gaming mode in normal desktop usage.
>
> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h                 |  1 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c             | 13 +++++++++++++
>  .../amd/display/modules/info_packet/info_packet.c   |  9 +++++++--
>  3 files changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 312aa32064d5..d49cd55e0f35 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -269,6 +269,7 @@ extern int amdgpu_rebar;
>  extern int amdgpu_wbrf;
>  extern int amdgpu_user_queue;
>  extern uint amdgpu_allm_mode;
> +extern bool amdgpu_hdmi_vrr_desktop_mode;
>
>  extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 4b038c8bbf9f..f53c2ffeffa2 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -249,6 +249,7 @@ int amdgpu_rebar = -1; /* auto */
>  int amdgpu_user_queue = -1;
>  uint amdgpu_hdmi_hpd_debounce_delay_ms;
>  uint amdgpu_allm_mode = 1;
> +bool amdgpu_hdmi_vrr_desktop_mode = true;
>
>  DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
>                         "DRM_UT_CORE",
> @@ -1146,6 +1147,18 @@ module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms
>  MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
>  module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);
>
> +/**
> + * DOC: hdmi_vrr_on_dekstop (bool)

*desktop

> + * Enables FreeSync behavior mimicking by keeping HDMI VRR signalling active in
> + * fixed refresh rate conditions like normal desktop work/web browsing.
> + * Possible values:
> + *
> + * - false = HDMI VRR is only enabled if refresh rate is truly variable
> + * - true  = Mimics FreeSync behavior and keeps HDMI VRR always active
> + */
> +MODULE_PARM_DESC(hdmi_vrr_desktop_mode, "Changes HDMI VRR desktop mode (false = disable, true = enable (default))");
> +module_param_named(hdmi_vrr_desktop_mode, amdgpu_hdmi_vrr_desktop_mode, bool, 0644);

This also seems like it would be better to be a KMS property.

Alex

> +
>  /* These devices are not supported by amdgpu.
>   * They are supported by the mach64, r128, radeon drivers
>   */
> 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 5fd9e8aadc98..b41e2240e1ae 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
> @@ -654,8 +654,13 @@ static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
>         bool vrr_active = false;
>         bool rb = false;
>
> -       vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
> -                    vrr->state == VRR_STATE_ACTIVE_FIXED;
> +       if (amdgpu_hdmi_vrr_desktop_mode) {
> +               vrr_active = vrr->state != VRR_STATE_UNSUPPORTED &&
> +                            vrr->state != VRR_STATE_DISABLED;
> +       } else {
> +               vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
> +                            vrr->state == VRR_STATE_ACTIVE_FIXED;
> +       }
>
>         infopacket->sb[VTEM_MD0] = VTEM_M_CONST << VTEM_M_CONST_BIT;
>         infopacket->sb[VTEM_MD0] |= VTEM_FVA_FACTOR << VTEM_FVA_BIT;
> --
> 2.52.0
>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior
  2026-02-06 22:04       ` Alex Deucher
@ 2026-02-10 18:44         ` Tomasz Pakuła
  2026-02-10 19:17           ` Alex Deucher
  0 siblings, 1 reply; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-10 18:44 UTC (permalink / raw)
  To: Alex Deucher
  Cc: Harry Wentland, alexander.deucher, sunpeng.li, maarten.lankhorst,
	mripard, tzimmermann, airlied, simona, siqueira, dri-devel,
	amd-gfx, linux-kernel, bernhard.berger, michel.daenzer, daniel,
	admin

On Fri, 2026-02-06 at 17:04 -0500, Alex Deucher wrote:
> 
> Also, maybe a per connector kms property would be preferable.  Then
> you could change it per display.
> 
> Alex

I've dealt with all Harry's comments but wanted to make sure I
understand properly. Do you mean, that the two settings should be a
connector property like VRR_ENABLED? I understand the intent and I think
in some time, it would be best to have these exposed in compositor
settings but how would a user control this until then?

Would it suffice to fire IOCTLs from a third-party tool like LACT where
support for this could be added in a short time?

I made it a module property in the first place, because I thought such
settings are pretty set-and-forget and module properties are just easy
to set :)

Still, I think the defaults are sane. If I have to spend some more time
to get the connector properties working, I could send the patches with
the module properties ripped out for now.

Tomasz
> > > 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior
  2026-02-10 18:44         ` Tomasz Pakuła
@ 2026-02-10 19:17           ` Alex Deucher
  2026-02-10 20:54             ` Tomasz Pakuła
  0 siblings, 1 reply; 33+ messages in thread
From: Alex Deucher @ 2026-02-10 19:17 UTC (permalink / raw)
  To: Tomasz Pakuła
  Cc: Harry Wentland, alexander.deucher, sunpeng.li, maarten.lankhorst,
	mripard, tzimmermann, airlied, simona, siqueira, dri-devel,
	amd-gfx, linux-kernel, bernhard.berger, michel.daenzer, daniel,
	admin

On Tue, Feb 10, 2026 at 1:44 PM Tomasz Pakuła
<tomasz.pakula.oficjalny@gmail.com> wrote:
>
> On Fri, 2026-02-06 at 17:04 -0500, Alex Deucher wrote:
> >
> > Also, maybe a per connector kms property would be preferable.  Then
> > you could change it per display.
> >
> > Alex
>
> I've dealt with all Harry's comments but wanted to make sure I
> understand properly. Do you mean, that the two settings should be a
> connector property like VRR_ENABLED? I understand the intent and I think
> in some time, it would be best to have these exposed in compositor
> settings but how would a user control this until then?
>
> Would it suffice to fire IOCTLs from a third-party tool like LACT where
> support for this could be added in a short time?
>
> I made it a module property in the first place, because I thought such
> settings are pretty set-and-forget and module properties are just easy
> to set :)
>
> Still, I think the defaults are sane. If I have to spend some more time
> to get the connector properties working, I could send the patches with
> the module properties ripped out for now.

My understanding is that these are something the compositor would like
to manage.  I'd like to avoid adding module parameters if we can help
it because they usually cause more trouble than they help due to
unforeseen interactions with other features or "conventional wisdom"
blindly followed which leads to a bad user experience.

Alex

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior
  2026-02-10 19:17           ` Alex Deucher
@ 2026-02-10 20:54             ` Tomasz Pakuła
  0 siblings, 0 replies; 33+ messages in thread
From: Tomasz Pakuła @ 2026-02-10 20:54 UTC (permalink / raw)
  To: Alex Deucher
  Cc: Harry Wentland, alexander.deucher, sunpeng.li, maarten.lankhorst,
	mripard, tzimmermann, airlied, simona, siqueira, dri-devel,
	amd-gfx, linux-kernel, bernhard.berger, michel.daenzer, daniel,
	admin

On Tue, 2026-02-10 at 14:17 -0500, Alex Deucher wrote:
> On Tue, Feb 10, 2026 at 1:44 PM Tomasz Pakuła
> <tomasz.pakula.oficjalny@gmail.com> wrote:
> > 
> > On Fri, 2026-02-06 at 17:04 -0500, Alex Deucher wrote:
> > > 
> > > Also, maybe a per connector kms property would be preferable.  Then
> > > you could change it per display.
> > > 
> > > Alex
> > 
> > I've dealt with all Harry's comments but wanted to make sure I
> > understand properly. Do you mean, that the two settings should be a
> > connector property like VRR_ENABLED? I understand the intent and I think
> > in some time, it would be best to have these exposed in compositor
> > settings but how would a user control this until then?
> > 
> > Would it suffice to fire IOCTLs from a third-party tool like LACT where
> > support for this could be added in a short time?
> > 
> > I made it a module property in the first place, because I thought such
> > settings are pretty set-and-forget and module properties are just easy
> > to set :)
> > 
> > Still, I think the defaults are sane. If I have to spend some more time
> > to get the connector properties working, I could send the patches with
> > the module properties ripped out for now.
> 
> My understanding is that these are something the compositor would like
> to manage.  I'd like to avoid adding module parameters if we can help
> it because they usually cause more trouble than they help due to
> unforeseen interactions with other features or "conventional wisdom"
> blindly followed which leads to a bad user experience.
> 
> Alex

Sure!

I'll remove the parameters for now and send v4 to get some feedback on
the cleanups and then I'll figure out the KMS properties. You're right,
leaving that in would surely lead to issues and then people lamenting
their removals..

Thanks for all the comments and all your work!

Tomasz

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2026-02-10 20:54 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-03 18:56 [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 01/19] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 02/19] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
2026-02-06 18:22   ` Harry Wentland
2026-02-06 20:46     ` Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 03/19] drm/amd/display: Check for VRR range in CEA AMD vsdb Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 04/19] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 05/19] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
2026-02-06 18:39   ` Harry Wentland
2026-02-03 18:56 ` [PATCH v3 06/19] drm/amd/display: Add PCON VRR ID check override Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 07/19] drm/amd/display: Add CH7218 PCON ID Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 08/19] drm/edid: Parse more info from HDMI Forum vsdb Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 09/19] drm/amd/display: Rename PCON adaptive sync types Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 10/19] drm/amd/display: Enable HDMI VRR over PCON Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 11/19] drm/amd/display: Support HDMI VRRmax=0 Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 12/19] drm/amd/display: Build HDMI vsif in correct slot Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 13/19] drm/amd/display: Save HDMI gaming info to edid caps Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 14/19] drm/amd/display: Restore ALLM support in HDMI vsif Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 15/19] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 16/19] drm/amd/display: Add parameter to control ALLM behavior Tomasz Pakuła
2026-02-06 18:52   ` Harry Wentland
2026-02-06 20:52     ` Tomasz Pakuła
2026-02-06 22:04       ` Alex Deucher
2026-02-10 18:44         ` Tomasz Pakuła
2026-02-10 19:17           ` Alex Deucher
2026-02-10 20:54             ` Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 17/19] drm/amd/display: Reintroduce VTEM info frame Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 18/19] drm/amd/display: Enable HDMI VRR Tomasz Pakuła
2026-02-03 18:56 ` [PATCH v3 19/19] drm/amd/display: Add HDMI VRR desktop mode Tomasz Pakuła
2026-02-06 18:58   ` Harry Wentland
2026-02-06 21:08     ` Tomasz Pakuła
2026-02-06 22:06   ` Alex Deucher
2026-02-06 19:00 ` [PATCH v3 00/19] drm/amd: VRR fixes, HDMI Gaming Features Harry Wentland

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®