ANDROID: drm: edid: add support for additional CEA extension blocks
Add support for parsing additional cea extension blocks such as CEA HDR metadata block, VCDB block, Colorimetry data block and VSVDB. Signed-off-by: Shashank Babu Chinta Venkata <sbchin@codeaurora.org> Bug: 139653858 Change-Id: Iae84749b816cd8bc0f598654c018cde475a31df9
This commit is contained in:
parent
1e98c11549
commit
f309826261
3 changed files with 343 additions and 1 deletions
|
@ -98,6 +98,14 @@ struct detailed_mode_closure {
|
|||
#define LEVEL_GTF2 2
|
||||
#define LEVEL_CVT 3
|
||||
|
||||
/*Enum storing luminance types for HDR blocks in EDID*/
|
||||
enum luminance_value {
|
||||
NO_LUMINANCE_DATA = 3,
|
||||
MAXIMUM_LUMINANCE = 4,
|
||||
FRAME_AVERAGE_LUMINANCE = 5,
|
||||
MINIMUM_LUMINANCE = 6
|
||||
};
|
||||
|
||||
static const struct edid_quirk {
|
||||
char vendor[4];
|
||||
int product_id;
|
||||
|
@ -2897,16 +2905,20 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
|||
|
||||
return closure.modes;
|
||||
}
|
||||
|
||||
#define VIDEO_CAPABILITY_EXTENDED_DATA_BLOCK 0x0
|
||||
#define AUDIO_BLOCK 0x01
|
||||
#define VIDEO_BLOCK 0x02
|
||||
#define VENDOR_BLOCK 0x03
|
||||
#define SPEAKER_BLOCK 0x04
|
||||
#define COLORIMETRY_EXTENDED_DATA_BLOCK 0x05
|
||||
#define HDR_STATIC_METADATA_BLOCK 0x6
|
||||
#define USE_EXTENDED_TAG 0x07
|
||||
#define EXT_VIDEO_CAPABILITY_BLOCK 0x00
|
||||
#define EXT_VIDEO_DATA_BLOCK_420 0x0E
|
||||
#define EXT_VIDEO_CAP_BLOCK_Y420CMDB 0x0F
|
||||
#define VENDOR_SPECIFIC_VIDEO_DATA_BLOCK 0x01
|
||||
#define VSVDB_HDR10_PLUS_IEEE_CODE 0x90848b
|
||||
#define VSVDB_HDR10_PLUS_APP_VER_MASK 0x3
|
||||
#define EDID_BASIC_AUDIO (1 << 6)
|
||||
#define EDID_CEA_YCRCB444 (1 << 5)
|
||||
#define EDID_CEA_YCRCB422 (1 << 4)
|
||||
|
@ -4005,6 +4017,232 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
|
|||
connector->audio_latency[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* drm_extract_vcdb_info - Parse the HDMI Video Capability Data Block
|
||||
* @connector: connector corresponding to the HDMI sink
|
||||
* @db: start of the CEA vendor specific block
|
||||
*
|
||||
* Parses the HDMI VCDB to extract sink info for @connector.
|
||||
*/
|
||||
static void
|
||||
drm_extract_vcdb_info(struct drm_connector *connector, const u8 *db)
|
||||
{
|
||||
/*
|
||||
* Check if the sink specifies underscan
|
||||
* support for:
|
||||
* BIT 5: preferred video format
|
||||
* BIT 3: IT video format
|
||||
* BIT 1: CE video format
|
||||
*/
|
||||
|
||||
connector->pt_scan_info =
|
||||
(db[2] & (BIT(4) | BIT(5))) >> 4;
|
||||
connector->it_scan_info =
|
||||
(db[2] & (BIT(3) | BIT(2))) >> 2;
|
||||
connector->ce_scan_info =
|
||||
db[2] & (BIT(1) | BIT(0));
|
||||
|
||||
DRM_DEBUG_KMS("Scan Info (pt|it|ce): (%d|%d|%d)",
|
||||
(int) connector->pt_scan_info,
|
||||
(int) connector->it_scan_info,
|
||||
(int) connector->ce_scan_info);
|
||||
}
|
||||
|
||||
static void
|
||||
drm_parse_vsvdb_hdr_plus(struct drm_connector *connector, const u8 *db)
|
||||
{
|
||||
connector->hdr_plus_app_ver = db[5] & VSVDB_HDR10_PLUS_APP_VER_MASK;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_extract_vsvdb_info(struct drm_connector *connector, const u8 *db)
|
||||
{
|
||||
u8 db_len = cea_db_payload_len(db);
|
||||
u32 ieee_code = 0;
|
||||
|
||||
if (db_len < 5)
|
||||
return;
|
||||
|
||||
/* Bytes 2-4: IEEE 24-bit code, LSB first */
|
||||
ieee_code = db[2] | (db[3] << 8) | (db[4] << 16);
|
||||
DRM_DEBUG_KMS("found VSVDB with IEEE code 0x%x\n", ieee_code);
|
||||
if (ieee_code == VSVDB_HDR10_PLUS_IEEE_CODE)
|
||||
drm_parse_vsvdb_hdr_plus(connector, db);
|
||||
}
|
||||
|
||||
static bool drm_edid_is_luminance_value_present(
|
||||
u32 block_length, enum luminance_value value)
|
||||
{
|
||||
return block_length > NO_LUMINANCE_DATA && value <= block_length;
|
||||
}
|
||||
|
||||
/*
|
||||
* drm_extract_clrmetry_db - Parse the HDMI colorimetry extended block
|
||||
* @connector: connector corresponding to the HDMI sink
|
||||
* @db: start of the HDMI colorimetry extended block
|
||||
*
|
||||
* Parses the HDMI colorimetry block to extract sink info for @connector.
|
||||
*/
|
||||
static void
|
||||
drm_extract_clrmetry_db(struct drm_connector *connector, const u8 *db)
|
||||
{
|
||||
|
||||
if (!db) {
|
||||
DRM_ERROR("invalid db\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Byte 3 Bit 0: xvYCC_601 */
|
||||
if (db[2] & BIT(0))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_xvYCC_601;
|
||||
/* Byte 3 Bit 1: xvYCC_709 */
|
||||
if (db[2] & BIT(1))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_xvYCC_709;
|
||||
/* Byte 3 Bit 2: sYCC_601 */
|
||||
if (db[2] & BIT(2))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_sYCC_601;
|
||||
/* Byte 3 Bit 3: ADBYCC_601 */
|
||||
if (db[2] & BIT(3))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_ADBYCC_601;
|
||||
/* Byte 3 Bit 4: ADB_RGB */
|
||||
if (db[2] & BIT(4))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_ADB_RGB;
|
||||
/* Byte 3 Bit 5: BT2020_CYCC */
|
||||
if (db[2] & BIT(5))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_BT2020_CYCC;
|
||||
/* Byte 3 Bit 6: BT2020_YCC */
|
||||
if (db[2] & BIT(6))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_BT2020_YCC;
|
||||
/* Byte 3 Bit 7: BT2020_RGB */
|
||||
if (db[2] & BIT(7))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_BT2020_RGB;
|
||||
/* Byte 4 Bit 7: DCI-P3 */
|
||||
if (db[3] & BIT(7))
|
||||
connector->color_enc_fmt |= DRM_EDID_CLRMETRY_DCI_P3;
|
||||
|
||||
DRM_DEBUG_KMS("colorimetry fmts = 0x%x\n", connector->color_enc_fmt);
|
||||
}
|
||||
|
||||
/*
|
||||
* drm_extract_hdr_db - Parse the HDMI HDR extended block
|
||||
* @connector: connector corresponding to the HDMI sink
|
||||
* @db: start of the HDMI HDR extended block
|
||||
*
|
||||
* Parses the HDMI HDR extended block to extract sink info for @connector.
|
||||
*/
|
||||
static void
|
||||
drm_extract_hdr_db(struct drm_connector *connector, const u8 *db)
|
||||
{
|
||||
|
||||
u8 len = 0;
|
||||
|
||||
if (!db)
|
||||
return;
|
||||
|
||||
len = db[0] & 0x1f;
|
||||
/* Byte 3: Electro-Optical Transfer Functions */
|
||||
connector->hdr_eotf = db[2] & 0x3F;
|
||||
|
||||
/* Byte 4: Static Metadata Descriptor Type 1 */
|
||||
connector->hdr_metadata_type_one = (db[3] & BIT(0));
|
||||
|
||||
/* Byte 5: Desired Content Maximum Luminance */
|
||||
if (drm_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE))
|
||||
connector->hdr_max_luminance =
|
||||
db[MAXIMUM_LUMINANCE];
|
||||
|
||||
/* Byte 6: Desired Content Max Frame-average Luminance */
|
||||
if (drm_edid_is_luminance_value_present(len, FRAME_AVERAGE_LUMINANCE))
|
||||
connector->hdr_avg_luminance =
|
||||
db[FRAME_AVERAGE_LUMINANCE];
|
||||
|
||||
/* Byte 7: Desired Content Min Luminance */
|
||||
if (drm_edid_is_luminance_value_present(len, MINIMUM_LUMINANCE))
|
||||
connector->hdr_min_luminance =
|
||||
db[MINIMUM_LUMINANCE];
|
||||
|
||||
connector->hdr_supported = true;
|
||||
|
||||
DRM_DEBUG_KMS("HDR electro-optical %d\n", connector->hdr_eotf);
|
||||
DRM_DEBUG_KMS("metadata desc 1 %d\n", connector->hdr_metadata_type_one);
|
||||
DRM_DEBUG_KMS("max luminance %d\n", connector->hdr_max_luminance);
|
||||
DRM_DEBUG_KMS("avg luminance %d\n", connector->hdr_avg_luminance);
|
||||
DRM_DEBUG_KMS("min luminance %d\n", connector->hdr_min_luminance);
|
||||
}
|
||||
/*
|
||||
* drm_hdmi_extract_extended_blk_info - Parse the HDMI extended tag blocks
|
||||
* @connector: connector corresponding to the HDMI sink
|
||||
* @edid: handle to the EDID structure
|
||||
* Parses the all extended tag blocks extract sink info for @connector.
|
||||
*/
|
||||
static void
|
||||
drm_hdmi_extract_extended_blk_info(struct drm_connector *connector,
|
||||
const struct edid *edid)
|
||||
{
|
||||
const u8 *cea = drm_find_cea_extension(edid);
|
||||
const u8 *db = NULL;
|
||||
|
||||
if (cea && cea_revision(cea) >= 3) {
|
||||
int i, start, end;
|
||||
|
||||
if (cea_db_offsets(cea, &start, &end))
|
||||
return;
|
||||
|
||||
for_each_cea_db(cea, i, start, end) {
|
||||
db = &cea[i];
|
||||
|
||||
if (cea_db_tag(db) == USE_EXTENDED_TAG) {
|
||||
DRM_DEBUG_KMS("found extended tag block = %d\n",
|
||||
db[1]);
|
||||
switch (db[1]) {
|
||||
case VIDEO_CAPABILITY_EXTENDED_DATA_BLOCK:
|
||||
drm_extract_vcdb_info(connector, db);
|
||||
break;
|
||||
case VENDOR_SPECIFIC_VIDEO_DATA_BLOCK:
|
||||
drm_extract_vsvdb_info(connector, db);
|
||||
break;
|
||||
case HDR_STATIC_METADATA_BLOCK:
|
||||
drm_extract_hdr_db(connector, db);
|
||||
break;
|
||||
case COLORIMETRY_EXTENDED_DATA_BLOCK:
|
||||
drm_extract_clrmetry_db(connector, db);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_hdmi_hf_vsdb(struct drm_connector *connector, const u8 *db)
|
||||
{
|
||||
u8 len = cea_db_payload_len(db);
|
||||
|
||||
if (len < 7)
|
||||
return;
|
||||
|
||||
if (db[4] != 1)
|
||||
return; /* invalid version */
|
||||
|
||||
connector->max_tmds_char = db[5] * 5;
|
||||
connector->scdc_present = db[6] & (1 << 7);
|
||||
connector->rr_capable = db[6] & (1 << 6);
|
||||
connector->flags_3d = db[6] & 0x7;
|
||||
connector->supports_scramble = connector->scdc_present &&
|
||||
(db[6] & (1 << 3));
|
||||
|
||||
DRM_DEBUG_KMS(
|
||||
"HDMI v2: max TMDS char %d, scdc %s, rr %s,3D flags 0x%x, scramble %s\n",
|
||||
connector->max_tmds_char,
|
||||
connector->scdc_present ? "available" : "not available",
|
||||
connector->rr_capable ? "capable" : "not capable",
|
||||
connector->flags_3d,
|
||||
connector->supports_scramble ? "supported" : "not supported");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
monitor_name(struct detailed_timing *t, void *data)
|
||||
{
|
||||
|
@ -4137,6 +4375,9 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
|
|||
/* HDMI Vendor-Specific Data Block */
|
||||
if (cea_db_is_hdmi_vsdb(db))
|
||||
drm_parse_hdmi_vsdb_audio(connector, db);
|
||||
/* HDMI Forum Vendor-Specific Data Block */
|
||||
else if (cea_db_is_hdmi_forum_vsdb(db))
|
||||
parse_hdmi_hf_vsdb(connector, db);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -4651,6 +4892,39 @@ drm_reset_display_info(struct drm_connector *connector)
|
|||
info->non_desktop = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_hdmi_extract_vsdbs_info(struct drm_connector *connector,
|
||||
const struct edid *edid)
|
||||
{
|
||||
const u8 *cea = drm_find_cea_extension(edid);
|
||||
const u8 *db = NULL;
|
||||
|
||||
if (cea && cea_revision(cea) >= 3) {
|
||||
int i, start, end;
|
||||
|
||||
if (cea_db_offsets(cea, &start, &end))
|
||||
return;
|
||||
|
||||
for_each_cea_db(cea, i, start, end) {
|
||||
db = &cea[i];
|
||||
|
||||
if (cea_db_tag(db) == VENDOR_BLOCK) {
|
||||
/* HDMI Vendor-Specific Data Block */
|
||||
if (cea_db_is_hdmi_vsdb(db)) {
|
||||
drm_parse_hdmi_vsdb_video(
|
||||
connector, db);
|
||||
drm_parse_hdmi_vsdb_audio(
|
||||
connector, db);
|
||||
}
|
||||
/* HDMI Forum Vendor-Specific Data Block */
|
||||
else if (cea_db_is_hdmi_forum_vsdb(db))
|
||||
parse_hdmi_hf_vsdb(connector, db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
|
||||
{
|
||||
struct drm_display_info *info = &connector->display_info;
|
||||
|
@ -4688,6 +4962,11 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi
|
|||
connector->name, info->bpc);
|
||||
}
|
||||
|
||||
/* Extract audio and video latency fields for the sink */
|
||||
drm_hdmi_extract_vsdbs_info(connector, edid);
|
||||
/* Extract info from extended tag blocks */
|
||||
drm_hdmi_extract_extended_blk_info(connector, edid);
|
||||
|
||||
/* Only defined for 1.4 with digital displays */
|
||||
if (edid->revision < 4)
|
||||
return quirks;
|
||||
|
|
|
@ -1013,6 +1013,54 @@ struct drm_connector {
|
|||
/** @bad_edid_counter: track sinks that give us an EDID with invalid checksum */
|
||||
unsigned bad_edid_counter;
|
||||
|
||||
/*
|
||||
* @pt_scan_info: PT scan info obtained from the VCDB of EDID
|
||||
* @it_scan_info: IT scan info obtained from the VCDB of EDID
|
||||
* @ce_scan_info: CE scan info obtained from the VCDB of EDID
|
||||
* @color_enc_fmt: Colorimetry encoding formats of sink
|
||||
* @hdr_eotf: Electro optical transfer function obtained from HDR block
|
||||
* @hdr_metadata_type_one: Metadata type one obtained from HDR block
|
||||
* @hdr_max_luminance: desired max luminance obtained from HDR block
|
||||
* @hdr_avg_luminance: desired avg luminance obtained from HDR block
|
||||
* @hdr_min_luminance: desired min luminance obtained from HDR block
|
||||
* @hdr_supported: does the sink support HDR content
|
||||
* @max_tmds_char: indicates the maximum TMDS Character Rate supported
|
||||
* @scdc_present: when set the sink supports SCDC functionality
|
||||
* @rr_capable: when set the sink is capable of initiating an
|
||||
* SCDC read request
|
||||
* @supports_scramble: when set the sink supports less than
|
||||
* 340Mcsc scrambling
|
||||
* @flags_3d: 3D view(s) supported by the sink, see drm_edid.h
|
||||
* DRM_EDID_3D_*)
|
||||
*/
|
||||
u8 pt_scan_info;
|
||||
u8 it_scan_info;
|
||||
u8 ce_scan_info;
|
||||
u32 color_enc_fmt;
|
||||
u32 hdr_eotf;
|
||||
bool hdr_metadata_type_one;
|
||||
u32 hdr_max_luminance;
|
||||
u32 hdr_avg_luminance;
|
||||
u32 hdr_min_luminance;
|
||||
bool hdr_supported;
|
||||
u8 hdr_plus_app_ver;
|
||||
|
||||
/* EDID bits HDMI 2.0
|
||||
* @max_tmds_char: indicates the maximum TMDS Character Rate supported
|
||||
* @scdc_present: when set the sink supports SCDC functionality
|
||||
* @rr_capable: when set the sink is capable of initiating an
|
||||
* SCDC read request
|
||||
* @supports_scramble: when set the sink supports less than
|
||||
* 340Mcsc scrambling
|
||||
* @flags_3d: 3D view(s) supported by the sink, see drm_edid.h
|
||||
* (DRM_EDID_3D_*)
|
||||
*/
|
||||
int max_tmds_char; /* in Mcsc */
|
||||
bool scdc_present;
|
||||
bool rr_capable;
|
||||
bool supports_scramble;
|
||||
int flags_3d;
|
||||
|
||||
/**
|
||||
* @edid_corrupt: Indicates whether the last read EDID was corrupt. Used
|
||||
* in Displayport compliance testing - Displayport Link CTS Core 1.2
|
||||
|
|
|
@ -221,6 +221,16 @@ struct detailed_timing {
|
|||
DRM_EDID_YCBCR420_DC_36 | \
|
||||
DRM_EDID_YCBCR420_DC_30)
|
||||
|
||||
#define DRM_EDID_CLRMETRY_xvYCC_601 (1 << 0)
|
||||
#define DRM_EDID_CLRMETRY_xvYCC_709 (1 << 1)
|
||||
#define DRM_EDID_CLRMETRY_sYCC_601 (1 << 2)
|
||||
#define DRM_EDID_CLRMETRY_ADBYCC_601 (1 << 3)
|
||||
#define DRM_EDID_CLRMETRY_ADB_RGB (1 << 4)
|
||||
#define DRM_EDID_CLRMETRY_BT2020_CYCC (1 << 5)
|
||||
#define DRM_EDID_CLRMETRY_BT2020_YCC (1 << 6)
|
||||
#define DRM_EDID_CLRMETRY_BT2020_RGB (1 << 7)
|
||||
#define DRM_EDID_CLRMETRY_DCI_P3 (1 << 15)
|
||||
|
||||
/* ELD Header Block */
|
||||
#define DRM_ELD_HEADER_BLOCK_SIZE 4
|
||||
|
||||
|
@ -279,6 +289,11 @@ struct detailed_timing {
|
|||
|
||||
#define DRM_ELD_CEA_SAD(mnl, sad) (20 + (mnl) + 3 * (sad))
|
||||
|
||||
/* HDMI 2.0 */
|
||||
#define DRM_EDID_3D_INDEPENDENT_VIEW (1 << 2)
|
||||
#define DRM_EDID_3D_DUAL_VIEW (1 << 1)
|
||||
#define DRM_EDID_3D_OSD_DISPARITY (1 << 0)
|
||||
|
||||
struct edid {
|
||||
u8 header[8];
|
||||
/* Vendor & product info */
|
||||
|
|
Loading…
Reference in a new issue