Merge "disp: msm: dp: Prevent disconnect from stopping HDCP"

This commit is contained in:
qctecmdr
2019-05-03 02:04:49 -07:00
committed by Gerrit - the friendly Code Review server
5 changed files with 243 additions and 168 deletions

View File

@@ -97,6 +97,9 @@ struct dp_display_private {
struct work_struct connect_work;
struct work_struct attention_work;
struct mutex session_lock;
bool suspended;
bool hdcp_delayed_off;
bool hdcp_abort;
u32 active_stream_cnt;
struct dp_mst mst;
@@ -304,9 +307,23 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
dp = container_of(dw, struct dp_display_private, hdcp_cb_work);
if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted))
if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted) ||
dp->hdcp_abort)
return;
if (dp->suspended) {
pr_debug("System suspending. Delay HDCP operations\n");
queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ);
return;
}
if (dp->hdcp_delayed_off) {
if (dp->hdcp.ops && dp->hdcp.ops->off)
dp->hdcp.ops->off(dp->hdcp.data);
dp_display_update_hdcp_status(dp, true);
dp->hdcp_delayed_off = false;
}
drm_dp_dpcd_readb(dp->aux->drm_aux, DP_SINK_STATUS, &sink_status);
sink_status &= (DP_RECEIVE_PORT_0_STATUS | DP_RECEIVE_PORT_1_STATUS);
if (sink_status < 1) {
@@ -891,9 +908,7 @@ static void dp_display_clean(struct dp_display_private *dp)
dp->power_on = false;
mutex_lock(&dp->session_lock);
dp->ctrl->off(dp->ctrl);
mutex_unlock(&dp->session_lock);
}
static int dp_display_handle_disconnect(struct dp_display_private *dp)
@@ -1649,8 +1664,18 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
goto end;
}
dp->hdcp_abort = true;
cancel_delayed_work_sync(&dp->hdcp_cb_work);
if (dp_display_is_hdcp_enabled(dp) &&
status->hdcp_state != HDCP_STATE_INACTIVE) {
bool off = true;
if (dp->suspended) {
pr_debug("Can't perform HDCP cleanup while suspended. Defer\n");
dp->hdcp_delayed_off = true;
goto clean;
}
flush_delayed_work(&dp->hdcp_cb_work);
if (dp->mst.mst_active) {
dp_display_hdcp_deregister_stream(dp,
@@ -1659,18 +1684,19 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
if (i != dp_panel->stream_id &&
dp->active_panels[i]) {
pr_debug("Streams are still active. Skip disabling HDCP\n");
goto stream;
off = false;
}
}
}
if (dp->hdcp.ops->off)
dp->hdcp.ops->off(dp->hdcp.data);
dp_display_update_hdcp_status(dp, true);
if (off) {
if (dp->hdcp.ops->off)
dp->hdcp.ops->off(dp->hdcp.data);
dp_display_update_hdcp_status(dp, true);
}
}
stream:
clean:
if (dp_panel->audio_supported)
dp_panel->audio->off(dp_panel->audio);
@@ -1683,8 +1709,10 @@ end:
static int dp_display_disable(struct dp_display *dp_display, void *panel)
{
int i;
struct dp_display_private *dp = NULL;
struct dp_panel *dp_panel = NULL;
struct dp_link_hdcp_status *status;
if (!dp_display || !panel) {
pr_err("invalid input\n");
@@ -1693,6 +1721,7 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel)
dp = container_of(dp_display, struct dp_display_private, dp_display);
dp_panel = panel;
status = &dp->link->hdcp_status;
mutex_lock(&dp->session_lock);
@@ -1703,6 +1732,16 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel)
dp_display_stream_disable(dp, dp_panel);
dp_display_update_dsc_resources(dp, dp_panel, false);
dp->hdcp_abort = false;
for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) {
if (dp->active_panels[i]) {
if (status->hdcp_state != HDCP_STATE_AUTHENTICATED)
queue_delayed_work(dp->wq, &dp->hdcp_cb_work,
HZ/4);
break;
}
}
end:
mutex_unlock(&dp->session_lock);
return 0;
@@ -2590,14 +2629,24 @@ static int dp_display_remove(struct platform_device *pdev)
static int dp_pm_prepare(struct device *dev)
{
struct dp_display_private *dp = container_of(g_dp_display,
struct dp_display_private, dp_display);
dp_display_set_mst_state(g_dp_display, PM_SUSPEND);
dp->suspended = true;
return 0;
}
static void dp_pm_complete(struct device *dev)
{
struct dp_display_private *dp = container_of(g_dp_display,
struct dp_display_private, dp_display);
dp_display_set_mst_state(g_dp_display, PM_DEFAULT);
dp->suspended = false;
}
static const struct dev_pm_ops dp_pm_ops = {

View File

@@ -238,19 +238,22 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl)
static int dp_hdcp2p2_register(void *input, bool mst_enabled)
{
int rc;
enum sde_hdcp_2x_device_type device_type;
struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
struct dp_hdcp2p2_ctrl *ctrl = input;
struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_ENABLE};
rc = dp_hdcp2p2_valid_handle(ctrl);
if (rc)
return rc;
if (mst_enabled)
device_type = HDCP_TXMTR_DP_MST;
cdata.device_type = HDCP_TXMTR_DP_MST;
else
device_type = HDCP_TXMTR_DP;
cdata.device_type = HDCP_TXMTR_DP;
return sde_hdcp_2x_enable(ctrl->lib_ctx, device_type);
cdata.context = ctrl->lib_ctx;
rc = ctrl->lib->wakeup(&cdata);
return rc;
}
static int dp_hdcp2p2_on(void *input)
@@ -276,25 +279,20 @@ static void dp_hdcp2p2_off(void *input)
{
int rc;
struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};
struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_DISABLE};
rc = dp_hdcp2p2_valid_handle(ctrl);
if (rc)
return;
if (atomic_read(&ctrl->auth_state) != HDCP_STATE_AUTH_FAIL) {
cdata.cmd = HDCP_2X_CMD_STOP;
cdata.context = ctrl->lib_ctx;
dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
}
dp_hdcp2p2_set_interrupts(ctrl, false);
dp_hdcp2p2_reset(ctrl);
kthread_park(ctrl->thread);
sde_hdcp_2x_disable(ctrl->lib_ctx);
cdata.context = ctrl->lib_ctx;
ctrl->lib->wakeup(&cdata);
}
static int dp_hdcp2p2_authenticate(void *input)

View File

@@ -51,6 +51,7 @@ struct sde_hdcp_stream {
u8 stream_id;
u8 virtual_channel;
u32 stream_handle;
bool active;
};
struct sde_hdcp_init_data {

View File

@@ -49,6 +49,7 @@ struct sde_hdcp_2x_ctrl {
u32 timeout_left;
u32 wait_timeout_ms;
u32 total_message_length;
atomic_t enable_pending;
bool no_stored_km;
bool feature_supported;
bool force_encryption;
@@ -66,8 +67,6 @@ struct sde_hdcp_2x_ctrl {
u8 min_enc_level;
struct list_head stream_handles;
u8 stream_count;
struct stream_info *streams;
u8 num_streams;
struct task_struct *thread;
struct completion response_completion;
@@ -194,10 +193,8 @@ static int sde_hdcp_2x_get_next_message(struct sde_hdcp_2x_ctrl *hdcp,
case REP_SEND_RECV_ID_LIST:
return REP_SEND_ACK;
case REP_STREAM_MANAGE:
if (hdcp->resend_stream_manage)
return REP_STREAM_MANAGE;
else
return REP_STREAM_READY;
hdcp->resend_stream_manage = false;
return REP_STREAM_READY;
default:
pr_err("Unknown message ID (%d)\n", hdcp->last_msg);
return -EINVAL;
@@ -301,6 +298,9 @@ static bool sde_hdcp_2x_client_feature_supported(void *data)
{
struct sde_hdcp_2x_ctrl *hdcp = data;
while (atomic_read(&hdcp->enable_pending))
usleep_range(1000, 1500);
return hdcp2_feature_supported(hdcp->hdcp2_ctx);
}
@@ -404,6 +404,12 @@ static void sde_hdcp_2x_query_stream(struct sde_hdcp_2x_ctrl *hdcp)
return;
}
if (!hdcp->authenticated &&
hdcp->app_data.response.data[0] != REP_SEND_ACK) {
pr_debug("invalid state. HDCP repeater not authenticated\n");
return;
}
rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_QUERY_STREAM,
&hdcp->app_data);
if (rc)
@@ -418,8 +424,11 @@ static void sde_hdcp_2x_query_stream(struct sde_hdcp_2x_ctrl *hdcp)
pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name(
hdcp->app_data.response.data[0]));
exit:
if (!rc && !atomic_read(&hdcp->hdcp_off))
if (!rc && !atomic_read(&hdcp->hdcp_off)) {
/* Modify last message to ensure the proper message is sent */
hdcp->last_msg = REP_SEND_ACK;
sde_hdcp_2x_send_message(hdcp);
}
}
static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp,
@@ -594,7 +603,9 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name(out_msg));
if (msg[0] == REP_STREAM_READY && out_msg != REP_STREAM_MANAGE) {
if (!hdcp->authenticated) {
if (hdcp->resend_stream_manage) {
pr_debug("resend stream management\n");
} else if (!hdcp->authenticated) {
rc = hdcp2_app_comm(hdcp->hdcp2_ctx,
HDCP2_CMD_EN_ENCRYPTION,
&hdcp->app_data);
@@ -622,9 +633,8 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
if (msg[0] == LC_SEND_L_PRIME && out_msg == LC_INIT)
hdcp->resend_lc_init = true;
hdcp->resend_stream_manage = false;
if (msg[0] == REP_STREAM_READY && out_msg == REP_STREAM_MANAGE)
hdcp->resend_stream_manage = true;
pr_debug("resend %s\n", sde_hdcp_2x_message_name(out_msg));
if (out_msg == AKE_NO_STORED_KM)
hdcp->no_stored_km = true;
@@ -671,125 +681,122 @@ static struct list_head *sde_hdcp_2x_stream_present(
return entry;
}
static void sde_hdcp_2x_open_stream(struct sde_hdcp_2x_ctrl *hdcp)
static void sde_hdcp_2x_manage_stream(struct sde_hdcp_2x_ctrl *hdcp)
{
int rc;
size_t iterations, i;
u8 stream_id;
u8 virtual_channel;
u32 stream_handle = 0;
struct list_head *entry;
struct list_head *element;
struct sde_hdcp_stream *stream_entry;
bool query_streams = false;
if (!hdcp->streams) {
pr_err("Array of streams to register is NULL\n");
return;
}
iterations = min(hdcp->num_streams, (u8)(MAX_STREAM_COUNT));
for (i = 0; i < iterations; i++) {
if (hdcp->stream_count == MAX_STREAM_COUNT) {
pr_debug("Registered the maximum amount of streams\n");
break;
}
stream_id = hdcp->streams[i].stream_id;
virtual_channel = hdcp->streams[i].virtual_channel;
pr_debug("Opening stream %d, virtual channel %d\n",
stream_id, virtual_channel);
if (sde_hdcp_2x_stream_present(hdcp, stream_id,
virtual_channel)) {
pr_debug("Stream %d, virtual channel %d already open\n",
stream_id, virtual_channel);
continue;
}
rc = hdcp2_open_stream(hdcp->hdcp2_ctx, virtual_channel,
stream_id, &stream_handle);
if (rc) {
pr_err("Unable to open stream %d, virtual channel %d\n",
stream_id, virtual_channel);
} else {
struct sde_hdcp_stream *stream =
kzalloc(sizeof(struct sde_hdcp_stream),
GFP_KERNEL);
if (!stream)
break;
INIT_LIST_HEAD(&stream->list);
stream->stream_handle = stream_handle;
stream->stream_id = stream_id;
stream->virtual_channel = virtual_channel;
list_add(&stream->list, &hdcp->stream_handles);
hdcp->stream_count++;
entry = hdcp->stream_handles.next;
while (entry != &hdcp->stream_handles) {
stream_entry = list_entry(entry, struct sde_hdcp_stream, list);
element = entry;
entry = entry->next;
if (!stream_entry->active) {
hdcp2_close_stream(hdcp->hdcp2_ctx,
stream_entry->stream_handle);
hdcp->stream_count--;
list_del(element);
kzfree(stream_entry);
query_streams = true;
} else if (!stream_entry->stream_handle) {
if (hdcp2_open_stream(hdcp->hdcp2_ctx,
stream_entry->virtual_channel,
stream_entry->stream_id,
&stream_entry->stream_handle))
pr_err("Unable to open stream %d, virtual channel %d\n",
stream_entry->stream_id,
stream_entry->virtual_channel);
else
query_streams = true;
}
}
if (query_streams && hdcp->authenticated)
sde_hdcp_2x_query_stream(hdcp);
if (query_streams) {
if (hdcp->authenticated) {
sde_hdcp_2x_query_stream(hdcp);
} else if (hdcp->last_msg == REP_STREAM_MANAGE ||
hdcp->last_msg == REP_STREAM_READY) {
hdcp->resend_stream_manage = true;
}
}
}
static void sde_hdcp_2x_close_stream(struct sde_hdcp_2x_ctrl *hdcp)
static bool sde_hdcp_2x_remove_streams(struct sde_hdcp_2x_ctrl *hdcp,
struct stream_info *streams, u8 num_streams)
{
int rc;
size_t iterations, i;
u8 i;
u8 stream_id;
u8 virtual_channel;
struct list_head *entry;
struct sde_hdcp_stream *stream_entry;
bool query_streams = false;
if (!hdcp->streams) {
pr_err("Array of streams to register is NULL\n");
return;
}
iterations = min(hdcp->num_streams, (u8)(MAX_STREAM_COUNT));
for (i = 0; i < iterations; i++) {
if (hdcp->stream_count == 0) {
pr_debug("No streams are currently registered\n");
return;
}
stream_id = hdcp->streams[i].stream_id;
virtual_channel = hdcp->streams[i].virtual_channel;
pr_debug("Closing stream %d, virtual channel %d\n",
stream_id, virtual_channel);
bool changed = false;
for (i = 0 ; i < num_streams; i++) {
stream_id = streams[i].stream_id;
virtual_channel = streams[i].virtual_channel;
entry = sde_hdcp_2x_stream_present(hdcp, stream_id,
virtual_channel);
if (!entry) {
pr_err("Unable to find stream %d, virtual channel %d\n"
, stream_id, virtual_channel);
if (!entry)
continue;
}
stream_entry = list_entry(entry, struct sde_hdcp_stream,
list);
rc = hdcp2_close_stream(hdcp->hdcp2_ctx,
stream_entry->stream_handle);
if (rc)
pr_err("Unable to close stream %d, virtual channel %d\n"
, stream_id, virtual_channel);
hdcp->stream_count--;
list_del(entry);
kzfree(stream_entry);
query_streams = true;
if (!stream_entry->stream_handle) {
/* Stream wasn't fully initialized so remove it */
hdcp->stream_count--;
list_del(entry);
kzfree(stream_entry);
} else {
stream_entry->active = false;
}
changed = true;
}
if (query_streams && hdcp->authenticated)
sde_hdcp_2x_query_stream(hdcp);
return changed;
}
static bool sde_hdcp_2x_add_streams(struct sde_hdcp_2x_ctrl *hdcp,
struct stream_info *streams, u8 num_streams)
{
u8 i;
u8 stream_id;
u8 virtual_channel;
struct sde_hdcp_stream *stream;
bool changed = false;
for (i = 0 ; i < num_streams; i++) {
stream_id = streams[i].stream_id;
virtual_channel = streams[i].virtual_channel;
if (sde_hdcp_2x_stream_present(hdcp, stream_id,
virtual_channel))
continue;
stream = kzalloc(sizeof(struct sde_hdcp_stream), GFP_KERNEL);
if (!stream)
continue;
INIT_LIST_HEAD(&stream->list);
stream->stream_handle = 0;
stream->stream_id = stream_id;
stream->virtual_channel = virtual_channel;
stream->active = true;
list_add(&stream->list, &hdcp->stream_handles);
hdcp->stream_count++;
changed = true;
}
return changed;
}
/** sde_hdcp_2x_wakeup() - wakeup the module to execute a requested command
* @data: data required for executing corresponding command.
*
@@ -813,18 +820,22 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)
hdcp->timeout_left = data->timeout;
hdcp->total_message_length = data->total_message_length;
hdcp->min_enc_level = data->min_enc_level;
hdcp->streams = data->streams;
hdcp->num_streams = data->num_streams;
if (!completion_done(&hdcp->response_completion))
complete_all(&hdcp->response_completion);
kfifo_put(&hdcp->cmd_q, data->cmd);
switch (data->cmd) {
case HDCP_2X_CMD_ENABLE:
if (!atomic_cmpxchg(&hdcp->enable_pending, 0, 1)) {
hdcp->device_type = data->device_type;
kfifo_put(&hdcp->cmd_q, data->cmd);
wake_up(&hdcp->wait_q);
}
break;
case HDCP_2X_CMD_STOP:
atomic_set(&hdcp->hdcp_off, 1);
kfifo_put(&hdcp->cmd_q, data->cmd);
kthread_park(hdcp->thread);
break;
case HDCP_2X_CMD_START:
@@ -836,10 +847,26 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)
hdcp->timeout_left = 0;
atomic_set(&hdcp->hdcp_off, 0);
kfifo_put(&hdcp->cmd_q, data->cmd);
kthread_unpark(hdcp->thread);
wake_up(&hdcp->wait_q);
break;
case HDCP_2X_CMD_OPEN_STREAMS:
if (sde_hdcp_2x_add_streams(hdcp, data->streams,
data->num_streams)) {
kfifo_put(&hdcp->cmd_q, data->cmd);
wake_up(&hdcp->wait_q);
}
break;
case HDCP_2X_CMD_CLOSE_STREAMS:
if (sde_hdcp_2x_remove_streams(hdcp, data->streams,
data->num_streams)) {
kfifo_put(&hdcp->cmd_q, data->cmd);
wake_up(&hdcp->wait_q);
}
break;
default:
kfifo_put(&hdcp->cmd_q, data->cmd);
wake_up(&hdcp->wait_q);
break;
}
@@ -847,6 +874,30 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)
return rc;
}
static void sde_hdcp_2x_enable(struct sde_hdcp_2x_ctrl *hdcp)
{
if (!hdcp)
return;
if (hdcp->hdcp2_ctx) {
pr_debug("HDCP library context already acquired\n");
return;
}
hdcp->hdcp2_ctx = hdcp2_init(hdcp->device_type);
if (!hdcp->hdcp2_ctx)
pr_err("Unable to acquire HDCP library handle\n");
}
static void sde_hdcp_2x_disable(struct sde_hdcp_2x_ctrl *hdcp)
{
if (!hdcp->hdcp2_ctx)
return;
hdcp2_deinit(hdcp->hdcp2_ctx);
hdcp->hdcp2_ctx = NULL;
}
static int sde_hdcp_2x_main(void *data)
{
struct sde_hdcp_2x_ctrl *hdcp = data;
@@ -870,6 +921,15 @@ static int sde_hdcp_2x_main(void *data)
continue;
switch (cmd) {
case HDCP_2X_CMD_ENABLE:
sde_hdcp_2x_enable(hdcp);
atomic_set(&hdcp->enable_pending, 0);
break;
case HDCP_2X_CMD_DISABLE:
if (!atomic_xchg(&hdcp->hdcp_off, 1))
sde_hdcp_2x_clean(hdcp);
sde_hdcp_2x_disable(hdcp);
break;
case HDCP_2X_CMD_START:
sde_hdcp_2x_init(hdcp);
break;
@@ -904,10 +964,8 @@ static int sde_hdcp_2x_main(void *data)
sde_hdcp_2x_query_stream(hdcp);
break;
case HDCP_2X_CMD_OPEN_STREAMS:
sde_hdcp_2x_open_stream(hdcp);
break;
case HDCP_2X_CMD_CLOSE_STREAMS:
sde_hdcp_2x_close_stream(hdcp);
sde_hdcp_2x_manage_stream(hdcp);
break;
default:
break;
@@ -961,6 +1019,7 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data)
init_waitqueue_head(&hdcp->wait_q);
atomic_set(&hdcp->hdcp_off, 1);
atomic_set(&hdcp->enable_pending, 0);
init_completion(&hdcp->response_completion);
@@ -985,40 +1044,6 @@ unlock:
return rc;
}
int sde_hdcp_2x_enable(void *data, enum sde_hdcp_2x_device_type device_type)
{
int rc = 0;
struct sde_hdcp_2x_ctrl *hdcp = data;
if (!hdcp)
return -EINVAL;
if (hdcp->hdcp2_ctx) {
pr_debug("HDCP library context already acquired\n");
return 0;
}
hdcp->device_type = device_type;
hdcp->hdcp2_ctx = hdcp2_init(hdcp->device_type);
if (!hdcp->hdcp2_ctx) {
pr_err("Unable to acquire HDCP library handle\n");
return -ENOMEM;
}
return rc;
}
void sde_hdcp_2x_disable(void *data)
{
struct sde_hdcp_2x_ctrl *hdcp = data;
if (!hdcp->hdcp2_ctx)
return;
hdcp2_deinit(hdcp->hdcp2_ctx);
hdcp->hdcp2_ctx = NULL;
}
void sde_hdcp_2x_deregister(void *data)
{
struct sde_hdcp_2x_ctrl *hdcp = data;
@@ -1026,7 +1051,7 @@ void sde_hdcp_2x_deregister(void *data)
if (!hdcp)
return;
sde_hdcp_2x_disable(data);
kthread_stop(hdcp->thread);
sde_hdcp_2x_disable(data);
kzfree(hdcp);
}

View File

@@ -32,6 +32,8 @@
*/
enum sde_hdcp_2x_wakeup_cmd {
HDCP_2X_CMD_INVALID,
HDCP_2X_CMD_ENABLE,
HDCP_2X_CMD_DISABLE,
HDCP_2X_CMD_START,
HDCP_2X_CMD_START_AUTH,
HDCP_2X_CMD_STOP,
@@ -79,6 +81,7 @@ enum sde_hdcp_2x_device_type {
/**
* struct sde_hdcp_2x_lib_wakeup_data - command and data send to HDCP driver
* @cmd: command type
* @device_type type of device in use by the HDCP driver
* @context: void pointer to the HDCP driver instance
* @buf: message received from the sink
* @buf_len: length of message received from the sink
@@ -88,6 +91,7 @@ enum sde_hdcp_2x_device_type {
*/
struct sde_hdcp_2x_wakeup_data {
enum sde_hdcp_2x_wakeup_cmd cmd;
enum sde_hdcp_2x_device_type device_type;
void *context;
uint32_t total_message_length;
uint32_t timeout;
@@ -211,7 +215,5 @@ struct sde_hdcp_2x_register_data {
/* functions for the HDCP 2.2 state machine module */
int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data);
int sde_hdcp_2x_enable(void *data, enum sde_hdcp_2x_device_type device_type);
void sde_hdcp_2x_disable(void *data);
void sde_hdcp_2x_deregister(void *data);
#endif