dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/4] drm/edid: Parse AMD VSDB FreeSync range in common code
@ 2026-08-04 14:33 Alex Huang
  2026-08-04 14:33 ` [PATCH v3 1/4] drm/edid: Parse AMD VSDB for FreeSync refresh range Alex Huang
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Alex Huang @ 2026-08-04 14:33 UTC (permalink / raw)
  To: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	harry.wentland, sunpeng.li, siqueira, alexander.deucher,
	christian.koenig, alex.hung
  Cc: superm1, dri-devel, amd-gfx, linux-kernel, Alex Huang

This patch series implements parsing for AMD VSDB block's FreeSync
related data directly in the EDID common parser.

Some monitor manufacturers advertise their VRR capability exclusively
using the AMD VSDB block's FreeSync data fields, many other
manufacturers (notably pre EDID 1.4 monitors and some post 1.4 monitors)
also do not include the relevant continuous frequency feature flag in
the EDID. This makes it difficult to differentiate true VRR capability
from supporting a few refresh rates between the range specified in EDID
refresh rate range field in a spec compliant manner.

Incidentally also resolves a recent regression where amdgpu failed to
detect some DP monitors as VRR capable after EDID parser was moved to
DRM common.

v2:
- Use a ladder style parser as suggested by Mario.
- Validate payload lengths before parsing.
- Removed an extra amd_vsdb_version reassignment.

v3:
- Parse future versions as v3 block as suggested by Mario.

Alex Huang (4):
  drm/edid: Parse AMD VSDB for FreeSync refresh range
  drm/amd/display: Use HDMI FreeSync range from common EDID parser
  drm/amd/display: Clean up FreeSync capability detection
  drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 252 +++---------------
 drivers/gpu/drm/amd/display/dc/Makefile       |   1 -
 .../gpu/drm/amd/display/dc/dc_edid_parser.c   |  80 ------
 .../gpu/drm/amd/display/dc/dc_edid_parser.h   |  44 ---
 drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 121 ---------
 drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h  |  10 -
 .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h   |  71 -----
 drivers/gpu/drm/drm_edid.c                    | 147 ++++++++--
 include/drm/drm_connector.h                   |  22 +-
 9 files changed, 181 insertions(+), 567 deletions(-)
 delete mode 100644 drivers/gpu/drm/amd/display/dc/dc_edid_parser.c
 delete mode 100644 drivers/gpu/drm/amd/display/dc/dc_edid_parser.h

-- 
2.34.1


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

* [PATCH v3 1/4] drm/edid: Parse AMD VSDB for FreeSync refresh range
  2026-08-04 14:33 [PATCH v3 0/4] drm/edid: Parse AMD VSDB FreeSync range in common code Alex Huang
@ 2026-08-04 14:33 ` Alex Huang
  2026-08-04 15:17   ` sashiko-bot
  2026-08-04 14:33 ` [PATCH v3 2/4] drm/amd/display: Use HDMI FreeSync range from common EDID parser Alex Huang
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Alex Huang @ 2026-08-04 14:33 UTC (permalink / raw)
  To: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	harry.wentland, sunpeng.li, siqueira, alexander.deucher,
	christian.koenig, alex.hung
  Cc: superm1, dri-devel, amd-gfx, linux-kernel, Alex Huang

Commit 118362a96286 ("drm/edid: Parse AMD Vendor-Specific Data Block")
added parsing of the AMD VSDB, but only for version 3 and only for the
replay/panel-type/luminance fields. Monitors that only advertise
FreeSync through a v1 or v2 AMD VSDB therefore get no variable refresh
rate range from the common EDID parser.

Restructure drm_parse_amd_vsdb() and implement parsing for the FreeSync
refresh range fields provided in the AMD VSDB. Additionally, version > 3
will be parsed as if they were version 3 (with a warning of this
occurring) as future versions will likely be backwards compatible.

