summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/msm
diff options
context:
space:
mode:
authorTatenda Chipeperekwa <tatendac@codeaurora.org>2016-06-16 15:49:18 -0700
committerTatenda Chipeperekwa <tatendac@codeaurora.org>2016-07-11 18:11:23 -0700
commit78c877d3d36f2d9af819a27f1497274592c63a91 (patch)
tree1adf2dc4e8bbefbce0f619fb0f3a9eee7cfd5f6f /drivers/video/fbdev/msm
parent1f1574bb1837ce7ee0bf24c40a178cdcbf2932da (diff)
msm: mdss: hdmi: parse High Dynamic Range (HDR) metadata
The HDR data block indicates the HDR capabilities of the sink: electro-optical transfer function, static metadata descriptor, desired content max luminance data, desired content max frame-average luminance data, and desired content min luminance data. This data parsed from the EDID block and provided to clients via a sysfs node. Change-Id: Ib78c315a43e98af4ea454998bc7ca8428522d5c0 Signed-off-by: Tatenda Chipeperekwa <tatendac@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev/msm')
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c115
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h18
2 files changed, 133 insertions, 0 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index 77d7c04e6f0e..6a6cdc8b502c 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -67,6 +67,13 @@ enum edid_sink_mode {
SINK_MODE_HDMI
};
+enum luminance_value {
+ NO_LUMINANCE_DATA = 3,
+ MAXIMUM_LUMINANCE = 4,
+ FRAME_AVERAGE_LUMINANCE = 5,
+ MINIMUM_LUMINANCE = 6
+};
+
enum data_block_types {
RESERVED,
AUDIO_DATA_BLOCK,
@@ -82,6 +89,7 @@ enum extended_data_block_types {
VIDEO_CAPABILITY_DATA_BLOCK = 0x0,
VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01,
HDMI_VIDEO_DATA_BLOCK = 0x04,
+ HDR_STATIC_METADATA_DATA_BLOCK = 0x06,
Y420_VIDEO_DATA_BLOCK = 0x0E,
VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D,
Y420_CAPABILITY_MAP_DATA_BLOCK = 0x0F,
@@ -143,11 +151,13 @@ struct hdmi_edid_ctrl {
char vendor_id[EDID_VENDOR_ID_SIZE];
bool keep_resv_timings;
bool edid_override;
+ bool hdr_supported;
struct hdmi_edid_sink_data sink_data;
struct hdmi_edid_init_data init_data;
struct hdmi_edid_sink_caps sink_caps;
struct hdmi_edid_override_data override_data;
+ struct hdmi_edid_hdr_data hdr_data;
};
static bool hdmi_edid_is_mode_supported(struct hdmi_edid_ctrl *edid_ctrl,
@@ -203,6 +213,14 @@ static int hdmi_edid_reset_parser(struct hdmi_edid_ctrl *edid_ctrl)
if (!edid_ctrl->keep_resv_timings)
hdmi_reset_resv_timing_info();
+ /* reset HDR related data */
+ edid_ctrl->hdr_supported = false;
+ edid_ctrl->hdr_data.eotf = 0;
+ edid_ctrl->hdr_data.descriptor = 0;
+ edid_ctrl->hdr_data.max_luminance = 0;
+ edid_ctrl->hdr_data.avg_luminance = 0;
+ edid_ctrl->hdr_data.min_luminance = 0;
+
return 0;
}
@@ -762,6 +780,30 @@ err:
}
static DEVICE_ATTR(add_res, S_IWUSR, NULL, hdmi_edid_sysfs_wta_add_resolution);
+static ssize_t hdmi_edid_sysfs_rda_hdr_data(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct hdmi_edid_ctrl *edid_ctrl = hdmi_edid_get_ctrl(dev);
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = scnprintf(buf, PAGE_SIZE, "%d, %u, %u, %u, %u, %u\n",
+ edid_ctrl->hdr_supported,
+ edid_ctrl->hdr_data.eotf,
+ edid_ctrl->hdr_data.descriptor,
+ edid_ctrl->hdr_data.max_luminance,
+ edid_ctrl->hdr_data.avg_luminance,
+ edid_ctrl->hdr_data.min_luminance);
+ DEV_DBG("%s: '%s'\n", __func__, buf);
+
+ return ret;
+}
+static DEVICE_ATTR(hdr_data, S_IRUGO, hdmi_edid_sysfs_rda_hdr_data, NULL);
+
static struct attribute *hdmi_edid_fs_attrs[] = {
&dev_attr_edid_modes.attr,
&dev_attr_pa.attr,
@@ -775,6 +817,7 @@ static struct attribute *hdmi_edid_fs_attrs[] = {
&dev_attr_res_info.attr,
&dev_attr_res_info_data.attr,
&dev_attr_add_res.attr,
+ &dev_attr_hdr_data.attr,
NULL,
};
@@ -899,6 +942,47 @@ static void hdmi_edid_parse_Y420VDB(struct hdmi_edid_ctrl *edid_ctrl,
}
}
+static bool hdmi_edid_is_luminance_value_present(u32 block_length,
+ enum luminance_value value)
+{
+ return block_length > NO_LUMINANCE_DATA && value <= block_length;
+}
+
+static void hdmi_edid_parse_hdrdb(struct hdmi_edid_ctrl *edid_ctrl,
+ const u8 *data_block)
+{
+ u8 len = 0;
+
+ if (!edid_ctrl || !data_block) {
+ pr_err("%s: invalid input\n", __func__);
+ return;
+ }
+
+ /* Byte 1: Length of Data Block */
+ len = data_block[0] & 0x1F;
+
+ /* Byte 3: Electro-Optical Transfer Functions */
+ edid_ctrl->hdr_data.eotf = data_block[2] & 0x3F;
+
+ /* Byte 4: Static Metadata Descriptors */
+ edid_ctrl->hdr_data.descriptor = data_block[3] & 0x1;
+
+ /* Byte 5: Desired Content Maximum Luminance */
+ if (hdmi_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE))
+ edid_ctrl->hdr_data.max_luminance =
+ data_block[MAXIMUM_LUMINANCE];
+
+ /* Byte 6: Desired Content Max Frame-average Luminance */
+ if (hdmi_edid_is_luminance_value_present(len, FRAME_AVERAGE_LUMINANCE))
+ edid_ctrl->hdr_data.avg_luminance =
+ data_block[FRAME_AVERAGE_LUMINANCE];
+
+ /* Byte 7: Desired Content Min Luminance */
+ if (hdmi_edid_is_luminance_value_present(len, MINIMUM_LUMINANCE))
+ edid_ctrl->hdr_data.min_luminance =
+ data_block[MINIMUM_LUMINANCE];
+}
+
static void hdmi_edid_parse_Y420CMDB(struct hdmi_edid_ctrl *edid_ctrl,
const u8 *in_buf)
{
@@ -1045,6 +1129,12 @@ static void hdmi_edid_extract_extended_data_blocks(
__func__, etag[2]);
hdmi_edid_parse_Y420VDB(edid_ctrl, etag);
break;
+ case HDR_STATIC_METADATA_DATA_BLOCK:
+ DEV_DBG("%s found HDR Static Metadata. Byte 3 = 0x%x",
+ __func__, etag[2]);
+ hdmi_edid_parse_hdrdb(edid_ctrl, etag);
+ edid_ctrl->hdr_supported = true;
+ break;
default:
DEV_DBG("%s: Tag Code %d not supported\n",
__func__, etag[1]);
@@ -2355,6 +2445,31 @@ u8 hdmi_edid_get_deep_color(void *input)
return edid_ctrl->deep_color;
}
+/**
+ * hdmi_edid_get_hdr_data() - get the HDR capabiliies of the sink
+ * @input: edid parser data
+ *
+ * This API returns HDR info associated with the sink:
+ * electro-optical transfer function, static metadata descriptor,
+ * desired content max luminance data, desired content max
+ * frame-average luminance data, and desired content min luminance
+ * data.
+ *
+ * Return: HDR data.
+ */
+void hdmi_edid_get_hdr_data(void *input,
+ struct hdmi_edid_hdr_data *hdr_data)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl || !hdr_data) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ hdr_data = &edid_ctrl->hdr_data;
+}
+
bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode)
{
int i;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
index 7b4b2dccc802..c818f3fc0d19 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
@@ -28,6 +28,22 @@ struct hdmi_edid_init_data {
u32 buf_size;
};
+/*
+ * struct hdmi_edid_hdr_data - HDR Static Metadata
+ * @eotf: Electro-Optical Transfer Function
+ * @descriptor: Static Metadata Descriptor
+ * @max_luminance: Desired Content Maximum Luminance
+ * @avg_luminance: Desired Content Frame-average Luminance
+ * @min_luminance: Desired Content Minimum Luminance
+ */
+struct hdmi_edid_hdr_data {
+ u32 eotf;
+ u32 descriptor;
+ u32 max_luminance;
+ u32 avg_luminance;
+ u32 min_luminance;
+};
+
int hdmi_edid_parser(void *edid_ctrl);
u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size);
u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
@@ -44,5 +60,7 @@ void *hdmi_edid_init(struct hdmi_edid_init_data *init_data);
bool hdmi_edid_is_s3d_mode_supported(void *input,
u32 video_mode, u32 s3d_mode);
u8 hdmi_edid_get_deep_color(void *edid_ctrl);
+void hdmi_edid_get_hdr_data(void *edid_ctrl,
+ struct hdmi_edid_hdr_data *hdr_data);
#endif /* __HDMI_EDID_H__ */