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:
Abhinav Kumar 2017-07-14 17:42:54 -07:00
parent 502914e130
commit 033b9198d0
9 changed files with 153 additions and 18 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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, &params);
@ -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);

View file

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

View file

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