Signed-off-by: Alex Huang <Alex.Huang2@amd.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
---
 drivers/gpu/drm/drm_edid.c  | 147 +++++++++++++++++++++++++++++-------
 include/drm/drm_connector.h |  22 +++++-
 2 files changed, 139 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index df3c25bac761..a12b5e6905fb 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -101,20 +101,42 @@ enum drm_edid_internal_quirk {
 #define MICROSOFT_IEEE_OUI	0xca125c
 #define AMD_IEEE_OUI        0x00001A
 
+#define AMD_VSDB_V1_PAYLOAD_LEN 8
+#define AMD_VSDB_V2_PAYLOAD_LEN 13
 #define AMD_VSDB_V3_PAYLOAD_MIN_LEN 15
-#define AMD_VSDB_V3_PAYLOAD_MAX_LEN 20
+#define AMD_VSDB_V3_PAYLOAD_MAX_LEN 21
 
-struct amd_vsdb_v3_payload {
+#define AMD_VSDB_V3_MAX_VFREQ_EXT2_LEN 21
+
+struct amd_vsdb_common_payload {
 	u8 oui[3];
 	u8 version;
+} __packed;
+
+struct amd_vsdb_v1_payload {
+	struct amd_vsdb_common_payload common;
 	u8 feature_caps;
-	u8 rsvd0[3];
+	u8 min_vfreq;
+	u8 max_vfreq;
+	u8 freesync_vcp_code;
+} __packed;
+
+struct amd_vsdb_v2_payload {
+	struct amd_vsdb_v1_payload v1;
 	u8 cs_eotf_support;
 	u8 lum1_max;
 	u8 lum1_min;
 	u8 lum2_max;
 	u8 lum2_min;
-	u8 rsvd1[2];
+} __packed;
+
+struct amd_vsdb_v3_payload {
+	struct amd_vsdb_v2_payload v2;
+	u8 max_vfreq_ext_low;
+	/*
+	 * byte 14: bits 0-1 extend MSB of max refresh rate
+	 */
+	u8 max_vfreq_ext_high;
 	/*
 	 * Bytes beyond AMD_VSDB_V3_PAYLOAD_MIN_LEN are optional; a
 	 * monitor may provide a payload as short as 15 bytes.  Always
@@ -123,6 +145,12 @@ struct amd_vsdb_v3_payload {
 	u8 extra[AMD_VSDB_V3_PAYLOAD_MAX_LEN - AMD_VSDB_V3_PAYLOAD_MIN_LEN];
 } __packed;
 
+static const u8 amd_vsdb_min_len[] = {
+	[1] = AMD_VSDB_V1_PAYLOAD_LEN,
+	[2] = AMD_VSDB_V2_PAYLOAD_LEN,
+	[3] = AMD_VSDB_V3_PAYLOAD_MIN_LEN,
+};
+
 struct detailed_mode_closure {
 	struct drm_connector *connector;
 	const struct drm_edid *drm_edid;
@@ -5231,7 +5259,7 @@ static bool cea_db_is_microsoft_vsdb(const struct cea_db *db)
 static bool cea_db_is_amd_vsdb(const struct cea_db *db)
 {
 	return cea_db_is_vendor(db, AMD_IEEE_OUI) &&
-		cea_db_payload_len(db) >= AMD_VSDB_V3_PAYLOAD_MIN_LEN &&
+		cea_db_payload_len(db) >= AMD_VSDB_V1_PAYLOAD_LEN &&
 		cea_db_payload_len(db) <= AMD_VSDB_V3_PAYLOAD_MAX_LEN;
 }
 
@@ -6431,43 +6459,104 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector,
 		    connector->base.id, connector->name, version, db[5]);
 }
 
+static void drm_parse_amd_vsdb_common(struct drm_display_info *info,
+				  const struct amd_vsdb_common_payload *data)
+{
+	info->amd_vsdb.version = data->version;
+}
+
+static void drm_parse_amd_vsdb_v1(struct drm_display_info *info,
+				  const struct amd_vsdb_v1_payload *data)
+{
+	info->amd_vsdb.freesync_supported = data->feature_caps & 0x1;
+	info->amd_vsdb.min_frame_rate = data->min_vfreq;
+	info->amd_vsdb.max_frame_rate = data->max_vfreq;
+	info->amd_vsdb.freesync_vcp_code = data->freesync_vcp_code;
+
+	drm_parse_amd_vsdb_common(info, &data->common);
+}
+
+static void drm_parse_amd_vsdb_v2(struct drm_display_info *info,
+				  const struct amd_vsdb_v2_payload *data)
+{
+	info->amd_vsdb.luminance_range1.max_luminance = data->lum1_max;
+	info->amd_vsdb.luminance_range1.min_luminance = data->lum1_min;
+	info->amd_vsdb.luminance_range2.max_luminance = data->lum2_max;
+	info->amd_vsdb.luminance_range2.min_luminance = data->lum2_min;
+
+	drm_parse_amd_vsdb_v1(info, &data->v1);
+}
+
+static void drm_parse_amd_vsdb_v3(struct drm_display_info *info,
+				  const struct amd_vsdb_v3_payload *data,
+				  int payload_len)
+{
+	u16 max_frame_rate;
+
+	info->amd_vsdb.replay_mode = data->v2.v1.feature_caps & 0x40;
+	info->amd_vsdb.panel_type = (data->v2.cs_eotf_support & 0xC0) >> 6;
+
+	drm_parse_amd_vsdb_v2(info, &data->v2);
+
+	/* vfreq is provided in a different set of fields for v3. */
+	max_frame_rate = data->max_vfreq_ext_low |
+			 (data->max_vfreq_ext_high & 0x3) << 8;
+
+	/*
+	 * The AMD VSDB v3 payload length is variable (15..21 bytes).
+	 * All fields through max_vfreq_ext_high (byte 14) are always
+	 * present, but data->extra[] (bytes 15+) may not be, so any access
+	 * to extra[] must be guarded with a runtime length check to
+	 * avoid out-of-bounds reads on shorter (but spec-valid) payloads.
+	 */
+	if (payload_len >= AMD_VSDB_V3_MAX_VFREQ_EXT2_LEN)
+		max_frame_rate |= (data->extra[5] & 0x3) << 10;
+
+	info->amd_vsdb.max_frame_rate = max_frame_rate;
+}
+
 static void drm_parse_amd_vsdb(struct drm_connector *connector,
 			       const struct cea_db *db)
 {
 	struct drm_display_info *info = &connector->display_info;
 	const u8 *data = cea_db_data(db);
-	const struct amd_vsdb_v3_payload *p;
+	int payload_len = cea_db_payload_len(db);
+	u8 version;
 
-	p = (const struct amd_vsdb_v3_payload *)data;
+	version = ((const struct amd_vsdb_common_payload *)data)->version;
 
-	if (p->version != 0x03) {
+	if (version < 1) {
 		drm_dbg_kms(connector->dev,
 			    "[CONNECTOR:%d:%s] Unsupported AMD VSDB version %u\n",
-			    connector->base.id, connector->name, p->version);
+			    connector->base.id, connector->name, version);
 		return;
 	}
 
-	info->amd_vsdb.version = p->version;
-	info->amd_vsdb.replay_mode = p->feature_caps & 0x40;
-	info->amd_vsdb.panel_type = (p->cs_eotf_support & 0xC0) >> 6;
-	info->amd_vsdb.luminance_range1.max_luminance = p->lum1_max;
-	info->amd_vsdb.luminance_range1.min_luminance = p->lum1_min;
-	info->amd_vsdb.luminance_range2.max_luminance = p->lum2_max;
-	info->amd_vsdb.luminance_range2.min_luminance = p->lum2_min;
+	if ((version <= 3 && payload_len < amd_vsdb_min_len[version]) ||
+		(version > 3 && payload_len < AMD_VSDB_V3_PAYLOAD_MIN_LEN)) {
+		drm_dbg_kms(connector->dev,
+			    "[CONNECTOR:%d:%s] AMD VSDB v%u payload too short (%d bytes)\n",
+			    connector->base.id, connector->name, version, payload_len);
+		return;
+	}
 
-	/*
-	 * The AMD VSDB v3 payload length is variable (15..20 bytes).
-	 * All fields through p->rsvd1 (byte 14) are always present,
-	 * but p->extra[] (bytes 15+) may not be.  Any future access to
-	 * extra[] must be guarded with a runtime length check to avoid
-	 * out-of-bounds reads on shorter (but spec-valid) payloads.
-	 * For example:
-	 *
-	 *   int len = cea_db_payload_len(db);
-	 *
-	 *   if (len > AMD_VSDB_V3_PAYLOAD_MIN_LEN)
-	 *       info->amd_vsdb.foo = p->extra[0];
-	 */
+	switch (version) {
+	default:
+		drm_dbg_kms(connector->dev,
+				"[CONNECTOR:%d:%s] AMD VSDB v%u is unsupported, VSDB will be parsed as v3.\n",
+				connector->base.id, connector->name, version);
+		fallthrough;
+	case 3:
+		drm_parse_amd_vsdb_v3(info, (const struct amd_vsdb_v3_payload *)data,
+				      payload_len);
+		break;
+	case 2:
+		drm_parse_amd_vsdb_v2(info, (const struct amd_vsdb_v2_payload *)data);
+		break;
+	case 1:
+		drm_parse_amd_vsdb_v1(info, (const struct amd_vsdb_v1_payload *)data);
+		break;
+	}
 }
 
 static void drm_parse_cea_ext(struct drm_connector *connector,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 5f5ca023cd65..0914a2bd8ef1 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -697,7 +697,7 @@ enum drm_bus_flags {
  * struct drm_amd_vsdb_info - AMD-specific VSDB information
  *
  * This structure holds information parsed from the AMD Vendor-Specific Data
- * Block (VSDB) version 3.
+ * Block (VSDB) versions 1 to 3.
  */
 struct drm_amd_vsdb_info {
 	/**
@@ -705,6 +705,26 @@ struct drm_amd_vsdb_info {
 	 */
 	u8 version;
 
+	/**
+	 * @freesync_supported: FreeSync (variable refresh rate) supported by panel
+	 */
+	bool freesync_supported;
+
+	/**
+	 * @min_frame_rate: FreeSync minimum refresh rate in Hz
+	 */
+	u16 min_frame_rate;
+
+	/**
+	 * @max_frame_rate: FreeSync maximum refresh rate in Hz
+	 */
+	u16 max_frame_rate;
+
+	/**
+	 * @freesync_vcp_code: MCCS VCP code for FreeSync
+	 */
+	u8 freesync_vcp_code;
+
 	/**
 	 * @replay_mode: Panel Replay supported
 	 */
-- 
2.34.1


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

* [PATCH v3 2/4] drm/amd/display: Use HDMI FreeSync range from common EDID parser
  2026-08-04 14:33 [PATCH v3 0/4] drm/edid: Parse AMD VSDB FreeSync range in common code Alex Huang
  2026-08-04 14:33 ` [PATCH v3 1/4] drm/edid: Parse AMD VSDB for FreeSync refresh range Alex Huang
@ 2026-08-04 14:33 ` Alex Huang
  2026-08-04 14:33 ` [PATCH v3 3/4] drm/amd/display: Clean up FreeSync capability detection Alex Huang
  2026-08-04 14:33 ` [PATCH v3 4/4] drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser Alex Huang
  3 siblings, 0 replies; 8+ messages in thread
From: Alex Huang @ 2026-08-04 14:33 UTC (permalink / raw)
  To: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	harry.wentland, sunpeng.li, siqueira, alexander.deucher,
	christian.koenig, alex.hung
  Cc: superm1, dri-devel, amd-gfx, linux-kernel, Alex Huang

HDMI FreeSync on amdgpu is detected using the AMD VSDB parser in the
DMUB firmware, now that the common DRM EDID parser can do the same, use
the common parser.

Extend get_amd_vsdb() to copy the relevant flags and data now being
extracted from the AMD VSDB. Additionally, parse_hdmi_amd_vsdb() and the
parse_edid_cea() firmware helpers now have no callers; remove them.

Signed-off-by: Alex Huang <Alex.Huang2@amd.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 178 +-----------------
 1 file changed, 8 insertions(+), 170 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 1820547b1dde..44b8dd000f5c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -36,7 +36,6 @@
 #include "dc/inc/hw/dmcu.h"
 #include "dc/inc/hw/abm.h"
 #include "dc/dc_dmub_srv.h"
-#include "dc/dc_edid_parser.h"
 #include "dc/dc_stat.h"
 #include "dc/dc_state.h"
 #include "amdgpu_dm_trace.h"
@@ -13647,139 +13646,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
 	return ret;
 }
 
-static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
-		unsigned int offset,
-		unsigned int total_length,
-		u8 *data,
-		unsigned int length,
-		struct amdgpu_hdmi_vsdb_info *vsdb)
-{
-	bool res;
-	union dmub_rb_cmd cmd;
-	struct dmub_cmd_send_edid_cea *input;
-	struct dmub_cmd_edid_cea_output *output;
-
-	if (length > DMUB_EDID_CEA_DATA_CHUNK_BYTES)
-		return false;
-
-	memset(&cmd, 0, sizeof(cmd));
-
-	input = &cmd.edid_cea.data.input;
-
-	cmd.edid_cea.header.type = DMUB_CMD__EDID_CEA;
-	cmd.edid_cea.header.sub_type = 0;
-	cmd.edid_cea.header.payload_bytes =
-		sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header);
-	input->offset = offset;
-	input->length = length;
-	input->cea_total_length = total_length;
-	memcpy(input->payload, data, length);
-
-	res = dc_wake_and_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);
-	if (!res) {
-		drm_err(adev_to_drm(dm->adev), "EDID CEA parser failed\n");
-		return false;
-	}
-
-	output = &cmd.edid_cea.data.output;
-
-	if (output->type == DMUB_CMD__EDID_CEA_ACK) {
-		if (!output->ack.success) {
-			drm_err(adev_to_drm(dm->adev), "EDID CEA ack failed at offset %d\n",
-					output->ack.offset);
-		}
-	} else if (output->type == DMUB_CMD__EDID_CEA_AMD_VSDB) {
-		if (!output->amd_vsdb.vsdb_found)
-			return false;
-
-		vsdb->freesync_supported = output->amd_vsdb.freesync_supported;
-		vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version;
-		vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate;
-		vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate;
-		vsdb->freesync_mccs_vcp_code = output->amd_vsdb.freesync_mccs_vcp_code;
-	} else {
-		drm_warn(adev_to_drm(dm->adev), "Unknown EDID CEA parser results\n");
-		return false;
-	}
-
-	return true;
-}
-
-static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
-		u8 *edid_ext, int len,
-		struct amdgpu_hdmi_vsdb_info *vsdb_info)
-{
-	int i;
-
-	/* send extension block to DMCU for parsing */
-	for (i = 0; i < len; i += 8) {
-		bool res;
-		int offset;
-
-		/* send 8 bytes a time */
-		if (!dc_edid_parser_send_cea(dm->dc, i, len, &edid_ext[i], 8))
-			return false;
-
-		if (i+8 == len) {
-			/* EDID block sent completed, expect result */
-			int version, min_rate, max_rate;
-
-			res = dc_edid_parser_recv_amd_vsdb(dm->dc, &version, &min_rate, &max_rate);
-			if (res) {
-				/* amd vsdb found */
-				vsdb_info->freesync_supported = 1;
-				vsdb_info->amd_vsdb_version = version;
-				vsdb_info->min_refresh_rate_hz = min_rate;
-				vsdb_info->max_refresh_rate_hz = max_rate;
-				/* Not enabled on DMCU*/
-				vsdb_info->freesync_mccs_vcp_code = 0;
-				return true;
-			}
-			/* not amd vsdb */
-			return false;
-		}
-
-		/* check for ack*/
-		res = dc_edid_parser_recv_cea_ack(dm->dc, &offset);
-		if (!res)
-			return false;
-	}
-
-	return false;
-}
-
-static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
-		u8 *edid_ext, int len,
-		struct amdgpu_hdmi_vsdb_info *vsdb_info)
-{
-	int i;
-
-	/* send extension block to DMCU for parsing */
-	for (i = 0; i < len; i += 8) {
-		/* send 8 bytes a time */
-		if (!dm_edid_parser_send_cea(dm, i, len, &edid_ext[i], 8, vsdb_info))
-			return false;
-	}
-
-	return vsdb_info->freesync_supported;
-}
-
-static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
-		u8 *edid_ext, int len,
-		struct amdgpu_hdmi_vsdb_info *vsdb_info)
-{
-	struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
-	bool ret;
-
-	mutex_lock(&adev->dm.dc_lock);
-	if (adev->dm.dmub_srv)
-		ret = parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
-	else
-		ret = parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
-	mutex_unlock(&adev->dm.dc_lock);
-	return ret;
-}
-
 static void parse_edid_displayid_vrr(struct drm_connector *connector,
 				     const struct edid *edid)
 {
@@ -13830,42 +13696,14 @@ static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 
 	vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode;
 	vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version;
+	vsdb_info->freesync_supported = connector->display_info.amd_vsdb.freesync_supported;
+	vsdb_info->min_refresh_rate_hz = connector->display_info.amd_vsdb.min_frame_rate;
+	vsdb_info->max_refresh_rate_hz = connector->display_info.amd_vsdb.max_frame_rate;
+	vsdb_info->freesync_mccs_vcp_code = connector->display_info.amd_vsdb.freesync_vcp_code;
 
 	return connector->display_info.amd_vsdb.version != 0;
 }
 
