* [PATCH 01/17] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb()
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 13:23 ` Jani Nikula
2026-01-19 1:11 ` [PATCH 02/17] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
` (15 subsequent siblings)
16 siblings, 1 reply; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
The function would continue to try to parse EDID even if DisplayID
extension block wasn't found. Sometimes it got lucky and found AMD vsdb
in CEA extension block which made debugging harder.
[How]
Add a return if DisplayID extension block wasn't found
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 655c9fcb078a..a0d23853b8fc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13113,6 +13113,9 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
break;
}
+ if (i == edid->extensions)
+ return false;
+
while (j < EDID_LENGTH - sizeof(struct amd_vsdb_block)) {
struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j];
unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) | (amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]);
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 01/17] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb()
2026-01-19 1:11 ` [PATCH 01/17] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
@ 2026-01-19 13:23 ` Jani Nikula
2026-01-20 12:07 ` Tomasz Pakuła
0 siblings, 1 reply; 25+ messages in thread
From: Jani Nikula @ 2026-01-19 13:23 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
On Mon, 19 Jan 2026, Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com> wrote:
> [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
Maybe don't use homegrown EDID parsing, but use drm_edid.c instead?
BR,
Jani.
>
> Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
> ---
> drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index 655c9fcb078a..a0d23853b8fc 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -13113,6 +13113,9 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
> break;
> }
>
> + if (i == edid->extensions)
> + return false;
> +
> while (j < EDID_LENGTH - sizeof(struct amd_vsdb_block)) {
> struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j];
> unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) | (amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]);
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH 01/17] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb()
2026-01-19 13:23 ` Jani Nikula
@ 2026-01-20 12:07 ` Tomasz Pakuła
0 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-20 12:07 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
On Mon, 2026-01-19 at 15:23 +0200, Jani Nikula wrote:
> On Mon, 19 Jan 2026, Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com> wrote:
> > [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
>
> Maybe don't use homegrown EDID parsing, but use drm_edid.c instead?
>
> BR,
> Jani.
>
I would be all for it but I didn't want to make even more changes. I
cannot refactor the whole amdgpu on my own :)
Plus, the generic drm code doesn't yet parse AMD vsdb. I could certainly
add such functionality, especially since it's already in projects like
edid-decode but amdgpu seems to be doing a lot of home-grown edid
parsing and I'm not really sure why, even sending stuff to firmware.
Especially confusing is the part where AMD vsdb is parsed differently if
it's in CTA extensiton block or DisplayID. They honestly are identical.
At least, here in, setting the freesync caps, getting info from generic
drm should be ok. I'll think about it and probably intoroduce AMD vsdb
parsing to drm in a separate series.
>
Tomasz
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 02/17] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 01/17] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 8:23 ` kernel test robot
2026-01-19 1:11 ` [PATCH 03/17] drm/amd/display: Check for VRR range in CEA AMD vsdb Tomasz Pakuła
` (14 subsequent siblings)
16 siblings, 1 reply; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[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 | 119 +++++++++++-------
1 file changed, 72 insertions(+), 47 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 a0d23853b8fc..d83c65dc93d7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13096,8 +13096,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;
@@ -13134,9 +13134,9 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
return false;
}
-static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
- const struct edid *edid,
- struct amdgpu_hdmi_vsdb_info *vsdb_info)
+static int parse_amd_vsdb_cea(struct amdgpu_dm_connector *aconnector,
+ const struct edid *edid,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
u8 *edid_ext = NULL;
int i;
@@ -13166,6 +13166,44 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
return valid_vsdb_found ? i : -ENODEV;
}
+static bool is_monitor_range_invalid(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(struct drm_monitor_range_info *range)
+{
+ return (range->max_vfreq - range->min_vfreq) > 10;
+}
+
+static void monitor_range_from_vsdb(struct drm_connector *conn,
+ struct amdgpu_hdmi_vsdb_info *vsdb)
+{
+ struct drm_monitor_range_info *range = &conn->display_info.monitor_range;
+
+ range->min_vfreq = vsdb->min_refresh_rate_hz;
+ 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);
+}
+
/**
* amdgpu_dm_update_freesync_caps - Update Freesync capabilities
*
@@ -13180,15 +13218,18 @@ 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;
+ bool valid_vsdb_cea = false;
+ bool vsdb_freesync = false;
enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
if (!connector->state) {
@@ -13218,62 +13259,46 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
goto update;
edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
+ valid_vsdb_cea = parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info) >= 0;
+ vsdb_freesync = valid_vsdb_cea && vsdb_info.freesync_supported;
+ if (amdgpu_dm_connector->dc_link)
+ dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
/* Some eDP panels only have the refresh rate range info in DisplayID */
- if ((connector->display_info.monitor_range.min_vfreq == 0 ||
- connector->display_info.monitor_range.max_vfreq == 0))
+ if (is_monitor_range_invalid(connector))
parse_edid_displayid_vrr(connector, edid);
- if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
- sink->sink_signal == SIGNAL_TYPE_EDP)) {
- if (amdgpu_dm_connector->dc_link &&
- amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
- amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
- amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
- if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- freesync_capable = true;
- }
+ if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
+ sink->sink_signal == SIGNAL_TYPE_EDP) {
- parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
+ if (dpcd_caps.allow_invalid_MSA_timing_param)
+ freesync_capable = copy_range_to_amdgpu_connector(connector);
- if (vsdb_info.replay_mode) {
- amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
- amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version;
+ /* eDP */
+ if (edid)
+ parse_amd_vsdb_did(amdgpu_dm_connector, edid, &vsdb_did);
+
+ if (vsdb_did.replay_mode) {
+ amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_did.replay_mode;
+ amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_did.amd_vsdb_version;
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
}
- } else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
- i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
- if (i >= 0 && vsdb_info.freesync_supported) {
- amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
- amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
- if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- freesync_capable = true;
-
- connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
- connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
- }
+ } else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_freesync) {
+ monitor_range_from_vsdb(connector, &vsdb_info);
+ freesync_capable = copy_range_to_amdgpu_connector(connector);
}
if (amdgpu_dm_connector->dc_link)
as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
- if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
- i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
- if (i >= 0 && vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
+ if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST && vsdb_freesync) {
+ amdgpu_dm_connector->pack_sdp_v1_3 = true;
+ amdgpu_dm_connector->as_type = as_type;
+ amdgpu_dm_connector->vsdb_info = vsdb_info;
- amdgpu_dm_connector->pack_sdp_v1_3 = true;
- amdgpu_dm_connector->as_type = as_type;
- amdgpu_dm_connector->vsdb_info = vsdb_info;
-
- amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
- amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
- if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- freesync_capable = true;
-
- connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
- connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
- }
+ monitor_range_from_vsdb(connector, &vsdb_info);
+ freesync_capable = copy_range_to_amdgpu_connector(connector);
}
update:
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 02/17] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
2026-01-19 1:11 ` [PATCH 02/17] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
@ 2026-01-19 8:23 ` kernel test robot
0 siblings, 0 replies; 25+ messages in thread
From: kernel test robot @ 2026-01-19 8:23 UTC (permalink / raw)
To: Tomasz Pakuła, alexander.deucher, harry.wentland, sunpeng.li
Cc: oe-kbuild-all, maarten.lankhorst, mripard, tzimmermann, airlied,
simona, siqueira, dri-devel, amd-gfx, linux-kernel,
tomasz.pakula.oficjalny, bernhard.berger
Hi Tomasz,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20260116]
[also build test WARNING on linus/master v6.19-rc6]
[cannot apply to drm-misc/drm-misc-next v6.19-rc5 v6.19-rc4 v6.19-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Tomasz-Paku-a/drm-amd-display-Return-if-DisplayID-not-found-in-parse_amd_vsdb/20260119-091453
base: next-20260116
patch link: https://lore.kernel.org/r/20260119011146.62302-3-tomasz.pakula.oficjalny%40gmail.com
patch subject: [PATCH 02/17] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
config: i386-buildonly-randconfig-001-20260119 (https://download.01.org/0day-ci/archive/20260119/202601191507.cZ9ZcocL-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260119/202601191507.cZ9ZcocL-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601191507.cZ9ZcocL-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> Warning: drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm.c:13200 This comment starts with '/**', but isn't a kernel-doc comment. Refer to Documentation/doc-guide/kernel-doc.rst
* Returns true if (max_vfreq - min_vfreq) > 10
Warning: drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm.c:13217 This comment starts with '/**', but isn't a kernel-doc comment. Refer to Documentation/doc-guide/kernel-doc.rst
* Returns true if connector is capable of freesync
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for NET_SELFTESTS
Depends on [n]: NET [=y] && PHYLIB [=y] && INET [=n]
Selected by [m]:
- AMD_XGBE [=m] && NETDEVICES [=y] && ETHERNET [=y] && NET_VENDOR_AMD [=y] && (OF_ADDRESS [=y] || ACPI [=y] || PCI [=y]) && HAS_IOMEM [=y] && (X86 [=y] || ARM64 || COMPILE_TEST [=y]) && PTP_1588_CLOCK_OPTIONAL [=m]
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 03/17] drm/amd/display: Check for VRR range in CEA AMD vsdb
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 01/17] drm/amd/display: Return if DisplayID not found in parse_amd_vsdb() Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 02/17] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps() Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 04/17] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
` (13 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
Some monitors only expose GTF ranges (or others, without Range Limits
Only flag). This breaks VRR even though they have explicit FreeSync
support.
Currently, if monitor ranges were missing, amdgpu only searched for AMD
vsdb in DisplayID but many monitors have it in CEA, just like HDMI.
[How]
For DP and eDP connections, check for VRR ranges provided in AMD vendor-
specific data block if VRR range wasn't detected.
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3894
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4457
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4747
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4856
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index d83c65dc93d7..69f3dbfe4ca3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13270,6 +13270,12 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
sink->sink_signal == SIGNAL_TYPE_EDP) {
+ /*
+ * Many monitors expose AMD vsdb in CAE even for DP and their
+ * monitor ranges do not contain Range Limits Only flag
+ */
+ if (valid_vsdb_cea && is_monitor_range_invalid(connector))
+ monitor_range_from_vsdb(connector, &vsdb_info);
if (dpcd_caps.allow_invalid_MSA_timing_param)
freesync_capable = copy_range_to_amdgpu_connector(connector);
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 04/17] drm/amd/display: Use bigger VRR range if found in AMD vsdb
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (2 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 03/17] drm/amd/display: Check for VRR range in CEA AMD vsdb Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 05/17] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
` (12 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
Some monitors only expose their full VRR range in AMD vsdb for some
reason.
[How]
Compare exposed ranges and use the bigger one.
This check could be merged with the previous one but it's better to keep
them separate to easily convey their meaning.
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4177
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 69f3dbfe4ca3..37ab89532408 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13204,6 +13204,18 @@ static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
return is_freesync_capable(range);
}
+/**
+ * Returns true if range from AMD vsdb is bigger
+ */
+static bool compare_ranges(struct drm_connector *conn,
+ struct amdgpu_hdmi_vsdb_info *vsdb)
+{
+ struct drm_monitor_range_info *range = &conn->display_info.monitor_range;
+
+ return (vsdb->max_refresh_rate_hz - vsdb->min_refresh_rate_hz) >
+ (range->max_vfreq - range->min_vfreq);
+}
+
/**
* amdgpu_dm_update_freesync_caps - Update Freesync capabilities
*
@@ -13277,6 +13289,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (valid_vsdb_cea && is_monitor_range_invalid(connector))
monitor_range_from_vsdb(connector, &vsdb_info);
+ /* Use bigger range if found in AMD vsdb */
+ if (valid_vsdb_cea && compare_ranges(connector, &vsdb_info))
+ monitor_range_from_vsdb(connector, &vsdb_info);
+
if (dpcd_caps.allow_invalid_MSA_timing_param)
freesync_capable = copy_range_to_amdgpu_connector(connector);
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 05/17] drm/amd/display: Refactor PCON VRR compatibility check
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (3 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 04/17] drm/amd/display: Use bigger VRR range if found in " Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 06/17] drm/amd/display: Add PCON VRR ID check override Tomasz Pakuła
` (11 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[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 | 25 +++++++-----
.../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 39 ++++++-------------
drivers/gpu/drm/amd/display/dc/dm_helpers.h | 2 +-
3 files changed, 28 insertions(+), 38 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 37ab89532408..662f51faf949 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13242,7 +13242,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
bool freesync_capable = false;
bool valid_vsdb_cea = false;
bool vsdb_freesync = false;
- enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
+ bool pcon_allowed = false;
+ bool is_pcon = false;
if (!connector->state) {
drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__);
@@ -13270,18 +13271,24 @@ 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()
valid_vsdb_cea = parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info) >= 0;
vsdb_freesync = valid_vsdb_cea && vsdb_info.freesync_supported;
- if (amdgpu_dm_connector->dc_link)
+
+ if (amdgpu_dm_connector->dc_link) {
dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
+ is_pcon = dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+ pcon_allowed = dm_helpers_is_vrr_pcon_allowed(amdgpu_dm_connector->dc_link);
+ }
/* Some eDP panels only have the refresh rate range info in DisplayID */
if (is_monitor_range_invalid(connector))
parse_edid_displayid_vrr(connector, edid);
- if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
- sink->sink_signal == SIGNAL_TYPE_EDP) {
+ /* DP & eDP excluding PCONs */
+ if ((sink->sink_signal == SIGNAL_TYPE_EDP ||
+ sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) && !is_pcon) {
/*
* Many monitors expose AMD vsdb in CAE even for DP and their
* monitor ranges do not contain Range Limits Only flag
@@ -13306,17 +13313,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
}
+ /* HDMI */
} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_freesync) {
monitor_range_from_vsdb(connector, &vsdb_info);
freesync_capable = copy_range_to_amdgpu_connector(connector);
- }
- if (amdgpu_dm_connector->dc_link)
- as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
-
- if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST && vsdb_freesync) {
+ /* DP -> HDMI PCON */
+ } else if (pcon_allowed && vsdb_freesync) {
+ amdgpu_dm_connector->as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
amdgpu_dm_connector->pack_sdp_v1_3 = true;
- amdgpu_dm_connector->as_type = as_type;
amdgpu_dm_connector->vsdb_info = vsdb_info;
monitor_range_from_vsdb(connector, &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 e5e993d3ef74..76a10fe8d545 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
@@ -1375,40 +1375,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 9d160b39e8c5..f8b45a09d680 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -219,10 +219,10 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
const struct dc_link *link,
struct set_config_cmd_payload *payload,
enum set_config_status *operation_result);
-enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link);
enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid);
+bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link);
bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state *stream);
bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream);
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 06/17] drm/amd/display: Add PCON VRR ID check override
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (4 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 05/17] drm/amd/display: Refactor PCON VRR compatibility check Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 07/17] drm/amd/display: Add CH7218 PCON ID Tomasz Pakuła
` (10 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
It's currently very hard to test if a random PCON supports VRR and
report it's ID.
[How]
Adds override as part of dc debug mask. Allows faster testing and
reporting of VRR-compatible DP->HDMI adapters.
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++++-
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +++++++-
drivers/gpu/drm/amd/display/dc/dc.h | 1 +
drivers/gpu/drm/amd/display/dc/dm_helpers.h | 2 +-
drivers/gpu/drm/amd/include/amd_shared.h | 6 ++++++
5 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 662f51faf949..859e34235769 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2062,6 +2062,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_debug_mask & DC_SKIP_DETECTION_LT)
adev->dm.dc->debug.skip_detection_link_training = true;
+ if (amdgpu_dc_debug_mask & DC_OVERRIDE_PCON_VRR_ID_CHECK)
+ adev->dm.dc->debug.override_pcon_vrr_id_check = true;
+
adev->dm.dc->debug.visual_confirm = amdgpu_dc_visual_confirm;
/* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */
@@ -13279,7 +13282,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (amdgpu_dm_connector->dc_link) {
dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
is_pcon = dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER;
- pcon_allowed = dm_helpers_is_vrr_pcon_allowed(amdgpu_dm_connector->dc_link);
+ pcon_allowed = dm_helpers_is_vrr_pcon_allowed(
+ amdgpu_dm_connector->dc_link, connector->dev);
}
/* Some eDP panels only have the refresh rate range info in DisplayID */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 76a10fe8d545..2ef515a4e1c4 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
@@ -1375,7 +1375,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;
@@ -1393,6 +1393,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 4068d5baef21..5be0507f8a27 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1056,6 +1056,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 f8b45a09d680..ea94c52d2b87 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -222,7 +222,7 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid);
-bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link);
+bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link, const struct drm_device *dev);
bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state *stream);
bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream);
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index ac2d3701e2bd..894e1e738ce0 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -412,6 +412,12 @@ enum DC_DEBUG_MASK {
* @DC_SKIP_DETECTION_LT: (0x200000) If set, skip detection link training
*/
DC_SKIP_DETECTION_LT = 0x200000,
+
+ /**
+ * @DC_OVERRIDE_PCON_VRR_ID_CHECK: (0x400000) If set, always return true if checking for
+ * PCON VRR compatibility and print it's ID in kernel log.
+ */
+ DC_OVERRIDE_PCON_VRR_ID_CHECK = 0x400000,
};
enum amd_dpm_forced_level;
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 07/17] drm/amd/display: Add CH7218 PCON ID
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (5 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 06/17] drm/amd/display: Add PCON VRR ID check override Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 08/17] drm/edid: Parse more info from HDMI Forum vsdb Tomasz Pakuła
` (9 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
Chrontel CH7218 found in Ugreen DP -> HDMI 2.1 adapter (model 85564)
works perfectly with VRR after testing. VRR and FreeSync compatibility
is explicitly advertised as a feature so it's addition is a formality.
Support FreeSync info packet passthrough and "generic" HDMI VRR.
[How]
Add CH7218's ID to dm_helpers_is_vrr_pcon_allowed()
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4773
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 1 +
drivers/gpu/drm/amd/display/include/ddc_service_types.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 2ef515a4e1c4..37747f87b55a 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
@@ -1390,6 +1390,7 @@ bool dm_helpers_is_vrr_pcon_allowed(const struct dc_link *link, const struct drm
case DP_BRANCH_DEVICE_ID_0060AD:
case DP_BRANCH_DEVICE_ID_00E04C:
case DP_BRANCH_DEVICE_ID_90CC24:
+ case DP_BRANCH_DEVICE_ID_2B02F0:
return true;
}
diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
index 1c603b12957f..e838f7c1269c 100644
--- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
@@ -36,6 +36,7 @@
#define DP_BRANCH_DEVICE_ID_006037 0x006037
#define DP_BRANCH_DEVICE_ID_001CF8 0x001CF8
#define DP_BRANCH_DEVICE_ID_0060AD 0x0060AD
+#define DP_BRANCH_DEVICE_ID_2B02F0 0x2B02F0 /* Chrontel CH7218 */
#define DP_BRANCH_HW_REV_10 0x10
#define DP_BRANCH_HW_REV_20 0x20
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 08/17] drm/edid: Parse more info from HDMI Forum vsdb
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (6 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 07/17] drm/amd/display: Add CH7218 PCON ID Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 09/17] drm/amd/display: Rename PCON adaptive sync types Tomasz Pakuła
` (8 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[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 e2e85345aa9a..5bdacd425908 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -6149,6 +6149,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)
{
@@ -6274,7 +6301,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;
@@ -6284,6 +6311,18 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
"[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n",
connector->base.id, connector->name,
max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support));
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] FAPA in blanking: %s, ALLM support: %s, Fast Vactive support: %s\n",
+ connector->base.id, connector->name, str_yes_no(hdmi->fapa_start_location),
+ str_yes_no(hdmi->allm), str_yes_no(hdmi->vrr_cap.fva));
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Negative M VRR support: %s, CinemaVRR support: %s, Mdelta: %d\n",
+ connector->base.id, connector->name, str_yes_no(hdmi->vrr_cap.cnmvrr),
+ str_yes_no(hdmi->vrr_cap.cinema_vrr), hdmi->vrr_cap.mdelta);
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] VRRmin: %u, VRRmax: %u, VRR supported: %s\n",
+ connector->base.id, connector->name, hdmi->vrr_cap.vrr_min,
+ hdmi->vrr_cap.vrr_max, str_yes_no(hdmi->vrr_cap.supported));
}
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 8f34f4b8183d..dab9d5521f41 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -254,6 +254,44 @@ struct drm_scdc {
struct drm_scrambling scrambling;
};
+/**
+ * struct drm_hdmi_vrr_cap - Information about VRR capabilities of a HDMI sink
+ *
+ * Describes the VRR support provided by HDMI 2.1 sink. The information is
+ * fetched fom additional HFVSDB blocks defined for HDMI 2.1.
+ */
+struct drm_hdmi_vrr_cap {
+ /** @fva: flag for Fast VActive (Quick Frame Transport) support */
+ bool fva;
+
+ /** @mcnmvrr: flag for Negative M VRR support */
+ bool cnmvrr;
+
+ /** @mcinema_vrr: flag for Cinema VRR support */
+ bool cinema_vrr;
+
+ /** @mdelta: flag for limited frame-to-frame compensation support */
+ bool mdelta;
+
+ /**
+ * @vrr_min : minimum supported variable refresh rate in Hz.
+ * Valid values only inide 1 - 48 range
+ */
+ u16 vrr_min;
+
+ /**
+ * @vrr_max : maximum supported variable refresh rate in Hz (optional).
+ * Valid values are either 0 (max based on video mode) or >= 100
+ */
+ u16 vrr_max;
+
+ /**
+ * @supported: flag for vrr support based on checking for VRRmin and
+ * VRRmax values having correct values.
+ */
+ bool supported;
+};
+
/**
* struct drm_hdmi_dsc_cap - DSC capabilities of HDMI sink
*
@@ -330,6 +368,15 @@ struct drm_hdmi_info {
/** @max_lanes: supported by sink */
u8 max_lanes;
+ /** @fapa_start_location: flag for the FAPA in blanking support */
+ bool fapa_start_location;
+
+ /** @allm: flag for Auto Low Latency Mode support by sink */
+ bool allm;
+
+ /** @vrr_cap: VRR capabilities of the sink */
+ struct drm_hdmi_vrr_cap vrr_cap;
+
/** @dsc_cap: DSC capabilities of the sink */
struct drm_hdmi_dsc_cap dsc_cap;
};
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 09/17] drm/amd/display: Rename PCON adaptive sync types
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (7 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 08/17] drm/edid: Parse more info from HDMI Forum vsdb Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 10/17] drm/amd/display: Enable HDMI VRR over PCON Tomasz Pakuła
` (7 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
PCONs support sending out HDMI VRR infopackets on their own and this
makes this types not specific to FreeSync
[How]
Make the name more generic for the upcoming HDMI VRR over PCON
implementation
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Tested-by: Bernhard Berger <bernhard.berger@gmail.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +++--
.../gpu/drm/amd/display/modules/inc/mod_info_packet.h | 10 +++++-----
.../drm/amd/display/modules/info_packet/info_packet.c | 4 ++--
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 859e34235769..b7deff137df4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9597,7 +9597,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)
@@ -13324,7 +13325,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
/* DP -> HDMI PCON */
} else if (pcon_allowed && vsdb_freesync) {
- amdgpu_dm_connector->as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
+ amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_PCON_ALLOWED;
amdgpu_dm_connector->pack_sdp_v1_3 = true;
amdgpu_dm_connector->vsdb_info = vsdb_info;
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
index ddd64b7e4c04..5de8a6918e6a 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
@@ -48,11 +48,11 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet);
enum adaptive_sync_type {
- ADAPTIVE_SYNC_TYPE_NONE = 0,
- ADAPTIVE_SYNC_TYPE_DP = 1,
- FREESYNC_TYPE_PCON_IN_WHITELIST = 2,
- FREESYNC_TYPE_PCON_NOT_IN_WHITELIST = 3,
- ADAPTIVE_SYNC_TYPE_EDP = 4,
+ ADAPTIVE_SYNC_TYPE_NONE = 0,
+ ADAPTIVE_SYNC_TYPE_DP = 1,
+ ADAPTIVE_SYNC_TYPE_PCON_ALLOWED = 2,
+ ADAPTIVE_SYNC_TYPE_PCON_NOT_ALLOWED = 3,
+ ADAPTIVE_SYNC_TYPE_EDP = 4,
};
enum adaptive_sync_sdp_version {
diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
index 00473c6284d5..294f56d20062 100644
--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
@@ -590,7 +590,7 @@ void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
if (stream != NULL)
mod_build_adaptive_sync_infopacket_v2(stream, param, info_packet);
break;
- case FREESYNC_TYPE_PCON_IN_WHITELIST:
+ case ADAPTIVE_SYNC_TYPE_PCON_ALLOWED:
case ADAPTIVE_SYNC_TYPE_EDP:
if (stream && stream->link->replay_settings.config.replay_supported &&
stream->link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY)
@@ -599,7 +599,7 @@ void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
mod_build_adaptive_sync_infopacket_v1(info_packet);
break;
case ADAPTIVE_SYNC_TYPE_NONE:
- case FREESYNC_TYPE_PCON_NOT_IN_WHITELIST:
+ case ADAPTIVE_SYNC_TYPE_PCON_NOT_ALLOWED:
default:
break;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 10/17] drm/amd/display: Enable HDMI VRR over PCON
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (8 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 09/17] drm/amd/display: Rename PCON adaptive sync types Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 11/17] drm/amd/display: Support HDMI VRRmax=0 Tomasz Pakuła
` (6 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
Not all TVs support FreeSync and many TVs suffer from VRR flickering
while Freesync is activated.
[How]
This works the same as FreeSync over PCON just without sending FreeSync
info packets (we're sending standard DisplayPort info packets) + reading
the VRR range from the HDMI Forum vendor specific data block. PCONs take
over HDMI VRR triggering.
Prefer HDMI VRR over FreeSync to reduce VRR flickering on many TVs.
FreeSync over HDMI seems to be a fallback solution and not a first-class
citizen. This especially helps VMM7100.
Tested with VMM7100 and CH7218 based adapters on multiple HDMI 2.1 and
HDMI 2.0 devices. (Samsung S95B, LG C4, Sony Bravia 8, Dell AW3423DWF)
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4805
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Tested-by: Bernhard Berger <bernhard.berger@gmail.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 31 ++++++++++++++++---
1 file changed, 26 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 b7deff137df4..772deaa136d7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13193,6 +13193,20 @@ static void monitor_range_from_vsdb(struct drm_connector *conn,
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_connector *conn)
+{
+ struct drm_monitor_range_info *range = &conn->display_info.monitor_range;
+ struct drm_hdmi_vrr_cap *caps = &conn->display_info.hdmi.vrr_cap;
+
+ range->min_vfreq = caps->vrr_min;
+ range->max_vfreq = caps->vrr_max;
+}
+
/**
* Returns true if connector is capable of freesync
* Optionally, can fetch the range from AMD vsdb
@@ -13242,6 +13256,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
struct amdgpu_hdmi_vsdb_info vsdb_did = {0};
struct dpcd_caps dpcd_caps = {0};
+ struct drm_hdmi_vrr_cap *hdmi_vrr;
const struct edid *edid;
bool freesync_capable = false;
bool valid_vsdb_cea = false;
@@ -13279,6 +13294,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
valid_vsdb_cea = parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info) >= 0;
vsdb_freesync = valid_vsdb_cea && vsdb_info.freesync_supported;
+ hdmi_vrr = &connector->display_info.hdmi.vrr_cap;
if (amdgpu_dm_connector->dc_link) {
dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
@@ -13324,12 +13340,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_freesync) {
- 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);
+ else if (vsdb_freesync) {
+ amdgpu_dm_connector->vsdb_info = vsdb_info;
+ monitor_range_from_vsdb(connector, &vsdb_info);
+ }
- monitor_range_from_vsdb(connector, &vsdb_info);
+ amdgpu_dm_connector->pack_sdp_v1_3 = true;
+ amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_PCON_ALLOWED;
freesync_capable = copy_range_to_amdgpu_connector(connector);
}
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 11/17] drm/amd/display: Support HDMI VRRmax=0
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (9 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 10/17] drm/amd/display: Enable HDMI VRR over PCON Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 12/17] drm/amd/display: Build HDMI vsif in correct slot Tomasz Pakuła
` (5 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[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 1000 Hz. Use this as the last resort VRRmax.
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 22 ++++++++++++++-----
.../amd/display/modules/inc/mod_info_packet.h | 2 ++
2 files changed, 19 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 772deaa136d7..3c535a361882 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13194,17 +13194,29 @@ static void monitor_range_from_vsdb(struct drm_connector *conn,
}
/*
- * 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 (if passed).
*
* @conn: drm_connector with HDMI VRR info
+ * @vsdb: AMD vsdb from CAE. Can be NULL if not found.
*/
-static void monitor_range_from_hdmi(struct drm_connector *conn)
+static void monitor_range_from_hdmi(struct drm_connector *conn,
+ const struct amdgpu_hdmi_vsdb_info *vsdb)
{
struct drm_monitor_range_info *range = &conn->display_info.monitor_range;
struct drm_hdmi_vrr_cap *caps = &conn->display_info.hdmi.vrr_cap;
+ u16 vrr_max = caps->vrr_max;
+
+ /* Try getting upper vrr bound from AMD vsdb */
+ if (vrr_max == 0 && vsdb)
+ 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;
range->min_vfreq = caps->vrr_min;
- range->max_vfreq = caps->vrr_max;
+ range->max_vfreq = vrr_max;
}
/**
@@ -13342,8 +13354,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);
+ if (hdmi_vrr->supported)
+ monitor_range_from_hdmi(connector, valid_vsdb_cea ? &vsdb_info : NULL);
else if (vsdb_freesync) {
amdgpu_dm_connector->vsdb_info = vsdb_info;
monitor_range_from_vsdb(connector, &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..67274ce129bd 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 1000
+
void set_vsc_packet_colorimetry_data(
const struct dc_stream_state *stream,
struct dc_info_packet *info_packet,
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 12/17] drm/amd/display: Build HDMI vsif in correct slot
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (10 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 11/17] drm/amd/display: Support HDMI VRRmax=0 Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 13/17] drm/amd/display: Save HDMI gaming info to edid caps Tomasz Pakuła
` (4 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
HDMI vsif was assigned to vsp_infopacket (FreeSync) field
[How]
Build HDMI vsif in the correct hfvsif_infopacket field
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 3c535a361882..ef7e02ebda41 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7362,7 +7362,7 @@ create_stream_for_sink(struct drm_connector *connector,
update_stream_signal(stream, sink);
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
- mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket);
+ mod_build_hf_vsif_infopacket(stream, &stream->hfvsif_infopacket);
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 13/17] drm/amd/display: Save HDMI gaming info to edid caps
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (11 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 12/17] drm/amd/display: Build HDMI vsif in correct slot Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 14/17] drm/amd/display: Restore ALLM support in HDMI vsif Tomasz Pakuła
` (3 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
We need info about these features in parts of the driver where fishing
for drm_connector struct is infeasible.
[How]
Add three new fields to dc_edid_caps and fill them if connected device
is HDMI based on it's EDID
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 7 ++++++-
drivers/gpu/drm/amd/display/dc/dc_types.h | 7 ++++++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 37747f87b55a..6413f2a587d5 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 bb1387233bd8..acc6db52f5d8 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -210,9 +210,14 @@ struct dc_edid_caps {
uint32_t max_tmds_clk_mhz;
- /*HDMI 2.0 caps*/
+ /* HDMI 2.0 caps */
bool lte_340mcsc_scramble;
+ /* HDMI 2.1 caps */
+ bool allm;
+ bool fva;
+ bool hdmi_vrr;
+
bool edid_hdmi;
bool hdr_supported;
bool rr_capable;
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 14/17] drm/amd/display: Restore ALLM support in HDMI vsif
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (12 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 13/17] drm/amd/display: Save HDMI gaming info to edid caps Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 15/17] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
` (2 subsequent siblings)
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[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 | 112 ++++++++++++------
1 file changed, 73 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..1a1ddcdb4362 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,28 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
}
}
+static bool is_hdmi_vic_mode(const struct dc_stream_state *stream)
+{
+ bool allm = stream->link->local_sink->edid_caps.allm;
+ bool stereo = stream->view_format != VIEW_3D_FORMAT_NONE;
+
+ if (stream->timing.hdmi_vic == 0)
+ return false;
+
+ if (stream->timing.h_total < 3840 ||
+ stream->timing.v_total < 2160)
+ return false;
+
+ if (stereo || 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 +528,75 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet)
{
- unsigned int length = 5;
bool hdmi_vic_mode = false;
+ bool allm = false;
+ bool stereo = false;
uint8_t checksum = 0;
- uint32_t i = 0;
+ uint8_t offset = 0;
+ uint8_t i = 0;
+ uint8_t length = 5;
+ uint32_t oui = HDMI_IEEE_OUI;
enum dc_timing_3d_format format;
info_packet->valid = false;
+
format = stream->timing.timing_3d_format;
if (stream->view_format == VIEW_3D_FORMAT_NONE)
format = TIMING_3D_FORMAT_NONE;
+ stereo = format != TIMING_3D_FORMAT_NONE;
+ hdmi_vic_mode = is_hdmi_vic_mode(stream);
- if (stream->timing.hdmi_vic != 0
- && stream->timing.h_total >= 3840
- && stream->timing.v_total >= 2160
- && format == TIMING_3D_FORMAT_NONE)
- hdmi_vic_mode = true;
-
- if ((format == TIMING_3D_FORMAT_NONE) && !hdmi_vic_mode)
+ if (!stereo && !hdmi_vic_mode && !allm)
return;
- info_packet->sb[1] = 0x03;
- info_packet->sb[2] = 0x0C;
- info_packet->sb[3] = 0x00;
+ if (allm)
+ oui = HDMI_FORUM_IEEE_OUI;
- if (format != TIMING_3D_FORMAT_NONE)
- info_packet->sb[4] = (2 << 5);
+ info_packet->sb[1] = oui & 0xff;
+ info_packet->sb[2] = (oui >> 8) & 0xff;
+ info_packet->sb[3] = (oui >> 16) & 0xff;
- else if (hdmi_vic_mode)
- info_packet->sb[4] = (1 << 5);
-
- switch (format) {
- case TIMING_3D_FORMAT_HW_FRAME_PACKING:
- case TIMING_3D_FORMAT_SW_FRAME_PACKING:
- info_packet->sb[5] = (0x0 << 4);
- break;
-
- case TIMING_3D_FORMAT_SIDE_BY_SIDE:
- case TIMING_3D_FORMAT_SBS_SW_PACKED:
- info_packet->sb[5] = (0x8 << 4);
- length = 6;
- break;
-
- case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
- case TIMING_3D_FORMAT_TB_SW_PACKED:
- info_packet->sb[5] = (0x6 << 4);
- break;
-
- default:
- break;
+ if (oui == HDMI_FORUM_IEEE_OUI) {
+ offset = 2;
+ length += 2;
+ info_packet->sb[4] = HF_VSIF_VERSION;
+ info_packet->sb[5] = stereo << HF_VSIF_3D_BIT;
+ info_packet->sb[5] = allm << HF_VSIF_ALLM_BIT;
}
- if (hdmi_vic_mode)
+ if (stereo) {
+ info_packet->sb[4 + offset] = (2 << 5);
+
+ switch (format) {
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING:
+ info_packet->sb[5 + offset] = (0x0 << 4);
+ break;
+
+ case TIMING_3D_FORMAT_SIDE_BY_SIDE:
+ case TIMING_3D_FORMAT_SBS_SW_PACKED:
+ info_packet->sb[5 + offset] = (0x8 << 4);
+ ++length;
+ break;
+
+ case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
+ case TIMING_3D_FORMAT_TB_SW_PACKED:
+ info_packet->sb[5 + offset] = (0x6 << 4);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Doesn't need the offset as it can't be used with hf-vsif */
+ } else if (hdmi_vic_mode) {
+ info_packet->sb[4] = (1 << 5);
info_packet->sb[5] = stream->timing.hdmi_vic;
+ }
info_packet->hb0 = HDMI_INFOFRAME_TYPE_VENDOR;
info_packet->hb1 = 0x01;
- info_packet->hb2 = (uint8_t) (length);
+ info_packet->hb2 = length & HDMI_INFOFRAME_LENGTH_MASK;
checksum += info_packet->hb0;
checksum += info_packet->hb1;
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 15/17] drm/amd/display: Trigger ALLM if it's available
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (13 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 14/17] drm/amd/display: Restore ALLM support in HDMI vsif Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-20 10:33 ` Michel Dänzer
2026-01-19 1:11 ` [PATCH 16/17] drm/amd/display: Reintroduce VTEM info frame Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 17/17] drm/amd/display: Enable HDMI VRR Tomasz Pakuła
16 siblings, 1 reply; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[Why]
ALLM automatically puts TVs into low latency modes (gaming modes) which
we basically always want for PC use, be it gaming, or using precise
inputs like mice and keyboards.
[How]
Read the ALLM info from HDMI caps and use it to determine if ALLM should
be indicated in HDMI Forum vsif. Additionally, make sure VIC modes are
translated in case of ALLM active as VIC cannot be used in conjunction
with hf-vsif. I learned this the hard way...
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
---
drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 4 +++-
.../gpu/drm/amd/display/modules/info_packet/info_packet.c | 7 ++++---
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 848c267ef11e..4a7c9f810e35 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -4504,6 +4504,7 @@ static void set_avi_info_frame(
unsigned int rid = pipe_ctx->stream->timing.rid;
unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
enum dc_timing_3d_format format;
+ bool allm;
if (stream->avi_infopacket.valid) {
*info_packet = stream->avi_infopacket;
@@ -4658,8 +4659,9 @@ static void set_avi_info_frame(
if (pipe_ctx->stream->timing.hdmi_vic != 0)
vic = 0;
format = stream->timing.timing_3d_format;
+ allm = stream->link->local_sink->edid_caps.allm;
/*todo, add 3DStereo support*/
- if (format != TIMING_3D_FORMAT_NONE) {
+ if ((format != TIMING_3D_FORMAT_NONE) || allm) {
// Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
switch (pipe_ctx->stream->timing.hdmi_vic) {
case 1:
diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
index 1a1ddcdb4362..0db2db7a197f 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
@@ -540,9 +540,10 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
info_packet->valid = false;
- format = stream->timing.timing_3d_format;
- if (stream->view_format == VIEW_3D_FORMAT_NONE)
- format = TIMING_3D_FORMAT_NONE;
+ allm = stream->link->local_sink->edid_caps.allm;
+ format = stream->view_format == VIEW_3D_FORMAT_NONE ?
+ TIMING_3D_FORMAT_NONE :
+ stream->timing.timing_3d_format;
stereo = format != TIMING_3D_FORMAT_NONE;
hdmi_vic_mode = is_hdmi_vic_mode(stream);
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 15/17] drm/amd/display: Trigger ALLM if it's available
2026-01-19 1:11 ` [PATCH 15/17] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
@ 2026-01-20 10:33 ` Michel Dänzer
2026-01-20 11:23 ` Daniel Stone
0 siblings, 1 reply; 25+ messages in thread
From: Michel Dänzer @ 2026-01-20 10:33 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
On 1/19/26 02:11, Tomasz Pakuła wrote:
> [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 about e.g. video playback though?
It might make sense to let the Wayland compositor control this, e.g. via the Wayland content type hint protocol.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 15/17] drm/amd/display: Trigger ALLM if it's available
2026-01-20 10:33 ` Michel Dänzer
@ 2026-01-20 11:23 ` Daniel Stone
2026-01-20 11:45 ` Jani Nikula
0 siblings, 1 reply; 25+ messages in thread
From: Daniel Stone @ 2026-01-20 11:23 UTC (permalink / raw)
To: Michel Dänzer
Cc: Tomasz Pakuła, alexander.deucher, harry.wentland, sunpeng.li,
maarten.lankhorst, mripard, tzimmermann, airlied, simona,
siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger
Hi,
On Tue, 20 Jan 2026 at 10:33, Michel Dänzer <michel.daenzer@mailbox.org> wrote:
> On 1/19/26 02:11, Tomasz Pakuła wrote:
> > [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 about e.g. video playback though?
>
> It might make sense to let the Wayland compositor control this, e.g. via the Wayland content type hint protocol.
Yes, I think this should be a connector property. We'll happily
implement support for Weston as the uAPI vehicle.
Cheers,
Daniel
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 15/17] drm/amd/display: Trigger ALLM if it's available
2026-01-20 11:23 ` Daniel Stone
@ 2026-01-20 11:45 ` Jani Nikula
2026-01-20 12:47 ` Tomasz Pakuła
0 siblings, 1 reply; 25+ messages in thread
From: Jani Nikula @ 2026-01-20 11:45 UTC (permalink / raw)
To: Daniel Stone, Michel Dänzer
Cc: Tomasz Pakuła, alexander.deucher, harry.wentland, sunpeng.li,
maarten.lankhorst, mripard, tzimmermann, airlied, simona,
siqueira, dri-devel, amd-gfx, linux-kernel, bernhard.berger,
ville.syrjala
On Tue, 20 Jan 2026, Daniel Stone <daniel@fooishbar.org> wrote:
> Hi,
>
> On Tue, 20 Jan 2026 at 10:33, Michel Dänzer <michel.daenzer@mailbox.org> wrote:
>> On 1/19/26 02:11, Tomasz Pakuła wrote:
>> > [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 about e.g. video playback though?
>>
>> It might make sense to let the Wayland compositor control this, e.g. via the Wayland content type hint protocol.
>
> Yes, I think this should be a connector property. We'll happily
> implement support for Weston as the uAPI vehicle.
Content type might be a useful policy hint also for content adaptive
brightness control and the like.
Ville and I have also tossed around ideas for passing the "power mode"
to the DRM drivers (e.g. Performance, Balanced, Power Saver). There are
various cases where the drivers need to make policy decisions that would
be better decided by userspace. However, it gets complicated and
unweildy if all of them are individual knobs. A power mode input might
be useful in making the latency decisions too.
BR,
Jani.
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 15/17] drm/amd/display: Trigger ALLM if it's available
2026-01-20 11:45 ` Jani Nikula
@ 2026-01-20 12:47 ` Tomasz Pakuła
0 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-20 12:47 UTC (permalink / raw)
To: Jani Nikula, Daniel Stone, Michel Dänzer
Cc: alexander.deucher, harry.wentland, sunpeng.li, maarten.lankhorst,
mripard, tzimmermann, airlied, simona, siqueira, dri-devel,
amd-gfx, linux-kernel, bernhard.berger, ville.syrjala
On Tue, 2026-01-20 at 13:45 +0200, Jani Nikula wrote:
> On Tue, 20 Jan 2026, Daniel Stone <daniel@fooishbar.org> wrote:
> > Hi,
> >
> > On Tue, 20 Jan 2026 at 10:33, Michel Dänzer <michel.daenzer@mailbox.org> wrote:
> > > On 1/19/26 02:11, Tomasz Pakuła wrote:
> > > > [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 about e.g. video playback though?
> > >
> > > It might make sense to let the Wayland compositor control this, e.g. via the Wayland content type hint protocol.
> >
> > Yes, I think this should be a connector property. We'll happily
> > implement support for Weston as the uAPI vehicle.
>
> Content type might be a useful policy hint also for content adaptive
> brightness control and the like.
>
> Ville and I have also tossed around ideas for passing the "power mode"
> to the DRM drivers (e.g. Performance, Balanced, Power Saver). There are
> various cases where the drivers need to make policy decisions that would
> be better decided by userspace. However, it gets complicated and
> unweildy if all of them are individual knobs. A power mode input might
> be useful in making the latency decisions too.
>
> BR,
> Jani.
Hmm, looking at the wp_content_type_v1 enum, I see it was probably based
on the CTA-861 Content Type information than can be supplied to the AVI
info frame? The values are identical. This surely could be plumbed into
drm_connector and basically directly set in the AVI info frame.
But, ALLM is something different and overrides the content type info. It
should be separate information, probably a simple switch to inform
drm_connector if it should be used. I don't know if ALLM setting should
always be exposed and let the drivers determine if it can be used, or
should it appear dynamically based on EDID though that's a consideration
for desktop environments.
In this case, ALLM of course would always take precedence and as far as
it's activation, it maybe would only be disabled when presenting
fullscreen photos/video? Content type notwithstanding.
Now, from a perspective of someone that actually uses PCs connected to
TVs and dip his toes into more TV topics, there should be a way to force
ALLM to be always on, no matter the content. I'd even advocate for it to
be the default because a long standing truth is that all the special
modes we have in our TVs and Monitors are garbage. They mess up the
picture, boost it to high heavens and some mode forcibly turn on motion-
smoothing.
With a PCs, we always expect the content to already be sent in high
quality, and even HTPC users prefer any post-process to be done on the
PC itself. Moreover, mode picture mode switching causes jarring
transitions and in same cases, toggling game mode can even blank a
screen for a moment, though it's rare.
We at least got Filmmaker mode as a crux, that often still need little
fine tuning, but doesn't make a mess of the picture. Oftentimes TVs will
detect PCs and disable most processing outright and content types can
have little to no effect. Again, like always with TVs, YMMV.
Game mode, sometimes merged with PC mode doesn't suck, and usually gives
the picture that's the closest to what the media actually is (be it
vide, HDR video, photo) and closest to selected color gamut standards
like bt.709, DCI-P3, bt.2020. In many ways, it will provide best picture
quality already, but maybe marketing departments wouldn't agree.
I can assure you, that as soon as the TV starts changing modes based on
the content, and there isn't a way to disable it, people will complain
hard.
All in all, if there will be a way to obtain all this information and
set appropriate info in AVI/HF-VSDB, then I'm sure it will be plumbed
through but for now, I think just having ALLM forced is a good idea.
Maybe, just maybe a property in sysfs/module setting could be used to
disable this if there's a big need.
There's another thing though. amdgpu already sets the IT content type
bit which already disables most if not all post-processing in sink
devices (or at least should). TVs often detect this as "PC" mode.
Sometimes ALLM is then needed to expose features like higher refresh
rate and VRR, thus the aforementioned mode change to update the exposed
EDID.
Oh, and ALLM only toggles the game mode if the game mode setting on the
TV is actually auto, with other values "off" and "on". It's just nice to
not have to manually turn it on.
Tomasz
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 16/17] drm/amd/display: Reintroduce VTEM info frame
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (14 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 15/17] drm/amd/display: Trigger ALLM if it's available Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
2026-01-19 1:11 ` [PATCH 17/17] drm/amd/display: Enable HDMI VRR Tomasz Pakuła
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[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. The standards for
RB and RBv2 use a fixed 160 or 80 lines for the horizontal blank period.
RB v3 can use either 160 or 80. Use this to detect if the current timing
mode uses reduced blankinig.
It doesn't hurt that the new functions look better and cleaner
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 | 173 ++++++++++++------
2 files changed, 116 insertions(+), 61 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
index 67274ce129bd..7bca0541443c 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 0db2db7a197f..42a736a5509a 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,80 +48,59 @@ 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
#define HF_VSIF_3D_BIT 0
#define HF_VSIF_ALLM_BIT 1
-// VTEM Byte Offset
-#define VTEM_PB0 0
-#define VTEM_PB1 1
-#define VTEM_PB2 2
-#define VTEM_PB3 3
-#define VTEM_PB4 4
-#define VTEM_PB5 5
-#define VTEM_PB6 6
+#define VTEM_ORG_ID 1
+#define VTEM_DATA_SET_TAG 1
+#define VTEM_DATA_SET_LENGTH 4
-#define VTEM_MD0 7
-#define VTEM_MD1 8
-#define VTEM_MD2 9
-#define VTEM_MD3 10
+#define VTEM_M_CONST 0
+#define VTEM_FVA_FACTOR 0
+#define VTEM_BRR_MASK_UPPER 0x03
+#define VTEM_BRR_MASK_LOWER 0xFF
-// VTEM Byte Masks
-//PB0
-#define MASK_VTEM_PB0__RESERVED0 0x01
-#define MASK_VTEM_PB0__SYNC 0x02
-#define MASK_VTEM_PB0__VFR 0x04
-#define MASK_VTEM_PB0__AFR 0x08
-#define MASK_VTEM_PB0__DS_TYPE 0x30
- //0: Periodic pseudo-static EM Data Set
- //1: Periodic dynamic EM Data Set
- //2: Unique EM Data Set
- //3: Reserved
-#define MASK_VTEM_PB0__END 0x40
-#define MASK_VTEM_PB0__NEW 0x80
+/* VTEM Byte Offset */
+#define VTEM_PB0 0
+#define VTEM_PB1 1
+#define VTEM_PB2 2
+#define VTEM_PB3 3
+#define VTEM_PB4 4
+#define VTEM_PB5 5
+#define VTEM_PB6 6
-//PB1
-#define MASK_VTEM_PB1__RESERVED1 0xFF
+#define VTEM_MD0 7
+#define VTEM_MD1 8
+#define VTEM_MD2 9
+#define VTEM_MD3 10
-//PB2
-#define MASK_VTEM_PB2__ORGANIZATION_ID 0xFF
- //0: This is a Vendor Specific EM Data Set
- //1: This EM Data Set is defined by This Specification (HDMI 2.1 r102.clean)
- //2: This EM Data Set is defined by CTA-861-G
- //3: This EM Data Set is defined by VESA
-//PB3
-#define MASK_VTEM_PB3__DATA_SET_TAG_MSB 0xFF
-//PB4
-#define MASK_VTEM_PB4__DATA_SET_TAG_LSB 0xFF
-//PB5
-#define MASK_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF
-//PB6
-#define MASK_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF
+/* Extended Metadata Packet */
+/* Header */
+#define EMP_LAST_BIT 6
+#define EMP_FIRST_BIT 7
+/* PB0 */
+#define EMP_SNC_BIT 1
+#define EMP_VFR_BIT 2
+#define EMP_AFR_BIT 3
+#define EMP_DST_BIT 4
+#define EMP_END_BIT 6
+#define EMP_NEW_BIT 7
+/* PB7 = MD0 */
+#define VTEM_VRR_BIT 0
+#define VTEM_M_CONST_BIT 1
+#define VTEM_FVA_BIT 4
+/* MD1 Base_Vfront */
+/* MD2 */
+#define VTEM_BRR_UPPER_BIT 0
+#define VTEM_RB_BIT 2
+/* MD3 BRR Lower */
-
-//PB7-27 (20 bytes):
-//PB7 = MD0
-#define MASK_VTEM_MD0__VRR_EN 0x01
-#define MASK_VTEM_MD0__M_CONST 0x02
-#define MASK_VTEM_MD0__QMS_EN 0x04
-#define MASK_VTEM_MD0__RESERVED2 0x08
-#define MASK_VTEM_MD0__FVA_FACTOR_M1 0xF0
-
-//MD1
-#define MASK_VTEM_MD1__BASE_VFRONT 0xFF
-
-//MD2
-#define MASK_VTEM_MD2__BASE_REFRESH_RATE_98 0x03
-#define MASK_VTEM_MD2__RB 0x04
-#define MASK_VTEM_MD2__NEXT_TFR 0xF8
-
-//MD3
-#define MASK_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF
-
enum ColorimetryRGBDP {
ColorimetryRGB_DP_sRGB = 0,
ColorimetryRGB_DP_AdobeRGB = 3,
@@ -611,6 +590,78 @@ 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 brr = 0;
+ bool hdmi_vic_mode = false;
+ bool vrr_active = false;
+ bool rb = false;
+
+ hdmi_vic_mode = is_hdmi_vic_mode(stream);
+ 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 (hdmi_vic_mode || !vrr_active)
+ return;
+ /*
+ * Reduced Blanking standard defines a fixed value of
+ * 160 for hblank, further reduced to 80 in RB2
+ */
+ rb = (stream->timing.h_total - stream->timing.h_addressable) <= 160;
+ brr = 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 & VTEM_BRR_MASK_UPPER) >> 8;
+ infopacket->sb[VTEM_MD3] = brr & VTEM_BRR_MASK_LOWER;
+}
+
+void mod_build_vtem_infopacket(const struct dc_stream_state *stream,
+ const struct mod_vrr_params *vrr,
+ struct dc_info_packet *infopacket)
+{
+ infopacket->valid = true;
+ build_vtem_infopacket_header(infopacket);
+ build_vtem_infopacket_data(stream, vrr, infopacket);
+}
+
void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
enum adaptive_sync_type asType,
const struct AS_Df_params *param,
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 17/17] drm/amd/display: Enable HDMI VRR
2026-01-19 1:11 [PATCH 00/17] drm/amd: VRR fixes, HDMI Gaming Features Tomasz Pakuła
` (15 preceding siblings ...)
2026-01-19 1:11 ` [PATCH 16/17] drm/amd/display: Reintroduce VTEM info frame Tomasz Pakuła
@ 2026-01-19 1:11 ` Tomasz Pakuła
16 siblings, 0 replies; 25+ messages in thread
From: Tomasz Pakuła @ 2026-01-19 1:11 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
[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 | 13 +++++++++++--
.../gpu/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, 17 insertions(+), 2 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 ef7e02ebda41..75c3c8ad07e5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9612,6 +9612,9 @@ static void update_freesync_state_on_stream(
&new_stream->adaptive_sync_infopacket);
}
+ if (aconn && aconn->as_type == ADAPTIVE_SYNC_TYPE_HDMI)
+ packet_type = PACKET_TYPE_VTEM;
+
mod_freesync_build_vrr_infopacket(
dm->freesync_module,
new_stream,
@@ -13347,8 +13350,14 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
}
/* HDMI */
- } else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && vsdb_freesync) {
- monitor_range_from_vsdb(connector, &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, valid_vsdb_cea ? &vsdb_info : NULL);
+ } else if (vsdb_freesync)
+ monitor_range_from_vsdb(connector, &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 7bca0541443c..3fef1890a3fa 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 42a736a5509a..e6d3398046d5 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
@@ -686,6 +686,7 @@ void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
break;
case ADAPTIVE_SYNC_TYPE_NONE:
case ADAPTIVE_SYNC_TYPE_PCON_NOT_ALLOWED:
+ case ADAPTIVE_SYNC_TYPE_HDMI:
default:
break;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread