diff options
author | Ch Ganesh Kumar <chganesh@codeaurora.org> | 2017-08-18 11:45:42 +0530 |
---|---|---|
committer | Ch Ganesh Kumar <chganesh@codeaurora.org> | 2017-09-22 16:44:18 +0530 |
commit | 05f00d16b64d31419c7939fefb4fc193bea19492 (patch) | |
tree | 8a2e170385e7a1dcef0d3486491caf65a9fa7e4d | |
parent | 6f777b2385c98a17d69bbeead6edbc7ad7470f72 (diff) |
fb/msm: add support for HDR playback control sequence
HDR playback needs metadata to be sent to the sink
while the playback is ongoing and needs a proper
teardown sequence when the playback has ended with respect
to the infoframe being sent to the sink.
This needs a state machine to synchronize start/stop of
the playback with sending the right metadata along with
resetting the infoframe HDMI registers.
Add support for this HDR playback control state machine.
Change-Id: I58ff03bc8db99febd17e0a0853acc74668892ea8
Signed-off-by: Ch Ganesh Kumar <chganesh@codeaurora.org>
-rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 144 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.h | 4 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_util.c | 49 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_util.h | 10 | ||||
-rw-r--r-- | include/uapi/linux/msm_mdp_ext.h | 22 |
5 files changed, 179 insertions, 50 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index af95a4a6dccd..a5a407708334 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -113,6 +113,7 @@ 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 void hdmi_panel_clear_hdr_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl); static int hdmi_tx_audio_info_setup(struct platform_device *pdev, struct msm_ext_disp_audio_setup_params *params); static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev, @@ -1276,6 +1277,7 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev, { int ret = 0; struct hdmi_tx_ctrl *ctrl = NULL; + u8 hdr_op; ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev); if (!ctrl) { @@ -1296,36 +1298,43 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev, goto end; } - memcpy(&ctrl->hdr_data, buf, sizeof(struct mdp_hdr_stream)); + memcpy(&ctrl->hdr_ctrl, buf, sizeof(struct mdp_hdr_stream_ctrl)); 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]); + ctrl->hdr_ctrl.hdr_stream.eotf, + ctrl->hdr_ctrl.hdr_stream.display_primaries_x[0], + ctrl->hdr_ctrl.hdr_stream.display_primaries_y[0], + ctrl->hdr_ctrl.hdr_stream.display_primaries_x[1], + ctrl->hdr_ctrl.hdr_stream.display_primaries_y[1], + ctrl->hdr_ctrl.hdr_stream.display_primaries_x[2], + ctrl->hdr_ctrl.hdr_stream.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); + ctrl->hdr_ctrl.hdr_stream.white_point_x, + ctrl->hdr_ctrl.hdr_stream.white_point_y, + ctrl->hdr_ctrl.hdr_stream.max_luminance, + ctrl->hdr_ctrl.hdr_stream.min_luminance, + ctrl->hdr_ctrl.hdr_stream.max_content_light_level, + ctrl->hdr_ctrl.hdr_stream.max_average_light_level); pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", __func__, - ctrl->hdr_data.pixel_encoding, - ctrl->hdr_data.colorimetry, - ctrl->hdr_data.range, - ctrl->hdr_data.bits_per_component, - ctrl->hdr_data.content_type); + ctrl->hdr_ctrl.hdr_stream.pixel_encoding, + ctrl->hdr_ctrl.hdr_stream.colorimetry, + ctrl->hdr_ctrl.hdr_stream.range, + ctrl->hdr_ctrl.hdr_stream.bits_per_component, + ctrl->hdr_ctrl.hdr_stream.content_type); + hdr_op = hdmi_hdr_get_ops(ctrl->curr_hdr_state, + ctrl->hdr_ctrl.hdr_state); - hdmi_panel_set_hdr_infoframe(ctrl); + if (hdr_op == HDR_SEND_INFO) + hdmi_panel_set_hdr_infoframe(ctrl); + else if (hdr_op == HDR_CLEAR_INFO) + hdmi_panel_clear_hdr_infoframe(ctrl); + + ctrl->curr_hdr_state = ctrl->hdr_ctrl.hdr_state; ret = strnlen(buf, PAGE_SIZE); end: @@ -2113,6 +2122,8 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl, goto err; } + /* reset HDR state */ + hdmi_ctrl->curr_hdr_state = HDR_DISABLE; return 0; err: hdmi_tx_deinit_features(hdmi_ctrl, deinit_features); @@ -2878,11 +2889,12 @@ static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) packet_header = type_code | (version << 8) | (length << 16); DSS_REG_W(io, HDMI_GENERIC0_HDR, packet_header); - packet_payload = (ctrl->hdr_data.eotf << 8); + packet_payload = (ctrl->hdr_ctrl.hdr_stream.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); + packet_payload |= + (descriptor_id << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + 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__); @@ -2891,44 +2903,56 @@ static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) } 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); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[0])) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[0]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[0]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + 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); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[1])) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[1]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[1]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + 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); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.display_primaries_x[2])) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[2]) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + display_primaries_y[2]) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.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); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.white_point_x)) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.white_point_y) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.white_point_y) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.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); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.max_luminance)) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream.min_luminance) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream.min_luminance) << 16) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + 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); + (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + max_content_light_level)) + | (HDMI_GET_LSB(ctrl->hdr_ctrl.hdr_stream. + max_average_light_level) << 8) + | (HDMI_GET_MSB(ctrl->hdr_ctrl.hdr_stream. + max_average_light_level) << 16); DSS_REG_W(io, HDMI_GENERIC0_6, packet_payload); enable_packet_control: @@ -2943,6 +2967,32 @@ enable_packet_control: DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control); } +static void hdmi_panel_clear_hdr_infoframe(struct hdmi_tx_ctrl *ctrl) +{ + u32 packet_control = 0; + 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; + } + + packet_control = DSS_REG_R_ND(io, HDMI_GEN_PKT_CTRL); + packet_control &= ~HDMI_GEN_PKT_CTRL_CLR_MASK; + 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 3469b8a5819f..ad02003631f6 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -21,6 +21,7 @@ #include "mdss_hdmi_audio.h" #define MAX_SWITCH_NAME_SIZE 5 +#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7 enum hdmi_tx_io_type { HDMI_TX_CORE_IO, @@ -90,7 +91,7 @@ struct hdmi_tx_ctrl { struct msm_ext_disp_audio_setup_params audio_params; struct msm_ext_disp_init_data ext_audio_data; struct work_struct fps_work; - struct mdp_hdr_stream hdr_data; + struct mdp_hdr_stream_ctrl hdr_ctrl; spinlock_t hpd_state_lock; @@ -116,6 +117,7 @@ struct hdmi_tx_ctrl { u8 hdcp_status; u8 spd_vendor_name[9]; u8 spd_product_description[17]; + u8 curr_hdr_state; bool hdcp_feature_on; bool hpd_disabled; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index 827013d06412..5bc46d8c8f92 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -16,6 +16,7 @@ #include <linux/io.h> #include <linux/delay.h> #include <linux/msm_mdp.h> +#include <linux/msm_mdp_ext.h> #include "mdss_hdmi_util.h" #define RESOLUTION_NAME_STR_LEN 30 @@ -1811,3 +1812,51 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl) return rc; } + +u8 hdmi_hdr_get_ops(u8 curr_state, u8 new_state) +{ + + /** There could be 3 valid state transitions: + * 1. HDR_DISABLE -> HDR_ENABLE + * + * In this transition, we shall start sending + * HDR metadata with metadata from the HDR clip + * + * 2. HDR_ENABLE -> HDR_RESET + * + * In this transition, we will keep sending + * HDR metadata but with EOTF and metadata as 0 + * + * 3. HDR_RESET -> HDR_ENABLE + * + * In this transition, we will start sending + * HDR metadata with metadata from the HDR clip + * + * 4. HDR_RESET -> HDR_DISABLE + * + * In this transition, we will stop sending + * metadata to the sink and clear PKT_CTRL register + * bits. + */ + + if ((curr_state == HDR_DISABLE) + && (new_state == HDR_ENABLE)) { + pr_debug("State changed HDR_DISABLE ---> HDR_ENABLE\n"); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_ENABLE) + && (new_state == HDR_RESET)) { + pr_debug("State changed HDR_ENABLE ---> HDR_RESET\n"); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_RESET) + && (new_state == HDR_ENABLE)) { + pr_debug("State changed HDR_RESET ---> HDR_ENABLE\n"); + return HDR_SEND_INFO; + } else if ((curr_state == HDR_RESET) + && (new_state == HDR_DISABLE)) { + pr_debug("State changed HDR_RESET ---> HDR_DISABLE\n"); + return HDR_CLEAR_INFO; + } + + pr_debug("Unsupported OR no state change\n"); + return HDR_UNSUPPORTED_OP; +} diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h index 4fd659616bcc..fe554f8e9e67 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -425,6 +425,12 @@ enum hdmi_tx_hdcp2p2_rxstatus_intr_mask { RXSTATUS_REAUTH_REQ = BIT(14), }; +enum hdmi_hdr_op { + HDR_UNSUPPORTED_OP, + HDR_SEND_INFO, + HDR_CLEAR_INFO +}; + struct hdmi_tx_hdcp2p2_ddc_data { enum hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask; u32 timeout_ms; @@ -518,5 +524,5 @@ void hdmi_hdcp2p2_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl); int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl); int hdmi_utils_get_timeout_in_hysnc(struct msm_hdmi_mode_timing_info *timing, u32 timeout_ms); - +u8 hdmi_hdr_get_ops(u8 curr_state, u8 new_state); #endif /* __HDMI_UTIL_H__ */ diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index da9ee3bcc525..61b5f8eaa7f9 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -821,4 +821,26 @@ struct mdp_hdr_stream { uint32_t content_type; uint32_t reserved[5]; }; + +/* hdr hdmi state takes possible values of 1, 2 and 4 respectively */ +#define HDR_ENABLE (1 << 0) +#define HDR_DISABLE (1 << 1) +#define HDR_RESET (1 << 2) + +/* + * HDR Control + * This encapsulates the HDR metadata as well as a state control + * for the HDR metadata as required by the HDMI spec to send the + * relevant metadata depending on the state of the HDR playback. + * hdr_state: Controls HDR state, takes values HDR_ENABLE, HDR_DISABLE + * and HDR_RESET. + * hdr_meta: Metadata sent by the userspace for the HDR clip. + */ + +#define DRM_MSM_EXT_PANEL_HDR_CTRL +struct mdp_hdr_stream_ctrl { + __u8 hdr_state; /* HDR state */ + struct mdp_hdr_stream hdr_stream; /* HDR metadata */ +}; + #endif |