Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0035372 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 4be499df 9b445309
Loading
Loading
Loading
Loading
+58 −9
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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) {
@@ -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)
@@ -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,
@@ -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);


@@ -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");
@@ -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);


@@ -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;
@@ -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 = {
+11 −13
Original line number Original line Diff line number Diff line
@@ -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)
@@ -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)
+1 −0
Original line number Original line Diff line number Diff line
@@ -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 {
+166 −141
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
@@ -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);
}
}


@@ -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)
@@ -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,
@@ -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);
@@ -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;
@@ -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.
 *
 *
@@ -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:
@@ -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;
	}
	}
@@ -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;
@@ -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;
@@ -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;
@@ -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);


@@ -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;
@@ -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);
}
}
+4 −2
Original line number Original line Diff line number Diff line
@@ -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,
@@ -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
@@ -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;
@@ -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