public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features
@ 2026-02-16 16:44 Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 01/27] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
                   ` (26 more replies)
  0 siblings, 27 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

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

Built on top of amd-staging-drm-next

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/

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

Changes in v4:
- Removed amdgpu module settings for vrr and allm
- Introduced passive_vrr properties to drm_crtc and drm_connector
- Introduced ALLM properites to drm_connector
- Implemented said properties in amdgpu for HDMI connectors
- Updated the range extending logic
- Rebased on current amd-staging-drm-next

I'd really love to figure out how to enable drivers to override property
defaults for crtc/connector. Ideally, ALLM would default to dynamic mode, 
but attaching with said value doesn't matter as it will be set back to 0
after connector reset.

Range extending logic better explained in the comment/commit but turns out,
some manufacturers modify the lower VRR bound in Monitor Ranges due to
issues found just before release but the range wasn't updated in vsdb.
Using VRR with the extended lower limit caused blanking and other issues.

The reworked range extending logic will only extend the lower range, if
the VRR min found in Monitor Ranges disables LFC (vrr_min > vrr_max / 2).

The report and findings can be found here:
https://github.com/CachyOS/distribution/issues/329

Passive VRR is enabled by default for connectors that support it. It's
not super useful for DisplayPort so amdgpu only attaches it and uses it
for HDMI connectors. It hooks up to the already established
freesync_on_desktop logic which wasn't used at all, at least in the public
code.

Tomasz Pakuła (27):
  drm/amd/display: Return if DisplayID not found in parse_amd_vsdb()
  drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
  drm/amd/display: Remove redundant edid checks
  drm/amd/display: Move DisplayID vrr parsing
  drm/amd/display: Always try to parse AMD vsdb
  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: Separate DP/eDP and PCON paths completely
  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: Reintroduce VTEM info frame
  drm/amd/display: Enable HDMI VRR
  drm/amd/display: freesync_on_desktop support for HDMI VRR
  drm: Add passive_vrr_disabled property to crtc
  drm: Add passive_vrr_capable property to connector
  drm: Add ALLM properties to connector
  drm/amd/display: Use passive_vrr properties in amdgpu
  drm/amd/display: Use ALLM properties in amdgpu

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 299 ++++++++++++++----
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   4 +
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  49 ++-
 drivers/gpu/drm/amd/display/dc/core/dc.c      |   3 +
 .../gpu/drm/amd/display/dc/core/dc_resource.c |   2 +-
 drivers/gpu/drm/amd/display/dc/dc.h           |   1 +
 drivers/gpu/drm/amd/display/dc/dc_stream.h    |   2 +
 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 |  17 +-
 .../display/modules/info_packet/info_packet.c | 298 +++++++++++------
 drivers/gpu/drm/amd/include/amd_shared.h      |   6 +
 drivers/gpu/drm/drm_atomic_uapi.c             |   8 +
 drivers/gpu/drm/drm_connector.c               | 188 +++++++++++
 drivers/gpu/drm/drm_crtc.c                    |   2 +
 drivers/gpu/drm/drm_edid.c                    |  41 ++-
 drivers/gpu/drm/drm_mode_config.c             |   6 +
 include/drm/drm_connector.h                   |  99 ++++++
 include/drm/drm_crtc.h                        |   9 +
 include/drm/drm_mode_config.h                 |   6 +
 22 files changed, 864 insertions(+), 190 deletions(-)

-- 
2.53.0


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

* [PATCH v4 01/27] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb()
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 02/27] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
                   ` (25 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.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 12bebdfd7fdc..2d770ed98871 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13162,6 +13162,9 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 			break;
 	}
 
+	if (i == edid->extensions)
+		return false;
+
 	total_ext_block_len = EDID_LENGTH * edid->extensions;
 	while (j < total_ext_block_len - sizeof(struct amd_vsdb_block)) {
 		struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j];
-- 
2.53.0


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

* [PATCH v4 02/27] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 01/27] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 03/27] drm/amd/display: Remove redundant edid checks Tomasz Pakuła
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

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

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

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 110 +++++++++++-------
 1 file changed, 69 insertions(+), 41 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 2d770ed98871..6218ad911fde 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13144,8 +13144,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;
@@ -13199,13 +13199,13 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 	return false;
 }
 
-static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
+static bool 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 */
@@ -13226,9 +13226,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 false;
+}
+
+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);
 }
 
 /**
@@ -13245,13 +13283,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;
@@ -13284,60 +13323,49 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 
 	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
 
+	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;
-		}
 
-		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 */
+		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 &&
+		   drm_edid) {
+		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
+		if (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 && drm_edid) {
+		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
+		if (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->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;
+			parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
+			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+			freesync_capable = copy_range_to_amdgpu_connector(connector);
 		}
 	}
 
-- 
2.53.0


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

* [PATCH v4 03/27] drm/amd/display: Remove redundant edid checks
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 01/27] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 02/27] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 04/27] drm/amd/display: Move DisplayID vrr parsing Tomasz Pakuła
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

[Why]
Edid parsing functions check if edid is not null themselves. In a case
where edid is not present, the structs will be left initialised to 0
so anu possible assigment won't change the detected (or undetected)
functionality.

[How]
Remove edid pointer checks

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 ++++-----
 1 file changed, 4 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 6218ad911fde..903264b26d1f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13330,8 +13330,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	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 (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
+	    sink->sink_signal == SIGNAL_TYPE_EDP) {
 
 		if (dpcd_caps.allow_invalid_MSA_timing_param)
 			freesync_capable = copy_range_to_amdgpu_connector(connector);
@@ -13344,8 +13344,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
 		}
 
-	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A &&
-		   drm_edid) {
+	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
 		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
 		if (vsdb_info.freesync_supported) {
 			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
@@ -13356,7 +13355,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_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 && drm_edid) {
+	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
 		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
 		if (vsdb_info.freesync_supported) {
 			amdgpu_dm_connector->pack_sdp_v1_3 = true;
-- 
2.53.0


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

* [PATCH v4 04/27] drm/amd/display: Move DisplayID vrr parsing
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (2 preceding siblings ...)
  2026-02-16 16:44 ` [PATCH v4 03/27] drm/amd/display: Remove redundant edid checks Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 05/27] drm/amd/display: Always try to parse AMD vsdb Tomasz Pakuła
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

[Why]
DisplayID vrr parsing was always attempted, even though it's data is
only ever used in the DP/eDP path.

[How]
Move the parsing to where it's actually needed

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 903264b26d1f..be3bb5a86959 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13326,12 +13326,11 @@ 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;
 
-	/* 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) {
+		/* 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 (dpcd_caps.allow_invalid_MSA_timing_param)
 			freesync_capable = copy_range_to_amdgpu_connector(connector);
-- 
2.53.0


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

* [PATCH v4 05/27] drm/amd/display: Always try to parse AMD vsdb
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (3 preceding siblings ...)
  2026-02-16 16:44 ` [PATCH v4 04/27] drm/amd/display: Move DisplayID vrr parsing Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 06/27] drm/amd/display: Check for VRR range in CEA " Tomasz Pakuła
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

[Why]
Allows us to make the code inside amdgpu_dm_update_freesync_caps() more
concise and prepares for vsdb usage outside of HDMI and
DP -> HDMI 2.1 dongles.

[How]
Move the parsing function outside of specific signal type blocks.
Merge signal type checks and freesync_supported checks

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 27 ++++++++-----------
 1 file changed, 11 insertions(+), 16 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 be3bb5a86959..64d1dae4d214 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13322,6 +13322,7 @@ 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;
@@ -13343,28 +13344,22 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
 		}
 
-	} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
-		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
-		if (vsdb_info.freesync_supported) {
-			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
-			freesync_capable = copy_range_to_amdgpu_connector(connector);
-		}
+	} 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) {
-		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
-		if (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;
+	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;
 
-			parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
-			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
-			freesync_capable = copy_range_to_amdgpu_connector(connector);
-		}
+		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
+		monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
+		freesync_capable = copy_range_to_amdgpu_connector(connector);
 	}
 
 update:
-- 
2.53.0


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

* [PATCH v4 06/27] drm/amd/display: Check for VRR range in CEA AMD vsdb
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (4 preceding siblings ...)
  2026-02-16 16:44 ` [PATCH v4 05/27] drm/amd/display: Always try to parse AMD vsdb Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.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 64d1dae4d214..b3bf5e0c19a5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13332,6 +13332,12 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 		/* Some eDP panels only have the refresh rate range info in DisplayID */
 		if (is_monitor_range_invalid(connector))
 			parse_edid_displayid_vrr(connector, edid);
+		/*
+		 * 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.53.0


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

* [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in AMD vsdb
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (5 preceding siblings ...)
  2026-02-16 16:44 ` [PATCH v4 06/27] drm/amd/display: Check for VRR range in CEA " Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-26 12:36   ` Jani Nikula
  2026-02-16 16:44 ` [PATCH v4 08/27] drm/amd/display: Separate DP/eDP and PCON paths completely Tomasz Pakuła
                   ` (19 subsequent siblings)
  26 siblings, 1 reply; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

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

[How]
Compare exposed ranges and use the bigger one.
Only adjust lower limit if it doesn't support LFC

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 | 31 +++++++++++++++++++
 1 file changed, 31 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 b3bf5e0c19a5..f36059bb0324 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13269,6 +13269,34 @@ static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
 	return is_freesync_capable(range);
 }
 