-static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
-			       const struct edid *edid,
-			       struct amdgpu_hdmi_vsdb_info *vsdb_info)
-{
-	u8 *edid_ext = NULL;
-	int i;
-	bool valid_vsdb_found = false;
-
-	/*----- drm_find_cea_extension() -----*/
-	/* No EDID or EDID extensions */
-	if (edid == NULL || edid->extensions == 0)
-		return -ENODEV;
-
-	/* Find CEA extension */
-	for (i = 0; i < edid->extensions; i++) {
-		edid_ext = (uint8_t *)edid + EDID_LENGTH * (i + 1);
-		if (edid_ext[0] == CEA_EXT)
-			break;
-	}
-
-	if (i == edid->extensions)
-		return -ENODEV;
-
-	/*----- cea_db_offsets() -----*/
-	if (edid_ext[0] != CEA_EXT)
-		return -ENODEV;
-
-	valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
-
-	return valid_vsdb_found ? i : -ENODEV;
-}
-
 /**
  * amdgpu_dm_update_freesync_caps - Update Freesync capabilities
  *
@@ -13947,8 +13785,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 		}
 
 	} 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) {
+		i = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
+		if (i) {
 			amdgpu_dm_connector->vsdb_info = vsdb_info;
 			sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
 
@@ -13968,8 +13806,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 		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) {
+		i = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
+		if (i) {
 			amdgpu_dm_connector->vsdb_info = vsdb_info;
 			sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
 
-- 
2.34.1


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

* [PATCH v3 3/4] drm/amd/display: Clean up FreeSync capability detection
  2026-08-04 14:33 [PATCH v3 0/4] drm/edid: Parse AMD VSDB FreeSync range in common code Alex Huang
  2026-08-04 14:33 ` [PATCH v3 1/4] drm/edid: Parse AMD VSDB for FreeSync refresh range Alex Huang
  2026-08-04 14:33 ` [PATCH v3 2/4] drm/amd/display: Use HDMI FreeSync range from common EDID parser Alex Huang
@ 2026-08-04 14:33 ` Alex Huang
  2026-08-04 15:35   ` sashiko-bot
  2026-08-04 14:33 ` [PATCH v3 4/4] drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser Alex Huang
  3 siblings, 1 reply; 8+ messages in thread
From: Alex Huang @ 2026-08-04 14:33 UTC (permalink / raw)
  To: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	harry.wentland, sunpeng.li, siqueira, alexander.deucher,
	christian.koenig, alex.hung
  Cc: superm1, dri-devel, amd-gfx, linux-kernel, Alex Huang

Many duplicate codes can be extracted to common code, fill
amdgpu_dm_connector fields outside of the DP/eDP, HDMI branches,
pull the VSDB data once using get_amd_vsdb() and then derive the refresh
rate ranges.

When a monitor advertises support for FreeSync, the refresh rate from
the AMD VSDB is used, otherwise, falls back on the monitor_range, either
EDID refresh rate range field or DisplayID VRR data.

Signed-off-by: Alex Huang <Alex.Huang2@amd.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 82 +++++++++----------
 1 file changed, 38 insertions(+), 44 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 44b8dd000f5c..6d83e9a42537 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13722,7 +13722,7 @@ static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 				    const struct drm_edid *drm_edid, bool do_mccs)
 {
-	int i = 0;
+	bool has_vsdb = 0;
 	struct amdgpu_dm_connector *amdgpu_dm_connector =
 			to_amdgpu_dm_connector(connector);
 	struct dm_connector_state *dm_con_state = NULL;
@@ -13766,63 +13766,57 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
 	     connector->display_info.monitor_range.max_vfreq == 0))
 		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;
+	has_vsdb = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info) != 0;
+
+	if (has_vsdb) {
+		amdgpu_dm_connector->vsdb_info = vsdb_info;
+
+		/* copy refresh rate info as long as VSDB advertises FreeSync */
+		if (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;
+
+			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 {
+		/* fall back to the base EDID range when there is no VSDB */
+		amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
+		amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
+	}
 
-		get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
+	if (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->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
+			freesync_capable = true;
 
 		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;
 			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
 		}
+	} else if (has_vsdb && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
+		sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
 
-	} else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
-		i = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
-		if (i) {
-			amdgpu_dm_connector->vsdb_info = vsdb_info;
-			sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
-
-			if (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;
-			}
-		}
+		if (vsdb_info.freesync_supported &&
+		    amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
+			freesync_capable = true;
 	}
 
 	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 = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
