瀏覽代碼

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

qctecmdr 6 年之前
父節點
當前提交
c0035372e5
共有 5 個文件被更改,包括 240 次插入165 次删除
  1. 58 9
      msm/dp/dp_display.c
  2. 11 13
      msm/dp/dp_hdcp2p2.c
  3. 1 0
      msm/sde_hdcp.h
  4. 166 141
      msm/sde_hdcp_2x.c
  5. 4 2
      msm/sde_hdcp_2x.h

+ 58 - 9
msm/dp/dp_display.c

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

+ 11 - 13
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)

+ 1 - 0
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 {

+ 166 - 141
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;
@@ -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;
+	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;
+		}
 	}
 
-	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;
+	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;
 		}
+	}
+}
 
-		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);
+static bool sde_hdcp_2x_remove_streams(struct sde_hdcp_2x_ctrl *hdcp,
+		struct stream_info *streams, u8 num_streams)
+{
+	u8 i;
+	u8 stream_id;
+	u8 virtual_channel;
+	struct list_head *entry;
+	struct sde_hdcp_stream *stream_entry;
+	bool changed = false;
 
-		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);
+	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)
 			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++;
+		stream_entry = list_entry(entry, struct sde_hdcp_stream,
+			list);
 
-			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 void sde_hdcp_2x_close_stream(struct sde_hdcp_2x_ctrl *hdcp)
+static bool sde_hdcp_2x_add_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;
-	}
+	struct sde_hdcp_stream *stream;
+	bool changed = false;
 
-	iterations = min(hdcp->num_streams, (u8)(MAX_STREAM_COUNT));
+	for (i = 0 ; i < num_streams; i++) {
+		stream_id = streams[i].stream_id;
+		virtual_channel = streams[i].virtual_channel;
 
-	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);
-
-		entry = sde_hdcp_2x_stream_present(hdcp, stream_id,
-			virtual_channel);
+		if (sde_hdcp_2x_stream_present(hdcp, stream_id,
+				virtual_channel))
+			continue;
 
-		if (!entry) {
-			pr_err("Unable to find stream %d, virtual channel %d\n"
-				, stream_id, virtual_channel);
+		stream = kzalloc(sizeof(struct sde_hdcp_stream), GFP_KERNEL);
+		if (!stream)
 			continue;
-		}
 
-		stream_entry = list_entry(entry, struct sde_hdcp_stream,
-			list);
+		INIT_LIST_HEAD(&stream->list);
+		stream->stream_handle = 0;
+		stream->stream_id = stream_id;
+		stream->virtual_channel = virtual_channel;
+		stream->active = true;
 
-		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;
+		list_add(&stream->list, &hdcp->stream_handles);
+		hdcp->stream_count++;
+		changed = true;
 	}
 
-	if (query_streams && hdcp->authenticated)
-		sde_hdcp_2x_query_stream(hdcp);
+	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);
 }

+ 4 - 2
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