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:
parent
6f777b2385
commit
05f00d16b6
5 changed files with 179 additions and 50 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue