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

Commit 209686b4 authored by Ajay Singh Parmar's avatar Ajay Singh Parmar
Browse files

msm: mdss: hdmi: cleanup wakeup calls



Do not lock in wakeup functions as it may block current thread.
Wakeup can trigger a callback looking to acquire same lock.
Also rename the wakeup command names to properly identify client
and lib commands.

Change-Id: I28411714d2d7f0104364726fc5ce0593e5ccff91
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent d0438c65
Loading
Loading
Loading
Loading
+98 −104
Original line number Diff line number Diff line
@@ -85,7 +85,11 @@
#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31
#define MAX_RCVR_ID_LIST_SIZE \
		(RCVR_ID_SIZE*MAX_RCVR_IDS_ALLOWED_IN_LIST)
#define SLEEP_SET_HW_KEY_MS 200
/*
 * minimum wait as per standard is 200 ms. keep it 300 ms
 * to be on safe side.
 */
#define SLEEP_SET_HW_KEY_MS 300


#define QSEECOM_ALIGN_SIZE    0x40
@@ -387,60 +391,30 @@ static const char *hdcp_lib_message_name(int msg_id)
	return "UNKNOWN";
}

static inline int hdcp_lib_report_error(struct hdcp_lib_handle *handle)
{
	int rc = -EINVAL;

	if (handle->client_ops->wakeup) {
		rc = handle->client_ops->wakeup(
			handle->client_ctx, HDMI_HDCP_STATUS_FAIL,
			0, 0, 0);
		if (rc)
			pr_err("error: report error\n");
	} else {
		pr_err("error: client ops wakeup not defined\n");
	}

	return rc;
}

static inline int hdcp_lib_recv_message(struct hdcp_lib_handle *handle)
static inline void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
	struct hdmi_hdcp_wakeup_data *data)
{
	int rc = -EINVAL;
	int rc = 0;

	if (handle->client_ops->wakeup) {
		rc = handle->client_ops->wakeup(
			handle->client_ctx, HDMI_HDCP_RECV_MESSAGE,
			0, 0, handle->hdcp_timeout);
	if (handle && handle->client_ops && handle->client_ops->wakeup &&
		data && (data->cmd != HDMI_HDCP_WKUP_CMD_INVALID)) {
		rc = handle->client_ops->wakeup(data);
		if (rc)
			pr_err("error receiving message from client\n");
	} else {
		pr_err("error: client ops wakeup not defined\n");
			pr_err("error sending %s to client\n",
				hdmi_hdcp_cmd_to_str(data->cmd));
	}

	return rc;
}

static inline int hdcp_lib_send_message(struct hdcp_lib_handle *handle)
static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle)
{
	int rc = -EINVAL;

	pr_debug("send msg: %s to sink\n",
		hdcp_lib_message_name((int)handle->listener_buf[0]));
	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_SEND_MESSAGE};

	if (handle->client_ops->wakeup) {
		rc = handle->client_ops->wakeup(
			handle->client_ctx, HDMI_HDCP_SEND_MESSAGE,
			handle->listener_buf, handle->msglen, 0);
		if (!rc)
			handle->last_msg_sent = (int)handle->listener_buf[0];
		else
			pr_err("error sending message to client\n");
	} else {
		pr_err("error: client ops wakeup not defined\n");
	}
	cdata.context = handle->client_ctx;
	cdata.send_msg_buf = handle->listener_buf;
	cdata.send_msg_len = handle->msglen;
	cdata.timeout = handle->hdcp_timeout;

	return rc;
	hdcp_lib_wakeup_client(handle, &cdata);
}

static int hdcp_lib_enable_encryption(struct hdcp_lib_handle *handle)
@@ -450,7 +424,7 @@ static int hdcp_lib_enable_encryption(struct hdcp_lib_handle *handle)
	struct hdcp_set_hw_key_rsp *rsp_buf;

	/*
	 * wait for 200ms before enabling encryption
	 * wait at least 200ms before enabling encryption
	 * as per hdcp2p2 sepcifications.
	 */
	msleep(SLEEP_SET_HW_KEY_MS);
@@ -781,43 +755,38 @@ exit:
	return supported;
}

static int hdcp_lib_wakeup(void *phdcpcontext,
	enum hdcp_lib_wakeup_cmd cmd, char *msg, uint32_t msglen)
static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
{
	struct hdcp_lib_handle *handle = phdcpcontext;
	struct hdcp_lib_handle *handle;
	int rc = 0;

	if (!handle)
	if (!data)
		return -EINVAL;

	mutex_lock(&handle->hdcp_lock);
	handle->wakeup_cmd = cmd;
	mutex_unlock(&handle->hdcp_lock);

	if (handle->wakeup_cmd == HDCP_WKUP_CMD_STOP) {
		atomic_set(&handle->hdcp_off_pending, 1);
		flush_kthread_worker(&handle->worker);
		atomic_set(&handle->hdcp_off_pending, 0);
	}
	handle = data->context;
	if (!handle)
		return -EINVAL;

	mutex_lock(&handle->hdcp_lock);
	handle->wakeup_cmd = data->cmd;

	pr_debug("wakeup_cmd: %s\n", hdcp_cmd_to_str(handle->wakeup_cmd));
	pr_debug("wakeup_cmd: %s\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd));

	if (msglen) {
		handle->last_msg_recvd_len = msglen;
	if (data->recvd_msg_len) {
		handle->last_msg_recvd_len = data->recvd_msg_len;

		handle->last_msg_recvd_buf = kzalloc(msglen, GFP_KERNEL);
		handle->last_msg_recvd_buf = kzalloc(data->recvd_msg_len,
			GFP_KERNEL);
		if (!handle->last_msg_recvd_buf) {
			rc = -ENOMEM;
			goto exit;
		}

		memcpy(handle->last_msg_recvd_buf, msg, msglen);
		memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf,
			data->recvd_msg_len);
	}

	switch (handle->wakeup_cmd) {
	case HDCP_WKUP_CMD_START:
	case HDCP_LIB_WKUP_CMD_START:
		handle->no_stored_km_flag = 0;
		handle->repeater_flag = 0;
		handle->hdcp_state = HDCP_STATE_INIT;
@@ -825,24 +794,26 @@ static int hdcp_lib_wakeup(void *phdcpcontext,
		if (!atomic_read(&handle->hdcp_off_pending))
			queue_kthread_work(&handle->worker, &handle->init);
		break;
	case HDCP_WKUP_CMD_STOP:
		/* wait for any work being executed */
	case HDCP_LIB_WKUP_CMD_STOP:
		atomic_set(&handle->hdcp_off_pending, 1);
		queue_kthread_work(&handle->worker, &handle->clean);
		break;
	case HDCP_WKUP_CMD_MSG_SEND_SUCCESS:
	case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
		handle->last_msg_sent = handle->listener_buf[0];

		if (!atomic_read(&handle->hdcp_off_pending))
			queue_kthread_work(&handle->worker, &handle->msg_sent);
		break;
	case HDCP_WKUP_CMD_MSG_SEND_FAILED:
	case HDCP_WKUP_CMD_MSG_RECV_FAILED:
	case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
	case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
		if (!atomic_read(&handle->hdcp_off_pending))
			queue_kthread_work(&handle->worker, &handle->clean);
		break;
	case HDCP_WKUP_CMD_MSG_RECV_SUCCESS:
	case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
		if (!atomic_read(&handle->hdcp_off_pending))
			queue_kthread_work(&handle->worker, &handle->msg_recvd);
		break;
	case HDCP_WKUP_CMD_MSG_RECV_TIMEOUT:
	case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
		if (!atomic_read(&handle->hdcp_off_pending))
			queue_kthread_work(&handle->worker, &handle->timeout);
		break;
@@ -850,7 +821,6 @@ static int hdcp_lib_wakeup(void *phdcpcontext,
		pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
	}
exit:
	mutex_unlock(&handle->hdcp_lock);
	return 0;
}

@@ -858,6 +828,7 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work)
{
	struct hdcp_lib_handle *handle = container_of(work,
		struct hdcp_lib_handle, msg_sent);
	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};

	if (!handle) {
		pr_err("invalid handle\n");
@@ -866,15 +837,17 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work)

	mutex_lock(&handle->hdcp_lock);

	if (handle->wakeup_cmd == HDCP_WKUP_CMD_MSG_SEND_SUCCESS) {
	cdata.context = handle->client_ctx;

	if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) {
		if (handle->last_msg_sent == SKE_SEND_EKS_MESSAGE_ID) {
			if (!hdcp_lib_enable_encryption(handle))
				handle->client_ops->wakeup(
					handle->client_ctx,
					HDMI_HDCP_STATUS_SUCCESS,
					0, 0, 0);
				cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS;
			else
				cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_FAILED;
		} else {
			hdcp_lib_recv_message(handle);
			cdata.cmd = HDMI_HDCP_WKUP_CMD_RECV_MESSAGE;
			cdata.timeout = handle->hdcp_timeout;
		}
	} else {
		pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
@@ -882,12 +855,14 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work)

	mutex_unlock(&handle->hdcp_lock);

	hdcp_lib_wakeup_client(handle, &cdata);
	return;
}

static void hdcp_lib_init_work(struct kthread_work *work)
{
	int rc = 0;
	bool send_msg = false;
	struct hdcp_lib_handle *handle = container_of(work,
		struct hdcp_lib_handle, init);

@@ -898,7 +873,7 @@ static void hdcp_lib_init_work(struct kthread_work *work)

	mutex_lock(&handle->hdcp_lock);

	if (handle->wakeup_cmd == HDCP_WKUP_CMD_START) {
	if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) {
		rc = hdcp_lib_library_load(handle);
		if (rc)
			goto exit;
@@ -907,10 +882,8 @@ static void hdcp_lib_init_work(struct kthread_work *work)
		if (rc)
			goto exit;

		rc = hdcp_lib_send_message(handle);
		if (rc)
			goto exit;
	} else if (handle->wakeup_cmd == HDCP_WKUP_CMD_STOP) {
		send_msg = true;
	} else if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_STOP) {
		rc = hdcp_lib_txmtr_deinit(handle);
		if (rc)
			goto exit;
@@ -922,16 +895,20 @@ static void hdcp_lib_init_work(struct kthread_work *work)
		pr_err("invalid wakeup cmd: %d\n", handle->wakeup_cmd);
	}
exit:
	mutex_unlock(&handle->hdcp_lock);

	if (send_msg)
		hdcp_lib_send_message(handle);

	if (rc && !atomic_read(&handle->hdcp_off_pending))
		queue_kthread_work(&handle->worker, &handle->clean);

	mutex_unlock(&handle->hdcp_lock);
	return;
}

