};
#define MICROSOFT_IEEE_OUI 0xca125c
+#define AMD_IEEE_OUI 0x00001A
+
+#define AMD_VSDB_V3_PAYLOAD_MIN_LEN 15
+#define AMD_VSDB_V3_PAYLOAD_MAX_LEN 20
+
+struct amd_vsdb_v3_payload {
+ u8 oui[3];
+ u8 version;
+ u8 feature_caps;
+ u8 rsvd0[3];
+ u8 cs_eotf_support;
+ u8 lum1_max;
+ u8 lum1_min;
+ u8 lum2_max;
+ u8 lum2_min;
+ u8 rsvd1[2];
+ /*
+ * Bytes beyond AMD_VSDB_V3_PAYLOAD_MIN_LEN are optional; a
+ * monitor may provide a payload as short as 15 bytes. Always
+ * check cea_db_payload_len() before accessing extra[].
+ */
+ u8 extra[AMD_VSDB_V3_PAYLOAD_MAX_LEN - AMD_VSDB_V3_PAYLOAD_MIN_LEN];
+} __packed;
struct detailed_mode_closure {
struct drm_connector *connector;
cea_db_payload_len(db) == 21;
}
+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_V3_PAYLOAD_MAX_LEN;
+}
+
static bool cea_db_is_vcdb(const struct cea_db *db)
{
return cea_db_is_extended_tag(db, CTA_EXT_DB_VIDEO_CAP) &&
connector->base.id, connector->name, version, db[5]);
}
+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;
+
+ p = (const struct amd_vsdb_v3_payload *)data;
+
+ if (p->version != 0x03) {
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Unsupported AMD VSDB version %u\n",
+ connector->base.id, connector->name, p->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;
+
+ /*
+ * 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];
+ */
+}
+
static void drm_parse_cea_ext(struct drm_connector *connector,
const struct drm_edid *drm_edid)
{
drm_parse_hdmi_forum_scds(connector, data);
else if (cea_db_is_microsoft_vsdb(db))
drm_parse_microsoft_vsdb(connector, data);
+ else if (cea_db_is_amd_vsdb(db))
+ drm_parse_amd_vsdb(connector, db);
else if (cea_db_is_y420cmdb(db))
parse_cta_y420cmdb(connector, db, &y420cmdb_map);
else if (cea_db_is_y420vdb(db))
info->quirks = 0;
info->source_physical_address = CEC_PHYS_ADDR_INVALID;
+ memset(&info->amd_vsdb, 0, sizeof(info->amd_vsdb));
}
static void update_displayid_info(struct drm_connector *connector,
DRM_BUS_FLAG_SHARP_SIGNALS = BIT(8),
};
+/**
+ * struct drm_amd_vsdb_info - AMD-specific VSDB information
+ *
+ * This structure holds information parsed from the AMD Vendor-Specific Data
+ * Block (VSDB) version 3.
+ */
+struct drm_amd_vsdb_info {
+ /**
+ * @version: Version of the Vendor-Specific Data Block (VSDB)
+ */
+ u8 version;
+
+ /**
+ * @replay_mode: Panel Replay supported
+ */
+ bool replay_mode;
+
+ /**
+ * @panel_type: Panel technology type
+ */
+ u8 panel_type;
+
+ /**
+ * @luminance_range1: Luminance for max back light
+ */
+ struct drm_luminance_range_info luminance_range1;
+
+ /**
+ * @luminance_range2: Luminance for min back light
+ */
+ struct drm_luminance_range_info luminance_range2;
+};
+
/**
* struct drm_display_info - runtime data about the connected sink
*
* Defaults to CEC_PHYS_ADDR_INVALID (0xffff).
*/
u16 source_physical_address;
+
+ /**
+ * @amd_vsdb: AMD-specific VSDB information.
+ */
+ struct drm_amd_vsdb_info amd_vsdb;
};
int drm_display_info_set_bus_formats(struct drm_display_info *info,