Procházet zdrojové kódy

Merge "disp: msm: add colorimetry block parsing to SDE EDID parser"

qctecmdr před 5 roky
rodič
revize
5d23842089

+ 7 - 7
msm/dp/dp_debug.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/debugfs.h>
@@ -1372,32 +1372,32 @@ static int dp_debug_print_hdr_params_to_buf(struct drm_connector *connector,
 		goto error;
 
 	rc = snprintf(buf + len, max_size, "eotf = %d\n",
-		connector->hdr_eotf);
+		c_conn->hdr_eotf);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size, "type_one = %d\n",
-		connector->hdr_metadata_type_one);
+		c_conn->hdr_metadata_type_one);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size, "hdr_plus_app_ver = %d\n",
-		connector->hdr_plus_app_ver);
+			c_conn->hdr_plus_app_ver);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size, "max_luminance = %d\n",
-		connector->hdr_max_luminance);
+		c_conn->hdr_max_luminance);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size, "avg_luminance = %d\n",
-		connector->hdr_avg_luminance);
+		c_conn->hdr_avg_luminance);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size, "min_luminance = %d\n",
-		connector->hdr_min_luminance);
+		c_conn->hdr_min_luminance);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 

+ 7 - 7
msm/dp/dp_panel.c

@@ -2313,13 +2313,13 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags)
 	sde_conn = to_sde_connector(connector);
 	c_state = to_sde_connector_state(connector->state);
 
-	connector->hdr_eotf = 0;
-	connector->hdr_metadata_type_one = 0;
-	connector->hdr_max_luminance = 0;
-	connector->hdr_avg_luminance = 0;
-	connector->hdr_min_luminance = 0;
-	connector->hdr_supported = false;
-	connector->hdr_plus_app_ver = 0;
+	sde_conn->hdr_eotf = 0;
+	sde_conn->hdr_metadata_type_one = 0;
+	sde_conn->hdr_max_luminance = 0;
+	sde_conn->hdr_avg_luminance = 0;
+	sde_conn->hdr_min_luminance = 0;
+	sde_conn->hdr_supported = false;
+	sde_conn->hdr_plus_app_ver = 0;
 
 	sde_conn->colorspace_updated = false;
 

+ 9 - 12
msm/sde/sde_connector.c