static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
{
	int rc = 0;
	bool send_msg = false;
	struct hdcp_send_timeout_req *req_buf;
	struct hdcp_send_timeout_rsp *rsp_buf;
	struct hdcp_lib_handle *handle = container_of(work,
@@ -986,20 +963,24 @@ static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
			handle->hdcp_timeout = rsp_buf->timeout;
			handle->msglen = rsp_buf->msglen;

			hdcp_lib_send_message(handle);
			send_msg = true;
		}
	}
error:
	mutex_unlock(&handle->hdcp_lock);

	if (send_msg)
		hdcp_lib_send_message(handle);

	if (rc && !atomic_read(&handle->hdcp_off_pending))
		queue_kthread_work(&handle->worker, &handle->clean);

	mutex_unlock(&handle->hdcp_lock);
}

static void hdcp_lib_cleanup_work(struct kthread_work *work)
{
	struct hdcp_lib_handle *handle = container_of(work,
		struct hdcp_lib_handle, clean);
	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};

	if (!handle) {
		pr_err("invalid input\n");
@@ -1008,18 +989,18 @@ static void hdcp_lib_cleanup_work(struct kthread_work *work)

	mutex_lock(&handle->hdcp_lock);

	if (atomic_read(&handle->hdcp_off_pending)) {
		pr_err("hdcp off underway\n");
		goto exit;
	}
	cdata.context = handle->client_ctx;
	cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_FAILED;

	hdcp_lib_txmtr_deinit(handle);
	hdcp_lib_library_unload(handle);

	if (handle->wakeup_cmd != HDCP_WKUP_CMD_STOP)
		hdcp_lib_report_error(handle);
exit:
	mutex_unlock(&handle->hdcp_lock);

	if (atomic_read(&handle->hdcp_off_pending))
		atomic_set(&handle->hdcp_off_pending, 0);
	else
		hdcp_lib_wakeup_client(handle, &cdata);
}

static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
@@ -1031,6 +1012,7 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
	char *msg;
	struct hdcp_lib_handle *handle = container_of(work,
		struct hdcp_lib_handle, msg_recvd);
	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};

	if (!handle) {
		pr_err("invalid handle\n");
@@ -1042,8 +1024,10 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
	msg = handle->last_msg_recvd_buf;
	msglen = handle->last_msg_recvd_len;

	cdata.context = handle->client_ctx;

	if (msglen <= 0) {
		pr_err("invalid msg\n");
		pr_err("invalid msg len\n");
		rc = -EINVAL;
		goto exit;
	}
@@ -1074,7 +1058,11 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
	/* get next message from sink if we receive H PRIME on no store km */
	if ((msg[0] == AKE_SEND_H_PRIME_MESSAGE_ID) &&
			handle->no_stored_km_flag) {
		hdcp_lib_recv_message(handle);
		handle->hdcp_timeout = rsp_buf->timeout;

		cdata.cmd = HDMI_HDCP_WKUP_CMD_RECV_MESSAGE;
		cdata.timeout = handle->hdcp_timeout;

		goto exit;
	}

@@ -1120,15 +1108,21 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
	handle->hdcp_timeout = rsp_buf->timeout;
	handle->msglen = rsp_buf->msglen;

	if (!atomic_read(&handle->hdcp_off_pending))
		hdcp_lib_send_message(handle);
	if (!atomic_read(&handle->hdcp_off_pending)) {
		cdata.cmd = HDMI_HDCP_WKUP_CMD_SEND_MESSAGE;
		cdata.send_msg_buf = handle->listener_buf;
		cdata.send_msg_len = handle->msglen;
		cdata.timeout = handle->hdcp_timeout;
	}

exit:
	kzfree(handle->last_msg_recvd_buf);
	mutex_unlock(&handle->hdcp_lock);

	hdcp_lib_wakeup_client(handle, &cdata);

	if (rc && !atomic_read(&handle->hdcp_off_pending))
		queue_kthread_work(&handle->worker, &handle->clean);

	mutex_unlock(&handle->hdcp_lock);
}

/* APIs exposed to all clients */
+120 −124
Original line number Diff line number Diff line
@@ -50,13 +50,13 @@ struct hdmi_hdcp2p2_ctrl {
	enum hdmi_hdcp2p2_sink_status sink_status; /* Is sink connected */
	struct hdmi_hdcp_init_data init_data; /* Feature data from HDMI drv */
	struct mutex mutex; /* mutex to protect access to ctrl */
	struct mutex wakeup_mutex; /* mutex to protect access to wakeup call*/
	struct hdmi_hdcp_ops *ops;
	void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */
	struct hdcp_txmtr_ops *txmtr_ops; /* Ops for driver to call into TZ */
	struct hdcp_client_ops *client_ops; /* Ops for driver to export to TZ */
	struct hdcp_txmtr_ops *lib; /* Ops for driver to call into TZ */
	struct completion rxstatus_completion; /* Rx status interrupt */

	enum hdmi_hdcp_cmd wakeup_cmd;
	enum hdmi_hdcp_wakeup_cmd wakeup_cmd;
	char *send_msg_buf;
	uint32_t send_msg_len;
	uint32_t timeout;
@@ -69,6 +69,80 @@ struct hdmi_hdcp2p2_ctrl {
	struct kthread_work recv_msg;
};

static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
{
	struct hdmi_hdcp2p2_ctrl *ctrl;

	if (!data) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	ctrl = data->context;
	if (!ctrl) {
		pr_err("invalid ctrl\n");
		return -EINVAL;
	}

	mutex_lock(&ctrl->wakeup_mutex);

	pr_debug("wakeup_cmd: %s\n", hdmi_hdcp_cmd_to_str(data->cmd));

	ctrl->wakeup_cmd = data->cmd;
	ctrl->timeout = data->timeout;

	if (data->send_msg_len)	{
		ctrl->send_msg_len = data->send_msg_len;

		ctrl->send_msg_buf = kzalloc(
			data->send_msg_len, GFP_KERNEL);

		if (!ctrl->send_msg_buf)
			goto exit;

		memcpy(ctrl->send_msg_buf, data->send_msg_buf,
			ctrl->send_msg_len);
	}

	switch (ctrl->wakeup_cmd) {
	case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
		if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
			queue_kthread_work(&ctrl->worker, &ctrl->send_msg);
		break;
	case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE:
		if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
			queue_kthread_work(&ctrl->worker, &ctrl->recv_msg);
		break;
	case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS:
	case HDMI_HDCP_WKUP_CMD_STATUS_FAILED:
		if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
			queue_kthread_work(&ctrl->worker, &ctrl->status);
		break;
	case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
		queue_kthread_work(&ctrl->worker, &ctrl->auth);
		break;
	default:
		pr_err("invalid wakeup command %d\n", ctrl->wakeup_cmd);
	}
exit:
	mutex_unlock(&ctrl->wakeup_mutex);
	return 0;
}

static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl,
	struct hdcp_lib_wakeup_data *data)
{
	int rc = 0;

	if (ctrl && ctrl->lib && ctrl->lib->wakeup &&
		data && (data->cmd != HDCP_LIB_WKUP_CMD_INVALID)) {
		rc = ctrl->lib->wakeup(data);
		if (rc)
			pr_err("error sending %s to lib\n",
				hdcp_lib_cmd_to_str(data->cmd));
	}
}

static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl)
{
	if (!ctrl) {
@@ -83,6 +157,7 @@ static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl)
static void hdmi_hdcp2p2_off(void *input)
{
	struct hdmi_hdcp2p2_ctrl *ctrl = (struct hdmi_hdcp2p2_ctrl *)input;
	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE};

	if (!ctrl) {
		pr_err("invalid input\n");
@@ -93,25 +168,25 @@ static void hdmi_hdcp2p2_off(void *input)

	flush_kthread_worker(&ctrl->worker);

	mutex_lock(&ctrl->mutex);
	queue_kthread_work(&ctrl->worker, &ctrl->auth);
	mutex_unlock(&ctrl->mutex);
	cdata.context = input;

	hdmi_hdcp2p2_wakeup(&cdata);
}

static int hdmi_hdcp2p2_authenticate(void *input)
{
	struct hdmi_hdcp2p2_ctrl *ctrl = input;
	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE};
	int rc = 0;

	flush_kthread_worker(&ctrl->worker);

	mutex_lock(&ctrl->mutex);
	ctrl->sink_status = SINK_CONNECTED;
	atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING);

	queue_kthread_work(&ctrl->worker, &ctrl->auth);
	cdata.context = input;
	hdmi_hdcp2p2_wakeup(&cdata);

	mutex_unlock(&ctrl->mutex);
	return rc;
}

@@ -208,7 +283,7 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
	}

	pr_debug("notification of minimum level change received\n");
	res = ctrl->txmtr_ops->
	res = ctrl->lib->
		hdcp_query_stream_type(ctrl->lib_ctx);

	return  count;
@@ -398,7 +473,7 @@ static bool hdmi_hdcp2p2_feature_supported(void *input)
		goto end;
	}

	lib = ctrl->txmtr_ops;
	lib = ctrl->lib;
	if (!lib) {
		pr_err("invalid lib ops data\n");
		goto end;
@@ -416,8 +491,7 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
	int rc = 0;
	struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
		struct hdmi_hdcp2p2_ctrl, send_msg);
	struct hdcp_txmtr_ops *lib = NULL;
	enum hdcp_lib_wakeup_cmd cmd;
	struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};

	if (!ctrl) {
		pr_err("invalid input\n");
@@ -426,34 +500,27 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)

	mutex_lock(&ctrl->mutex);

	cdata.context = ctrl->lib_ctx;

	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
		pr_err("hdcp is off\n");
		goto exit;
	}

	lib = ctrl->txmtr_ops;

	if (!lib) {
		pr_err("invalid lib data\n");
		goto exit;
	}

	/* Forward the message to the sink */
	rc = hdmi_hdcp2p2_ddc_write_message(ctrl,
		ctrl->send_msg_buf,
		(size_t)ctrl->send_msg_len);
		ctrl->send_msg_buf, (size_t)ctrl->send_msg_len);
	if (rc) {
		pr_err("Error sending msg to sink %d\n", rc);
		cmd = HDCP_WKUP_CMD_MSG_SEND_FAILED;
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED;
	} else {
		cmd = HDCP_WKUP_CMD_MSG_SEND_SUCCESS;
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS;
	}

	if (lib->wakeup)
		lib->wakeup(ctrl->lib_ctx, cmd, 0, 0);
exit:
	kzfree(ctrl->send_msg_buf);
	mutex_unlock(&ctrl->mutex);

	hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
}