-		if (i) {
-			amdgpu_dm_connector->vsdb_info = vsdb_info;
-			sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
+	if (has_vsdb && as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
+		sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
 
-			if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
-				amdgpu_dm_connector->pack_sdp_v1_3 = true;
-				amdgpu_dm_connector->as_type = as_type;
+		if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
+			amdgpu_dm_connector->pack_sdp_v1_3 = true;
+			amdgpu_dm_connector->as_type = as_type;
 
-				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;
-			}
+			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
+				freesync_capable = true;
 		}
 	}
 
-- 
2.34.1


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

* [PATCH v3 4/4] drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser
  2026-08-04 14:33 [PATCH v3 0/4] drm/edid: Parse AMD VSDB FreeSync range in common code Alex Huang
                   ` (2 preceding siblings ...)
  2026-08-04 14:33 ` [PATCH v3 3/4] drm/amd/display: Clean up FreeSync capability detection Alex Huang
@ 2026-08-04 14:33 ` Alex Huang
  2026-08-04 15:49   ` sashiko-bot
  3 siblings, 1 reply; 8+ messages in thread
From: Alex Huang @ 2026-08-04 14:33 UTC (permalink / raw)
  To: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	harry.wentland, sunpeng.li, siqueira, alexander.deucher,
	christian.koenig, alex.hung
  Cc: superm1, dri-devel, amd-gfx, linux-kernel, Alex Huang

