mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 04:21:09 -04:00
drm/edid: Parse AMD Vendor-Specific Data Block
Parse the AMD VSDB v3 from CTA extension blocks and store the result in struct drm_amd_vsdb_info, a new field of drm_display_info. This includes replay mode, panel type, and luminance ranges. Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
committed by
Alex Deucher
parent
57ce498faa
commit
118362a962
@@ -99,6 +99,29 @@ enum drm_edid_internal_quirk {
|
||||
};
|
||||
|
||||
#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;
|
||||
@@ -5205,6 +5228,13 @@ static bool cea_db_is_microsoft_vsdb(const struct cea_db *db)
|
||||
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) &&
|
||||
@@ -6401,6 +6431,45 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector,
|
||||
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)
|
||||
{
|
||||
@@ -6449,6 +6518,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
|
||||
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))
|
||||
@@ -6641,6 +6712,7 @@ static void drm_reset_display_info(struct drm_connector *connector)
|
||||
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,
|
||||
|
||||
@@ -693,6 +693,39 @@ enum drm_bus_flags {
|
||||
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
|
||||
*
|
||||
@@ -883,6 +916,11 @@ struct drm_display_info {
|
||||
* 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,
|
||||
|
||||
Reference in New Issue
Block a user