mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 1/2] drm/edid: populate monitor_range from DisplayID Dynamic Video Timing block
@ 2026-03-28 13:20 Adriano Vero
  2026-03-28 13:20 ` [PATCH 2/2] drm/amd/display: remove manual DisplayID VRR parsing from freesync caps Adriano Vero
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Adriano Vero @ 2026-03-28 13:20 UTC (permalink / raw)
  To: dri-devel
  Cc: jani.nikula, alexander.deucher, harry.wentland, sunpeng.li,
	siqueira, christian.koenig, amd-gfx, linux-kernel, Adriano Vero

Some eDP panels report their VRR limits only via a DisplayID v1r2
Dynamic Video Timing Range Limits block (tag 0x25), without setting
DRM_EDID_FEATURE_CONTINUOUS_FREQ. drm_get_monitor_range() returns
early for such panels, leaving monitor_range zeroed.

Add drm_get_monitor_range_displayid() and call it from
update_display_info() immediately after drm_get_monitor_range(). It
uses displayid_iter_edid_begin() to locate Dynamic Video Timing blocks
and extracts min/max refresh rates, including the 10-bit max_vfreq
encoding signalled by block->rev bits [2:0]. It is a no-op when
monitor_range is already populated by the classic EDID path.

All drivers reading display_info.monitor_range now receive correct VRR
limits from DisplayID-only panels without any raw EDID access.

Byte offsets verified against parse_edid_displayid_vrr() in amdgpu_dm.c.

Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: dri-devel@lists.freedesktop.org
Signed-off-by: Adriano Vero <litaliano00.contact@gmail.com>
---
 drivers/gpu/drm/drm_edid.c | 68 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index ff432ac6b..d2c360178 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -6504,6 +6504,71 @@ void get_monitor_range(const struct detailed_timing *timing, void *c)
 	}
 }
 
+/**
+ * drm_get_monitor_range_displayid - populate monitor_range from a
+ * DisplayID v1r2 Dynamic Video Timing Range Limits block (tag 0x25).
+ *
+ * Some eDP panels report their VRR limits only in a DisplayID block,
+ * without setting DRM_EDID_FEATURE_CONTINUOUS_FREQ. drm_get_monitor_range()
+ * returns early for such panels, leaving monitor_range zeroed. This
+ * function is called separately from update_display_info() as a fallback.
+ *
+ * Block payload layout (block->num_bytes == 9):
+ *   data[6]       min_vfreq in Hz
+ *   data[7]       max_vfreq low 8 bits
+ *   data[8][1:0]  max_vfreq high bits (when block->rev & 7 is nonzero)
+ *
+ * Byte offsets verified against parse_edid_displayid_vrr() in amdgpu_dm.c.
+ */
+static void
+drm_get_monitor_range_displayid(struct drm_connector *connector,
+				const struct drm_edid *drm_edid)
+{
+	struct drm_display_info *info = &connector->display_info;
+	const struct displayid_block *block;
+	struct displayid_iter iter;
+
+	/* Only run when the classic EDID path left these zeroed */
+	if (info->monitor_range.min_vfreq && info->monitor_range.max_vfreq)
+		return;
+
+	displayid_iter_edid_begin(drm_edid, &iter);
+	displayid_iter_for_each(block, &iter) {
+		const u8 *data;
+		u16 min_vfreq, max_vfreq;
+
+		if (block->tag != DATA_BLOCK_2_DYNAMIC_VIDEO_TIMING)
+			continue;
+
+		/* rev bits [7:1] must be zero; payload must be exactly 9 bytes */
+		if ((block->rev & 0xFE) != 0 || block->num_bytes != 9)
+			continue;
+
+		data = (const u8 *)(block + 1);
+
+		min_vfreq = data[6];
+
+		/* rev bits [2:0] nonzero: max_vfreq is 10-bit */
+		if (block->rev & 7)
+			max_vfreq = data[7] | ((u16)(data[8] & 3) << 8);
+		else
+			max_vfreq = data[7];
+
+		if (!min_vfreq || !max_vfreq)
+			continue;
+
+		info->monitor_range.min_vfreq = min_vfreq;
+		info->monitor_range.max_vfreq = max_vfreq;
+
+		drm_dbg_kms(connector->dev,
+			    "[CONNECTOR:%d:%s] DisplayID dynamic video timing range: %u-%u Hz\n",
+			    connector->base.id, connector->name,
+			    min_vfreq, max_vfreq);
+		break;
+	}
+	displayid_iter_end(&iter);
+}
+
 static void drm_get_monitor_range(struct drm_connector *connector,
 				  const struct drm_edid *drm_edid)
 {
@@ -6691,10 +6756,9 @@ static void update_display_info(struct drm_connector *connector,
 	info->height_mm = edid->height_cm * 10;
 
 	drm_get_monitor_range(connector, drm_edid);
-
+	drm_get_monitor_range_displayid(connector, drm_edid);
 	if (edid->revision < 3)
 		goto out;
-
 	if (!drm_edid_is_digital(drm_edid))
 		goto out;
 
-- 
2.47.3


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

end of thread, other threads:[~2026-04-01 23:07 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-28 13:20 [PATCH 1/2] drm/edid: populate monitor_range from DisplayID Dynamic Video Timing block Adriano Vero
2026-03-28 13:20 ` [PATCH 2/2] drm/amd/display: remove manual DisplayID VRR parsing from freesync caps Adriano Vero
2026-03-30  6:01 ` [PATCH 1/2] drm/edid: populate monitor_range from DisplayID Dynamic Video Timing block kernel test robot
2026-03-30  6:34 ` kernel test robot
2026-03-30 12:35 ` Jani Nikula
2026-04-01 23:07 ` [PATCH v2 1/2] drm/edid: populate monitor_range from DisplayID v2r0 " Adriano Vero
2026-04-01 23:07   ` [PATCH v2 2/2] drm/amd/display: remove manual DisplayID VRR parsing from freesync caps Adriano Vero

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

all inboxes | Powered by JetHome®