static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
@@ -463,11 +530,10 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
	char *recvd_msg_buf = NULL;
	struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
		struct hdmi_hdcp2p2_ctrl, recv_msg);
	struct hdcp_txmtr_ops *lib = NULL;
	enum hdcp_lib_wakeup_cmd cmd;
	struct hdmi_tx_hdcp2p2_ddc_data hdcp2p2_ddc_data;
	struct hdmi_tx_ddc_ctrl *ddc_ctrl;
	struct msm_hdmi_mode_timing_info *timing;
	struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};

	if (!ctrl) {
		pr_err("invalid input\n");
@@ -476,13 +542,7 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)

	mutex_lock(&ctrl->mutex);

	lib = ctrl->txmtr_ops;

	if (!lib) {
		pr_err("invalid lib data\n");
		rc = -EINVAL;
		goto exit;
	}
	cdata.context = ctrl->lib_ctx;

	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
		pr_err("hdcp is off\n");
@@ -539,20 +599,20 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
	hdmi_hdcp2p2_ddc_abort(ctrl);
	hdmi_hdcp2p2_ddc_reset(ddc_ctrl);
	hdmi_hdcp2p2_ddc_disable(ddc_ctrl);

	cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS;
	cdata.recvd_msg_buf = recvd_msg_buf;
	cdata.recvd_msg_len = msg_size;
exit:
	if (rc == -ETIMEDOUT)
		cmd = HDCP_WKUP_CMD_MSG_RECV_TIMEOUT;
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT;
	else if (rc)
		cmd = HDCP_WKUP_CMD_MSG_RECV_FAILED;
	else
		cmd = HDCP_WKUP_CMD_MSG_RECV_SUCCESS;
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED;

	if (lib->wakeup)
		lib->wakeup(ctrl->lib_ctx, cmd,
			recvd_msg_buf, msg_size);
	mutex_unlock(&ctrl->mutex);

	hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
	kfree(recvd_msg_buf);
	mutex_unlock(&ctrl->mutex);
}

static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work)
@@ -572,9 +632,9 @@ static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work)
		goto exit;
	}

	if (ctrl->wakeup_cmd == HDMI_HDCP_STATUS_FAIL) {
	if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_FAILED) {
		hdmi_hdcp2p2_auth_failed(ctrl);
	} else if (ctrl->wakeup_cmd == HDMI_HDCP_STATUS_SUCCESS) {
	} else if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS) {
		/* Enable interrupts */
		u32 regval = DSS_REG_R(ctrl->init_data.core_io,
				HDMI_HDCP_INT_CTRL2);
@@ -598,8 +658,7 @@ static void hdmi_hdcp2p2_auth_work(struct kthread_work *work)
{
	struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
		struct hdmi_hdcp2p2_ctrl, auth);
	enum hdcp_lib_wakeup_cmd cmd;
	struct hdcp_txmtr_ops *lib = NULL;
	struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};

	if (!ctrl) {
		pr_err("invalid input\n");
@@ -608,93 +667,31 @@ static void hdmi_hdcp2p2_auth_work(struct kthread_work *work)

	mutex_lock(&ctrl->mutex);

	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
		pr_err("hdcp is off\n");
		goto exit;
	}
	cdata.context = ctrl->lib_ctx;

	lib = ctrl->txmtr_ops;
	if (lib && lib->wakeup) {
		if (atomic_read(&ctrl->auth_state) ==
			HDCP_STATE_AUTHENTICATING)
			cmd = HDCP_WKUP_CMD_START;
	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING)
		cdata.cmd = HDCP_LIB_WKUP_CMD_START;
	else
			cmd = HDCP_WKUP_CMD_STOP;
		cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;

		lib->wakeup(ctrl->lib_ctx, cmd, 0, 0);
	}
exit:
	mutex_unlock(&ctrl->mutex);
}

