diff --git a/msm/dp/dp_hdcp2p2.c b/msm/dp/dp_hdcp2p2.c index f71c25e66c..61404be550 100644 --- a/msm/dp/dp_hdcp2p2.c +++ b/msm/dp/dp_hdcp2p2.c @@ -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) diff --git a/msm/sde_hdcp.h b/msm/sde_hdcp.h index 5c1dc4af20..49a6a951f5 100644 --- a/msm/sde_hdcp.h +++ b/msm/sde_hdcp.h @@ -51,6 +51,7 @@ struct sde_hdcp_stream { u8 stream_id; u8 virtual_channel; u32 stream_handle; + bool active; }; struct sde_hdcp_init_data { diff --git a/msm/sde_hdcp_2x.c b/msm/sde_hdcp_2x.c index f578e09cd2..5131bc3f9a 100644 --- a/msm/sde_hdcp_2x.c +++ b/msm/sde_hdcp_2x.c @@ -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; @@ -301,6 +300,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); } @@ -671,62 +673,37 @@ 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; } } @@ -734,62 +711,78 @@ static void sde_hdcp_2x_open_stream(struct sde_hdcp_2x_ctrl *hdcp) sde_hdcp_2x_query_stream(hdcp); } -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 +806,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 +833,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 +860,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 +907,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 +950,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 +1005,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 +1030,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 +1037,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); } diff --git a/msm/sde_hdcp_2x.h b/msm/sde_hdcp_2x.h index cfcd7ce1b5..4669564dec 100644 --- a/msm/sde_hdcp_2x.h +++ b/msm/sde_hdcp_2x.h @@ -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