drm/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: I229183531f7ccb48579e74d02e0a1dea1cb945ff Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
This commit is contained in:
parent
502914e130
commit
033b9198d0
9 changed files with 153 additions and 18 deletions
|
@ -1961,6 +1961,30 @@ enable_packet_control:
|
|||
hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control);
|
||||
}
|
||||
|
||||
static void sde_hdmi_clear_hdr_infoframe(struct sde_hdmi *display)
|
||||
{
|
||||
struct hdmi *hdmi;
|
||||
struct drm_connector *connector;
|
||||
u32 packet_control = 0;
|
||||
|
||||
if (!display) {
|
||||
SDE_ERROR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdmi = display->ctrl.ctrl;
|
||||
connector = display->ctrl.ctrl->connector;
|
||||
|
||||
if (!hdmi || !connector) {
|
||||
SDE_ERROR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL);
|
||||
packet_control &= ~HDMI_GEN_PKT_CTRL_CLR_MASK;
|
||||
hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control);
|
||||
}
|
||||
|
||||
int sde_hdmi_set_property(struct drm_connector *connector,
|
||||
struct drm_connector_state *state,
|
||||
int property_index,
|
||||
|
@ -2305,15 +2329,28 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector,
|
|||
void *display,
|
||||
struct msm_display_kickoff_params *params)
|
||||
{
|
||||
struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
|
||||
struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl;
|
||||
u8 hdr_op;
|
||||
|
||||
if (!connector || !display || !params) {
|
||||
pr_err("Invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (connector->hdr_supported)
|
||||
sde_hdmi_panel_set_hdr_infoframe(display,
|
||||
params->hdr_metadata);
|
||||
hdr_ctrl = params->hdr_ctrl;
|
||||
|
||||
hdr_op = sde_hdmi_hdr_get_ops(hdmi_display->curr_hdr_state,
|
||||
hdr_ctrl->hdr_state);
|
||||
|
||||
if (hdr_op == HDR_SEND_INFO) {
|
||||
if (connector->hdr_supported)
|
||||
sde_hdmi_panel_set_hdr_infoframe(display,
|
||||
&hdr_ctrl->hdr_meta);
|
||||
} else if (hdr_op == HDR_CLEAR_INFO)
|
||||
sde_hdmi_clear_hdr_infoframe(display);
|
||||
|
||||
hdmi_display->curr_hdr_state = hdr_ctrl->hdr_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -147,6 +147,7 @@ struct sde_hdmi {
|
|||
u32 hdcp22_present;
|
||||
u8 hdcp_status;
|
||||
u32 enc_lvl;
|
||||
u8 curr_hdr_state;
|
||||
bool auth_state;
|
||||
bool sink_hdcp22_support;
|
||||
bool src_hdcp22_support;
|
||||
|
@ -198,6 +199,8 @@ enum hdmi_tx_scdc_access_type {
|
|||
#define HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2
|
||||
#define HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
|
||||
|
||||
#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7
|
||||
|
||||
/* Maximum pixel clock rates for hdmi tx */
|
||||
#define HDMI_DEFAULT_MAX_PCLK_RATE 148500
|
||||
#define HDMI_TX_3_MAX_PCLK_RATE 297000
|
||||
|
|
|
@ -518,12 +518,17 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
|
|||
{
|
||||
struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
|
||||
struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
|
||||
struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
|
||||
|
||||
/* need to update hdcp info here to ensure right HDCP support*/
|
||||
sde_hdmi_update_hdcp_info(hdmi->connector);
|
||||
|
||||
/* start HDCP authentication */
|
||||
sde_hdmi_start_hdcp(hdmi->connector);
|
||||
|
||||
/* reset HDR state */
|
||||
display->curr_hdr_state = HDR_DISABLE;
|
||||
}
|
||||
|
||||
static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge)
|
||||
|
|
|
@ -68,6 +68,15 @@ static void sde_hdmi_hdcp2p2_ddc_clear_status(struct sde_hdmi *display)
|
|||
hdmi_write(hdmi, HDMI_HDCP2P2_DDC_STATUS, reg_val);
|
||||
}
|
||||
|
||||
static const char *sde_hdmi_hdr_sname(enum sde_hdmi_hdr_state hdr_state)
|
||||
{
|
||||
switch (hdr_state) {
|
||||
case HDR_DISABLE: return "HDR_DISABLE";
|
||||
case HDR_ENABLE: return "HDR_ENABLE";
|
||||
default: return "HDR_INVALID_STATE";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sde_hdmi_dump_regs - utility to dump HDMI regs
|
||||
* @hdmi_display: Pointer to private display handle
|
||||
|
@ -898,3 +907,50 @@ int sde_hdmi_sink_dc_support(struct drm_connector *connector,
|
|||
|
||||
return dc_format;
|
||||
}
|
||||
|
||||
u8 sde_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_ENABLE
|
||||
*
|
||||
* In this transition, we will keep sending
|
||||
* HDR metadata but with EOTF and metadata as 0
|
||||
*
|
||||
* 3. HDR_ENABLE -> 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)) {
|
||||
HDMI_UTIL_DEBUG("State changed %s ---> %s\n",
|
||||
sde_hdmi_hdr_sname(curr_state),
|
||||
sde_hdmi_hdr_sname(new_state));
|
||||
return HDR_SEND_INFO;
|
||||
} else if ((curr_state == HDR_ENABLE)
|
||||
&& (new_state == HDR_ENABLE)) {
|
||||
HDMI_UTIL_DEBUG("State changed %s ---> %s\n",
|
||||
sde_hdmi_hdr_sname(curr_state),
|
||||
sde_hdmi_hdr_sname(new_state));
|
||||
return HDR_SEND_INFO;
|
||||
} else if ((curr_state == HDR_ENABLE)
|
||||
&& (new_state == HDR_DISABLE)) {
|
||||
HDMI_UTIL_DEBUG("State changed %s ---> %s\n",
|
||||
sde_hdmi_hdr_sname(curr_state),
|
||||
sde_hdmi_hdr_sname(new_state));
|
||||
return HDR_CLEAR_INFO;
|
||||
}
|
||||
|
||||
HDMI_UTIL_DEBUG("Unsupported OR no state change\n");
|
||||
return HDR_UNSUPPORTED_OP;
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,17 @@ enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask {
|
|||
RXSTATUS_REAUTH_REQ = BIT(14),
|
||||
};
|
||||
|
||||
enum sde_hdmi_hdr_state {
|
||||
HDR_DISABLE,
|
||||
HDR_ENABLE
|
||||
};
|
||||
|
||||
enum sde_hdmi_hdr_op {
|
||||
HDR_UNSUPPORTED_OP,
|
||||
HDR_SEND_INFO,
|
||||
HDR_CLEAR_INFO
|
||||
};
|
||||
|
||||
struct sde_hdmi_tx_hdcp2p2_ddc_data {
|
||||
enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask;
|
||||
u32 timeout_ms;
|
||||
|
@ -170,4 +181,6 @@ bool sde_hdmi_validate_pixclk(struct drm_connector *connector,
|
|||
unsigned long pclk);
|
||||
int sde_hdmi_sink_dc_support(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode);
|
||||
u8 sde_hdmi_hdr_get_ops(u8 curr_state,
|
||||
u8 new_state);
|
||||
#endif /* _SDE_HDMI_UTIL_H_ */
|
||||
|
|
|
@ -144,7 +144,7 @@ enum msm_mdp_conn_property {
|
|||
/* blob properties, always put these first */
|
||||
CONNECTOR_PROP_SDE_INFO,
|
||||
CONNECTOR_PROP_HDR_INFO,
|
||||
CONNECTOR_PROP_HDR_METADATA,
|
||||
CONNECTOR_PROP_HDR_CONTROL,
|
||||
|
||||
/* # of blob properties */
|
||||
CONNECTOR_PROP_BLOBCOUNT,
|
||||
|
@ -237,10 +237,10 @@ struct msm_display_info {
|
|||
|
||||
/**
|
||||
* struct - msm_display_kickoff_params - info for display features at kickoff
|
||||
* @hdr_metadata: HDR metadata info passed from userspace
|
||||
* @hdr_ctrl: HDR control info passed from userspace
|
||||
*/
|
||||
struct msm_display_kickoff_params {
|
||||
struct drm_msm_ext_panel_hdr_metadata *hdr_metadata;
|
||||
struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,7 +83,7 @@ int sde_connector_pre_kickoff(struct drm_connector *connector)
|
|||
if (!c_conn->ops.pre_kickoff)
|
||||
return 0;
|
||||
|
||||
params.hdr_metadata = &c_state->hdr_meta;
|
||||
params.hdr_ctrl = &c_state->hdr_ctrl;
|
||||
|
||||
rc = c_conn->ops.pre_kickoff(connector, c_conn->display, ¶ms);
|
||||
|
||||
|
@ -247,6 +247,7 @@ static int _sde_connector_set_hdr_info(
|
|||
void *usr_ptr)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl;
|
||||
struct drm_msm_ext_panel_hdr_metadata *hdr_meta;
|
||||
int i;
|
||||
|
||||
|
@ -262,21 +263,26 @@ static int _sde_connector_set_hdr_info(
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
|
||||
memset(&c_state->hdr_ctrl, 0, sizeof(c_state->hdr_ctrl));
|
||||
|
||||
if (!usr_ptr) {
|
||||
SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n");
|
||||
SDE_DEBUG_CONN(c_conn, "hdr control cleared\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (copy_from_user(&c_state->hdr_meta,
|
||||
if (copy_from_user(&c_state->hdr_ctrl,
|
||||
(void __user *)usr_ptr,
|
||||
sizeof(*hdr_meta))) {
|
||||
SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n");
|
||||
sizeof(*hdr_ctrl))) {
|
||||
SDE_ERROR_CONN(c_conn, "failed to copy hdr control\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
hdr_meta = &c_state->hdr_meta;
|
||||
hdr_ctrl = &c_state->hdr_ctrl;
|
||||
|
||||
SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n",
|
||||
hdr_ctrl->hdr_state);
|
||||
|
||||
hdr_meta = &hdr_ctrl->hdr_meta;
|
||||
|
||||
SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n",
|
||||
hdr_meta->hdr_supported);
|
||||
|
@ -362,7 +368,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
|
|||
SDE_ERROR("invalid topology_control: 0x%llX\n", val);
|
||||
}
|
||||
|
||||
if (idx == CONNECTOR_PROP_HDR_METADATA) {
|
||||
if (idx == CONNECTOR_PROP_HDR_CONTROL) {
|
||||
rc = _sde_connector_set_hdr_info(c_conn, c_state, (void *)val);
|
||||
if (rc)
|
||||
SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc);
|
||||
|
@ -718,8 +724,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
|
|||
}
|
||||
|
||||
msm_property_install_volatile_range(&c_conn->property_info,
|
||||
"hdr_metadata", 0x0, 0, ~0, 0,
|
||||
CONNECTOR_PROP_HDR_METADATA);
|
||||
"hdr_control", 0x0, 0, ~0, 0,
|
||||
CONNECTOR_PROP_HDR_CONTROL);
|
||||
|
||||
msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
|
||||
0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
|
||||
|
|
|
@ -221,14 +221,14 @@ struct sde_connector {
|
|||
* @out_fb: Pointer to output frame buffer, if applicable
|
||||
* @aspace: Address space for accessing frame buffer objects, if applicable
|
||||
* @property_values: Local cache of current connector property values
|
||||
* @hdr_meta: HDR metadata info passed from userspace
|
||||
* @hdr_ctrl: HDR control info passed from userspace
|
||||
*/
|
||||
struct sde_connector_state {
|
||||
struct drm_connector_state base;
|
||||
struct drm_framebuffer *out_fb;
|
||||
struct msm_gem_address_space *aspace;
|
||||
uint64_t property_values[CONNECTOR_PROP_COUNT];
|
||||
struct drm_msm_ext_panel_hdr_metadata hdr_meta;
|
||||
struct drm_msm_ext_panel_hdr_ctrl hdr_ctrl;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,6 +83,21 @@ struct drm_msm_ext_panel_hdr_metadata {
|
|||
__u32 max_average_light_level; /* max average light level */
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 ENABLE(1)/DISABLE(0)
|
||||
* hdr_meta: Metadata sent by the userspace for the HDR clip
|
||||
*/
|
||||
|
||||
#define DRM_MSM_EXT_PANEL_HDR_CTRL
|
||||
struct drm_msm_ext_panel_hdr_ctrl {
|
||||
__u8 hdr_state; /* HDR state */
|
||||
struct drm_msm_ext_panel_hdr_metadata hdr_meta; /* HDR metadata */
|
||||
};
|
||||
|
||||
/**
|
||||
* HDR sink properties
|
||||
* These are defined as per EDID spec and shall be used by the userspace
|
||||
|
|
Loading…
Add table
Reference in a new issue