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>
This commit is contained in:
Ch Ganesh Kumar 2017-08-18 11:45:42 +05:30
parent 6f777b2385
commit 05f00d16b6
5 changed files with 179 additions and 50 deletions

View file

@ -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);
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)
{

View file

@ -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;

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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