+static void extend_range_from_vsdb(struct drm_display_info *display,
+				   const struct amdgpu_hdmi_vsdb_info *vsdb)
+{
+	u16 vrr_min = display->monitor_range.min_vfreq;
+	u16 vrr_max = display->monitor_range.max_vfreq;
+
+	/* Always extend upper limit */
+	if (vsdb->max_refresh_rate_hz > vrr_max)
+		vrr_max = vsdb->max_refresh_rate_hz;
+
+	/*
+	 * Only extend lower limit if current one disables LFC.
+
+	 * During widespread testing, we found that some manufacturers probably
+	 * had issues with their monitors' lower VRR boundaries and adjusted
+	 * them up (Gigabyte X34GS with official range 48 - 180, AMD vsdb 48 -
+	 * 180 yet Monitor Ranges 55 - 180). After setting the lower boundary
+	 * from AMD vsdb, such monitors start having blanking issues.
+	 *
+	 * Work around that by not touching VRR min if it still supports LFC.
+	 */
+	if (vsdb->min_refresh_rate_hz < vrr_min && (vrr_min * 2 >= vrr_max))
+		vrr_min = vsdb->min_refresh_rate_hz;
+
+	display->monitor_range.min_vfreq = vrr_min;
+	display->monitor_range.max_vfreq = vrr_max;
+}
+
 /**
  * amdgpu_dm_update_freesync_caps - Update Freesync capabilities
  *
@@ -13339,6 +13367,9 @@ 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);
 
+		/* Try extending range if found in AMD vsdb */
+		extend_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.53.0


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

* [PATCH v4 08/27] drm/amd/display: Separate DP/eDP and PCON paths completely
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (6 preceding siblings ...)
  2026-02-16 16:44 ` [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 09/27] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

[Why]
DP -> HDMI PCONs need a completely separate treatment but they did fall
into DP/eDP path in amdgpu_dm_update_freesync_caps() previously. This
could sometimes result in weird values assigned to the connector even
though it doesn't support VRR at all and needs a bit of HDMI-like
treatment.

[How]
Check if the connected sink is a HDMI -> DP converter earlier and
gate DP/eDP path

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index f36059bb0324..2f31fe7265d9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13321,6 +13321,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	struct dpcd_caps dpcd_caps = {0};
 	const struct edid *edid;
 	bool freesync_capable = false;
+	bool is_pcon = false;
 	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
 
 	if (!connector->state) {
@@ -13349,14 +13350,18 @@ 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;
+	}
 
-	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) {
 		/* Some eDP panels only have the refresh rate range info in DisplayID */
 		if (is_monitor_range_invalid(connector))
 			parse_edid_displayid_vrr(connector, edid);
@@ -13381,14 +13386,16 @@ 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)
+	if (amdgpu_dm_connector->dc_link && is_pcon)
 		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
 
+	/* DP -> HDMI PCON */
 	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;
-- 
2.53.0


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

* [PATCH v4 09/27] drm/amd/display: Refactor PCON VRR compatibility check
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (7 preceding siblings ...)
  2026-02-16 16:44 ` [PATCH v4 08/27] drm/amd/display: Separate DP/eDP and PCON paths completely Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:44 ` [PATCH v4 10/27] drm/amd/display: Add PCON VRR ID check override Tomasz Pakuła
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

[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 | 11 ++----
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 39 ++++++-------------
 drivers/gpu/drm/amd/display/dc/dm_helpers.h   |  2 +-
 3 files changed, 17 insertions(+), 35 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 2f31fe7265d9..2603da69d772 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13321,8 +13321,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;
+	bool pcon_allowed = false;
 	bool is_pcon = false;
-	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
 
 	if (!connector->state) {
 		drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__);
@@ -13357,6 +13357,7 @@ 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);
 	}
 
 	/* DP & eDP excluding PCONs */
@@ -13390,15 +13391,11 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	} 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 && is_pcon)
-		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
 
 	/* DP -> HDMI PCON */
-	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST && vsdb_info.freesync_supported) {
+	} 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;
 
 		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &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.53.0


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

* [PATCH v4 10/27] drm/amd/display: Add PCON VRR ID check override
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (8 preceding siblings ...)
  2026-02-16 16:44 ` [PATCH v4 09/27] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
@ 2026-02-16 16:44 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 11/27] drm/amd/display: Add CH7218 PCON ID Tomasz Pakuła
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:44 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.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 2603da69d772..b6079a1ce2ac 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2060,6 +2060,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 */
@@ -13357,7 +13360,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);
 	}
 
 	/* DP & eDP excluding PCONs */
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 ce08477d1ccd..141d8c76d001 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1058,6 +1058,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.53.0


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

* [PATCH v4 11/27] drm/amd/display: Add CH7218 PCON ID
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (9 preceding siblings ...)
  2026-02-16 16:44 ` [PATCH v4 10/27] drm/amd/display: Add PCON VRR ID check override Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 12/27] drm/edid: Parse more info from HDMI Forum vsdb Tomasz Pakuła
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.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.53.0


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

* [PATCH v4 12/27] drm/edid: Parse more info from HDMI Forum vsdb
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (10 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 11/27] drm/amd/display: Add CH7218 PCON ID Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 13/27] drm/amd/display: Rename PCON adaptive sync types Tomasz Pakuła
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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.53.0


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

* [PATCH v4 13/27] drm/amd/display: Rename PCON adaptive sync types
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (11 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 12/27] drm/edid: Parse more info from HDMI Forum vsdb Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 14/27] drm/amd/display: Enable HDMI VRR over PCON Tomasz Pakuła
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.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 b6079a1ce2ac..e511eb5a1f7f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9629,7 +9629,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)
@@ -13398,7 +13399,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.53.0


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

* [PATCH v4 14/27] drm/amd/display: Enable HDMI VRR over PCON
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (12 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 13/27] drm/amd/display: Rename PCON adaptive sync types Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 15/27] drm/amd/display: Support HDMI VRRmax=0 Tomasz Pakuła
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 29 +++++++++++++++----
 1 file changed, 23 insertions(+), 6 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 e511eb5a1f7f..931493433439 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13258,6 +13258,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
@@ -13322,6 +13333,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;
@@ -13357,6 +13369,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;
@@ -13398,13 +13411,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);
+		}
 
-		parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &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.53.0


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

* [PATCH v4 15/27] drm/amd/display: Support HDMI VRRmax=0
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (13 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 14/27] drm/amd/display: Enable HDMI VRR over PCON Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 16/27] drm/amd/display: Build HDMI vsif in correct slot Tomasz Pakuła
                   ` (11 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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.

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 931493433439..991e2262ecbc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13259,14 +13259,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;
 }
 
 /*
@@ -13413,8 +13426,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.53.0


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

* [PATCH v4 16/27] drm/amd/display: Build HDMI vsif in correct slot
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (14 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 15/27] drm/amd/display: Support HDMI VRRmax=0 Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 17/27] drm/amd/display: Save HDMI gaming info to edid caps Tomasz Pakuła
                   ` (10 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.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 991e2262ecbc..288437ada2a5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7391,7 +7391,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.53.0


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

* [PATCH v4 17/27] drm/amd/display: Save HDMI gaming info to edid caps
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (15 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 16/27] drm/amd/display: Build HDMI vsif in correct slot Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 18/27] drm/amd/display: Restore ALLM support in HDMI vsif Tomasz Pakuła
                   ` (9 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.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 bddb16bb76d4..2efca21a6561 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.53.0


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

* [PATCH v4 18/27] drm/amd/display: Restore ALLM support in HDMI vsif
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (16 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 17/27] drm/amd/display: Save HDMI gaming info to edid caps Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 19/27] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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.53.0


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

* [PATCH v4 19/27] drm/amd/display: Trigger ALLM if it's available
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (17 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 18/27] drm/amd/display: Restore ALLM support in HDMI vsif Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 20/27] drm/amd/display: Reintroduce VTEM info frame Tomasz Pakuła
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
---
 .../gpu/drm/amd/display/modules/info_packet/info_packet.c  | 7 ++++---
 1 file changed, 4 insertions(+), 3 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 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.53.0


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

* [PATCH v4 20/27] drm/amd/display: Reintroduce VTEM info frame
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (18 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 19/27] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 21/27] drm/amd/display: Enable HDMI VRR Tomasz Pakuła
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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).

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 | 167 ++++++++++++------
 2 files changed, 119 insertions(+), 52 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 306eb7355c25..027113ec147d 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
@@ -49,6 +49,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 53e488fdb4ea..96c84f70ed44 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
@@ -48,6 +48,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
@@ -63,65 +64,52 @@ enum vsc_packet_revision {
 #define VTEM_PB5		5
 #define VTEM_PB6		6
 
-#define VTEM_MD0		7
-#define VTEM_MD1		8
-#define VTEM_MD2		9
-#define VTEM_MD3		10
+#define VTEM_ORG_ID          1
+#define VTEM_DATA_SET_TAG    1
+#define VTEM_DATA_SET_LENGTH 4
 
+#define VTEM_M_CONST    0
+#define VTEM_FVA_FACTOR 0
 
-// 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
+#define VTEM_BRR_MASK_UPPER 0x03
+#define VTEM_BRR_MASK_LOWER 0xFF
 
-//PB1
-#define MASK_VTEM_PB1__RESERVED1 0xFF
+/* 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
 
-//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
+#define VTEM_MD0 7
+#define VTEM_MD1 8
+#define VTEM_MD2 9
+#define VTEM_MD3 10
 
+/* 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,
@@ -612,6 +600,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.53.0


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

* [PATCH v4 21/27] drm/amd/display: Enable HDMI VRR
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (19 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 20/27] drm/amd/display: Reintroduce VTEM info frame Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 22/27] drm/amd/display: freesync_on_desktop support for " Tomasz Pakuła
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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 288437ada2a5..6a2806cc800a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9629,7 +9629,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;
 
@@ -13419,8 +13422,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 027113ec147d..03d37b6f1cd0 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
@@ -59,6 +59,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 96c84f70ed44..7106b409ae54 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
@@ -699,6 +699,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.53.0


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

* [PATCH v4 22/27] drm/amd/display: freesync_on_desktop support for HDMI VRR
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (20 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 21/27] drm/amd/display: Enable HDMI VRR Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 23/27] drm: Add passive_vrr_disabled property to crtc Tomasz Pakuła
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[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. DisplayPort and eDP enforce seamless VRR transitions but
HDMI unfortunately doesn't.

[How]
Keep HDMI VRR toggled if it's supported and not explicitly disabled.
Add logic that control this behavior and use this mode by default until
it can be controlled by connector KMS property.

Functionally, for an end user, this is the same as normal, fixed refresh
rate mode. The only difference is that sink is kept in VRR state which
enables seamless transitions into/out of variable refresh rate.

Uses the already established freesync_on_desktop field and logic.

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

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 7106b409ae54..7e0adb90af39 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
@@ -633,6 +633,14 @@ static void build_vtem_infopacket_data(const struct dc_stream_state *stream,
 
 	vrr_active = vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
 		     vrr->state == VRR_STATE_ACTIVE_FIXED;
+	/*
+	 * Enables FreeSync-like behavior by keeping HDMI VRR signalling active
+	 * in fixed refresh rate conditions like normal desktop work/web browsing.
+	 * Functinally behaves like non-VRR mode by keeping the actual refresh
+	 * rate fixed.
+	 */
+	if (stream->freesync_on_desktop)
+		vrr_active |= vrr->state == VRR_STATE_INACTIVE;
 
 	infopacket->sb[VTEM_MD0] = VTEM_M_CONST << VTEM_M_CONST_BIT;
 	infopacket->sb[VTEM_MD0] |= VTEM_FVA_FACTOR << VTEM_FVA_BIT;
