Merge "msm: mdss: hdmi: parse High Dynamic Range (HDR) metadata"
This commit is contained in:
commit
5e9b45c7ed
2 changed files with 133 additions and 0 deletions
|
@ -67,6 +67,13 @@ enum edid_sink_mode {
|
||||||
SINK_MODE_HDMI
|
SINK_MODE_HDMI
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum luminance_value {
|
||||||
|
NO_LUMINANCE_DATA = 3,
|
||||||
|
MAXIMUM_LUMINANCE = 4,
|
||||||
|
FRAME_AVERAGE_LUMINANCE = 5,
|
||||||
|
MINIMUM_LUMINANCE = 6
|
||||||
|
};
|
||||||
|
|
||||||
enum data_block_types {
|
enum data_block_types {
|
||||||
RESERVED,
|
RESERVED,
|
||||||
AUDIO_DATA_BLOCK,
|
AUDIO_DATA_BLOCK,
|
||||||
|
@ -82,6 +89,7 @@ enum extended_data_block_types {
|
||||||
VIDEO_CAPABILITY_DATA_BLOCK = 0x0,
|
VIDEO_CAPABILITY_DATA_BLOCK = 0x0,
|
||||||
VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01,
|
VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01,
|
||||||
HDMI_VIDEO_DATA_BLOCK = 0x04,
|
HDMI_VIDEO_DATA_BLOCK = 0x04,
|
||||||
|
HDR_STATIC_METADATA_DATA_BLOCK = 0x06,
|
||||||
Y420_VIDEO_DATA_BLOCK = 0x0E,
|
Y420_VIDEO_DATA_BLOCK = 0x0E,
|
||||||
VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D,
|
VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D,
|
||||||
Y420_CAPABILITY_MAP_DATA_BLOCK = 0x0F,
|
Y420_CAPABILITY_MAP_DATA_BLOCK = 0x0F,
|
||||||
|
@ -143,11 +151,13 @@ struct hdmi_edid_ctrl {
|
||||||
char vendor_id[EDID_VENDOR_ID_SIZE];
|
char vendor_id[EDID_VENDOR_ID_SIZE];
|
||||||
bool keep_resv_timings;
|
bool keep_resv_timings;
|
||||||
bool edid_override;
|
bool edid_override;
|
||||||
|
bool hdr_supported;
|
||||||
|
|
||||||
struct hdmi_edid_sink_data sink_data;
|
struct hdmi_edid_sink_data sink_data;
|
||||||
struct hdmi_edid_init_data init_data;
|
struct hdmi_edid_init_data init_data;
|
||||||
struct hdmi_edid_sink_caps sink_caps;
|
struct hdmi_edid_sink_caps sink_caps;
|
||||||
struct hdmi_edid_override_data override_data;
|
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,
|
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)
|
if (!edid_ctrl->keep_resv_timings)
|
||||||
hdmi_reset_resv_timing_info();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,6 +780,30 @@ err:
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR(add_res, S_IWUSR, NULL, hdmi_edid_sysfs_wta_add_resolution);
|
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[] = {
|
static struct attribute *hdmi_edid_fs_attrs[] = {
|
||||||
&dev_attr_edid_modes.attr,
|
&dev_attr_edid_modes.attr,
|
||||||
&dev_attr_pa.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.attr,
|
||||||
&dev_attr_res_info_data.attr,
|
&dev_attr_res_info_data.attr,
|
||||||
&dev_attr_add_res.attr,
|
&dev_attr_add_res.attr,
|
||||||
|
&dev_attr_hdr_data.attr,
|
||||||
NULL,
|
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,
|
static void hdmi_edid_parse_Y420CMDB(struct hdmi_edid_ctrl *edid_ctrl,
|
||||||
const u8 *in_buf)
|
const u8 *in_buf)
|
||||||
{
|
{
|
||||||
|
@ -1045,6 +1129,12 @@ static void hdmi_edid_extract_extended_data_blocks(
|
||||||
__func__, etag[2]);
|
__func__, etag[2]);
|
||||||
hdmi_edid_parse_Y420VDB(edid_ctrl, etag);
|
hdmi_edid_parse_Y420VDB(edid_ctrl, etag);
|
||||||
break;
|
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:
|
default:
|
||||||
DEV_DBG("%s: Tag Code %d not supported\n",
|
DEV_DBG("%s: Tag Code %d not supported\n",
|
||||||
__func__, etag[1]);
|
__func__, etag[1]);
|
||||||
|
@ -2355,6 +2445,31 @@ u8 hdmi_edid_get_deep_color(void *input)
|
||||||
return edid_ctrl->deep_color;
|
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)
|
bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -28,6 +28,22 @@ struct hdmi_edid_init_data {
|
||||||
u32 buf_size;
|
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);
|
int hdmi_edid_parser(void *edid_ctrl);
|
||||||
u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size);
|
u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size);
|
||||||
u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
|
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,
|
bool hdmi_edid_is_s3d_mode_supported(void *input,
|
||||||
u32 video_mode, u32 s3d_mode);
|
u32 video_mode, u32 s3d_mode);
|
||||||
u8 hdmi_edid_get_deep_color(void *edid_ctrl);
|
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__ */
|
#endif /* __HDMI_EDID_H__ */
|
||||||
|
|
Loading…
Add table
Reference in a new issue