Merge "disp: msm: dp: Prevent disconnect from stopping HDCP"
This commit is contained in:
committed by
Gerrit - the friendly Code Review server
commit
c0035372e5
@@ -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 = {
|
||||
|
@@ -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)
|
||||
|
@@ -51,6 +51,7 @@ struct sde_hdcp_stream {
|
||||
u8 stream_id;
|
||||
u8 virtual_channel;
|
||||
u32 stream_handle;
|
||||
bool active;
|
||||
};
|
||||
|
||||
struct sde_hdcp_init_data {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user