static int hdmi_hdcp2p2_wakeup(void *client_ctx, enum hdmi_hdcp_cmd cmd,
	char *msg, uint32_t msglen, uint32_t timeout)
{
	struct hdmi_hdcp2p2_ctrl *ctrl = client_ctx;

	if (!ctrl) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	mutex_lock(&ctrl->mutex);

	pr_debug("wakeup_cmd: %s\n", hdmi_hdcp_cmd_to_str(cmd));

	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
		pr_err("hdcp is off\n");
		goto exit;
	}

	ctrl->wakeup_cmd = cmd;
	ctrl->send_msg_len = msglen;
	ctrl->timeout = timeout;

	if (msglen)	{
		ctrl->send_msg_buf = kzalloc(
			ctrl->send_msg_len, GFP_KERNEL);

		if (!ctrl->send_msg_buf)
			goto exit;

		memcpy(ctrl->send_msg_buf, msg, msglen);
	}

	switch (ctrl->wakeup_cmd) {
	case HDMI_HDCP_SEND_MESSAGE:
		queue_kthread_work(&ctrl->worker, &ctrl->send_msg);
		break;
	case HDMI_HDCP_RECV_MESSAGE:
		queue_kthread_work(&ctrl->worker, &ctrl->recv_msg);
		break;
	case HDMI_HDCP_STATUS_SUCCESS:
	case HDMI_HDCP_STATUS_FAIL:
		queue_kthread_work(&ctrl->worker, &ctrl->status);
		break;
	default:
		pr_err("invalid wakeup command %d\n",
			ctrl->wakeup_cmd);
	}
exit:
	mutex_unlock(&ctrl->mutex);
	return 0;
	hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
}

void hdmi_hdcp2p2_deinit(void *input)
{
	struct hdmi_hdcp2p2_ctrl *ctrl = (struct hdmi_hdcp2p2_ctrl *)input;
	struct hdcp_txmtr_ops *lib = NULL;
	struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};

	if (!ctrl) {
		pr_err("invalid input\n");
		return;
	}

	lib = ctrl->txmtr_ops;

	if (lib && lib->wakeup)
		lib->wakeup(ctrl->lib_ctx,
			HDCP_WKUP_CMD_STOP, 0, 0);
	cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
	cdata.context = ctrl->lib_ctx;
	hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);

	kthread_stop(ctrl->thread);

@@ -742,8 +739,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
		return ERR_PTR(-ENOMEM);

	ctrl->init_data = *init_data;
	ctrl->client_ops = &client_ops;
	ctrl->txmtr_ops = &txmtr_ops;
	ctrl->lib = &txmtr_ops;

	rc = sysfs_create_group(init_data->sysfs_kobj,
				&hdmi_hdcp2p2_fs_attr_group);