@@ -1184,7 +1184,6 @@ static int _sde_connector_set_ext_hdr_info(
 	void __user *usr_ptr)
 {
 	int rc = 0;
-	struct drm_connector *connector;
 	struct drm_msm_ext_hdr_metadata *hdr_meta;
 	size_t payload_size = 0;
 	u8 *payload = NULL;
@@ -1196,9 +1195,7 @@ static int _sde_connector_set_ext_hdr_info(
 		goto end;
 	}
 
-	connector = &c_conn->base;
-
-	if (!connector->hdr_supported) {
+	if (!c_conn->hdr_supported) {
 		SDE_ERROR_CONN(c_conn, "sink doesn't support HDR\n");
 		rc = -ENOTSUPP;
 		goto end;
@@ -1225,7 +1222,7 @@ static int _sde_connector_set_ext_hdr_info(
 	if (!hdr_meta->hdr_plus_payload_size || !hdr_meta->hdr_plus_payload)
 		goto skip_dhdr;
 
-	if (!connector->hdr_plus_app_ver) {
+	if (!c_conn->hdr_plus_app_ver) {
 		SDE_ERROR_CONN(c_conn, "sink doesn't support dynamic HDR\n");
 		rc = -ENOTSUPP;
 		goto end;
@@ -1515,13 +1512,13 @@ static void sde_connector_update_hdr_props(struct drm_connector *connector)
 	struct sde_connector *c_conn = to_sde_connector(connector);
 	struct drm_msm_ext_hdr_properties hdr = {0};
 
-	hdr.hdr_metadata_type_one = connector->hdr_metadata_type_one ? 1 : 0;
-	hdr.hdr_supported = connector->hdr_supported ? 1 : 0;
-	hdr.hdr_eotf = connector->hdr_eotf;
-	hdr.hdr_max_luminance = connector->hdr_max_luminance;
-	hdr.hdr_avg_luminance = connector->hdr_avg_luminance;
-	hdr.hdr_min_luminance = connector->hdr_min_luminance;
-	hdr.hdr_plus_supported = connector->hdr_plus_app_ver;
+	hdr.hdr_metadata_type_one = c_conn->hdr_metadata_type_one ? 1 : 0;
+	hdr.hdr_supported = c_conn->hdr_supported ? 1 : 0;
+	hdr.hdr_eotf = c_conn->hdr_eotf;
+	hdr.hdr_max_luminance = c_conn->hdr_max_luminance;
+	hdr.hdr_avg_luminance = c_conn->hdr_avg_luminance;
+	hdr.hdr_min_luminance = c_conn->hdr_min_luminance;
+	hdr.hdr_plus_supported = c_conn->hdr_plus_app_ver;
 
 	msm_property_set_blob(&c_conn->property_info, &c_conn->blob_ext_hdr,
 			&hdr, sizeof(hdr), CONNECTOR_PROP_EXT_HDR_INFO);

+ 17 - 0
msm/sde/sde_connector.h

@@ -418,6 +418,13 @@ struct sde_connector_dyn_hdr_metadata {
  * @bl_scale: BL scale value for ABA feature
  * @bl_scale_sv: BL scale value for sunlight visibility feature
  * @unset_bl_level: BL level that needs to be set later
+ * @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
+ * @color_enc_fmt: Colorimetry encoding formats of sink
  * @allow_bl_update: Flag to indicate if BL update is allowed currently or not
  * @qsync_mode: Cached Qsync mode, 0=disabled, 1=continuous mode
  * @qsync_updated: Qsync settings were updated
@@ -471,6 +478,16 @@ struct sde_connector {
 	u32 unset_bl_level;
 	bool allow_bl_update;
 
+	u32 hdr_eotf;
+	bool hdr_metadata_type_one;
+	u32 hdr_max_luminance;
+	u32 hdr_avg_luminance;
+	u32 hdr_min_luminance;
+	bool hdr_supported;
+
+	u32 color_enc_fmt;
+
+	u8 hdr_plus_app_ver;
 	u32 qsync_mode;
 	bool qsync_updated;
 

+ 182 - 1
msm/sde_edid_parser.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <drm/drm_edid.h>
@@ -8,6 +8,7 @@
 
 #include "sde_kms.h"
 #include "sde_edid_parser.h"
+#include "sde/sde_connector.h"
 
 #define DBC_START_OFFSET 4
 #define EDID_DTD_LEN 18
@@ -464,6 +465,184 @@ static void _sde_edid_extract_audio_data_blocks(
 	SDE_EDID_DEBUG("%s -", __func__);
 }
 
+static void sde_edid_parse_hdr_plus_info(struct drm_connector *connector,
+	const u8 *db)
+{
+	struct sde_connector *c_conn;
+
+	c_conn = to_sde_connector(connector);
+	c_conn->hdr_plus_app_ver = db[5] & VSVDB_HDR10_PLUS_APP_VER_MASK;
+}
+
+static void sde_edid_parse_vsvdb_info(struct drm_connector *connector,
+	const u8 *db)
+{
+	u8 db_len = 0;
+	u32 ieee_code = 0;
+
+	SDE_EDID_DEBUG("%s +\n", __func__);
+
+	db_len = sde_cea_db_payload_len(db);
+
+	if (db_len < 5)
+		return;
+
+	/* Bytes 2-4: IEEE 24-bit code, LSB first */
+	ieee_code = db[2] | (db[3] << 8) | (db[4] << 16);
+
+	if (ieee_code == VSVDB_HDR10_PLUS_IEEE_CODE)
+		sde_edid_parse_hdr_plus_info(connector, db);
+
+	SDE_EDID_DEBUG("%s -\n", __func__);
+}
+
+static bool sde_edid_is_luminance_value_present(u32 block_length,
+	enum luminance_value value)
+{
+	return block_length > NO_LUMINANCE_DATA && value <= block_length;
+}
+
+/*
+ * sde_edid_parse_hdr_db - Parse the HDR extended block
+ * @connector: connector for the external sink
+ * @db: start of the HDR extended block
+ *
+ * Parses the HDR extended block to extract sink info for @connector.
+ */
+static void
+sde_edid_parse_hdr_db(struct drm_connector *connector, const u8 *db)
+{
+
+	u8 len = 0;
+	struct sde_connector *c_conn;
+
+	c_conn = to_sde_connector(connector);
+
+	if (!db)
+		return;
+
+	len = db[0] & 0x1f;
+	/* Byte 3: Electro-Optical Transfer Functions */
+	c_conn->hdr_eotf = db[2] & 0x3F;
+
+	/* Byte 4: Static Metadata Descriptor Type 1 */
+	c_conn->hdr_metadata_type_one = (db[3] & BIT(0));
+
+	/* Byte 5: Desired Content Maximum Luminance */
+	if (sde_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE))
+		c_conn->hdr_max_luminance = db[MAXIMUM_LUMINANCE];
+
+	/* Byte 6: Desired Content Max Frame-average Luminance */
+	if (sde_edid_is_luminance_value_present(len, FRAME_AVERAGE_LUMINANCE))
+		c_conn->hdr_avg_luminance = db[FRAME_AVERAGE_LUMINANCE];
+
+	/* Byte 7: Desired Content Min Luminance */
+	if (sde_edid_is_luminance_value_present(len, MINIMUM_LUMINANCE))
+		c_conn->hdr_min_luminance = db[MINIMUM_LUMINANCE];
+
+	c_conn->hdr_supported = true;
+	SDE_EDID_DEBUG("HDR electro-optical %d\n", c_conn->hdr_eotf);
+	SDE_EDID_DEBUG("metadata desc 1 %d\n", c_conn->hdr_metadata_type_one);
+	SDE_EDID_DEBUG("max luminance %d\n", c_conn->hdr_max_luminance);
+	SDE_EDID_DEBUG("avg luminance %d\n", c_conn->hdr_avg_luminance);
+	SDE_EDID_DEBUG("min luminance %d\n", c_conn->hdr_min_luminance);
+}
+
+
+/*
+ * 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
+sde_parse_clrmetry_db(struct drm_connector *connector, const u8 *db)
+{
+
+	struct sde_connector *c_conn;
+
+	c_conn = to_sde_connector(connector);
+
+	if (!db) {
+		DRM_ERROR("invalid db\n");
+		return;
+	}
+
+	/* Byte 3 Bit 0: xvYCC_601 */
+	if (db[2] & BIT(0))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_xvYCC_601;
+	/* Byte 3 Bit 1: xvYCC_709 */
+	if (db[2] & BIT(1))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_xvYCC_709;
+	/* Byte 3 Bit 2: sYCC_601 */
+	if (db[2] & BIT(2))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_sYCC_601;
+	/* Byte 3 Bit 3: ADBYCC_601 */
+	if (db[2] & BIT(3))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_ADBYCC_601;
+	/* Byte 3 Bit 4: ADB_RGB */
+	if (db[2] & BIT(4))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_ADB_RGB;
+	/* Byte 3 Bit 5: BT2020_CYCC */
+	if (db[2] & BIT(5))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_BT2020_CYCC;
+	/* Byte 3 Bit 6: BT2020_YCC */
+	if (db[2] & BIT(6))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_BT2020_YCC;
+	/* Byte 3 Bit 7: BT2020_RGB */
+	if (db[2] & BIT(7))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_BT2020_RGB;
+	/* Byte 4 Bit 7: DCI-P3 */
+	if (db[3] & BIT(7))
+		c_conn->color_enc_fmt |= DRM_EDID_CLRMETRY_DCI_P3;
+
+	DRM_DEBUG_KMS("colorimetry fmts = 0x%x\n", c_conn->color_enc_fmt);
+}
+
+/*
+ * sde_edid_parse_extended_blk_info - Parse the HDMI extended tag blocks
+ * @connector: connector corresponding to external sink
+ * @edid: handle to the EDID structure
+ * Parses the all extended tag blocks extract sink info for @connector.
+ */
+static void
+sde_edid_parse_extended_blk_info(struct drm_connector *connector,
+	struct edid *edid)
+{
+	const u8 *cea = sde_find_cea_extension(edid);
+	const u8 *db = NULL;
+
+	if (cea && sde_cea_revision(cea) >= 3) {
+		int i, start, end;
+
+		if (sde_cea_db_offsets(cea, &start, &end))
+			return;
+
+		sde_for_each_cea_db(cea, i, start, end) {
+			db = &cea[i];
+
+			if (sde_cea_db_tag(db) == USE_EXTENDED_TAG) {
+				SDE_EDID_DEBUG("found ext tag block = %d\n",
+						db[1]);
+				switch (db[1]) {
+				case VENDOR_SPECIFIC_VIDEO_DATA_BLOCK:
+					sde_edid_parse_vsvdb_info(connector,
+							db);
+					break;
+				case HDR_STATIC_METADATA_DATA_BLOCK:
+					sde_edid_parse_hdr_db(connector, db);
+					break;
+				case COLORIMETRY_EXTENDED_DATA_BLOCK:
+					sde_parse_clrmetry_db(connector, db);
+				default:
+					break;
+				}
+			}
+		}
+	}
+}
+
 static void _sde_edid_extract_speaker_allocation_data(
 	struct sde_edid_ctrl *edid_ctrl)
 {
@@ -552,6 +731,8 @@ int _sde_edid_update_modes(struct drm_connector *connector,
 		rc = drm_add_edid_modes(connector, edid_ctrl->edid);
 		sde_edid_set_mode_format(connector, edid_ctrl);
 		_sde_edid_update_dc_modes(connector, edid_ctrl);
+		sde_edid_parse_extended_blk_info(connector,
+				edid_ctrl->edid);
 		SDE_EDID_DEBUG("%s -", __func__);
 		return rc;
 	}

+ 13 - 1
msm/sde_edid_parser.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_EDID_PARSER_H_
@@ -26,10 +26,22 @@
 
 #define SDE_DRM_MODE_FLAG_FMT_MASK (0x3 << 20)
 
+#define VSVDB_HDR10_PLUS_IEEE_CODE 0x90848b
+#define VSVDB_HDR10_PLUS_APP_VER_MASK 0x3
+
+/*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
+};
+
 enum extended_data_block_types {
 	VIDEO_CAPABILITY_DATA_BLOCK = 0x0,
 	VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01,
 	HDMI_VIDEO_DATA_BLOCK = 0x04,
+	COLORIMETRY_EXTENDED_DATA_BLOCK = 0x5,
 	HDR_STATIC_METADATA_DATA_BLOCK = 0x06,
 	Y420_VIDEO_DATA_BLOCK = 0x0E,
 	VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D,