With HDMI FreeSync detection now sourced from the common DRM EDID
parser, the DMUB parsing for AMD VSDB is no longer used.

Remove all relevant fields and files for this flow, it is no longer
necessary to ever take firmware round-trip for this.

Signed-off-by: Alex Huang <Alex.Huang2@amd.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
---
 drivers/gpu/drm/amd/display/dc/Makefile       |   1 -
 .../gpu/drm/amd/display/dc/dc_edid_parser.c   |  80 ------------
 .../gpu/drm/amd/display/dc/dc_edid_parser.h   |  44 -------
 drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 121 ------------------
 drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h  |  10 --
 .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h   |  71 ----------
 6 files changed, 327 deletions(-)
 delete mode 100644 drivers/gpu/drm/amd/display/dc/dc_edid_parser.c
 delete mode 100644 drivers/gpu/drm/amd/display/dc/dc_edid_parser.h

diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index 93d02956c5eb..e88a9cea8d88 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -63,7 +63,6 @@ include $(AMD_DC)
 
 FILES =
 FILES += dc_dmub_srv.o
-FILES += dc_edid_parser.o
 FILES += dc_fused_io.o
 FILES += dc_helper.o
 FILES += core/dc.o
diff --git a/drivers/gpu/drm/amd/display/dc/dc_edid_parser.c b/drivers/gpu/drm/amd/display/dc/dc_edid_parser.c
deleted file mode 100644
index 0db5b49e9d5e..000000000000
--- a/drivers/gpu/drm/amd/display/dc/dc_edid_parser.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2021 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#include "dce/dce_dmcu.h"
-#include "dc_edid_parser.h"
-
-bool dc_edid_parser_send_cea(struct dc *dc,
-		int offset,
-		int total_length,
-		uint8_t *data,
-		int length)
-{
-	struct dmcu *dmcu = dc->res_pool->dmcu;
-
-	if (dmcu &&
-	    dmcu->funcs->is_dmcu_initialized(dmcu) &&
-	    dmcu->funcs->send_edid_cea) {
-		return dmcu->funcs->send_edid_cea(dmcu,
-				offset,
-				total_length,
-				data,
-				length);
-	}
-
-	return false;
-}
-
-bool dc_edid_parser_recv_cea_ack(struct dc *dc, int *offset)
-{
-	struct dmcu *dmcu = dc->res_pool->dmcu;
-
-	if (dmcu &&
-	    dmcu->funcs->is_dmcu_initialized(dmcu) &&
-	    dmcu->funcs->recv_edid_cea_ack) {
-		return dmcu->funcs->recv_edid_cea_ack(dmcu, offset);
-	}
-
-	return false;
-}
-
-bool dc_edid_parser_recv_amd_vsdb(struct dc *dc,
-		int *version,
-		int *min_frame_rate,
-		int *max_frame_rate)
-{
-	struct dmcu *dmcu = dc->res_pool->dmcu;
-
-	if (dmcu &&
-	    dmcu->funcs->is_dmcu_initialized(dmcu) &&
-	    dmcu->funcs->recv_amd_vsdb) {
-		return dmcu->funcs->recv_amd_vsdb(dmcu,
-				version,
-				min_frame_rate,
-				max_frame_rate);
-	}
-
-	return false;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/dc_edid_parser.h b/drivers/gpu/drm/amd/display/dc/dc_edid_parser.h
deleted file mode 100644
index da67ec06f0a2..000000000000
--- a/drivers/gpu/drm/amd/display/dc/dc_edid_parser.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2021 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef _DC_EDID_PARSER_H_
-#define _DC_EDID_PARSER_H_
-
-#include "core_types.h"
-
-bool dc_edid_parser_send_cea(struct dc *dc,
-		int offset,
-		int total_length,
-		uint8_t *data,
-		int length);
-
-bool dc_edid_parser_recv_cea_ack(struct dc *dc, int *offset);
-
-bool dc_edid_parser_recv_amd_vsdb(struct dc *dc,
-		int *version,
-		int *min_frame_rate,
-		int *max_frame_rate);
-
-#endif /* _DC_EDID_PARSER_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
index 25ebd8a52ae4..23de1c793ec3 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
@@ -56,9 +56,6 @@
 #define MCP_BL_SET_PWM_FRAC 0x6A  /* Enable or disable Fractional PWM */
 #define CRC_WIN_NOTIFY 0x92
 #define CRC_STOP_UPDATE 0x93
-#define MCP_SEND_EDID_CEA 0xA0
-#define EDID_CEA_CMD_ACK 1
-#define EDID_CEA_CMD_NACK 2
 #define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK   0x00000001L
 
 // PSP FW version
@@ -812,121 +809,6 @@ static bool dcn20_unlock_phy(struct dmcu *dmcu)
 	return true;
 }
 
