Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 443aedf7 authored by Padmanabhan Komanduru's avatar Padmanabhan Komanduru Committed by Gerrit - the friendly Code Review server
Browse files

drm: edid: add support for parsing additional EDID blocks



Currently the DRM upstream EDID parser doesn't have support to
parse all EDID blocks such as extension tag blocks.

Add support for parsing these blocks and extract necessary info.

Change-Id: Iae92de79960f6f0e73a8e2ff7944c1bf101d90a6
Signed-off-by: default avatarAbhinav Kumar <abhinavk@codeaurora.org>
Signed-off-by: default avatarPadmanabhan Komanduru <pkomandu@codeaurora.org>
Signed-off-by: default avatarTatenda Chipeperekwa <tatendac@codeaurora.org>
parent df072230
Loading
Loading
Loading
Loading
+161 −1
Original line number Diff line number Diff line
@@ -2787,7 +2787,7 @@ 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
@@ -3846,6 +3846,130 @@ add_YCbCr420VDB_modes(struct drm_connector *connector, struct edid *edid)
	return modes;
}

/*
 * 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 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_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,
		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 HDR_STATIC_METADATA_EXTENDED_DATA_BLOCK:
					drm_extract_hdr_db(connector, db);
					break;
				default:
					break;
				}
			}
		}
	}
}

static void
parse_hdmi_hf_vsdb(struct drm_connector *connector, const u8 *db)
{
@@ -4495,6 +4619,37 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
	}
}

static void
drm_hdmi_extract_vsdbs_info(struct drm_connector *connector, 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);
			}
		}
	}
}

static void drm_add_display_info(struct drm_connector *connector,
				 struct edid *edid)
{
@@ -4532,6 +4687,11 @@ static void drm_add_display_info(struct drm_connector *connector,
			  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;