-- 
2.53.0


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

* [PATCH v4 23/27] drm: Add passive_vrr_disabled property to crtc
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (21 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 22/27] drm/amd/display: freesync_on_desktop support for " Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-17  8:21   ` Michel Dänzer
  2026-02-16 16:45 ` [PATCH v4 24/27] drm: Add passive_vrr_capable property to connector Tomasz Pakuła
                   ` (3 subsequent siblings)
  26 siblings, 1 reply; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

Many TVs and other HDMI sinks suffer from blanking and possibly other
glitches when VRR is toggled. With VRR present on such sinks and
vrr_on_desktop enabled, they behave like the signal is always variable,
even in fixed refresh rate situations. DisplayPort and eDP enforce
seamless VRR transitions but HDMI unfortunately doesn't.

Keep VRR toggled if it's supported and not explicitly disabled. It can
be used for any VRR sinks, but this is mainly targeted for HDMI.

Functionally, for an end user, this is the same as normal, fixed refresh
rate mode. The only difference is that sink is kept in VRR state which
enables seamless transitions into/out of variable refresh rate.

Basically, the driver shouldn't change it's behavior around VRR_ENABLED
set to false, jut keep sending info packets/frames with VRR/FreeSync/
G-Sync/HDMI VRR active.

Enabled by default for sinks that claim it's support

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/drm_atomic_uapi.c | 4 ++++
 drivers/gpu/drm/drm_crtc.c        | 2 ++
 drivers/gpu/drm/drm_mode_config.c | 6 ++++++
 include/drm/drm_crtc.h            | 9 +++++++++
 include/drm/drm_mode_config.h     | 6 ++++++
 5 files changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index b2cb5ae5a139..a3ad2fe3306b 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -383,6 +383,8 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 		return ret;
 	} else if (property == config->prop_vrr_enabled) {
 		state->vrr_enabled = val;
+	} else if (property == config->prop_passive_vrr_disabled) {
+		state->passive_vrr_disabled = val;
 	} else if (property == config->degamma_lut_property) {
 		ret = drm_property_replace_blob_from_id(dev,
 					&state->degamma_lut,
@@ -448,6 +450,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
 		*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
 	else if (property == config->prop_vrr_enabled)
 		*val = state->vrr_enabled;
+	else if (property == config->prop_passive_vrr_disabled)
+		*val = state->passive_vrr_disabled;
 	else if (property == config->degamma_lut_property)
 		*val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
 	else if (property == config->ctm_property)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index a7797d260f1e..4f2c871552e5 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -322,6 +322,8 @@ static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *
 					   config->prop_out_fence_ptr, 0);
 		drm_object_attach_property(&crtc->base,
 					   config->prop_vrr_enabled, 0);
+		drm_object_attach_property(&crtc->base,
+					   config->prop_passive_vrr_disabled, 0);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 25f376869b3a..542d21d7ca36 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -340,6 +340,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
 		return -ENOMEM;
 	dev->mode_config.prop_vrr_enabled = prop;
 
+	prop = drm_property_create_bool(dev, 0,
+			"PASSIVE_VRR_DISABLED");
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_passive_vrr_disabled = prop;
+
 	prop = drm_property_create(dev,
 			DRM_MODE_PROP_BLOB,
 			"DEGAMMA_LUT", 0);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 66278ffeebd6..59dbb7ce1358 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -299,6 +299,15 @@ struct drm_crtc_state {
 	 */
 	bool vrr_enabled;
 
+	/**
+	 * @passive_vrr_disabled:
+	 *
+	 * Indicates if variable refresh rate on desktop should be enabled for
+	 * the CRTC. Support for the requested state will depend on driver and
+	 * hardware capabiltiy - lacking support is not treated as failure.
+	 */
+	bool passive_vrr_disabled;
+
 	/**
 	 * @self_refresh_active:
 	 *
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 2e848b816218..541cfaba67a2 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -679,6 +679,12 @@ struct drm_mode_config {
 	 * whether variable refresh rate should be enabled on the CRTC.
 	 */
 	struct drm_property *prop_vrr_enabled;
+	/**
+	 * @prop_passive_vrr_disabled: Default atomic CRTC property to indicate
+	 * whether passive variable refresh rate should be disabled
+	 * on the CRTC.
+	 */
+	struct drm_property *prop_passive_vrr_disabled;
 
 	/**
 	 * @dvi_i_subconnector_property: Optional DVI-I property to
-- 
2.53.0


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

* [PATCH v4 24/27] drm: Add passive_vrr_capable property to connector
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (22 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 23/27] drm: Add passive_vrr_disabled property to crtc Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 25/27] drm: Add ALLM properties " Tomasz Pakuła
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

Supplement to the passive_vrr_disabled crtc property

Drivers can add the property to a connector with
drm_connector_attach_passive_vrr_capable_property().
The value should be updated based on driver and hardware capability
by using drm_connector_set_passive_vrr_capable_property().

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/drm_connector.c | 73 +++++++++++++++++++++++++++++++++
 include/drm/drm_connector.h     | 15 +++++++
 2 files changed, 88 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 272d6254ea47..5bb38b80e214 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -2346,6 +2346,16 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
  *
  *	Absence of the property should indicate absence of support.
  *
+ * "passive_vrr_capable":
+ *	Optional &drm_connector boolean property that drivers should attach
+ *	with drm_connector_attach_passive_vrr_capable_property() on
+ *	connectors that could support keeping variable refresh rate signalling
+ *	in fixed-refresh rate scenarios like desktop work. Drivers should update
+ *	the property value by calling
+ *	drm_connector_set_passive_vrr_capable_property().
+ *
+ *	Absence of the property should indicate absence of support.
+ *
  * "VRR_ENABLED":
  *	Default &drm_crtc boolean property that notifies the driver that the
  *	content on the CRTC is suitable for variable refresh rate presentation.
@@ -2364,6 +2374,17 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
  *
  *	The driver may place further restrictions within these minimum
  *	and maximum bounds.
+ *
+ * "PASSIVE_VRR_DISABLED":
+ *	Default &drm_crtc boolean property that notifies the driver that the
+ *	VRR singalling should be disabled in fixed refresh rate scenarios.
+ *	Functionally, psssive vrr works the same as VRR_ENABLED == false
+ *	but works around displays blanking (mainly HDMI) that do not support
+ *	seamless VRR transitions. Also helps with brightness flickering during
+ *	VRR transitions.
+ *
+ *	Passive VRR mode is not that useful for DP/eDP sinks where seamless VRR
+ *	transitions are enforced by the standard.
  */
 
 /**
@@ -2397,6 +2418,37 @@ int drm_connector_attach_vrr_capable_property(
 }
 EXPORT_SYMBOL(drm_connector_attach_vrr_capable_property);
 
+/**
+ * drm_connector_attach_passive_vrr_capable_property - creates the
+ * passive_vrr_capable property
+ * @connector: connector to create the passive_vrr_capable property on.
+ *
+ * This is used by atomic drivers to add support for querying
+ * variable refresh rate on desktop capability for a connector.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_attach_passive_vrr_capable_property(
+	struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_property *prop;
+
+	if (!connector->passive_vrr_capable_property) {
+		prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE,
+			"passive_vrr_capable");
+		if (!prop)
+			return -ENOMEM;
+
+		connector->passive_vrr_capable_property = prop;
+		drm_object_attach_property(&connector->base, prop, 0);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_passive_vrr_capable_property);
+
 /**
  * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property
  * @connector: connector to attach scaling mode property on.
@@ -2968,6 +3020,27 @@ void drm_connector_set_vrr_capable_property(
 }
 EXPORT_SYMBOL(drm_connector_set_vrr_capable_property);
 
+/**
+ * drm_connector_set_passive_vrr_disabled_capable_property - sets the variable refresh
+ * rate on desktop capable property for a connector
+ * @connector: drm connector
+ * @capable: True if the connector is variable refresh rate on desktop capable
+ *
+ * Should be used by atomic drivers to update the indicated support for
+ * variable refresh rate on desktop over a connector.
+ */
+void drm_connector_set_passive_vrr_capable_property(
+		struct drm_connector *connector, bool capable)
+{
+	if (!connector->passive_vrr_capable_property)
+		return;
+
+	drm_object_property_set_value(&connector->base,
+				      connector->passive_vrr_capable_property,
+				      capable);
+}
+EXPORT_SYMBOL(drm_connector_set_passive_vrr_capable_property);
+
 /**
  * drm_connector_set_panel_orientation - sets the connector's panel_orientation
  * @connector: connector for which to set the panel-orientation property.
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index dab9d5521f41..30dd9737bfe0 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2101,6 +2101,17 @@ struct drm_connector {
 	 */
 	struct drm_property *vrr_capable_property;
 
+	/**
+	 * @passive_vrr_capable_property: Optional property to help userspace
+	 * query hardware support for passive variable refresh rate on a
+	 * connector. Drivers can add the property to a connector by
+	 * calling drm_connector_attach_passive_vrr_capable_property().
+	 *
+	 * This should be updated only by calling
+	 * drm_connector_set_passive_vrr_capable_property().
+	 */
+	struct drm_property *passive_vrr_capable_property;
+
 	/**
 	 * @colorspace_property: Connector property to set the suitable
 	 * colorspace supported by the sink.
@@ -2495,6 +2506,8 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
 					       u32 scaling_mode_mask);
 int drm_connector_attach_vrr_capable_property(
 		struct drm_connector *connector);
+int drm_connector_attach_passive_vrr_capable_property(
+		struct drm_connector *connector);
 int drm_connector_attach_broadcast_rgb_property(struct drm_connector *connector);
 int drm_connector_attach_colorspace_property(struct drm_connector *connector);
 int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector);
@@ -2517,6 +2530,8 @@ void drm_connector_set_link_status_property(struct drm_connector *connector,
 					    uint64_t link_status);
 void drm_connector_set_vrr_capable_property(
 		struct drm_connector *connector, bool capable);
+void drm_connector_set_passive_vrr_capable_property(
+		struct drm_connector *connector, bool capable);
 int drm_connector_set_panel_orientation(
 	struct drm_connector *connector,
 	enum drm_panel_orientation panel_orientation);
-- 
2.53.0


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

* [PATCH v4 25/27] drm: Add ALLM properties to connector
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (23 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 24/27] drm: Add passive_vrr_capable property to connector Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 26/27] drm/amd/display: Use passive_vrr properties in amdgpu Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 27/27] drm/amd/display: Use ALLM " Tomasz Pakuła
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

Adds HDMI Auto Low Latency Mode optional connector properties allm_mode
and allm_mode_capable.

ALLM automatically puts TVs into low latency modes (gaming modes) and
it's part of the HDMI Gaming Features introduced in HDMI 2.1.

allm_mode_capable indicates whether connector (sink) supports ALLM
allm_mode tells the driver which triggering mode to use. Off, dynamic
and always on. Dynamic mode should consider the content type and the
state of the crtc to discern whether ALLM should be activated.

Recommendation is Content Type Hint == Game || VRR_ENABLED based on
testing behaviors on other operating systems and multiple GPU vendors +
how TVs behave.

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
 drivers/gpu/drm/drm_atomic_uapi.c |   4 ++
 drivers/gpu/drm/drm_connector.c   | 115 ++++++++++++++++++++++++++++++
 include/drm/drm_connector.h       |  37 ++++++++++
 3 files changed, 156 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index a3ad2fe3306b..cfb50a3d617d 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -758,6 +758,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
 		state->content_type = val;
 	} else if (property == connector->scaling_mode_property) {
 		state->scaling_mode = val;
+	} else if (property == connector->allm_mode_property) {
+		state->allm_mode = val;
 	} else if (property == config->content_protection_property) {
 		if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
 			drm_dbg_kms(dev, "only drivers can set CP Enabled\n");
@@ -855,6 +857,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		*val = state->colorspace;
 	} else if (property == connector->scaling_mode_property) {
 		*val = state->scaling_mode;
+	} else if (property == connector->allm_mode_property) {
+		*val = state->allm_mode;
 	} else if (property == config->hdr_output_metadata_property) {
 		*val = state->hdr_output_metadata ?
 			state->hdr_output_metadata->base.id : 0;
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 5bb38b80e214..14d504ca73f4 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1226,6 +1226,12 @@ static const struct drm_prop_enum_list drm_content_type_enum_list[] = {
 	{ DRM_MODE_CONTENT_TYPE_GAME, "Game" },
 };
 
+static const struct drm_prop_enum_list drm_allm_mode_enum_list[] = {
+	{ DRM_ALLM_MODE_DISABLED, "Disabled" },
+	{ DRM_ALLM_MODE_ENABLED_DYNAMIC, "Dynamic" },
+	{ DRM_ALLM_MODE_ENABLED_FORCED, "Always On" },
+};
+
 static const struct drm_prop_enum_list drm_panel_orientation_enum_list[] = {
 	{ DRM_MODE_PANEL_ORIENTATION_NORMAL,	"Normal"	},
 	{ DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP,	"Upside Down"	},
@@ -2449,6 +2455,94 @@ int drm_connector_attach_passive_vrr_capable_property(
 }
 EXPORT_SYMBOL(drm_connector_attach_passive_vrr_capable_property);
 
+/**
+ * DOC: Auto Low Latency Mode properties
+ *
+ * Auto Low Latency capable HDMI displays (be it PC monitors or TVs)
+ * can automatically enter a "low latency" mode, usually named "Game Mode" by
+ * receiving specific data in HDMI Forum vendor-specific info frame.
+ *
+ * This usually is the best mode for PC usage but disables as much processing as
+ * possible which might not be desireable on lower end devices casing them to
+ * produce an image that's unsatisfactory to some users.
+ *
+ * "allm_capable":
+ *	Optional &drm_connector boolean property that drivers should attach
+ *	with drm_connector_attach_allm_capable_property() on connectors that
+ *	could support Auto Low Latency Mode. Drivers should update the
+ *	property value by calling drm_connector_set_allm_capable_property().
+ *
+ *	Absence of the property should indicate absence of support.
+ *
+ * "ALLM_MODE":
+ *	Optional &drm_connector enum property enables compositors to control and
+ *	expose ALLM triggering behavior modes to the end user where:
+ *
+ *	- ALLM_MODE_DISABLED: completely disabled ALLM signalling.
+ *	- ALLM_MODE_ENABLED_DYNAMIC: triggers ALLM based on current needs.
+ *	  preferrably display content type hint being set to Game by compositor
+ *	  or VRR being enabled and active.
+ *	- ALLM_MODE_ENABLED_FORCED: always-on ALLM triggering.
+ *
+ *	ALLM_MODE_ENABLED_DYNAMIC should behave like gaming devices such as
+ *	consoles where ALLM is only triggered when needed. It's main purpose is
+ *	gaming (part of so-called HDMI gaming features).
+ *
+ *	If compositors wish to control ALLM completely on their own, they can
+ *	switch between disabled and enabled_forced modes.
+ */
+
+/**
+ * drm_connector_attach_allm_capable_property - creates the
+ * allm_capable property
+ * @connector: connector to create the allm_capable property on.
+ *
+ * This is used by atomic drivers to add support for querying
+ * Auto Low Latency Mode capability for a connector.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_attach_allm_capable_property(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_property *prop;
+
+	if (!connector->allm_capable_property) {
+		prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE,
+			"allm_capable");
+		if (!prop)
+			return -ENOMEM;
+
+		connector->allm_capable_property = prop;
+		drm_object_attach_property(&connector->base, prop, 0);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_allm_capable_property);
+
+int drm_connector_attach_allm_mode_property(struct drm_connector *connector)
+{
+	struct drm_property *prop;
+
+	if (connector->allm_mode_property)
+		return 0;
+
+	prop = drm_property_create_enum(connector->dev, 0, "allm_mode",
+					drm_allm_mode_enum_list,
+					ARRAY_SIZE(drm_allm_mode_enum_list));
+	if (!prop)
+		return -ENOMEM;
+
+	connector->allm_mode_property = prop;
+	drm_object_attach_property(&connector->base, prop,
+				   DRM_ALLM_MODE_DISABLED);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_allm_mode_property);
+
 /**
  * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property
  * @connector: connector to attach scaling mode property on.
@@ -3041,6 +3135,27 @@ void drm_connector_set_passive_vrr_capable_property(
 }
 EXPORT_SYMBOL(drm_connector_set_passive_vrr_capable_property);
 
+/**
+ * drm_connector_set_allm_capable_property - sets Auto Low Latency Mode
+ * capable property for a connector
+ * @connector: drm connector
+ * @capable: True if the connector is ALLM capable
+ *
+ * Should be used by atomic drivers to update the indicated support for
+ * Auto Low Latency Mode over a connector.
+ */
+void drm_connector_set_allm_capable_property(
+		struct drm_connector *connector, bool capable)
+{
+	if (!connector->allm_capable_property)
+		return;
+
+	drm_object_property_set_value(&connector->base,
+				      connector->allm_capable_property,
+				      capable);
+}
+EXPORT_SYMBOL(drm_connector_set_allm_capable_property);
+
 /**
  * drm_connector_set_panel_orientation - sets the connector's panel_orientation
  * @connector: connector for which to set the panel-orientation property.
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 30dd9737bfe0..fa4abfe8971e 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -58,6 +58,12 @@ enum drm_connector_force {
 	DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
 };
 
+enum drm_allm_mode {
+	DRM_ALLM_MODE_DISABLED,
+	DRM_ALLM_MODE_ENABLED_DYNAMIC,
+	DRM_ALLM_MODE_ENABLED_FORCED,
+};
+
 /**
  * enum drm_connector_status - status for a &drm_connector
  *
@@ -1147,6 +1153,13 @@ struct drm_connector_state {
 	 */
 	unsigned int content_protection;
 
+	/**
+	 * @allm_mode: Connector property to control the
+	 * HDMI Auto Low Latency Mode trigger setting.
+	 * The %DRM_ALLM_MODE_\* values must match the values.
+	 */
+	enum drm_allm_mode allm_mode;
+
 	/**
 	 * @colorspace: State variable for Connector property to request
 	 * colorspace change on Sink. This is most commonly used to switch
@@ -2112,6 +2125,26 @@ struct drm_connector {
 	 */
 	struct drm_property *passive_vrr_capable_property;
 
+	/**
+	 * @allm_capable_property: Optional property to help userspace
+	 * query hardware support for HDMI Auto Low Latency Mode on a connector.
+	 * Drivers can add the property to a connector by calling
+	 * drm_connector_attach_allm_capable_property().
+	 *
+	 * This should be updated only by calling
+	 * drm_connector_set_allm_capable_property().
+	 */
+	struct drm_property *allm_capable_property;
+
+	/**
+	 * @allm_mode_property:
+	 *
+	 * Indicates HDMI Auto Low Latency Mode triggering mode for connector.
+	 * Support for the requested state will depend on driver and hardware
+	 * capabiltiy - lacking support is not treated as failure.
+	 */
+	struct drm_property *allm_mode_property;
+
 	/**
 	 * @colorspace_property: Connector property to set the suitable
 	 * colorspace supported by the sink.
@@ -2508,6 +2541,8 @@ int drm_connector_attach_vrr_capable_property(
 		struct drm_connector *connector);
 int drm_connector_attach_passive_vrr_capable_property(
 		struct drm_connector *connector);
+int drm_connector_attach_allm_capable_property(struct drm_connector *connector);
+int drm_connector_attach_allm_mode_property(struct drm_connector *connector);
 int drm_connector_attach_broadcast_rgb_property(struct drm_connector *connector);
 int drm_connector_attach_colorspace_property(struct drm_connector *connector);
 int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector);
@@ -2532,6 +2567,8 @@ void drm_connector_set_vrr_capable_property(
 		struct drm_connector *connector, bool capable);
 void drm_connector_set_passive_vrr_capable_property(
 		struct drm_connector *connector, bool capable);
+void drm_connector_set_allm_capable_property(
+		struct drm_connector *connector, bool capable);
 int drm_connector_set_panel_orientation(
 	struct drm_connector *connector,
 	enum drm_panel_orientation panel_orientation);
-- 
2.53.0


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

* [PATCH v4 26/27] drm/amd/display: Use passive_vrr properties in amdgpu
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (24 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 25/27] drm: Add ALLM properties " Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  2026-02-16 16:45 ` [PATCH v4 27/27] drm/amd/display: Use ALLM " Tomasz Pakuła
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[How]
Attach and use this properties for HDMI sinks which are troublesome
with their VRR state transitions. Hook into already-established
freesync_on_desktop logic.

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

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 6a2806cc800a..41677c50b3d2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7850,6 +7850,8 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
 	__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
 
 	new_state->freesync_capable = state->freesync_capable;
+	new_state->freesync_on_desktop_capable =
+		state->freesync_on_desktop_capable;
 	new_state->abm_level = state->abm_level;
 	new_state->scaling = state->scaling;
 	new_state->underscan_enable = state->underscan_enable;
@@ -9057,8 +9059,10 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
 	    connector_type == DRM_MODE_CONNECTOR_eDP) {
 		drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
 
-		if (!aconnector->mst_root)
+		if (!aconnector->mst_root) {
 			drm_connector_attach_vrr_capable_property(&aconnector->base);
+			drm_connector_attach_passive_vrr_capable_property(&aconnector->base);
+		}
 
 		if (adev->dm.hdcp_workqueue)
 			drm_connector_attach_content_protection_property(&aconnector->base, true);
@@ -11338,6 +11342,12 @@ static void get_freesync_config_for_crtc(
 		config.vsif_supported = true;
 		config.btr = true;
 
+		if (new_con_state->freesync_on_desktop_capable)
+			new_crtc_state->stream->freesync_on_desktop =
+				!new_crtc_state->base.passive_vrr_disabled;
+		else
+			new_crtc_state->stream->freesync_on_desktop = false;
+
 		if (fs_vid_mode) {
 			config.state = VRR_STATE_ACTIVE_FIXED;
 			config.fixed_refresh_in_uhz = new_crtc_state->freesync_config.fixed_refresh_in_uhz;
@@ -11349,6 +11359,7 @@ static void get_freesync_config_for_crtc(
 		}
 	} else {
 		config.state = VRR_STATE_UNSUPPORTED;
+		new_crtc_state->stream->freesync_on_desktop = false;
 	}
 out:
 	new_crtc_state->freesync_config = config;
@@ -13352,6 +13363,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	struct drm_hdmi_vrr_cap hdmi_vrr = {0};
 	struct dpcd_caps dpcd_caps = {0};
 	const struct edid *edid;
+	bool freesync_on_desktop = false;
 	bool freesync_capable = false;
 	bool pcon_allowed = false;
 	bool is_pcon = false;
@@ -13431,6 +13443,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 			monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
 
 		freesync_capable = copy_range_to_amdgpu_connector(connector);
+		freesync_on_desktop = freesync_capable;
 
 	/* DP -> HDMI PCON */
 	} else if (pcon_allowed) {
@@ -13445,11 +13458,14 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 		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);
+		freesync_on_desktop = freesync_capable;
 	}
 
 update:
-	if (dm_con_state)
+	if (dm_con_state) {
 		dm_con_state->freesync_capable = freesync_capable;
+		dm_con_state->freesync_on_desktop_capable = freesync_on_desktop;
+	}
 
 	if (connector->state && amdgpu_dm_connector->dc_link && !freesync_capable &&
 	    amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported) {
@@ -13458,8 +13474,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	}
 
 	if (connector->vrr_capable_property)
-		drm_connector_set_vrr_capable_property(connector,
-						       freesync_capable);
+		drm_connector_set_vrr_capable_property(connector, freesync_capable);
+
+	if (connector->passive_vrr_capable_property)
+		drm_connector_set_passive_vrr_capable_property(connector, freesync_on_desktop);
 }
 
 void amdgpu_dm_trigger_timing_sync(struct drm_device *dev)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 800813671748..88ec2b88dcaf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1020,6 +1020,7 @@ struct dm_connector_state {
 	uint8_t underscan_hborder;
 	bool underscan_enable;
 	bool freesync_capable;
+	bool freesync_on_desktop_capable;
 	bool update_hdcp;
 	bool abm_sysfs_forbidden;
 	uint8_t abm_level;
-- 
2.53.0


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

* [PATCH v4 27/27] drm/amd/display: Use ALLM properties in amdgpu
  2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
                   ` (25 preceding siblings ...)
  2026-02-16 16:45 ` [PATCH v4 26/27] drm/amd/display: Use passive_vrr properties in amdgpu Tomasz Pakuła
@ 2026-02-16 16:45 ` Tomasz Pakuła
  26 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-16 16:45 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

[Why]
To enable ALLM when asked for by compositor

[How]
Attach properties to HDMI sinks, detect support and set allm_capable
property, set allm_capable property for amdgpu_dm_connector

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

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 41677c50b3d2..695100c78314 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8969,6 +8969,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
 	aconnector->audio_inst = -1;
 	aconnector->pack_sdp_v1_3 = false;
 	aconnector->as_type = ADAPTIVE_SYNC_TYPE_NONE;
+	aconnector->hdmi_allm_capable = false;
 	memset(&aconnector->vsdb_info, 0, sizeof(aconnector->vsdb_info));
 	mutex_init(&aconnector->hpd_lock);
 	mutex_init(&aconnector->handle_mst_msg_ready);
@@ -9166,6 +9167,10 @@ int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector)
 	struct drm_device *ddev = aconnector->base.dev;
 	struct device *hdmi_dev = ddev->dev;
 
+	/* ALLM */
+	drm_connector_attach_allm_capable_property(&aconnector->base);
+	drm_connector_attach_allm_mode_property(&aconnector->base);
+
 	if (amdgpu_dc_debug_mask & DC_DISABLE_HDMI_CEC) {
 		drm_info(ddev, "HDMI-CEC feature masked\n");
 		return -EINVAL;
@@ -10856,6 +10861,31 @@ static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_state *state)
 	return 0;
 }
 
+static void update_allm_state_on_crtc_stream(struct dm_crtc_state *new_crtc_state,
+					     const struct drm_connector_state *new_conn)
+{
+	struct mod_freesync_config *config = &new_crtc_state->freesync_config;
+	struct dc_stream_state *new_stream = new_crtc_state->stream;
+	bool allm_active = false;
+
+	switch (new_conn->allm_mode) {
+	case DRM_ALLM_MODE_ENABLED_DYNAMIC:
+		allm_active = config->state == VRR_STATE_ACTIVE_VARIABLE ||
+			      new_stream->content_type == DISPLAY_CONTENT_TYPE_GAME;
+		break;
+
+	case DRM_ALLM_MODE_ENABLED_FORCED:
+		allm_active = true;
+		break;
+
+	case DRM_ALLM_MODE_DISABLED:
+	default:
+		allm_active = false;
+	}
+
+	new_stream->hdmi_allm_active = allm_active;
+}
+
 /**
  * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation.
  * @state: The atomic state to commit
@@ -10898,12 +10928,14 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 	for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
 		struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
 		struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
+		struct amdgpu_dm_connector *dm_conn = to_amdgpu_dm_connector(connector);
 		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
 		struct dc_surface_update *dummy_updates;
 		struct dc_stream_update stream_update;
 		struct dc_info_packet hdr_packet;
 		struct dc_stream_status *status = NULL;
 		bool abm_changed, hdr_changed, scaling_changed, output_color_space_changed = false;
+		bool allm_changed = false;
 
 		memset(&stream_update, 0, sizeof(stream_update));
 
@@ -10933,7 +10965,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 		hdr_changed =
 			!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state);
 
-		if (!scaling_changed && !abm_changed && !hdr_changed && !output_color_space_changed)
+		allm_changed = dm_conn->hdmi_allm_capable &&
+			       (new_con_state->allm_mode != old_con_state->allm_mode);
+
+		if (!scaling_changed && !abm_changed && !hdr_changed &&
+		    !output_color_space_changed && !allm_changed)
 			continue;
 
 		stream_update.stream = dm_new_crtc_state->stream;
@@ -10963,6 +10999,17 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 			stream_update.hdr_static_metadata = &hdr_packet;
 		}
 
+		if (allm_changed) {
+			update_allm_state_on_crtc_stream(dm_new_crtc_state, new_con_state);
+			mod_build_hf_vsif_infopacket(dm_new_crtc_state->stream,
+				&dm_new_crtc_state->stream->hfvsif_infopacket);
+
+			stream_update.hdmi_allm_active =
+				&dm_new_crtc_state->stream->hdmi_allm_active;
+			stream_update.hfvsif_infopacket =
+				&dm_new_crtc_state->stream->hfvsif_infopacket;
+		}
+
 		status = dc_stream_get_status(dm_new_crtc_state->stream);
 
 		if (WARN_ON(!status))
@@ -13478,6 +13525,11 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 
 	if (connector->passive_vrr_capable_property)
 		drm_connector_set_passive_vrr_capable_property(connector, freesync_on_desktop);
+
+	amdgpu_dm_connector->hdmi_allm_capable = connector->display_info.hdmi.allm;
+	if (connector->allm_capable_property)
+		drm_connector_set_allm_capable_property(
+			connector, connector->display_info.hdmi.allm);
 }
 
 void amdgpu_dm_trigger_timing_sync(struct drm_device *dev)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 88ec2b88dcaf..b9d27a483b1e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -847,6 +847,9 @@ struct amdgpu_dm_connector {
 	unsigned int hdmi_hpd_debounce_delay_ms;
 	struct delayed_work hdmi_hpd_debounce_work;
 	struct dc_sink *hdmi_prev_sink;
+
+	/* HDMI ALLM */
+	bool hdmi_allm_capable;
 };
 
 static inline void amdgpu_dm_set_mst_status(uint8_t *status,
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 17ba7af0ddcd..bfaa2fb0cba8 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -3295,6 +3295,9 @@ static void copy_stream_update_to_stream(struct dc *dc,
 	if (update->vrr_active_fixed)
 		stream->vrr_active_fixed = *update->vrr_active_fixed;
 
+	if (update->hdmi_allm_active)
+		stream->hdmi_allm_active = *update->hdmi_allm_active;
+
 	if (update->crtc_timing_adjust) {
 		if (stream->adjust.v_total_min != update->crtc_timing_adjust->v_total_min ||
 			stream->adjust.v_total_max != update->crtc_timing_adjust->v_total_max ||
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 639831295b21..078ca4a7258f 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -4660,7 +4660,7 @@ static void set_avi_info_frame(
 		vic = 0;
 	format = stream->timing.timing_3d_format;
 	/*todo, add 3DStereo support*/
-	if (format != TIMING_3D_FORMAT_NONE) {
+	if (format != TIMING_3D_FORMAT_NONE || stream->hdmi_allm_active) {
 		// 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/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index 9960494007ff..17f891b03416 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -242,6 +242,7 @@ struct dc_stream_state {
 	bool vrr_active_variable;
 	bool freesync_on_desktop;
 	bool vrr_active_fixed;
+	bool hdmi_allm_active;
 
 	bool converter_disable_audio;
 	uint8_t qs_bit;
@@ -345,6 +346,7 @@ struct dc_stream_update {
 	bool *allow_freesync;
 	bool *vrr_active_variable;
 	bool *vrr_active_fixed;
+	bool *hdmi_allm_active;
 
 	struct colorspace_transform *gamut_remap;
 	enum dc_color_space *output_color_space;
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 7e0adb90af39..fcfab7b9e0e2 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
@@ -500,7 +500,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 (stream->hdmi_allm_active)
 		return false;
 
 	return true;
@@ -529,7 +529,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 = stream->hdmi_allm_active;
 		format = stream->view_format == VIEW_3D_FORMAT_NONE ?
 			 TIMING_3D_FORMAT_NONE :
 			 stream->timing.timing_3d_format;
-- 
2.53.0


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

* Re: [PATCH v4 23/27] drm: Add passive_vrr_disabled property to crtc
  2026-02-16 16:45 ` [PATCH v4 23/27] drm: Add passive_vrr_disabled property to crtc Tomasz Pakuła
@ 2026-02-17  8:21   ` Michel Dänzer
  2026-02-17 16:41     ` Tomasz Pakuła
  0 siblings, 1 reply; 34+ messages in thread
From: Michel Dänzer @ 2026-02-17  8:21 UTC (permalink / raw)
  To: Tomasz Pakuła, alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	daniel

On 2/16/26 17:45, Tomasz Pakuła wrote:
> Many TVs and other HDMI sinks suffer from blanking and possibly other
> glitches when VRR is toggled. With VRR present on such sinks and
> vrr_on_desktop enabled, they behave like the signal is always variable,
> even in fixed refresh rate situations. DisplayPort and eDP enforce
> seamless VRR transitions but HDMI unfortunately doesn't.
> 
> Keep VRR toggled if it's supported and not explicitly disabled. It can
> be used for any VRR sinks, but this is mainly targeted for HDMI.
> 
> Functionally, for an end user, this is the same as normal, fixed refresh
> rate mode. The only difference is that sink is kept in VRR state which
> enables seamless transitions into/out of variable refresh rate.
> 
> Basically, the driver shouldn't change it's behavior around VRR_ENABLED
> set to false, jut keep sending info packets/frames with VRR/FreeSync/
> G-Sync/HDMI VRR active.
> 
> Enabled by default for sinks that claim it's support

Having a negation term like "disabled" in the property name can be confusing (as it involves double negation when the property value is 0) and is better avoided.


-- 
Earthling Michel Dänzer       \        GNOME / Xwayland / Mesa developer
https://redhat.com             \               Libre software enthusiast

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

* Re: [PATCH v4 23/27] drm: Add passive_vrr_disabled property to crtc
  2026-02-17  8:21   ` Michel Dänzer
@ 2026-02-17 16:41     ` Tomasz Pakuła
  0 siblings, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-17 16:41 UTC (permalink / raw)
  To: Michel Dänzer, alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	daniel

On Tue, 2026-02-17 at 09:21 +0100, Michel Dänzer wrote:
> On 2/16/26 17:45, Tomasz Pakuła wrote:
> > Many TVs and other HDMI sinks suffer from blanking and possibly other
> > glitches when VRR is toggled. With VRR present on such sinks and
> > vrr_on_desktop enabled, they behave like the signal is always variable,
> > even in fixed refresh rate situations. DisplayPort and eDP enforce
> > seamless VRR transitions but HDMI unfortunately doesn't.
> > 
> > Keep VRR toggled if it's supported and not explicitly disabled. It can
> > be used for any VRR sinks, but this is mainly targeted for HDMI.
> > 
> > Functionally, for an end user, this is the same as normal, fixed refresh
> > rate mode. The only difference is that sink is kept in VRR state which
> > enables seamless transitions into/out of variable refresh rate.
> > 
> > Basically, the driver shouldn't change it's behavior around VRR_ENABLED
> > set to false, jut keep sending info packets/frames with VRR/FreeSync/
> > G-Sync/HDMI VRR active.
> > 
> > Enabled by default for sinks that claim it's support
> 
> Having a negation term like "disabled" in the property name can be confusing (as it involves double negation when the property value is 0) and is better avoided.
> 

I understand that and felt a little cheaty by doing this but I couldn't
for the life of my figure out how to make it so a driver could override
this by default, before the compositor will set this. Would a "set"
function work, just like for "capable" properties?
 
I 100% believe this "Passive VRR" for HDMI should be the default and
helps massively but I'm not even that convinced if this must be user
configurable. Alex asked to make it a property, but In the end, it's not
something thsdat can be controlled on other OSes. I still believe that
users should be able to change this somehow, but if amdgpu module
setting wasn't a good fit, I don't know what is.

In the end, I can just yeet all this completely and hardcode
freesync_on_desktop = true for HDMI like it's done in the windows
driver.

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

* Re: [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in AMD vsdb
  2026-02-16 16:44 ` [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
@ 2026-02-26 12:36   ` Jani Nikula
  2026-02-26 13:42     ` Tomasz Pakuła
  2026-03-17 10:03     ` Tomasz Pakuła
  0 siblings, 2 replies; 34+ messages in thread
From: Jani Nikula @ 2026-02-26 12:36 UTC (permalink / raw)
  To: Tomasz Pakuła, 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

On Mon, 16 Feb 2026, Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com> wrote:
> [Why]
> Some monitors only expose their full VRR range in AMD vsdb for some
> reason.
>
> [How]
> Compare exposed ranges and use the bigger one.
> Only adjust lower limit if it doesn't support LFC
>
> 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 | 31 +++++++++++++++++++
>  1 file changed, 31 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 b3bf5e0c19a5..f36059bb0324 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -13269,6 +13269,34 @@ static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
>  	return is_freesync_capable(range);
>  }
>  
> +static void extend_range_from_vsdb(struct drm_display_info *display,
> +				   const struct amdgpu_hdmi_vsdb_info *vsdb)
> +{
> +	u16 vrr_min = display->monitor_range.min_vfreq;
> +	u16 vrr_max = display->monitor_range.max_vfreq;
> +
> +	/* Always extend upper limit */
> +	if (vsdb->max_refresh_rate_hz > vrr_max)
> +		vrr_max = vsdb->max_refresh_rate_hz;
> +
> +	/*
> +	 * Only extend lower limit if current one disables LFC.
> +
> +	 * During widespread testing, we found that some manufacturers probably
> +	 * had issues with their monitors' lower VRR boundaries and adjusted
> +	 * them up (Gigabyte X34GS with official range 48 - 180, AMD vsdb 48 -
> +	 * 180 yet Monitor Ranges 55 - 180). After setting the lower boundary
> +	 * from AMD vsdb, such monitors start having blanking issues.
> +	 *
> +	 * Work around that by not touching VRR min if it still supports LFC.
> +	 */
> +	if (vsdb->min_refresh_rate_hz < vrr_min && (vrr_min * 2 >= vrr_max))
> +		vrr_min = vsdb->min_refresh_rate_hz;
> +
> +	display->monitor_range.min_vfreq = vrr_min;
> +	display->monitor_range.max_vfreq = vrr_max;

Random driver code should *not* modify struct drm_display_info,
especially the fields that drm_edid.c parses. Drivers should cease to
parse EDID and DisplayID altogether.

I'm on the verge of NAKing, to the extent that I have control over this,
any further improvements on driver EDID/DisplayID parsing, with the
expectation that everything's moved to shared EDID parser in drm_edid.c
first, and improved there.

BR,
Jani.


> +}
> +
>  /**
>   * amdgpu_dm_update_freesync_caps - Update Freesync capabilities
>   *
> @@ -13339,6 +13367,9 @@ 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);
>  
> +		/* Try extending range if found in AMD vsdb */
> +		extend_range_from_vsdb(&connector->display_info, &vsdb_info);
> +
>  		if (dpcd_caps.allow_invalid_MSA_timing_param)
>  			freesync_capable = copy_range_to_amdgpu_connector(connector);

-- 
Jani Nikula, Intel

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

* Re: [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in AMD vsdb
  2026-02-26 12:36   ` Jani Nikula
@ 2026-02-26 13:42     ` Tomasz Pakuła
  2026-03-17 10:03     ` Tomasz Pakuła
  1 sibling, 0 replies; 34+ messages in thread
From: Tomasz Pakuła @ 2026-02-26 13:42 UTC (permalink / raw)
  To: Jani Nikula, alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel

On Thu, 2026-02-26 at 14:36 +0200, Jani Nikula wrote:
> On Mon, 16 Feb 2026, Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com> wrote:
> > [Why]
> > Some monitors only expose their full VRR range in AMD vsdb for some
> > reason.
> > 
> > [How]
> > Compare exposed ranges and use the bigger one.
> > Only adjust lower limit if it doesn't support LFC
> > 
> > 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 | 31 +++++++++++++++++++
> >  1 file changed, 31 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 b3bf5e0c19a5..f36059bb0324 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > @@ -13269,6 +13269,34 @@ static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
> >  	return is_freesync_capable(range);
> >  }
> >  
> > +static void extend_range_from_vsdb(struct drm_display_info *display,
> > +				   const struct amdgpu_hdmi_vsdb_info *vsdb)
> > +{
> > +	u16 vrr_min = display->monitor_range.min_vfreq;
> > +	u16 vrr_max = display->monitor_range.max_vfreq;
> > +
> > +	/* Always extend upper limit */
> > +	if (vsdb->max_refresh_rate_hz > vrr_max)
> > +		vrr_max = vsdb->max_refresh_rate_hz;
> > +
> > +	/*
> > +	 * Only extend lower limit if current one disables LFC.
> > +
> > +	 * During widespread testing, we found that some manufacturers probably
> > +	 * had issues with their monitors' lower VRR boundaries and adjusted
> > +	 * them up (Gigabyte X34GS with official range 48 - 180, AMD vsdb 48 -
> > +	 * 180 yet Monitor Ranges 55 - 180). After setting the lower boundary
> > +	 * from AMD vsdb, such monitors start having blanking issues.
> > +	 *
> > +	 * Work around that by not touching VRR min if it still supports LFC.
> > +	 */
> > +	if (vsdb->min_refresh_rate_hz < vrr_min && (vrr_min * 2 >= vrr_max))
> > +		vrr_min = vsdb->min_refresh_rate_hz;
> > +
> > +	display->monitor_range.min_vfreq = vrr_min;
> > +	display->monitor_range.max_vfreq = vrr_max;
> 
> Random driver code should *not* modify struct drm_display_info,
> especially the fields that drm_edid.c parses. Drivers should cease to
> parse EDID and DisplayID altogether.
> 
> I'm on the verge of NAKing, to the extent that I have control over this,
> any further improvements on driver EDID/DisplayID parsing, with the
> expectation that everything's moved to shared EDID parser in drm_edid.c
> first, and improved there.
> 
> BR,
> Jani.

I completely agree with you, and I too am saddened by how selective AMD
can be when contributing to open source, BUT I'm just a guy who figured
out some fixes neglected by them. Not being an AMD employee, I don't
have access to their plans or what has been their idea behind modifying
drm_display_info (probably just a lack of understanding, like in my
case).

If maybe I could get OK from Alex or Harry to completely rip out
drm_display_info modifications from amdgpu_dm_update_freesync_caps, then
sure, but currently, I'm not in a position to do so. Still, it seems
like amdgpu already relies purely on it's internal structs from there on
out, so it should be pretty straightforward.

Moreover, moving all DisplayID and CTA extension parsing would be
amazing, BUT AMD vsdb specification isn't public. Here, amdgpu even uses
firmware to parse it, which is bonkers IMO, but they want to keep their
secrets (for some reason). There always will be some VRR meddling in the
drivers based on hardware features, though I do think AMD should release
their whole Freesync vsdb to the public as other drivers could parse
this info as well, because we can already see it's needed to properly
support all monitors.

Hell, even some of my fixes could be moved to general drm code to
facilitate proper VRR range detection.

Going back to the issue at hand, if I could get OK from AMD to rip out
all drm_display_info modifications from amdgpu_dm_update_freesync_caps
then it won't be a problem, but until then, I'm dealing with what I've
been given, doing as little functional, changes as possible. We already
know amdgpu code is... unoptimal, and I wouldn't want to add to that :D

Tomasz

> 
> 
> > +}
> > +
> >  /**
> >   * amdgpu_dm_update_freesync_caps - Update Freesync capabilities
> >   *
> > @@ -13339,6 +13367,9 @@ 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);
> >  
> > +		/* Try extending range if found in AMD vsdb */
> > +		extend_range_from_vsdb(&connector->display_info, &vsdb_info);
> > +
> >  		if (dpcd_caps.allow_invalid_MSA_timing_param)
> >  			freesync_capable = copy_range_to_amdgpu_connector(connector);

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

* Re: [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in AMD vsdb
  2026-02-26 12:36   ` Jani Nikula
  2026-02-26 13:42     ` Tomasz Pakuła
@ 2026-03-17 10:03     ` Tomasz Pakuła
  2026-03-20 14:48       ` Leo Li
  1 sibling, 1 reply; 34+ messages in thread
From: Tomasz Pakuła @ 2026-03-17 10:03 UTC (permalink / raw)
  To: Jani Nikula, alexander.deucher, harry.wentland, sunpeng.li
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel

On Thu, 2026-02-26 at 14:36 +0200, Jani Nikula wrote:
> On Mon, 16 Feb 2026, Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com> wrote:
> > [Why]
> > Some monitors only expose their full VRR range in AMD vsdb for some
> > reason.
> > 
> > [How]
> > Compare exposed ranges and use the bigger one.
> > Only adjust lower limit if it doesn't support LFC
> > 
> > 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 | 31 +++++++++++++++++++
> >  1 file changed, 31 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 b3bf5e0c19a5..f36059bb0324 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > @@ -13269,6 +13269,34 @@ static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
> >  	return is_freesync_capable(range);
> >  }
> >  
> > +static void extend_range_from_vsdb(struct drm_display_info *display,
> > +				   const struct amdgpu_hdmi_vsdb_info *vsdb)
> > +{
> > +	u16 vrr_min = display->monitor_range.min_vfreq;
> > +	u16 vrr_max = display->monitor_range.max_vfreq;
> > +
> > +	/* Always extend upper limit */
> > +	if (vsdb->max_refresh_rate_hz > vrr_max)
> > +		vrr_max = vsdb->max_refresh_rate_hz;
> > +
> > +	/*
> > +	 * Only extend lower limit if current one disables LFC.
> > +
> > +	 * During widespread testing, we found that some manufacturers probably
> > +	 * had issues with their monitors' lower VRR boundaries and adjusted
> > +	 * them up (Gigabyte X34GS with official range 48 - 180, AMD vsdb 48 -
> > +	 * 180 yet Monitor Ranges 55 - 180). After setting the lower boundary
> > +	 * from AMD vsdb, such monitors start having blanking issues.
> > +	 *
> > +	 * Work around that by not touching VRR min if it still supports LFC.
> > +	 */
> > +	if (vsdb->min_refresh_rate_hz < vrr_min && (vrr_min * 2 >= vrr_max))
> > +		vrr_min = vsdb->min_refresh_rate_hz;
> > +
> > +	display->monitor_range.min_vfreq = vrr_min;
> > +	display->monitor_range.max_vfreq = vrr_max;
> 
> Random driver code should *not* modify struct drm_display_info,
> especially the fields that drm_edid.c parses. Drivers should cease to
> parse EDID and DisplayID altogether.
> 
> I'm on the verge of NAKing, to the extent that I have control over this,
> any further improvements on driver EDID/DisplayID parsing, with the
> expectation that everything's moved to shared EDID parser in drm_edid.c
> first, and improved there.
> 
> BR,
> Jani.

Hi!

So I prepared a version which completely removes the drm_display_info
modifications from this part of the driver, but I think I know why it
was there in there in the first place. Without changing these fields,
the dri debug information, reports wrong vrr range vs what the driver
decided to do.

Basically, with monitor that have different vrr range in 'monitor
ranges' and AMD vsdb, it only reports the range from monitor ranges,
worse, for monitors that report GTF range (all HDMI TV, even some DP
monitors) the vrr_range for the connector in dri debug is reported to be
0 - 0 even though the correct range was picked up from other places like
DisplayID, AMD vsdb, HDMI Forum vsdb or nvidia specific vsdb.

Moving all this into generic edid handling could be quite a problem as
well since different manufacturers might want to handle VRR differenty.
For example, Intel could decide to support FreeSync sinnalling or just
getting the range from there, or not. HDMI VRR is another issue where
one brand could decide to prioritize their own solution over the generic
one (FreeSync over HDMI vs HDMI VRR).

The vrr_range in debug ony exposes display_info.monitor_range but it's
name suggests that it does something different. Maybe it needs a
dedicated place for drivers to show what they ended up deciding upon?
monitr_range alrady is only used to expose the range if it has 'range
limits only' flag so only for VRR. My concern is that we would have bad
debug info in there now.

I'm working on adding a drp connector property that would expose the vrr
range so compositors could easily parse it instead of relying on edid
parsing, that will be impossible to match.

And again, I'm just a guy providing fixes, I think bigger changes should
be taken with AMD. The functionality is already in the driver and my
patches do not change what it does with it. I'm not even changing how it
parses anything when it comes to edid, just using what's already there
to decide how to handle VRR.

Tomasz

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

* Re: [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in AMD vsdb
  2026-03-17 10:03     ` Tomasz Pakuła
@ 2026-03-20 14:48       ` Leo Li
  0 siblings, 0 replies; 34+ messages in thread
From: Leo Li @ 2026-03-20 14:48 UTC (permalink / raw)
  To: Tomasz Pakuła, Jani Nikula, alexander.deucher,
	harry.wentland
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
	michel.daenzer, daniel



On 2026-03-17 06:03, Tomasz Pakuła wrote:
> Hi!
> 
> So I prepared a version which completely removes the drm_display_info
> modifications from this part of the driver, but I think I know why it
> was there in there in the first place. Without changing these fields,
> the dri debug information, reports wrong vrr range vs what the driver
> decided to do.
> 
> Basically, with monitor that have different vrr range in 'monitor
> ranges' and AMD vsdb, it only reports the range from monitor ranges,
> worse, for monitors that report GTF range (all HDMI TV, even some DP
> monitors) the vrr_range for the connector in dri debug is reported to be
> 0 - 0 even though the correct range was picked up from other places like
> DisplayID, AMD vsdb, HDMI Forum vsdb or nvidia specific vsdb.
> 
> Moving all this into generic edid handling could be quite a problem as
> well since different manufacturers might want to handle VRR differenty.
> For example, Intel could decide to support FreeSync sinnalling or just
> getting the range from there, or not. HDMI VRR is another issue where
> one brand could decide to prioritize their own solution over the generic
> one (FreeSync over HDMI vs HDMI VRR).
> 
> The vrr_range in debug ony exposes display_info.monitor_range but it's
> name suggests that it does something different. Maybe it needs a
> dedicated place for drivers to show what they ended up deciding upon?
> monitr_range alrady is only used to expose the range if it has 'range
> limits only' flag so only for VRR. My concern is that we would have bad
> debug info in there now.
> 
> I'm working on adding a drp connector property that would expose the vrr
> range so compositors could easily parse it instead of relying on edid
> parsing, that will be impossible to match.
> 
> And again, I'm just a guy providing fixes, I think bigger changes should
> be taken with AMD. The functionality is already in the driver and my
> patches do not change what it does with it. I'm not even changing how it
> parses anything when it comes to edid, just using what's already there
> to decide how to handle VRR.
> 
> Tomasz

Hi Tomasz,

First of all, thanks for creating and testing these patches. I can't
_currently_ comment on the HDMI related things. But regarding VSDB parsing,
there's work in progress (not on the mailing lists yet) to move it to
drm_edid.c, looking to store everything in a "struct amd_vsdb_info"
within drm_display_info.

There will be duplicated vrr_min/max values stored in different places in
display_info, but I think that's OK, since they're also duplicated across
EDID/DID/VSDB? Drivers can then make their own selection for the final vrr
min/max, and reported in a new read-only property like you suggested.

I'm not sure if compositors would prefer to decode the edid themselves, or
rather have driver tell them via new properties. Maybe it's something to
bring up at the display hackfest.

Thanks,
Leo


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

end of thread, other threads:[~2026-03-20 14:48 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-16 16:44 [PATCH v4 00/27] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 01/27] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 02/27] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 03/27] drm/amd/display: Remove redundant edid checks Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 04/27] drm/amd/display: Move DisplayID vrr parsing Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 05/27] drm/amd/display: Always try to parse AMD vsdb Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 06/27] drm/amd/display: Check for VRR range in CEA " Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 07/27] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
2026-02-26 12:36   ` Jani Nikula
2026-02-26 13:42     ` Tomasz Pakuła
2026-03-17 10:03     ` Tomasz Pakuła
2026-03-20 14:48       ` Leo Li
2026-02-16 16:44 ` [PATCH v4 08/27] drm/amd/display: Separate DP/eDP and PCON paths completely Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 09/27] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
2026-02-16 16:44 ` [PATCH v4 10/27] drm/amd/display: Add PCON VRR ID check override Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 11/27] drm/amd/display: Add CH7218 PCON ID Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 12/27] drm/edid: Parse more info from HDMI Forum vsdb Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 13/27] drm/amd/display: Rename PCON adaptive sync types Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 14/27] drm/amd/display: Enable HDMI VRR over PCON Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 15/27] drm/amd/display: Support HDMI VRRmax=0 Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 16/27] drm/amd/display: Build HDMI vsif in correct slot Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 17/27] drm/amd/display: Save HDMI gaming info to edid caps Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 18/27] drm/amd/display: Restore ALLM support in HDMI vsif Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 19/27] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 20/27] drm/amd/display: Reintroduce VTEM info frame Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 21/27] drm/amd/display: Enable HDMI VRR Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 22/27] drm/amd/display: freesync_on_desktop support for " Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 23/27] drm: Add passive_vrr_disabled property to crtc Tomasz Pakuła
2026-02-17  8:21   ` Michel Dänzer
2026-02-17 16:41     ` Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 24/27] drm: Add passive_vrr_capable property to connector Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 25/27] drm: Add ALLM properties " Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 26/27] drm/amd/display: Use passive_vrr properties in amdgpu Tomasz Pakuła
2026-02-16 16:45 ` [PATCH v4 27/27] drm/amd/display: Use ALLM " Tomasz Pakuła

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