-static bool dcn10_send_edid_cea(struct dmcu *dmcu,
-		int offset,
-		int total_length,
-		uint8_t *data,
-		int length)
-{
-	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
-	uint32_t header, data1, data2;
-
-	/* If microcontroller is not running, do nothing */
-	if (dmcu->dmcu_state != DMCU_RUNNING)
-		return false;
-
-	if (length > 8 || length <= 0)
-		return false;
-
-	header = ((uint32_t)offset & 0xFFFF) << 16 | (total_length & 0xFFFF);
-	data1 = (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) |
-		(((uint32_t)data[2]) << 8) | ((uint32_t)data[3]);
-	data2 = (((uint32_t)data[4]) << 24) | (((uint32_t)data[5]) << 16) |
-		(((uint32_t)data[6]) << 8) | ((uint32_t)data[7]);
-
-	/* waitDMCUReadyForCmd */
-	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
-
-	/* setDMCUParam_Cmd */
-	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SEND_EDID_CEA);
-
-	REG_WRITE(MASTER_COMM_DATA_REG1, header);
-	REG_WRITE(MASTER_COMM_DATA_REG2, data1);
-	REG_WRITE(MASTER_COMM_DATA_REG3, data2);
-
-	/* notifyDMCUMsg */
-	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
-
-	/* waitDMCUReadyForCmd */
-	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
-
-	return true;
-}
-
-static bool dcn10_get_scp_results(struct dmcu *dmcu,
-		uint32_t *cmd,
-		uint32_t *data1,
-		uint32_t *data2,
-		uint32_t *data3)
-{
-	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
-
-	/* If microcontroller is not running, do nothing */
-	if (dmcu->dmcu_state != DMCU_RUNNING)
-		return false;
-
-	*cmd = REG_READ(SLAVE_COMM_CMD_REG);
-	*data1 =  REG_READ(SLAVE_COMM_DATA_REG1);
-	*data2 =  REG_READ(SLAVE_COMM_DATA_REG2);
-	*data3 =  REG_READ(SLAVE_COMM_DATA_REG3);
-
-	/* clear SCP interrupt */
-	REG_UPDATE(SLAVE_COMM_CNTL_REG, SLAVE_COMM_INTERRUPT, 0);
-
-	return true;
-}
-
-static bool dcn10_recv_amd_vsdb(struct dmcu *dmcu,
-		int *version,
-		int *min_frame_rate,
-		int *max_frame_rate)
-{
-	uint32_t data[4];
-	int cmd, ack, len;
-
-	if (!dcn10_get_scp_results(dmcu, &data[0], &data[1], &data[2], &data[3]))
-		return false;
-
-	cmd = data[0] & 0x3FF;
-	len = (data[0] >> 10) & 0x3F;
-	ack = data[1];
-
-	if (cmd != MCP_SEND_EDID_CEA || ack != EDID_CEA_CMD_ACK || len != 12)
-		return false;
-
-	if ((data[2] & 0xFF)) {
-		*version = (data[2] >> 8) & 0xFF;
-		*min_frame_rate = (data[3] >> 16) & 0xFFFF;
-		*max_frame_rate = data[3] & 0xFFFF;
-		return true;
-	}
-
-	return false;
-}
-
-static bool dcn10_recv_edid_cea_ack(struct dmcu *dmcu, int *offset)
-{
-	uint32_t data[4];
-	int cmd, ack;
-
-	if (!dcn10_get_scp_results(dmcu,
-				&data[0], &data[1], &data[2], &data[3]))
-		return false;
-
-	cmd = data[0] & 0x3FF;
-	ack = data[1];
-
-	if (cmd != MCP_SEND_EDID_CEA)
-		return false;
-
-	if (ack == EDID_CEA_CMD_ACK)
-		return true;
-
-	*offset = data[2]; /* nack */
-	return false;
-}
-
-
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
 static void dcn10_forward_crc_window(struct dmcu *dmcu,
 					struct rect *rect,
@@ -1030,9 +912,6 @@ static const struct dmcu_funcs dcn10_funcs = {
 	.get_psr_state = dcn10_get_dmcu_psr_state,
 	.set_psr_wait_loop = dcn10_psr_wait_loop,
 	.get_psr_wait_loop = dcn10_get_psr_wait_loop,
-	.send_edid_cea = dcn10_send_edid_cea,
-	.recv_amd_vsdb = dcn10_recv_amd_vsdb,
-	.recv_edid_cea_ack = dcn10_recv_edid_cea_ack,
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
 	.forward_crc_window = dcn10_forward_crc_window,
 	.stop_crc_win_update = dcn10_stop_crc_win_update,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
index de3113ecbc77..eebfd177463d 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
@@ -74,16 +74,6 @@ struct dmcu_funcs {
 	bool (*is_dmcu_initialized)(struct dmcu *dmcu);
 	bool (*lock_phy)(struct dmcu *dmcu);
 	bool (*unlock_phy)(struct dmcu *dmcu);
-	bool (*send_edid_cea)(struct dmcu *dmcu,
-			int offset,
-			int total_length,
-			uint8_t *data,
-			int length);
-	bool (*recv_amd_vsdb)(struct dmcu *dmcu,
-			int *version,
-			int *min_frame_rate,
-			int *max_frame_rate);
-	bool (*recv_edid_cea_ack)(struct dmcu *dmcu, int *offset);
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
 	void (*forward_crc_window)(struct dmcu *dmcu,
 			struct rect *rect,
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index 6f6a59a23495..ffe8192d223b 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -1891,10 +1891,6 @@ enum dmub_cmd_type {
 	 * Command type used for interfacing with DPIA.
 	 */
 	DMUB_CMD__DPIA = 77,
-	/**
-	 * Command type used for EDID CEA parsing
-	 */
-	DMUB_CMD__EDID_CEA = 79,
 	/**
 	 * Command type used for getting usbc cable ID
 	 */
@@ -6732,69 +6728,6 @@ struct dmub_rb_cmd_transmitter_set_phy_fsm {
 	struct dmub_rb_cmd_transmitter_set_phy_fsm_data data; /**< payload */
 };
 
-/**
- * Maximum number of bytes a chunk sent to DMUB for parsing
- */
-#define DMUB_EDID_CEA_DATA_CHUNK_BYTES 8
-
-/**
- *  Represent a chunk of CEA blocks sent to DMUB for parsing
- */
-struct dmub_cmd_send_edid_cea {
-	uint16_t offset;	/**< offset into the CEA block */
-	uint8_t length;	/**< number of bytes in payload to copy as part of CEA block */
-	uint16_t cea_total_length;  /**< total length of the CEA block */
-	uint8_t payload[DMUB_EDID_CEA_DATA_CHUNK_BYTES]; /**< data chunk of the CEA block */
-	uint8_t pad[3]; /**< padding and for future expansion */
-};
-
-/**
- * Result of VSDB parsing from CEA block
- */
-struct dmub_cmd_edid_cea_amd_vsdb {
-	uint8_t vsdb_found;		/**< 1 if parsing has found valid AMD VSDB */
-	uint8_t freesync_supported;	/**< 1 if Freesync is supported */
-	uint16_t amd_vsdb_version;	/**< AMD VSDB version */
-	uint16_t min_frame_rate;	/**< Maximum frame rate */
-	uint16_t max_frame_rate;	/**< Minimum frame rate */
-	uint8_t freesync_mccs_vcp_code; /**< Freesync MCCS VCP code */
-};
-
-/**
- * Result of sending a CEA chunk
- */
-struct dmub_cmd_edid_cea_ack {
-	uint16_t offset;	/**< offset of the chunk into the CEA block */
-	uint8_t success;	/**< 1 if this sending of chunk succeeded */
-	uint8_t pad;		/**< padding and for future expansion */
-};
-
-/**
- * Specify whether the result is an ACK/NACK or the parsing has finished
- */
-enum dmub_cmd_edid_cea_reply_type {
-	DMUB_CMD__EDID_CEA_AMD_VSDB	= 1, /**< VSDB parsing has finished */
-	DMUB_CMD__EDID_CEA_ACK		= 2, /**< acknowledges the CEA sending is OK or failing */
-};
-
-/**
- * Definition of a DMUB_CMD__EDID_CEA command.
- */
-struct dmub_rb_cmd_edid_cea {
-	struct dmub_cmd_header header;	/**< Command header */
-	union dmub_cmd_edid_cea_data {
-		struct dmub_cmd_send_edid_cea input; /**< input to send CEA chunks */
-		struct dmub_cmd_edid_cea_output { /**< output with results */
-			uint8_t type;	/**< dmub_cmd_edid_cea_reply_type */
-			union {
-				struct dmub_cmd_edid_cea_amd_vsdb amd_vsdb;
-				struct dmub_cmd_edid_cea_ack ack;
-			};
-		} output;	/**< output to retrieve ACK/NACK or VSDB parsing results */
-	} data;	/**< Command data */
-
-};
-
 /**
  * struct dmub_cmd_cable_id_input - Defines the input of DMUB_CMD_GET_USBC_CABLE_ID command.
  */
@@ -7588,10 +7521,6 @@ union dmub_rb_cmd {
 	 * Definition of a DMUB_CMD__DPIA_SET_TPS_NOTIFICATION command.
 	 */
 	struct dmub_rb_cmd_set_tps_notification set_tps_notification;
-	/**
-	 * Definition of a DMUB_CMD__EDID_CEA command.
-	 */
-	struct dmub_rb_cmd_edid_cea edid_cea;
 	/**
 	 * Definition of a DMUB_CMD_GET_USBC_CABLE_ID command.
 	 */
-- 
2.34.1


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

* Re: [PATCH v3 1/4] drm/edid: Parse AMD VSDB for FreeSync refresh range
  2026-08-04 14:33 ` [PATCH v3 1/4] drm/edid: Parse AMD VSDB for FreeSync refresh range Alex Huang
@ 2026-08-04 15:17   ` sashiko-bot
  0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-08-04 15:17 UTC (permalink / raw)
  To: Alex Huang; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The maximum payload length check in `cea_db_is_amd_vsdb()` rejects payloads larger than 21 bytes, silently breaking the intended forward compatibility for future VSDB versions.
--

--- Patch [1]: [PATCH v3 1/4] drm/edid: Parse AMD VSDB for FreeSync refresh range ---
commit 26fe9de2b3686b271fb4f7932172730167732cdb
Author: Alex Huang <Alex.Huang2@amd.com>

drm/edid: Parse AMD VSDB for FreeSync refresh range

This commit restructures the AMD VSDB parser to support FreeSync refresh
range fields from version 1 and 2 blocks. It also updates the parser to
handle versions > 3 as if they were version 3 for forward compatibility.

> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index df3c25bac761d..a12b5e6905fb7 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c

[ ... ]

> @@ -5231,7 +5259,7 @@ static bool cea_db_is_microsoft_vsdb(const struct cea_db *db)
>  static bool cea_db_is_amd_vsdb(const struct cea_db *db)
>  {
>  	return cea_db_is_vendor(db, AMD_IEEE_OUI) &&
> -		cea_db_payload_len(db) >= AMD_VSDB_V3_PAYLOAD_MIN_LEN &&
> +		cea_db_payload_len(db) >= AMD_VSDB_V1_PAYLOAD_LEN &&
>  		cea_db_payload_len(db) <= AMD_VSDB_V3_PAYLOAD_MAX_LEN;

[Severity: Medium]
Will this hard limit at AMD_VSDB_V3_PAYLOAD_MAX_LEN (21 bytes) prevent the
intended forward compatibility for future VSDB versions?

The commit message notes that versions > 3 will be parsed as if they were
version 3 because future versions will likely be backwards compatible. 
However, if a future version introduces new fields and the payload exceeds
21 bytes, cea_db_is_amd_vsdb() will return false.

Doesn't this mean the block will be completely ignored before it can ever
reach the fallback logic in drm_parse_amd_vsdb()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260804143339.714548-1-Alex.Huang2@amd.com?part=1

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

* Re: [PATCH v3 3/4] drm/amd/display: Clean up FreeSync capability detection
  2026-08-04 14:33 ` [PATCH v3 3/4] drm/amd/display: Clean up FreeSync capability detection Alex Huang
@ 2026-08-04 15:35   ` sashiko-bot
  0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-08-04 15:35 UTC (permalink / raw)
  To: Alex Huang; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing fallback to EDID monitor range when an AMD VSDB is present but does not advertise FreeSync support, breaking VRR on DP/eDP displays.
--

--- Patch [3]: [PATCH v3 3/4] drm/amd/display: Clean up FreeSync capability detection ---
commit 54e384ef3776414446c8d6bb002d768a87198a34
Author: Alex Huang <Alex.Huang2@amd.com>

drm/amd/display: Clean up FreeSync capability detection

This commit refactors FreeSync capability detection in the amdgpu_dm driver.
It extracts duplicate code for reading the AMD VSDB and sets up the connector
fields outside of the specific display interface branches. It also falls back
to the monitor_range data if the VSDB is not present.

> 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 44b8dd000f5ca..6d83e9a425377 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
[ ... ]
> @@ -13766,63 +13766,57 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
>  	     connector->display_info.monitor_range.max_vfreq == 0))
>  		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;
> +	has_vsdb = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info) != 0;
> +
> +	if (has_vsdb) {
> +		amdgpu_dm_connector->vsdb_info = vsdb_info;
> +
> +		/* copy refresh rate info as long as VSDB advertises FreeSync */
> +		if (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;
> +
> +			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 {
> +		/* fall back to the base EDID range when there is no VSDB */
> +		amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
> +		amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
> +	}

[Severity: High]
Does this code inadvertently drop the EDID monitor range fallback when an AMD
VSDB is present but does not support FreeSync?

Looking at amdgpu_dm_update_freesync_caps(), if has_vsdb is true but
vsdb_info.freesync_supported is false, the code skips updating the frequency
limits in the if block.

Because has_vsdb is true, the else block is also bypassed, leaving
amdgpu_dm_connector->min_vfreq and max_vfreq at their default zero values.

Would this cause the subsequent VRR capability check 
max_vfreq - min_vfreq > 10 to fail, disabling FreeSync on DP/eDP displays?

Should the EDID fallback assignment be applied whenever
!vsdb_info.freesync_supported, rather than only when the VSDB is entirely
absent?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260804143339.714548-1-Alex.Huang2@amd.com?part=3

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

* Re: [PATCH v3 4/4] drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser
  2026-08-04 14:33 ` [PATCH v3 4/4] drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser Alex Huang
@ 2026-08-04 15:49   ` sashiko-bot
  0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-08-04 15:49 UTC (permalink / raw)
  To: Alex Huang; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] FreeSync standard fallback range is skipped for monitors with an AMD VSDB that does not advertise FreeSync support.
--

--- Patch [4]: [PATCH v3 4/4] drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser ---
commit dc49dbde5bae751a6f9eaf5e370f73f95f12ba84
Author: Alex Huang <Alex.Huang2@amd.com>
Subject: drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser

This commit removes the DMCU/DMUB EDID CEA parsing code, as HDMI FreeSync
detection is now handled by the common DRM EDID parser. All related fields
and files are deleted to avoid unnecessary firmware round-trips.

> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ ... @@ amdgpu_dm_update_freesync_caps()
>  		/* copy refresh rate info as long as VSDB advertises FreeSync */
>  		if (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;
>  
>  			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;
>  		}

[Severity: Medium]
Will this leave amdgpu_dm_connector->min_vfreq and max_vfreq uninitialized
when a monitor has an AMD VSDB but doesn't advertise FreeSync support within
it?

By omitting an else branch for the freesync_supported == false condition,
it appears the fallback to connector->display_info.monitor_range is bypassed.

Could this silently disable FreeSync for monitors that otherwise support it
via standard DisplayID or base EDID VRR data, since the subsequent check
(max_vfreq - min_vfreq > 10) would then fail?

>  	} else {
>  		/* fall back to the base EDID range when there is no VSDB */
>  		amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
>  		amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260804143339.714548-1-Alex.Huang2@amd.com?part=4

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

end of thread, other threads:[~2026-08-04 15:49 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-04 14:33 [PATCH v3 0/4] drm/edid: Parse AMD VSDB FreeSync range in common code Alex Huang
2026-08-04 14:33 ` [PATCH v3 1/4] drm/edid: Parse AMD VSDB for FreeSync refresh range Alex Huang
2026-08-04 15:17   ` sashiko-bot
2026-08-04 14:33 ` [PATCH v3 2/4] drm/amd/display: Use HDMI FreeSync range from common EDID parser Alex Huang
2026-08-04 14:33 ` [PATCH v3 3/4] drm/amd/display: Clean up FreeSync capability detection Alex Huang
2026-08-04 15:35   ` sashiko-bot
2026-08-04 14:33 ` [PATCH v3 4/4] drm/amd/display: Remove unused DMCU/DMUB EDID CEA parser Alex Huang
2026-08-04 15:49   ` sashiko-bot

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