Loading msm/dp/dp_display.c +58 −9 Original line number Original line Diff line number Diff line Loading @@ -97,6 +97,9 @@ struct dp_display_private { struct work_struct connect_work; struct work_struct connect_work; struct work_struct attention_work; struct work_struct attention_work; struct mutex session_lock; struct mutex session_lock; bool suspended; bool hdcp_delayed_off; bool hdcp_abort; u32 active_stream_cnt; u32 active_stream_cnt; struct dp_mst mst; struct dp_mst mst; Loading Loading @@ -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); 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; 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); 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); sink_status &= (DP_RECEIVE_PORT_0_STATUS | DP_RECEIVE_PORT_1_STATUS); if (sink_status < 1) { if (sink_status < 1) { Loading Loading @@ -891,9 +908,7 @@ static void dp_display_clean(struct dp_display_private *dp) dp->power_on = false; dp->power_on = false; mutex_lock(&dp->session_lock); dp->ctrl->off(dp->ctrl); dp->ctrl->off(dp->ctrl); mutex_unlock(&dp->session_lock); } } static int dp_display_handle_disconnect(struct dp_display_private *dp) static int dp_display_handle_disconnect(struct dp_display_private *dp) Loading Loading @@ -1649,8 +1664,18 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) goto end; goto end; } } dp->hdcp_abort = true; cancel_delayed_work_sync(&dp->hdcp_cb_work); if (dp_display_is_hdcp_enabled(dp) && if (dp_display_is_hdcp_enabled(dp) && status->hdcp_state != HDCP_STATE_INACTIVE) { 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); flush_delayed_work(&dp->hdcp_cb_work); if (dp->mst.mst_active) { if (dp->mst.mst_active) { dp_display_hdcp_deregister_stream(dp, dp_display_hdcp_deregister_stream(dp, Loading @@ -1659,18 +1684,19 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) if (i != dp_panel->stream_id && if (i != dp_panel->stream_id && dp->active_panels[i]) { dp->active_panels[i]) { pr_debug("Streams are still active. Skip disabling HDCP\n"); pr_debug("Streams are still active. Skip disabling HDCP\n"); goto stream; off = false; } } } } } } if (off) { if (dp->hdcp.ops->off) if (dp->hdcp.ops->off) dp->hdcp.ops->off(dp->hdcp.data); dp->hdcp.ops->off(dp->hdcp.data); dp_display_update_hdcp_status(dp, true); dp_display_update_hdcp_status(dp, true); } } } stream: clean: if (dp_panel->audio_supported) if (dp_panel->audio_supported) dp_panel->audio->off(dp_panel->audio); dp_panel->audio->off(dp_panel->audio); Loading @@ -1683,8 +1709,10 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) static int dp_display_disable(struct dp_display *dp_display, void *panel) static int dp_display_disable(struct dp_display *dp_display, void *panel) { { int i; struct dp_display_private *dp = NULL; struct dp_display_private *dp = NULL; struct dp_panel *dp_panel = NULL; struct dp_panel *dp_panel = NULL; struct dp_link_hdcp_status *status; if (!dp_display || !panel) { if (!dp_display || !panel) { pr_err("invalid input\n"); pr_err("invalid input\n"); Loading @@ -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 = container_of(dp_display, struct dp_display_private, dp_display); dp_panel = panel; dp_panel = panel; status = &dp->link->hdcp_status; mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); Loading @@ -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_stream_disable(dp, dp_panel); dp_display_update_dsc_resources(dp, dp_panel, false); 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: end: mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); return 0; return 0; Loading Loading @@ -2590,14 +2629,24 @@ static int dp_display_remove(struct platform_device *pdev) static int dp_pm_prepare(struct device *dev) 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_display_set_mst_state(g_dp_display, PM_SUSPEND); dp->suspended = true; return 0; return 0; } } static void dp_pm_complete(struct device *dev) 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_display_set_mst_state(g_dp_display, PM_DEFAULT); dp->suspended = false; } } static const struct dev_pm_ops dp_pm_ops = { static const struct dev_pm_ops dp_pm_ops = { Loading msm/dp/dp_hdcp2p2.c +11 −13 Original line number Original line Diff line number Diff line Loading @@ -238,19 +238,22 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) static int dp_hdcp2p2_register(void *input, bool mst_enabled) static int dp_hdcp2p2_register(void *input, bool mst_enabled) { { int rc; int rc; enum sde_hdcp_2x_device_type device_type; struct dp_hdcp2p2_ctrl *ctrl = input; struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_ENABLE}; rc = dp_hdcp2p2_valid_handle(ctrl); rc = dp_hdcp2p2_valid_handle(ctrl); if (rc) if (rc) return rc; return rc; if (mst_enabled) if (mst_enabled) device_type = HDCP_TXMTR_DP_MST; cdata.device_type = HDCP_TXMTR_DP_MST; else 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) static int dp_hdcp2p2_on(void *input) Loading @@ -276,25 +279,20 @@ static void dp_hdcp2p2_off(void *input) { { int rc; int rc; struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; 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); rc = dp_hdcp2p2_valid_handle(ctrl); if (rc) if (rc) return; 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_set_interrupts(ctrl, false); dp_hdcp2p2_reset(ctrl); dp_hdcp2p2_reset(ctrl); kthread_park(ctrl->thread); 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) static int dp_hdcp2p2_authenticate(void *input) Loading msm/sde_hdcp.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -51,6 +51,7 @@ struct sde_hdcp_stream { u8 stream_id; u8 stream_id; u8 virtual_channel; u8 virtual_channel; u32 stream_handle; u32 stream_handle; bool active; }; }; struct sde_hdcp_init_data { struct sde_hdcp_init_data { Loading msm/sde_hdcp_2x.c +166 −141 Original line number Original line Diff line number Diff line Loading @@ -49,6 +49,7 @@ struct sde_hdcp_2x_ctrl { u32 timeout_left; u32 timeout_left; u32 wait_timeout_ms; u32 wait_timeout_ms; u32 total_message_length; u32 total_message_length; atomic_t enable_pending; bool no_stored_km; bool no_stored_km; bool feature_supported; bool feature_supported; bool force_encryption; bool force_encryption; Loading @@ -66,8 +67,6 @@ struct sde_hdcp_2x_ctrl { u8 min_enc_level; u8 min_enc_level; struct list_head stream_handles; struct list_head stream_handles; u8 stream_count; u8 stream_count; struct stream_info *streams; u8 num_streams; struct task_struct *thread; struct task_struct *thread; struct completion response_completion; struct completion response_completion; Loading Loading @@ -194,9 +193,7 @@ static int sde_hdcp_2x_get_next_message(struct sde_hdcp_2x_ctrl *hdcp, case REP_SEND_RECV_ID_LIST: case REP_SEND_RECV_ID_LIST: return REP_SEND_ACK; return REP_SEND_ACK; case REP_STREAM_MANAGE: case REP_STREAM_MANAGE: if (hdcp->resend_stream_manage) hdcp->resend_stream_manage = false; return REP_STREAM_MANAGE; else return REP_STREAM_READY; return REP_STREAM_READY; default: default: pr_err("Unknown message ID (%d)\n", hdcp->last_msg); pr_err("Unknown message ID (%d)\n", hdcp->last_msg); Loading Loading @@ -301,6 +298,9 @@ static bool sde_hdcp_2x_client_feature_supported(void *data) { { struct sde_hdcp_2x_ctrl *hdcp = 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); return hdcp2_feature_supported(hdcp->hdcp2_ctx); } } Loading Loading @@ -404,6 +404,12 @@ static void sde_hdcp_2x_query_stream(struct sde_hdcp_2x_ctrl *hdcp) return; 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, rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_QUERY_STREAM, &hdcp->app_data); &hdcp->app_data); if (rc) if (rc) Loading @@ -418,9 +424,12 @@ static void sde_hdcp_2x_query_stream(struct sde_hdcp_2x_ctrl *hdcp) pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name( pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name( hdcp->app_data.response.data[0])); hdcp->app_data.response.data[0])); exit: 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); sde_hdcp_2x_send_message(hdcp); } } } static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp, static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp, enum hdcp_transport_wakeup_cmd cmd, enum hdcp_transport_wakeup_cmd cmd, Loading Loading @@ -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)); pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name(out_msg)); if (msg[0] == REP_STREAM_READY && out_msg != REP_STREAM_MANAGE) { 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, rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_EN_ENCRYPTION, HDCP2_CMD_EN_ENCRYPTION, &hdcp->app_data); &hdcp->app_data); Loading Loading @@ -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) if (msg[0] == LC_SEND_L_PRIME && out_msg == LC_INIT) hdcp->resend_lc_init = true; hdcp->resend_lc_init = true; hdcp->resend_stream_manage = false; if (msg[0] == REP_STREAM_READY && out_msg == REP_STREAM_MANAGE) 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) if (out_msg == AKE_NO_STORED_KM) hdcp->no_stored_km = true; hdcp->no_stored_km = true; Loading Loading @@ -671,125 +681,122 @@ static struct list_head *sde_hdcp_2x_stream_present( return entry; 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; struct list_head *entry; size_t iterations, i; struct list_head *element; u8 stream_id; struct sde_hdcp_stream *stream_entry; u8 virtual_channel; u32 stream_handle = 0; bool query_streams = false; bool query_streams = false; if (!hdcp->streams) { entry = hdcp->stream_handles.next; pr_err("Array of streams to register is NULL\n"); while (entry != &hdcp->stream_handles) { return; stream_entry = list_entry(entry, struct sde_hdcp_stream, list); } element = entry; entry = entry->next; iterations = min(hdcp->num_streams, (u8)(MAX_STREAM_COUNT)); for (i = 0; i < iterations; i++) { if (!stream_entry->active) { if (hdcp->stream_count == MAX_STREAM_COUNT) { hdcp2_close_stream(hdcp->hdcp2_ctx, pr_debug("Registered the maximum amount of streams\n"); stream_entry->stream_handle); break; hdcp->stream_count--; } list_del(element); kzfree(stream_entry); stream_id = hdcp->streams[i].stream_id; query_streams = true; virtual_channel = hdcp->streams[i].virtual_channel; } else if (!stream_entry->stream_handle) { if (hdcp2_open_stream(hdcp->hdcp2_ctx, pr_debug("Opening stream %d, virtual channel %d\n", stream_entry->virtual_channel, stream_id, virtual_channel); stream_entry->stream_id, &stream_entry->stream_handle)) 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", pr_err("Unable to open stream %d, virtual channel %d\n", stream_id, virtual_channel); stream_entry->stream_id, } else { stream_entry->virtual_channel); struct sde_hdcp_stream *stream = else 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++; query_streams = true; query_streams = true; } } } } if (query_streams && hdcp->authenticated) if (query_streams) { if (hdcp->authenticated) { sde_hdcp_2x_query_stream(hdcp); 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; u8 i; size_t iterations, i; u8 stream_id; u8 stream_id; u8 virtual_channel; u8 virtual_channel; struct list_head *entry; struct list_head *entry; struct sde_hdcp_stream *stream_entry; struct sde_hdcp_stream *stream_entry; bool query_streams = false; bool changed = 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); 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, entry = sde_hdcp_2x_stream_present(hdcp, stream_id, virtual_channel); virtual_channel); if (!entry) if (!entry) { pr_err("Unable to find stream %d, virtual channel %d\n" , stream_id, virtual_channel); continue; continue; } stream_entry = list_entry(entry, struct sde_hdcp_stream, stream_entry = list_entry(entry, struct sde_hdcp_stream, list); list); rc = hdcp2_close_stream(hdcp->hdcp2_ctx, if (!stream_entry->stream_handle) { stream_entry->stream_handle); /* Stream wasn't fully initialized so remove it */ if (rc) pr_err("Unable to close stream %d, virtual channel %d\n" , stream_id, virtual_channel); hdcp->stream_count--; hdcp->stream_count--; list_del(entry); list_del(entry); kzfree(stream_entry); kzfree(stream_entry); query_streams = true; } else { stream_entry->active = false; } changed = true; } } if (query_streams && hdcp->authenticated) return changed; sde_hdcp_2x_query_stream(hdcp); } 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 /** sde_hdcp_2x_wakeup() - wakeup the module to execute a requested command * @data: data required for executing corresponding command. * @data: data required for executing corresponding command. * * Loading @@ -813,18 +820,22 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data) hdcp->timeout_left = data->timeout; hdcp->timeout_left = data->timeout; hdcp->total_message_length = data->total_message_length; hdcp->total_message_length = data->total_message_length; hdcp->min_enc_level = data->min_enc_level; hdcp->min_enc_level = data->min_enc_level; hdcp->streams = data->streams; hdcp->num_streams = data->num_streams; if (!completion_done(&hdcp->response_completion)) if (!completion_done(&hdcp->response_completion)) complete_all(&hdcp->response_completion); complete_all(&hdcp->response_completion); kfifo_put(&hdcp->cmd_q, data->cmd); switch (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: case HDCP_2X_CMD_STOP: atomic_set(&hdcp->hdcp_off, 1); atomic_set(&hdcp->hdcp_off, 1); kfifo_put(&hdcp->cmd_q, data->cmd); kthread_park(hdcp->thread); kthread_park(hdcp->thread); break; break; case HDCP_2X_CMD_START: case HDCP_2X_CMD_START: Loading @@ -836,10 +847,26 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data) hdcp->timeout_left = 0; hdcp->timeout_left = 0; atomic_set(&hdcp->hdcp_off, 0); atomic_set(&hdcp->hdcp_off, 0); kfifo_put(&hdcp->cmd_q, data->cmd); kthread_unpark(hdcp->thread); kthread_unpark(hdcp->thread); wake_up(&hdcp->wait_q); wake_up(&hdcp->wait_q); break; 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: default: kfifo_put(&hdcp->cmd_q, data->cmd); wake_up(&hdcp->wait_q); wake_up(&hdcp->wait_q); break; break; } } Loading @@ -847,6 +874,30 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data) return rc; 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) static int sde_hdcp_2x_main(void *data) { { struct sde_hdcp_2x_ctrl *hdcp = data; struct sde_hdcp_2x_ctrl *hdcp = data; Loading @@ -870,6 +921,15 @@ static int sde_hdcp_2x_main(void *data) continue; continue; switch (cmd) { 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: case HDCP_2X_CMD_START: sde_hdcp_2x_init(hdcp); sde_hdcp_2x_init(hdcp); break; break; Loading Loading @@ -904,10 +964,8 @@ static int sde_hdcp_2x_main(void *data) sde_hdcp_2x_query_stream(hdcp); sde_hdcp_2x_query_stream(hdcp); break; break; case HDCP_2X_CMD_OPEN_STREAMS: case HDCP_2X_CMD_OPEN_STREAMS: sde_hdcp_2x_open_stream(hdcp); break; case HDCP_2X_CMD_CLOSE_STREAMS: case HDCP_2X_CMD_CLOSE_STREAMS: sde_hdcp_2x_close_stream(hdcp); sde_hdcp_2x_manage_stream(hdcp); break; break; default: default: break; break; Loading Loading @@ -961,6 +1019,7 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data) init_waitqueue_head(&hdcp->wait_q); init_waitqueue_head(&hdcp->wait_q); atomic_set(&hdcp->hdcp_off, 1); atomic_set(&hdcp->hdcp_off, 1); atomic_set(&hdcp->enable_pending, 0); init_completion(&hdcp->response_completion); init_completion(&hdcp->response_completion); Loading @@ -985,40 +1044,6 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data) return rc; 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) void sde_hdcp_2x_deregister(void *data) { { struct sde_hdcp_2x_ctrl *hdcp = data; struct sde_hdcp_2x_ctrl *hdcp = data; Loading @@ -1026,7 +1051,7 @@ void sde_hdcp_2x_deregister(void *data) if (!hdcp) if (!hdcp) return; return; sde_hdcp_2x_disable(data); kthread_stop(hdcp->thread); kthread_stop(hdcp->thread); sde_hdcp_2x_disable(data); kzfree(hdcp); kzfree(hdcp); } } msm/sde_hdcp_2x.h +4 −2 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,8 @@ */ */ enum sde_hdcp_2x_wakeup_cmd { enum sde_hdcp_2x_wakeup_cmd { HDCP_2X_CMD_INVALID, HDCP_2X_CMD_INVALID, HDCP_2X_CMD_ENABLE, HDCP_2X_CMD_DISABLE, HDCP_2X_CMD_START, HDCP_2X_CMD_START, HDCP_2X_CMD_START_AUTH, HDCP_2X_CMD_START_AUTH, HDCP_2X_CMD_STOP, HDCP_2X_CMD_STOP, Loading Loading @@ -79,6 +81,7 @@ enum sde_hdcp_2x_device_type { /** /** * struct sde_hdcp_2x_lib_wakeup_data - command and data send to HDCP driver * struct sde_hdcp_2x_lib_wakeup_data - command and data send to HDCP driver * @cmd: command type * @cmd: command type * @device_type type of device in use by the HDCP driver * @context: void pointer to the HDCP driver instance * @context: void pointer to the HDCP driver instance * @buf: message received from the sink * @buf: message received from the sink * @buf_len: length of message received from the sink * @buf_len: length of message received from the sink Loading @@ -88,6 +91,7 @@ enum sde_hdcp_2x_device_type { */ */ struct sde_hdcp_2x_wakeup_data { struct sde_hdcp_2x_wakeup_data { enum sde_hdcp_2x_wakeup_cmd cmd; enum sde_hdcp_2x_wakeup_cmd cmd; enum sde_hdcp_2x_device_type device_type; void *context; void *context; uint32_t total_message_length; uint32_t total_message_length; uint32_t timeout; uint32_t timeout; Loading Loading @@ -211,7 +215,5 @@ struct sde_hdcp_2x_register_data { /* functions for the HDCP 2.2 state machine module */ /* 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_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); void sde_hdcp_2x_deregister(void *data); #endif #endif Loading
msm/dp/dp_display.c +58 −9 Original line number Original line Diff line number Diff line Loading @@ -97,6 +97,9 @@ struct dp_display_private { struct work_struct connect_work; struct work_struct connect_work; struct work_struct attention_work; struct work_struct attention_work; struct mutex session_lock; struct mutex session_lock; bool suspended; bool hdcp_delayed_off; bool hdcp_abort; u32 active_stream_cnt; u32 active_stream_cnt; struct dp_mst mst; struct dp_mst mst; Loading Loading @@ -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); 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; 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); 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); sink_status &= (DP_RECEIVE_PORT_0_STATUS | DP_RECEIVE_PORT_1_STATUS); if (sink_status < 1) { if (sink_status < 1) { Loading Loading @@ -891,9 +908,7 @@ static void dp_display_clean(struct dp_display_private *dp) dp->power_on = false; dp->power_on = false; mutex_lock(&dp->session_lock); dp->ctrl->off(dp->ctrl); dp->ctrl->off(dp->ctrl); mutex_unlock(&dp->session_lock); } } static int dp_display_handle_disconnect(struct dp_display_private *dp) static int dp_display_handle_disconnect(struct dp_display_private *dp) Loading Loading @@ -1649,8 +1664,18 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) goto end; goto end; } } dp->hdcp_abort = true; cancel_delayed_work_sync(&dp->hdcp_cb_work); if (dp_display_is_hdcp_enabled(dp) && if (dp_display_is_hdcp_enabled(dp) && status->hdcp_state != HDCP_STATE_INACTIVE) { 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); flush_delayed_work(&dp->hdcp_cb_work); if (dp->mst.mst_active) { if (dp->mst.mst_active) { dp_display_hdcp_deregister_stream(dp, dp_display_hdcp_deregister_stream(dp, Loading @@ -1659,18 +1684,19 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) if (i != dp_panel->stream_id && if (i != dp_panel->stream_id && dp->active_panels[i]) { dp->active_panels[i]) { pr_debug("Streams are still active. Skip disabling HDCP\n"); pr_debug("Streams are still active. Skip disabling HDCP\n"); goto stream; off = false; } } } } } } if (off) { if (dp->hdcp.ops->off) if (dp->hdcp.ops->off) dp->hdcp.ops->off(dp->hdcp.data); dp->hdcp.ops->off(dp->hdcp.data); dp_display_update_hdcp_status(dp, true); dp_display_update_hdcp_status(dp, true); } } } stream: clean: if (dp_panel->audio_supported) if (dp_panel->audio_supported) dp_panel->audio->off(dp_panel->audio); dp_panel->audio->off(dp_panel->audio); Loading @@ -1683,8 +1709,10 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) static int dp_display_disable(struct dp_display *dp_display, void *panel) static int dp_display_disable(struct dp_display *dp_display, void *panel) { { int i; struct dp_display_private *dp = NULL; struct dp_display_private *dp = NULL; struct dp_panel *dp_panel = NULL; struct dp_panel *dp_panel = NULL; struct dp_link_hdcp_status *status; if (!dp_display || !panel) { if (!dp_display || !panel) { pr_err("invalid input\n"); pr_err("invalid input\n"); Loading @@ -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 = container_of(dp_display, struct dp_display_private, dp_display); dp_panel = panel; dp_panel = panel; status = &dp->link->hdcp_status; mutex_lock(&dp->session_lock); mutex_lock(&dp->session_lock); Loading @@ -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_stream_disable(dp, dp_panel); dp_display_update_dsc_resources(dp, dp_panel, false); 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: end: mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock); return 0; return 0; Loading Loading @@ -2590,14 +2629,24 @@ static int dp_display_remove(struct platform_device *pdev) static int dp_pm_prepare(struct device *dev) 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_display_set_mst_state(g_dp_display, PM_SUSPEND); dp->suspended = true; return 0; return 0; } } static void dp_pm_complete(struct device *dev) 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_display_set_mst_state(g_dp_display, PM_DEFAULT); dp->suspended = false; } } static const struct dev_pm_ops dp_pm_ops = { static const struct dev_pm_ops dp_pm_ops = { Loading
msm/dp/dp_hdcp2p2.c +11 −13 Original line number Original line Diff line number Diff line Loading @@ -238,19 +238,22 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) static int dp_hdcp2p2_register(void *input, bool mst_enabled) static int dp_hdcp2p2_register(void *input, bool mst_enabled) { { int rc; int rc; enum sde_hdcp_2x_device_type device_type; struct dp_hdcp2p2_ctrl *ctrl = input; struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_ENABLE}; rc = dp_hdcp2p2_valid_handle(ctrl); rc = dp_hdcp2p2_valid_handle(ctrl); if (rc) if (rc) return rc; return rc; if (mst_enabled) if (mst_enabled) device_type = HDCP_TXMTR_DP_MST; cdata.device_type = HDCP_TXMTR_DP_MST; else 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) static int dp_hdcp2p2_on(void *input) Loading @@ -276,25 +279,20 @@ static void dp_hdcp2p2_off(void *input) { { int rc; int rc; struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; 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); rc = dp_hdcp2p2_valid_handle(ctrl); if (rc) if (rc) return; 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_set_interrupts(ctrl, false); dp_hdcp2p2_reset(ctrl); dp_hdcp2p2_reset(ctrl); kthread_park(ctrl->thread); 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) static int dp_hdcp2p2_authenticate(void *input) Loading
msm/sde_hdcp.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -51,6 +51,7 @@ struct sde_hdcp_stream { u8 stream_id; u8 stream_id; u8 virtual_channel; u8 virtual_channel; u32 stream_handle; u32 stream_handle; bool active; }; }; struct sde_hdcp_init_data { struct sde_hdcp_init_data { Loading
msm/sde_hdcp_2x.c +166 −141 Original line number Original line Diff line number Diff line Loading @@ -49,6 +49,7 @@ struct sde_hdcp_2x_ctrl { u32 timeout_left; u32 timeout_left; u32 wait_timeout_ms; u32 wait_timeout_ms; u32 total_message_length; u32 total_message_length; atomic_t enable_pending; bool no_stored_km; bool no_stored_km; bool feature_supported; bool feature_supported; bool force_encryption; bool force_encryption; Loading @@ -66,8 +67,6 @@ struct sde_hdcp_2x_ctrl { u8 min_enc_level; u8 min_enc_level; struct list_head stream_handles; struct list_head stream_handles; u8 stream_count; u8 stream_count; struct stream_info *streams; u8 num_streams; struct task_struct *thread; struct task_struct *thread; struct completion response_completion; struct completion response_completion; Loading Loading @@ -194,9 +193,7 @@ static int sde_hdcp_2x_get_next_message(struct sde_hdcp_2x_ctrl *hdcp, case REP_SEND_RECV_ID_LIST: case REP_SEND_RECV_ID_LIST: return REP_SEND_ACK; return REP_SEND_ACK; case REP_STREAM_MANAGE: case REP_STREAM_MANAGE: if (hdcp->resend_stream_manage) hdcp->resend_stream_manage = false; return REP_STREAM_MANAGE; else return REP_STREAM_READY; return REP_STREAM_READY; default: default: pr_err("Unknown message ID (%d)\n", hdcp->last_msg); pr_err("Unknown message ID (%d)\n", hdcp->last_msg); Loading Loading @@ -301,6 +298,9 @@ static bool sde_hdcp_2x_client_feature_supported(void *data) { { struct sde_hdcp_2x_ctrl *hdcp = 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); return hdcp2_feature_supported(hdcp->hdcp2_ctx); } } Loading Loading @@ -404,6 +404,12 @@ static void sde_hdcp_2x_query_stream(struct sde_hdcp_2x_ctrl *hdcp) return; 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, rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_QUERY_STREAM, &hdcp->app_data); &hdcp->app_data); if (rc) if (rc) Loading @@ -418,9 +424,12 @@ static void sde_hdcp_2x_query_stream(struct sde_hdcp_2x_ctrl *hdcp) pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name( pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name( hdcp->app_data.response.data[0])); hdcp->app_data.response.data[0])); exit: 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); sde_hdcp_2x_send_message(hdcp); } } } static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp, static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp, enum hdcp_transport_wakeup_cmd cmd, enum hdcp_transport_wakeup_cmd cmd, Loading Loading @@ -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)); pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name(out_msg)); if (msg[0] == REP_STREAM_READY && out_msg != REP_STREAM_MANAGE) { 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, rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_EN_ENCRYPTION, HDCP2_CMD_EN_ENCRYPTION, &hdcp->app_data); &hdcp->app_data); Loading Loading @@ -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) if (msg[0] == LC_SEND_L_PRIME && out_msg == LC_INIT) hdcp->resend_lc_init = true; hdcp->resend_lc_init = true; hdcp->resend_stream_manage = false; if (msg[0] == REP_STREAM_READY && out_msg == REP_STREAM_MANAGE) 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) if (out_msg == AKE_NO_STORED_KM) hdcp->no_stored_km = true; hdcp->no_stored_km = true; Loading Loading @@ -671,125 +681,122 @@ static struct list_head *sde_hdcp_2x_stream_present( return entry; 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; struct list_head *entry; size_t iterations, i; struct list_head *element; u8 stream_id; struct sde_hdcp_stream *stream_entry; u8 virtual_channel; u32 stream_handle = 0; bool query_streams = false; bool query_streams = false; if (!hdcp->streams) { entry = hdcp->stream_handles.next; pr_err("Array of streams to register is NULL\n"); while (entry != &hdcp->stream_handles) { return; stream_entry = list_entry(entry, struct sde_hdcp_stream, list); } element = entry; entry = entry->next; iterations = min(hdcp->num_streams, (u8)(MAX_STREAM_COUNT)); for (i = 0; i < iterations; i++) { if (!stream_entry->active) { if (hdcp->stream_count == MAX_STREAM_COUNT) { hdcp2_close_stream(hdcp->hdcp2_ctx, pr_debug("Registered the maximum amount of streams\n"); stream_entry->stream_handle); break; hdcp->stream_count--; } list_del(element); kzfree(stream_entry); stream_id = hdcp->streams[i].stream_id; query_streams = true; virtual_channel = hdcp->streams[i].virtual_channel; } else if (!stream_entry->stream_handle) { if (hdcp2_open_stream(hdcp->hdcp2_ctx, pr_debug("Opening stream %d, virtual channel %d\n", stream_entry->virtual_channel, stream_id, virtual_channel); stream_entry->stream_id, &stream_entry->stream_handle)) 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", pr_err("Unable to open stream %d, virtual channel %d\n", stream_id, virtual_channel); stream_entry->stream_id, } else { stream_entry->virtual_channel); struct sde_hdcp_stream *stream = else 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++; query_streams = true; query_streams = true; } } } } if (query_streams && hdcp->authenticated) if (query_streams) { if (hdcp->authenticated) { sde_hdcp_2x_query_stream(hdcp); 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; u8 i; size_t iterations, i; u8 stream_id; u8 stream_id; u8 virtual_channel; u8 virtual_channel; struct list_head *entry; struct list_head *entry; struct sde_hdcp_stream *stream_entry; struct sde_hdcp_stream *stream_entry; bool query_streams = false; bool changed = 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); 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, entry = sde_hdcp_2x_stream_present(hdcp, stream_id, virtual_channel); virtual_channel); if (!entry) if (!entry) { pr_err("Unable to find stream %d, virtual channel %d\n" , stream_id, virtual_channel); continue; continue; } stream_entry = list_entry(entry, struct sde_hdcp_stream, stream_entry = list_entry(entry, struct sde_hdcp_stream, list); list); rc = hdcp2_close_stream(hdcp->hdcp2_ctx, if (!stream_entry->stream_handle) { stream_entry->stream_handle); /* Stream wasn't fully initialized so remove it */ if (rc) pr_err("Unable to close stream %d, virtual channel %d\n" , stream_id, virtual_channel); hdcp->stream_count--; hdcp->stream_count--; list_del(entry); list_del(entry); kzfree(stream_entry); kzfree(stream_entry); query_streams = true; } else { stream_entry->active = false; } changed = true; } } if (query_streams && hdcp->authenticated) return changed; sde_hdcp_2x_query_stream(hdcp); } 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 /** sde_hdcp_2x_wakeup() - wakeup the module to execute a requested command * @data: data required for executing corresponding command. * @data: data required for executing corresponding command. * * Loading @@ -813,18 +820,22 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data) hdcp->timeout_left = data->timeout; hdcp->timeout_left = data->timeout; hdcp->total_message_length = data->total_message_length; hdcp->total_message_length = data->total_message_length; hdcp->min_enc_level = data->min_enc_level; hdcp->min_enc_level = data->min_enc_level; hdcp->streams = data->streams; hdcp->num_streams = data->num_streams; if (!completion_done(&hdcp->response_completion)) if (!completion_done(&hdcp->response_completion)) complete_all(&hdcp->response_completion); complete_all(&hdcp->response_completion); kfifo_put(&hdcp->cmd_q, data->cmd); switch (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: case HDCP_2X_CMD_STOP: atomic_set(&hdcp->hdcp_off, 1); atomic_set(&hdcp->hdcp_off, 1); kfifo_put(&hdcp->cmd_q, data->cmd); kthread_park(hdcp->thread); kthread_park(hdcp->thread); break; break; case HDCP_2X_CMD_START: case HDCP_2X_CMD_START: Loading @@ -836,10 +847,26 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data) hdcp->timeout_left = 0; hdcp->timeout_left = 0; atomic_set(&hdcp->hdcp_off, 0); atomic_set(&hdcp->hdcp_off, 0); kfifo_put(&hdcp->cmd_q, data->cmd); kthread_unpark(hdcp->thread); kthread_unpark(hdcp->thread); wake_up(&hdcp->wait_q); wake_up(&hdcp->wait_q); break; 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: default: kfifo_put(&hdcp->cmd_q, data->cmd); wake_up(&hdcp->wait_q); wake_up(&hdcp->wait_q); break; break; } } Loading @@ -847,6 +874,30 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data) return rc; 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) static int sde_hdcp_2x_main(void *data) { { struct sde_hdcp_2x_ctrl *hdcp = data; struct sde_hdcp_2x_ctrl *hdcp = data; Loading @@ -870,6 +921,15 @@ static int sde_hdcp_2x_main(void *data) continue; continue; switch (cmd) { 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: case HDCP_2X_CMD_START: sde_hdcp_2x_init(hdcp); sde_hdcp_2x_init(hdcp); break; break; Loading Loading @@ -904,10 +964,8 @@ static int sde_hdcp_2x_main(void *data) sde_hdcp_2x_query_stream(hdcp); sde_hdcp_2x_query_stream(hdcp); break; break; case HDCP_2X_CMD_OPEN_STREAMS: case HDCP_2X_CMD_OPEN_STREAMS: sde_hdcp_2x_open_stream(hdcp); break; case HDCP_2X_CMD_CLOSE_STREAMS: case HDCP_2X_CMD_CLOSE_STREAMS: sde_hdcp_2x_close_stream(hdcp); sde_hdcp_2x_manage_stream(hdcp); break; break; default: default: break; break; Loading Loading @@ -961,6 +1019,7 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data) init_waitqueue_head(&hdcp->wait_q); init_waitqueue_head(&hdcp->wait_q); atomic_set(&hdcp->hdcp_off, 1); atomic_set(&hdcp->hdcp_off, 1); atomic_set(&hdcp->enable_pending, 0); init_completion(&hdcp->response_completion); init_completion(&hdcp->response_completion); Loading @@ -985,40 +1044,6 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data) return rc; 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) void sde_hdcp_2x_deregister(void *data) { { struct sde_hdcp_2x_ctrl *hdcp = data; struct sde_hdcp_2x_ctrl *hdcp = data; Loading @@ -1026,7 +1051,7 @@ void sde_hdcp_2x_deregister(void *data) if (!hdcp) if (!hdcp) return; return; sde_hdcp_2x_disable(data); kthread_stop(hdcp->thread); kthread_stop(hdcp->thread); sde_hdcp_2x_disable(data); kzfree(hdcp); kzfree(hdcp); } }
msm/sde_hdcp_2x.h +4 −2 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,8 @@ */ */ enum sde_hdcp_2x_wakeup_cmd { enum sde_hdcp_2x_wakeup_cmd { HDCP_2X_CMD_INVALID, HDCP_2X_CMD_INVALID, HDCP_2X_CMD_ENABLE, HDCP_2X_CMD_DISABLE, HDCP_2X_CMD_START, HDCP_2X_CMD_START, HDCP_2X_CMD_START_AUTH, HDCP_2X_CMD_START_AUTH, HDCP_2X_CMD_STOP, HDCP_2X_CMD_STOP, Loading Loading @@ -79,6 +81,7 @@ enum sde_hdcp_2x_device_type { /** /** * struct sde_hdcp_2x_lib_wakeup_data - command and data send to HDCP driver * struct sde_hdcp_2x_lib_wakeup_data - command and data send to HDCP driver * @cmd: command type * @cmd: command type * @device_type type of device in use by the HDCP driver * @context: void pointer to the HDCP driver instance * @context: void pointer to the HDCP driver instance * @buf: message received from the sink * @buf: message received from the sink * @buf_len: length of message received from the sink * @buf_len: length of message received from the sink Loading @@ -88,6 +91,7 @@ enum sde_hdcp_2x_device_type { */ */ struct sde_hdcp_2x_wakeup_data { struct sde_hdcp_2x_wakeup_data { enum sde_hdcp_2x_wakeup_cmd cmd; enum sde_hdcp_2x_wakeup_cmd cmd; enum sde_hdcp_2x_device_type device_type; void *context; void *context; uint32_t total_message_length; uint32_t total_message_length; uint32_t timeout; uint32_t timeout; Loading Loading @@ -211,7 +215,5 @@ struct sde_hdcp_2x_register_data { /* functions for the HDCP 2.2 state machine module */ /* 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_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); void sde_hdcp_2x_deregister(void *data); #endif #endif