@@ -760,10 +756,10 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)

	ctrl->ops = &ops;
	mutex_init(&ctrl->mutex);
	mutex_init(&ctrl->wakeup_mutex);

	rc = hdcp_library_register(&ctrl->lib_ctx,
			ctrl->client_ops,
			ctrl->txmtr_ops, ctrl);
			&client_ops, ctrl->lib, ctrl);
	if (rc) {
		pr_err("Unable to register with HDCP 2.2 library\n");
		goto error;
+1 −1
Original line number Diff line number Diff line
@@ -1242,7 +1242,7 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work)
			rc = hdmi_tx_config_avmute(hdmi_ctrl, true);
		}

		if (hdmi_ctrl->hpd_state) {
		if (hdmi_ctrl->hpd_state && hdmi_ctrl->panel_power_on) {
			DEV_DBG("%s: Reauthenticating\n", __func__);
			rc = hdmi_ctrl->hdcp_ops->hdmi_hdcp_reauthenticate(
				hdmi_ctrl->hdcp_feature_data);
+58 −39
Original line number Diff line number Diff line
@@ -15,63 +15,83 @@
#include <linux/types.h>

enum hdcp_lib_wakeup_cmd {
	HDCP_WKUP_CMD_START,
	HDCP_WKUP_CMD_STOP,
	HDCP_WKUP_CMD_MSG_SEND_SUCCESS,
	HDCP_WKUP_CMD_MSG_SEND_FAILED,
	HDCP_WKUP_CMD_MSG_RECV_SUCCESS,
	HDCP_WKUP_CMD_MSG_RECV_FAILED,
	HDCP_WKUP_CMD_MSG_RECV_TIMEOUT,
	HDCP_LIB_WKUP_CMD_INVALID,
	HDCP_LIB_WKUP_CMD_START,
	HDCP_LIB_WKUP_CMD_STOP,
	HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS,
	HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED,
	HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS,
	HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED,
	HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT,
};

enum hdmi_hdcp_cmd {
	HDMI_HDCP_SEND_MESSAGE,
	HDMI_HDCP_RECV_MESSAGE,
	HDMI_HDCP_STATUS_SUCCESS,
	HDMI_HDCP_STATUS_FAIL
enum hdmi_hdcp_wakeup_cmd {
	HDMI_HDCP_WKUP_CMD_INVALID,
	HDMI_HDCP_WKUP_CMD_SEND_MESSAGE,
	HDMI_HDCP_WKUP_CMD_RECV_MESSAGE,
	HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS,
	HDMI_HDCP_WKUP_CMD_STATUS_FAILED,
	HDMI_HDCP_WKUP_CMD_AUTHENTICATE
};

struct hdcp_lib_wakeup_data {
	enum hdcp_lib_wakeup_cmd cmd;
	void *context;
	char *recvd_msg_buf;
	uint32_t recvd_msg_len;
	uint32_t timeout;
};

struct hdmi_hdcp_wakeup_data {
	enum hdmi_hdcp_wakeup_cmd cmd;
	void *context;
	char *send_msg_buf;
	uint32_t send_msg_len;
	uint32_t timeout;
};

static inline char *hdmi_hdcp_cmd_to_str(uint32_t cmd)
{
	switch (cmd) {
	case HDMI_HDCP_SEND_MESSAGE:
		return "HDMI_HDCP_SEND_MESSAGE";
	case HDMI_HDCP_RECV_MESSAGE:
		return "HDMI_HDCP_RECV_MESSAGE";
	case HDMI_HDCP_STATUS_SUCCESS:
		return "HDMI_HDCP_STATUS_SUCCESS";
	case HDMI_HDCP_STATUS_FAIL:
		return "HDMI_HDCP_STATUS_FAIL";
	case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
		return "HDMI_HDCP_WKUP_CMD_SEND_MESSAGE";
	case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE:
		return "HDMI_HDCP_WKUP_CMD_RECV_MESSAGE";
	case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS:
		return "HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS";
	case HDMI_HDCP_WKUP_CMD_STATUS_FAILED:
		return "HDMI_HDCP_WKUP_CMD_STATUS_FAIL";
	case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
		return "HDMI_HDCP_WKUP_CMD_AUTHENTICATE";
	default:
		return "???";
	}
}

static inline char *hdcp_cmd_to_str(uint32_t cmd)
static inline char *hdcp_lib_cmd_to_str(uint32_t cmd)
{
	switch (cmd) {
	case HDCP_WKUP_CMD_START:
		return "HDCP_WKUP_CMD_START";
	case HDCP_WKUP_CMD_STOP:
		return "HDCP_WKUP_CMD_STOP";
	case HDCP_WKUP_CMD_MSG_SEND_SUCCESS:
		return "HDCP_WKUP_CMD_MSG_SEND_SUCCESS";
	case HDCP_WKUP_CMD_MSG_SEND_FAILED:
		return "HDCP_WKUP_CMD_MSG_SEND_FAILED";
	case HDCP_WKUP_CMD_MSG_RECV_SUCCESS:
		return "HDCP_WKUP_CMD_MSG_RECV_SUCCESS";
	case HDCP_WKUP_CMD_MSG_RECV_FAILED:
		return "HDCP_WKUP_CMD_MSG_RECV_FAILED";
	case HDCP_WKUP_CMD_MSG_RECV_TIMEOUT:
		return "HDCP_WKUP_CMD_MSG_RECV_TIMEOUT";
	case HDCP_LIB_WKUP_CMD_START:
		return "HDCP_LIB_WKUP_CMD_START";
	case HDCP_LIB_WKUP_CMD_STOP:
		return "HDCP_LIB_WKUP_CMD_STOP";
	case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
		return "HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS";
	case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
		return "HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED";
	case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
		return "HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS";
	case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
		return "HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED";
	case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
		return "HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT";
	default:
		return "???";
	}
}

struct hdcp_txmtr_ops {
	int (*wakeup)(void *phdcpcontext, enum hdcp_lib_wakeup_cmd cmd,
		char *msg, uint32_t len);
	int (*wakeup)(struct hdcp_lib_wakeup_data *data);
	bool (*feature_supported)(void *phdcpcontext);

	int (*hdcp_txmtr_get_state)(void *phdcpcontext,
@@ -80,8 +100,7 @@ struct hdcp_txmtr_ops {
};

struct hdcp_client_ops {
	int (*wakeup)(void *client_ctx, enum hdmi_hdcp_cmd cmd,
		char *msg, uint32_t msglen, uint32_t timeout);
	int (*wakeup)(struct hdmi_hdcp_wakeup_data *data);
};

int hdcp_library_register(void **pphdcpcontext,