From 6a6788db5c37171d1c8d8ab7ebb892076101b057 Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Thu, 14 Jul 2016 20:09:55 -0700 Subject: [PATCH 1/2] msm: mdss: hdmi: use pinctrl API to toggle 5v on msmcobalt Use the pinctrl API to toggle the 5v supply line on msmcobalt since this target no longer uses the older GPIO configuration path. CRs-Fixed: 1044301 Change-Id: Id968f2541e1a543d3d7cf1c96af9936c9ae564ea Signed-off-by: Tatenda Chipeperekwa --- drivers/video/fbdev/msm/mdss_hdmi_tx.c | 33 +++++++++++++------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 3d773371713d..27cf10a70233 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -111,6 +111,8 @@ static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, int enable); static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl); static void hdmi_tx_fps_work(struct work_struct *work); +static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl, + enum hdmi_tx_power_module_type module, bool active); static struct mdss_hw hdmi_tx_hw = { .hw_ndx = MDSS_HW_HDMI, @@ -478,25 +480,30 @@ void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, } /* hdmi_tx_get_featuredata_from_sysfs_dev */ EXPORT_SYMBOL(hdmi_get_featuredata_from_sysfs_dev); -static int hdmi_tx_config_5v(struct hdmi_tx_ctrl *hdmi_ctrl, bool enable) +static int hdmi_tx_config_5v(struct hdmi_tx_ctrl *ctrl, bool enable) { - struct dss_module_power *pd = NULL; int ret = 0; + struct dss_module_power *pd = NULL; - if (!hdmi_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); + if (!ctrl) { + DEV_ERR("%s: Invalid HDMI ctrl\n", __func__); ret = -EINVAL; goto end; } - pd = &hdmi_ctrl->pdata.power_data[HDMI_TX_HPD_PM]; - if (!pd || !pd->gpio_config) { - DEV_ERR("%s: Error: invalid power data\n", __func__); - ret = -EINVAL; - goto end; + if (ctrl->hdmi_tx_version >= HDMI_TX_VERSION_403) + ret = hdmi_tx_pinctrl_set_state(ctrl, HDMI_TX_HPD_PM, enable); + else { + pd = &ctrl->pdata.power_data[HDMI_TX_HPD_PM]; + if (!pd || !pd->gpio_config) { + DEV_ERR("%s: Invalid power data\n", __func__); + ret = -EINVAL; + goto end; + } + + gpio_set_value(pd->gpio_config->gpio, enable); } - gpio_set_value(pd->gpio_config->gpio, enable); end: return ret; } @@ -1220,12 +1227,6 @@ static ssize_t hdmi_tx_sysfs_wta_5v(struct device *dev, } mutex_lock(&hdmi_ctrl->tx_lock); - pd = &hdmi_ctrl->pdata.power_data[HDMI_TX_HPD_PM]; - if (!pd || !pd->gpio_config) { - DEV_ERR("%s: Error: invalid power data\n", __func__); - ret = -EINVAL; - goto end; - } ret = kstrtoint(buf, 10, &read); if (ret) { From 71ebcf5f02449a4d621c0aeeda631861ed7ec63d Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Wed, 13 Jul 2016 17:37:27 -0700 Subject: [PATCH 2/2] msm: mdss: hdmi: send info frame for HDR video streams Send the dynamic range and mastering info frame if the sink supports at least one electro-optical transfer function. This info frame will be used by the sink to render the HDR video stream for the duration of the transmission. CRs-Fixed: 1044326 Change-Id: Iaa2c9e45fe0ed0392e084a381d2d1e1d506bc609 Signed-off-by: Tatenda Chipeperekwa --- drivers/video/fbdev/msm/mdss_hdmi_edid.c | 14 +- drivers/video/fbdev/msm/mdss_hdmi_edid.h | 6 +- drivers/video/fbdev/msm/mdss_hdmi_tx.c | 192 ++++++++++++++++++++++- drivers/video/fbdev/msm/mdss_hdmi_tx.h | 26 +++ 4 files changed, 227 insertions(+), 11 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index 6a6cdc8b502c..4f1435d006b2 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -216,7 +216,7 @@ static int hdmi_edid_reset_parser(struct hdmi_edid_ctrl *edid_ctrl) /* 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.metadata_type_one = false; edid_ctrl->hdr_data.max_luminance = 0; edid_ctrl->hdr_data.avg_luminance = 0; edid_ctrl->hdr_data.min_luminance = 0; @@ -794,7 +794,7 @@ static ssize_t hdmi_edid_sysfs_rda_hdr_data(struct device *dev, 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.metadata_type_one, edid_ctrl->hdr_data.max_luminance, edid_ctrl->hdr_data.avg_luminance, edid_ctrl->hdr_data.min_luminance); @@ -964,8 +964,8 @@ static void hdmi_edid_parse_hdrdb(struct hdmi_edid_ctrl *edid_ctrl, /* 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 4: Static Metadata Descriptor Type 1 */ + edid_ctrl->hdr_data.metadata_type_one = (data_block[3] & 0x1) & BIT(0); /* Byte 5: Desired Content Maximum Luminance */ if (hdmi_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE)) @@ -2458,16 +2458,16 @@ u8 hdmi_edid_get_deep_color(void *input) * Return: HDR data. */ void hdmi_edid_get_hdr_data(void *input, - struct hdmi_edid_hdr_data *hdr_data) + struct hdmi_edid_hdr_data **hdr_data) { struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; - if (!edid_ctrl || !hdr_data) { + if (!edid_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return; } - hdr_data = &edid_ctrl->hdr_data; + *hdr_data = &edid_ctrl->hdr_data; } bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode) diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index c818f3fc0d19..ce6cecbb2e03 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -31,14 +31,14 @@ struct hdmi_edid_init_data { /* * struct hdmi_edid_hdr_data - HDR Static Metadata * @eotf: Electro-Optical Transfer Function - * @descriptor: Static Metadata Descriptor + * @metadata_type_one: Static Metadata Type 1 support * @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; + bool metadata_type_one; u32 max_luminance; u32 avg_luminance; u32 min_luminance; @@ -61,6 +61,6 @@ 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); + struct hdmi_edid_hdr_data **hdr_data); #endif /* __HDMI_EDID_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 27cf10a70233..10e7a2d1a940 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -79,6 +79,8 @@ #define HDMI_TX_MAX_FPS 120000 #define HDMI_TX_VERSION_403 0x40000003 /* msmcobalt */ +#define HDMI_GET_MSB(x) (x >> 8) +#define HDMI_GET_LSB(x) (x & 0xff) /* Enable HDCP by default */ static bool hdcp_feature_on = true; @@ -113,6 +115,7 @@ static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl); static void hdmi_tx_fps_work(struct work_struct *work); static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, bool active); +static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl); static struct mdss_hw hdmi_tx_hw = { .hw_ndx = MDSS_HW_HDMI, @@ -287,6 +290,29 @@ static inline bool hdmi_tx_is_hdcp_enabled(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->hdcp_ops; } +/* + * The sink must support at least one electro-optical transfer function for + * HDMI controller to sendi the dynamic range and mastering infoframe. + */ +static inline bool hdmi_tx_is_hdr_supported(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct hdmi_edid_hdr_data *hdr_data; + + hdmi_edid_get_hdr_data(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), &hdr_data); + + return (hdr_data->eotf & BIT(0)) || (hdr_data->eotf & BIT(1)) || + (hdr_data->eotf & BIT(2)); +} + +static inline bool hdmi_tx_metadata_type_one(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct hdmi_edid_hdr_data *hdr_data; + + hdmi_edid_get_hdr_data(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), &hdr_data); + + return hdr_data->metadata_type_one; +} + static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl) { return hdmi_ctrl->dc_feature_on && hdmi_ctrl->dc_support && @@ -1246,6 +1272,72 @@ end: return ret; } +static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + u32 const hdr_param_count = 13; + struct hdmi_tx_ctrl *ctrl = NULL; + + ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev); + if (!ctrl) { + pr_err("%s: invalid input\n", __func__); + ret = -EINVAL; + goto end; + } + + if (!hdmi_tx_is_hdr_supported(ctrl)) { + pr_err("%s: Sink does not support HDR\n", __func__); + ret = -EINVAL; + goto end; + } + + if (sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u %u", + &ctrl->hdr_data.eotf, + &ctrl->hdr_data.display_primaries_x[0], + &ctrl->hdr_data.display_primaries_y[0], + &ctrl->hdr_data.display_primaries_x[1], + &ctrl->hdr_data.display_primaries_y[1], + &ctrl->hdr_data.display_primaries_x[2], + &ctrl->hdr_data.display_primaries_y[2], + &ctrl->hdr_data.white_point_x, + &ctrl->hdr_data.white_point_y, + &ctrl->hdr_data.max_luminance, + &ctrl->hdr_data.min_luminance, + &ctrl->hdr_data.max_content_light_level, + &ctrl->hdr_data.max_average_light_level) + != hdr_param_count) { + pr_err("%s: Invalid HDR stream data\n", __func__); + ret = -EINVAL; + goto end; + } + + pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", + __func__, + ctrl->hdr_data.eotf, + ctrl->hdr_data.display_primaries_x[0], + ctrl->hdr_data.display_primaries_y[0], + ctrl->hdr_data.display_primaries_x[1], + ctrl->hdr_data.display_primaries_y[1], + ctrl->hdr_data.display_primaries_x[2], + ctrl->hdr_data.display_primaries_y[2]); + + pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", + __func__, + ctrl->hdr_data.white_point_x, + ctrl->hdr_data.white_point_y, + ctrl->hdr_data.max_luminance, + ctrl->hdr_data.min_luminance, + ctrl->hdr_data.max_content_light_level, + ctrl->hdr_data.max_average_light_level); + + hdmi_panel_set_hdr_infoframe(ctrl); + + ret = strnlen(buf, PAGE_SIZE); +end: + return ret; +} + static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL); static DEVICE_ATTR(hdmi_audio_cb, S_IWUSR, NULL, hdmi_tx_sysfs_wta_audio_cb); static DEVICE_ATTR(hot_plug, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hot_plug); @@ -1266,6 +1358,7 @@ static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn_bits); static DEVICE_ATTR(s3d_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_s3d_mode, hdmi_tx_sysfs_wta_s3d_mode); static DEVICE_ATTR(5v, S_IWUSR, NULL, hdmi_tx_sysfs_wta_5v); +static DEVICE_ATTR(hdr_stream, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hdr_stream); static struct attribute *hdmi_tx_fs_attrs[] = { &dev_attr_connected.attr, @@ -1281,6 +1374,7 @@ static struct attribute *hdmi_tx_fs_attrs[] = { &dev_attr_avi_cn0_1.attr, &dev_attr_s3d_mode.attr, &dev_attr_5v.attr, + &dev_attr_hdr_stream.attr, NULL, }; static struct attribute_group hdmi_tx_fs_attrs_group = { @@ -2210,7 +2304,7 @@ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl) DEV_DBG("%s: Features \n", __func__, hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON", - hdmi_ctrl->dc_feature_on ? "OFF" : "ON"); + !hdmi_ctrl->dc_feature_on ? "OFF" : "ON"); if (hdmi_disabled) { DEV_ERR("%s: HDMI disabled\n", __func__); @@ -2636,6 +2730,102 @@ static void hdmi_tx_phy_reset(struct hdmi_tx_ctrl *hdmi_ctrl) DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL); } /* hdmi_tx_phy_reset */ +static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) +{ + u32 packet_payload = 0; + u32 packet_header = 0; + u32 packet_control = 0; + u32 const type_code = 0x87; + u32 const version = 0x01; + u32 const length = 0x1a; + u32 const descriptor_id = 0x00; + struct dss_io_data *io = NULL; + + if (!ctrl) { + pr_err("%s: invalid input\n", __func__); + return; + } + + if (!hdmi_tx_is_hdr_supported(ctrl)) { + pr_err("%s: Sink does not support HDR\n", __func__); + return; + } + + io = &ctrl->pdata.io[HDMI_TX_CORE_IO]; + if (!io->base) { + pr_err("%s: core io not inititalized\n", __func__); + return; + } + + /* Setup Packet header and payload */ + packet_header = type_code | (version << 8) | (length << 16); + DSS_REG_W(io, HDMI_GENERIC0_HDR, packet_header); + + packet_payload = (ctrl->hdr_data.eotf << 8); + if (hdmi_tx_metadata_type_one(ctrl)) { + packet_payload |= (descriptor_id << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[0]) + << 24); + DSS_REG_W(io, HDMI_GENERIC0_0, packet_payload); + } else { + pr_debug("%s: Metadata Type 1 not supported\n", __func__); + DSS_REG_W(io, HDMI_GENERIC0_0, packet_payload); + goto enable_packet_control; + } + + packet_payload = + (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[0])) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[0]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[0]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[1]) << 24); + DSS_REG_W(io, HDMI_GENERIC0_1, packet_payload); + + packet_payload = + (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[1])) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[1]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[1]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[2]) << 24); + DSS_REG_W(io, HDMI_GENERIC0_2, packet_payload); + + packet_payload = + (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[2])) + | (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[2]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[2]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.white_point_x) << 24); + DSS_REG_W(io, HDMI_GENERIC0_3, packet_payload); + + packet_payload = + (HDMI_GET_MSB(ctrl->hdr_data.white_point_x)) + | (HDMI_GET_LSB(ctrl->hdr_data.white_point_y) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.white_point_y) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.max_luminance) << 24); + DSS_REG_W(io, HDMI_GENERIC0_4, packet_payload); + + packet_payload = + (HDMI_GET_MSB(ctrl->hdr_data.max_luminance)) + | (HDMI_GET_LSB(ctrl->hdr_data.min_luminance) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.min_luminance) << 16) + | (HDMI_GET_LSB(ctrl->hdr_data.max_content_light_level) << 24); + DSS_REG_W(io, HDMI_GENERIC0_5, packet_payload); + + packet_payload = + (HDMI_GET_MSB(ctrl->hdr_data.max_content_light_level)) + | (HDMI_GET_LSB(ctrl->hdr_data.max_average_light_level) << 8) + | (HDMI_GET_MSB(ctrl->hdr_data.max_average_light_level) << 16); + DSS_REG_W(io, HDMI_GENERIC0_6, packet_payload); + +enable_packet_control: + /* + * GENERIC0_LINE | GENERIC0_CONT | GENERIC0_SEND + * Setup HDMI TX generic packet control + * Enable this packet to transmit every frame + * Enable HDMI TX engine to transmit Generic packet 1 + */ + packet_control = DSS_REG_R_ND(io, HDMI_GEN_PKT_CTRL); + packet_control |= BIT(0) | BIT(1) | BIT(2) | BIT(16); + DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control); +} + static int hdmi_tx_audio_info_setup(struct platform_device *pdev, struct msm_ext_disp_audio_setup_params *params) { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index 462edac31c09..1c306df70c7e 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -20,6 +20,7 @@ #include "mdss_hdmi_audio.h" #define MAX_SWITCH_NAME_SIZE 5 +#define HDR_PRIMARIES_COUNT 3 enum hdmi_tx_io_type { HDMI_TX_CORE_IO, @@ -61,6 +62,30 @@ struct hdmi_tx_pinctrl { struct hdmi_tx_ctrl; typedef int (*hdmi_tx_evt_handler) (struct hdmi_tx_ctrl *); +/* + * struct hdmi_tx_hdr_stream - HDR video stream characteristics + * @eotf: Electro-Optical Transfer Function + * @display_primaries_x: display primaries data for x-coordinate + * @display_primaries_y: display primaries data for y-coordinate + * @white_point_x: white point data for x-coordinate + * @white_point_y: white point data for y-coordinate + * @max_luminance: content maximum luminance + * @min_luminance: content minimum luminance + * @max_content_light_level: content maximum light level + * @max_average_light_level: content average light level + */ +struct hdmi_tx_hdr_stream_data { + u32 eotf; + u32 display_primaries_x[HDR_PRIMARIES_COUNT]; + u32 display_primaries_y[HDR_PRIMARIES_COUNT]; + u32 white_point_x; + u32 white_point_y; + u32 max_luminance; + u32 min_luminance; + u32 max_content_light_level; + u32 max_average_light_level; +}; + struct hdmi_tx_ctrl { struct platform_device *pdev; struct hdmi_tx_platform_data pdata; @@ -88,6 +113,7 @@ struct hdmi_tx_ctrl { struct hdmi_panel_ops panel_ops; struct msm_ext_disp_audio_setup_params audio_params; struct work_struct fps_work; + struct hdmi_tx_hdr_stream_data hdr_data; spinlock_t hpd_state_lock;