summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbhinav Kumar <abhinavk@codeaurora.org>2017-03-22 15:33:18 -0700
committerAbhinav Kumar <abhinavk@codeaurora.org>2017-04-10 23:41:56 -0700
commit31604f1c6f99f726111c21f28fe0c84120a9a3eb (patch)
tree99be81d42629fff9f4cfe4f87a04c9ae684ced10
parent89ed892b18328c278359da4437d42b93d313a3ae (diff)
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: Abhinav Kumar <abhinavk@codeaurora.org>
-rw-r--r--drivers/gpu/drm/drm_edid.c239
-rw-r--r--include/drm/drm_crtc.h19
-rw-r--r--include/uapi/drm/drm_mode.h3
3 files changed, 258 insertions, 3 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 8714643ccee8..02a60a1df50d 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -89,6 +89,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 struct edid_quirk {
char vendor[4];
int product_id;
@@ -2697,12 +2705,15 @@ 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 HDR_STATIC_METADATA_EXTENDED_DATA_BLOCK 0x06
+#define EXTENDED_TAG 0x07
#define VIDEO_CAPABILITY_BLOCK 0x07
+#define Y420_VIDEO_DATA_BLOCK 0x0E
#define EDID_BASIC_AUDIO (1 << 6)
#define EDID_CEA_YCRCB444 (1 << 5)
#define EDID_CEA_YCRCB422 (1 << 4)
@@ -3460,6 +3471,227 @@ parse_hdmi_hf_vsdb(struct drm_connector *connector, const u8 *db)
}
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))
+ parse_hdmi_vsdb(connector, db);
+ /* HDMI Forum Vendor-Specific Data Block */
+ else if (cea_db_is_hdmi_hf_vsdb(db))
+ parse_hdmi_hf_vsdb(connector, db);
+ }
+ }
+ }
+}
+
+/*
+ * 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) {
+ DRM_ERROR("invalid db\n");
+ 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) == 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 u8 *
+drm_edid_find_extended_tag_block(struct edid *edid, int blk_id)
+{
+ u8 *db = NULL;
+ u8 *cea = NULL;
+
+ if (!edid) {
+ pr_err("%s: invalid input\n", __func__);
+ return NULL;
+ }
+
+ cea = drm_find_cea_extension(edid);
+
+ if (cea && cea_revision(cea) >= 3) {
+ int i, start, end;
+
+ if (cea_db_offsets(cea, &start, &end))
+ return NULL;
+
+ for_each_cea_db(cea, i, start, end) {
+ db = &cea[i];
+ if ((cea_db_tag(db) == EXTENDED_TAG) &&
+ (db[1] == blk_id))
+ return db;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * add_YCbCr420VDB_modes - add the modes found in Ycbcr420 VDB block
+ * @connector: connector corresponding to the HDMI sink
+ * @edid: handle to the EDID structure
+ * Parses the YCbCr420 VDB block and adds the modes to @connector.
+ */
+static int
+add_YCbCr420VDB_modes(struct drm_connector *connector, struct edid *edid)
+{
+
+ const u8 *db = NULL;
+ u32 i = 0;
+ u32 modes = 0;
+ u32 video_format = 0;
+ u8 len = 0;
+
+ /*Find the YCbCr420 VDB*/
+ db = drm_edid_find_extended_tag_block(edid, Y420_VIDEO_DATA_BLOCK);
+ /* Offset to byte 3 */
+ if (db) {
+ len = db[0] & 0x1F;
+ db += 2;
+ for (i = 0; i < len - 1; i++) {
+ struct drm_display_mode *mode;
+
+ video_format = *(db + i) & 0x7F;
+ mode = drm_display_mode_from_vic_index(connector,
+ db, len-1, i);
+ if (mode) {
+ DRM_DEBUG_KMS("Adding mode for vic = %d\n",
+ video_format);
+ drm_mode_probed_add(connector, mode);
+ modes++;
+ }
+ }
+ }
+ return modes;
+}
+
+static void
monitor_name(struct detailed_timing *t, void *data)
{
if (t->data.other_data.type == EDID_DETAIL_MONITOR_NAME)
@@ -3997,6 +4229,10 @@ static void drm_add_display_info(struct edid *edid,
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
}
+ /* 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);
/* HDMI deep color modes supported? Assign to info, if so */
drm_assign_hdmi_deep_color_info(edid, info, connector);
@@ -4227,6 +4463,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
num_modes += add_cea_modes(connector, edid);
num_modes += add_alternate_cea_modes(connector, edid);
num_modes += add_displayid_detailed_modes(connector, edid);
+ num_modes += add_YCbCr420VDB_modes(connector, edid);
if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
num_modes += add_inferred_modes(connector, edid);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 729fd9ff570b..6555fdbee88a 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -649,6 +649,15 @@ struct drm_encoder {
* @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_*)
+ * @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
+ * @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
* @edid_corrupt: indicates whether the last read EDID was corrupt
* @debugfs_entry: debugfs directory for this connector
* @state: current atomic state for this connector
@@ -728,7 +737,15 @@ struct drm_connector {
bool rr_capable;
bool supports_scramble;
int flags_3d;
-
+ u8 pt_scan_info;
+ u8 it_scan_info;
+ u8 ce_scan_info;
+ u32 hdr_eotf;
+ bool hdr_metadata_type_one;
+ u32 hdr_max_luminance;
+ u32 hdr_avg_luminance;
+ u32 hdr_min_luminance;
+ bool hdr_supported;
/* Flag for raw EDID header corruption - used in Displayport
* compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6
*/
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 09c22caf34dd..1c5e74f1ea39 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -73,7 +73,8 @@
#define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7<<14)
#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8<<14)
#define DRM_MODE_FLAG_SEAMLESS (1<<19)
-
+#define DRM_MODE_FLAG_SUPPORTS_RGB (1<<20)
+#define DRM_MODE_FLAG_SUPPORTS_YUV (1<<21)
/* DPMS flags */
/* bit compatible with the xorg definitions. */