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

Commit c57441e3 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: hdmi: fix fps calculation"

parents cf43c416 f41f73ef
Loading
Loading
Loading
Loading
+107 −19
Original line number Diff line number Diff line
@@ -337,6 +337,7 @@ struct hdcp_lib_handle {
	void *client_ctx;
	struct hdcp_client_ops *client_ops;
	struct mutex hdcp_lock;
	struct mutex msg_lock;
	struct mutex wakeup_mutex;
	enum hdcp_state hdcp_state;
	enum hdcp_lib_wakeup_cmd wakeup_cmd;
@@ -755,6 +756,77 @@ exit:
	return supported;
}

static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
{
	if (!list_empty(&handle->init.node))
		pr_debug("init work queued\n");

	if (handle->worker.current_work == &handle->init)
		pr_debug("init work executing\n");

	if (!list_empty(&handle->msg_sent.node))
		pr_debug("msg_sent work queued\n");

	if (handle->worker.current_work == &handle->msg_sent)
		pr_debug("msg_sent work executing\n");

	if (!list_empty(&handle->msg_recvd.node))
		pr_debug("msg_recvd work queued\n");

	if (handle->worker.current_work == &handle->msg_recvd)
		pr_debug("msg_recvd work executing\n");

	if (!list_empty(&handle->timeout.node))
		pr_debug("timeout work queued\n");

	if (handle->worker.current_work == &handle->timeout)
		pr_debug("timeout work executing\n");

	if (!list_empty(&handle->clean.node))
		pr_debug("clean work queued\n");

	if (handle->worker.current_work == &handle->clean)
		pr_debug("clean work executing\n");

	if (!list_empty(&handle->topology.node))
		pr_debug("topology work queued\n");

	if (handle->worker.current_work == &handle->topology)
		pr_debug("topology work executing\n");

	if (!list_empty(&handle->stream.node))
		pr_debug("stream work queued\n");

	if (handle->worker.current_work == &handle->stream)
		pr_debug("stream work executing\n");
}

static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle)
{
	int rc = 0;

	if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) {
		if (!list_empty(&handle->worker.work_list)) {
			hdcp_lib_check_worker_status(handle);
			rc = -EBUSY;
			goto exit;
		}
	} else {
		if (atomic_read(&handle->hdcp_off)) {
			pr_warn("hdcp2.2 session tearing down\n");
			goto exit;
		}

		if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
			pr_err("hdcp 2.2 app not loaded\n");
			rc = -EINVAL;
			goto exit;
		}
	}
exit:
	return rc;
}

static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
{
	struct hdcp_lib_handle *handle;
@@ -770,22 +842,29 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
	mutex_lock(&handle->wakeup_mutex);

	handle->wakeup_cmd = data->cmd;
	pr_debug("%s\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd));

	pr_debug("cmd: %s\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd));
	rc = hdcp_lib_check_valid_state(handle);
	if (rc)
		goto exit;

	mutex_lock(&handle->msg_lock);
	if (data->recvd_msg_len) {
		handle->last_msg_recvd_len = data->recvd_msg_len;
		kzfree(handle->last_msg_recvd_buf);

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

		memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf,
			data->recvd_msg_len);
	}
	mutex_unlock(&handle->msg_lock);

	if (!completion_done(&handle->topo_wait))
		complete_all(&handle->topo_wait);
@@ -807,24 +886,19 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
	case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
		handle->last_msg_sent = handle->listener_buf[0];

		if (!atomic_read(&handle->hdcp_off))
		queue_kthread_work(&handle->worker, &handle->msg_sent);
		break;
	case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
	case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
		if (!atomic_read(&handle->hdcp_off))
		queue_kthread_work(&handle->worker, &handle->clean);
		break;
	case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
		if (!atomic_read(&handle->hdcp_off))
		queue_kthread_work(&handle->worker, &handle->msg_recvd);
		break;
	case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
		if (!atomic_read(&handle->hdcp_off))
		queue_kthread_work(&handle->worker, &handle->timeout);
		break;
	case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
		if (!atomic_read(&handle->hdcp_off))
		queue_kthread_work(&handle->worker, &handle->stream);
		break;
	default:
@@ -832,7 +906,7 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
	}
exit:
	mutex_unlock(&handle->wakeup_mutex);
	return 0;
	return rc;
}

static void hdcp_lib_msg_sent_work(struct kthread_work *work)
@@ -926,7 +1000,6 @@ exit:

	if (rc && !atomic_read(&handle->hdcp_off))
		queue_kthread_work(&handle->worker, &handle->clean);
	return;
}

static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
@@ -1044,18 +1117,29 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
	}

	mutex_lock(&handle->hdcp_lock);
	cdata.context = handle->client_ctx;

	msg = handle->last_msg_recvd_buf;
	mutex_lock(&handle->msg_lock);
	msglen = handle->last_msg_recvd_len;

	cdata.context = handle->client_ctx;

	if (msglen <= 0) {
		pr_err("invalid msg len\n");
		mutex_unlock(&handle->msg_lock);
		rc = -EINVAL;
		goto exit;
	}

	msg = kzalloc(msglen, GFP_KERNEL);
	if (!msg) {
		mutex_unlock(&handle->msg_lock);
		rc = -ENOMEM;
		goto exit;
	}

	memcpy(msg, handle->last_msg_recvd_buf, msglen);

	mutex_unlock(&handle->msg_lock);

	pr_debug("msg received: %s from sink\n",
		hdcp_lib_message_name((int)msg[0]));

@@ -1140,7 +1224,7 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
	}

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

	hdcp_lib_wakeup_client(handle, &cdata);
@@ -1160,7 +1244,6 @@ static void hdcp_lib_topology_work(struct kthread_work *work)
		return;
	}


	reinit_completion(&handle->topo_wait);
	timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3);
	if (!timeout) {
@@ -1185,6 +1268,9 @@ bool hdcp1_check_if_supported_load_app(void)
		}
	}

	pr_debug("hdcp1 app %s loaded\n",
		hdcp1_supported ? "successfully" : "not");

	return hdcp1_supported;
}

@@ -1274,6 +1360,7 @@ int hdcp_library_register(void **pphdcpcontext,
	atomic_set(&handle->hdcp_off, 0);

	mutex_init(&handle->hdcp_lock);
	mutex_init(&handle->msg_lock);
	mutex_init(&handle->wakeup_mutex);

	init_kthread_worker(&handle->worker);
@@ -1326,6 +1413,7 @@ void hdcp_library_deregister(void *phdcpcontext)
	kthread_stop(handle->thread);

	kzfree(handle->qseecom_handle);
	kzfree(handle->last_msg_recvd_buf);

	mutex_destroy(&handle->hdcp_lock);
	mutex_destroy(&handle->wakeup_mutex);
+10 −10
Original line number Diff line number Diff line
@@ -1208,9 +1208,9 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
	u32	pulse_width_v       = 0;
	u32	active_low_h        = 0;
	u32	active_low_v        = 0;

	const u32 khz_to_hz         = 1000;
	u32 frame_data;
	struct msm_hdmi_mode_timing_info timing = {0};
	u64 rr_tmp, frame_data;
	int rc;

	/*
@@ -1326,15 +1326,10 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
	active_low_h = ((data_buf[0x11] & BIT(1)) &&
				(data_buf[0x11] & BIT(4))) ? 0 : 1;

	DEV_DBG("%s: A[%ux%u] B[%ux%u] V[%ux%u] %s\n", __func__,
		active_h, active_v, blank_h, blank_v, img_size_h, img_size_v,
		interlaced ? "i" : "p");

	rr_tmp = pixel_clk * 1000 * 1000;
	frame_data = (blank_h + active_h) * (blank_v + active_v);
	frame_data = (active_h + blank_h) * (active_v + blank_v);

	if (frame_data) {
		do_div(rr_tmp, frame_data);
		int refresh_rate_khz = (pixel_clk * khz_to_hz) / frame_data;

		timing.active_h      = active_h;
		timing.front_porch_h = front_porch_h;
@@ -1349,13 +1344,18 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
					(front_porch_v + pulse_width_v);
		timing.active_low_v  = active_low_v;
		timing.pixel_freq    = pixel_clk;
		timing.refresh_rate  = (u32) rr_tmp;
		timing.refresh_rate  = refresh_rate_khz * khz_to_hz;
		timing.interlaced    = interlaced;
		timing.supported     = true;
		timing.ar            = aspect_ratio_4_3 ? HDMI_RES_AR_4_3 :
					(aspect_ratio_5_4 ? HDMI_RES_AR_5_4 :
					HDMI_RES_AR_16_9);

		DEV_DBG("%s: new res: %dx%d%s@%dHz\n", __func__,
			timing.active_h, timing.active_v,
			interlaced ? "i" : "p",
			timing.refresh_rate / khz_to_hz);

		rc = hdmi_set_resv_timing_info(&timing);
	} else {
		DEV_ERR("%s: Invalid frame data\n", __func__);
+29 −22
Original line number Diff line number Diff line
@@ -167,8 +167,9 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
	struct dss_io_data *io = NULL;
	u32 hdcp_ddc_status, ddc_hw_status;
	u32 ddc_xfer_done, ddc_xfer_req, ddc_hw_done;
	u32 ddc_hw_not_ready;
	u32 ddc_xfer_done, ddc_xfer_req;
	u32 ddc_hw_req, ddc_hw_not_idle;
	bool ddc_hw_not_ready, xfer_not_done, hw_not_done;
	u32 timeout_count;

	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
@@ -182,17 +183,24 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
			return;
	}

	if (DSS_REG_R(io, HDMI_DDC_HW_STATUS) != 0) {
	/* Wait to be clean on DDC HW engine */
	timeout_count = 100;
	do {
		hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
			ddc_hw_status = DSS_REG_R(io, HDMI_DDC_HW_STATUS);
			ddc_xfer_done = hdcp_ddc_status & BIT(10);
		ddc_xfer_req    = hdcp_ddc_status & BIT(4);
			ddc_hw_done = ddc_hw_status & BIT(3);
			ddc_hw_not_ready = !ddc_xfer_done ||
				ddc_xfer_req || !ddc_hw_done;
		ddc_xfer_done   = hdcp_ddc_status & BIT(10);

		ddc_hw_status   = DSS_REG_R(io, HDMI_DDC_HW_STATUS);
		ddc_hw_req      = ddc_hw_status & BIT(16);
		ddc_hw_not_idle = ddc_hw_status & (BIT(0) | BIT(1));

		/* ddc transfer was requested but not completed */
		xfer_not_done = ddc_xfer_req && !ddc_xfer_done;

		/* ddc status is not idle or a hw request pending */
		hw_not_done = ddc_hw_not_idle || ddc_hw_req;

		ddc_hw_not_ready = xfer_not_done || hw_not_done;

		DEV_DBG("%s: %s: timeout count(%d): ddc hw%sready\n",
			__func__, HDCP_STATE_NAME, timeout_count,
@@ -202,7 +210,6 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
		if (ddc_hw_not_ready)
			msleep(20);
		} while (ddc_hw_not_ready && --timeout_count);
	}
} /* hdmi_hdcp_hw_ddc_clean */

static int hdcp_scm_call(struct scm_hdcp_req *req, u32 *resp)
+4 −1
Original line number Diff line number Diff line
@@ -21,7 +21,10 @@ enum hdmi_hdcp_state {
	HDCP_STATE_INACTIVE,
	HDCP_STATE_AUTHENTICATING,
	HDCP_STATE_AUTHENTICATED,
	HDCP_STATE_AUTH_FAIL
	HDCP_STATE_AUTH_FAIL,
	HDCP_STATE_AUTH_ENC_NONE,
	HDCP_STATE_AUTH_ENC_1X,
	HDCP_STATE_AUTH_ENC_2P2
};

struct hdmi_hdcp_init_data {
+145 −36
Original line number Diff line number Diff line
@@ -36,6 +36,10 @@

#define HDCP2P2_LINK_CHECK_TIME_MS 500 /* link check within 1 sec */

#define HDCP2P2_SEC_TO_US 1000000
#define HDCP2P2_MS_TO_US  1000
#define HDCP2P2_KHZ_TO_HZ 1000

/*
 * HDCP 2.2 encryption requires the data encryption block that is present in
 * HDMI controller version 4.0.0 and above
@@ -52,6 +56,7 @@ 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 msg_lock; /* mutex to protect access to msg buffer */
	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 */
@@ -95,18 +100,24 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
	ctrl->wakeup_cmd = data->cmd;
	ctrl->timeout = data->timeout;

	mutex_lock(&ctrl->msg_lock);
	if (data->send_msg_len) {
		ctrl->send_msg_len = data->send_msg_len;

		kzfree(ctrl->send_msg_buf);

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

		if (!ctrl->send_msg_buf)
		if (!ctrl->send_msg_buf) {
			mutex_unlock(&ctrl->msg_lock);
			goto exit;
		}

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

	switch (ctrl->wakeup_cmd) {
	case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
@@ -133,7 +144,7 @@ exit:
	return 0;
}

static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl,
static inline int hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl,
	struct hdcp_lib_wakeup_data *data)
{
	int rc = 0;
@@ -145,6 +156,8 @@ static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl,
			pr_err("error sending %s to lib\n",
				hdcp_lib_cmd_to_str(data->cmd));
	}

	return rc;
}

static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl)
@@ -172,6 +185,8 @@ static void hdmi_hdcp2p2_off(void *input)

	flush_kthread_worker(&ctrl->worker);

	hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl);

	cdata.context = input;

	hdmi_hdcp2p2_wakeup(&cdata);
@@ -281,18 +296,48 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP2P2);
	struct hdcp_lib_wakeup_data cdata = {
		HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE};
	bool enc_notify = true;
	enum hdmi_hdcp_state enc_lvl;
	int min_enc_lvl;
	int rc;

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

	pr_debug("notification of minimum level change received\n");
	rc = kstrtoint(buf, 10, &min_enc_lvl);
	if (rc) {
		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
		goto exit;
	}

	switch (min_enc_lvl) {
	case 0:
		enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
		break;
	case 1:
		enc_lvl = HDCP_STATE_AUTH_ENC_1X;
		break;
	case 2:
		enc_lvl = HDCP_STATE_AUTH_ENC_2P2;
		break;
	default:
		enc_notify = false;
	}

	pr_debug("enc level changed %d\n", min_enc_lvl);

	cdata.context = ctrl->lib_ctx;
	hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);

	return  count;
	if (enc_notify && ctrl->init_data.notify_status)
		ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);

	rc = count;
exit:
	return  rc;
}

static void hdmi_hdcp2p2_auth_failed(struct hdmi_hdcp2p2_ctrl *ctrl)
@@ -304,6 +349,8 @@ static void hdmi_hdcp2p2_auth_failed(struct hdmi_hdcp2p2_ctrl *ctrl)

	atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);

	hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl);

	/* notify hdmi tx about HDCP failure */
	ctrl->init_data.notify_status(ctrl->init_data.cb_data,
		HDCP_STATE_AUTH_FAIL);
@@ -457,6 +504,8 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
	struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
		struct hdmi_hdcp2p2_ctrl, send_msg);
	struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
	char *msg;
	uint32_t msglen;

	if (!ctrl) {
		pr_err("invalid input\n");
@@ -472,9 +521,25 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
		goto exit;
	}

	mutex_lock(&ctrl->msg_lock);
	msglen = ctrl->send_msg_len;

	if (!msglen) {
		mutex_unlock(&ctrl->msg_lock);
		goto exit;
	}

	msg = kzalloc(msglen, GFP_KERNEL);
	if (!msg) {
		mutex_unlock(&ctrl->msg_lock);
		goto exit;
	}

	memcpy(msg, ctrl->send_msg_buf, msglen);
	mutex_unlock(&ctrl->msg_lock);

	/* Forward the message to the sink */
	rc = hdmi_hdcp2p2_ddc_write_message(ctrl,
		ctrl->send_msg_buf, (size_t)ctrl->send_msg_len);
	rc = hdmi_hdcp2p2_ddc_write_message(ctrl, msg, (size_t)msglen);
	if (rc) {
		pr_err("Error sending msg to sink %d\n", rc);
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED;
@@ -482,7 +547,7 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS;
	}
exit:
	kzfree(ctrl->send_msg_buf);
	kzfree(msg);
	mutex_unlock(&ctrl->mutex);

	hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
@@ -491,7 +556,9 @@ exit:
static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
{
	int rc = 0;
	u64 mult;
	u32 fps, v_total;
	u32 time_taken_by_one_line_us;
	u32 lines_needed_for_given_time;
	char *recvd_msg_buf = NULL;
	struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
		struct hdmi_hdcp2p2_ctrl, recv_msg);
@@ -525,12 +592,26 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
	memset(ddc_data, 0, sizeof(*ddc_data));

	timing = ctrl->init_data.timing;
	mult = hdmi_tx_get_v_total(timing) / 20;

	fps = timing->refresh_rate / HDCP2P2_KHZ_TO_HZ;
	v_total = hdmi_tx_get_v_total(timing);

	/*
	 * pixel clock  = h_total * v_total * fps
	 * 1 sec = pixel clock number of pixels are transmitted.
	 * time taken by one line (h_total) = 1 / (v_total * fps).
	 */
	time_taken_by_one_line_us = HDCP2P2_SEC_TO_US / (v_total * fps);
	lines_needed_for_given_time = (ctrl->timeout * HDCP2P2_MS_TO_US) /
		time_taken_by_one_line_us;

	pr_debug("timeout for rxstatus %d\n", lines_needed_for_given_time);

	ddc_data->intr_mask = RXSTATUS_MESSAGE_SIZE;
	ddc_data->timer_delay_lines = (u32)mult;
	ddc_data->timer_delay_lines = lines_needed_for_given_time;
	ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER;

	rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl);
	rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, true);
	if (rc) {
		pr_err("error reading rxstatus %d\n", rc);
		goto exit;
@@ -568,6 +649,42 @@ exit:
	kfree(recvd_msg_buf);
}

static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl)
{
	struct hdmi_tx_ddc_ctrl *ddc_ctrl;
	struct hdmi_tx_hdcp2p2_ddc_data *ddc_data;
	struct msm_hdmi_mode_timing_info *timing;
	u32 fps, v_total;
	u32 time_taken_by_one_line_us;
	u32 lines_needed_for_given_time;

	ddc_ctrl = ctrl->init_data.ddc_ctrl;
	if (!ddc_ctrl)
		return -EINVAL;

	hdmi_ddc_config(ddc_ctrl);

	ddc_data = &ddc_ctrl->hdcp2p2_ddc_data;

	memset(ddc_data, 0, sizeof(*ddc_data));

	timing = ctrl->init_data.timing;
	fps = timing->refresh_rate / HDCP2P2_KHZ_TO_HZ;
	v_total = hdmi_tx_get_v_total(timing);
	time_taken_by_one_line_us = HDCP2P2_SEC_TO_US / (v_total * fps);
	lines_needed_for_given_time = (jiffies_to_msecs(HZ / 2) *
		HDCP2P2_MS_TO_US) / time_taken_by_one_line_us;

	pr_debug("timeout for rxstatus %d\n", lines_needed_for_given_time);

	ddc_data->intr_mask = RXSTATUS_READY | RXSTATUS_MESSAGE_SIZE |
		RXSTATUS_REAUTH_REQ;
	ddc_data->timer_delay_lines = lines_needed_for_given_time;
	ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER;

	return hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, false);
}

static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work)
{
	struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
@@ -602,7 +719,7 @@ static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work)
		ctrl->init_data.notify_status(ctrl->init_data.cb_data,
			HDCP_STATE_AUTHENTICATED);

		/* recheck within 1sec as per hdcp 2.2 standard */
		if (!hdmi_hdcp2p2_link_check(ctrl))
			schedule_delayed_work(&ctrl->link_check_work,
				msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS));
	}
@@ -625,11 +742,9 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
	struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
		struct hdmi_hdcp2p2_ctrl, link);
	struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
	struct hdmi_tx_ddc_ctrl *ddc_ctrl;
	struct hdmi_tx_hdcp2p2_ddc_data *ddc_data;
	u64 mult;
	struct msm_hdmi_mode_timing_info *timing;
	char *recvd_msg_buf = NULL;
	struct hdmi_tx_hdcp2p2_ddc_data *ddc_data;
	struct hdmi_tx_ddc_ctrl *ddc_ctrl;

	if (!ctrl) {
		pr_err("invalid input\n");
@@ -647,26 +762,14 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
		goto exit;
	}

	hdmi_ddc_config(ddc_ctrl);

	ddc_data = &ddc_ctrl->hdcp2p2_ddc_data;

	memset(ddc_data, 0, sizeof(*ddc_data));

	timing = ctrl->init_data.timing;
	mult = hdmi_tx_get_v_total(timing) / 20;
	ddc_data->intr_mask = RXSTATUS_READY | RXSTATUS_MESSAGE_SIZE |
		RXSTATUS_REAUTH_REQ;
	ddc_data->timer_delay_lines = (u32)mult;
	ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER;

	rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl);
	rc = hdmi_ddc_check_status(ddc_ctrl);
	if (rc) {
		pr_err("error reading rxstatus %d\n", rc);
		cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
		goto exit;
	}

	ddc_data = &ddc_ctrl->hdcp2p2_ddc_data;

	if (ddc_data->reauth_req) {
		pr_debug("sync reported loss of synchronization, reauth\n");
		rc = -ENOLINK;
@@ -693,6 +796,8 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
			cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS;
			cdata.recvd_msg_buf = recvd_msg_buf;
			cdata.recvd_msg_len = ddc_data->message_size;

			hdmi_hdcp2p2_link_check(ctrl);
		}
	}
exit:
@@ -735,7 +840,8 @@ static void hdmi_hdcp2p2_auth_work(struct kthread_work *work)

	mutex_unlock(&ctrl->mutex);

	hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
	if (hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata))
		hdmi_hdcp2p2_auth_failed(ctrl);
}

void hdmi_hdcp2p2_deinit(void *input)
@@ -758,6 +864,8 @@ void hdmi_hdcp2p2_deinit(void *input)
				&hdmi_hdcp2p2_fs_attr_group);

	mutex_destroy(&ctrl->mutex);
	mutex_destroy(&ctrl->msg_lock);
	mutex_destroy(&ctrl->wakeup_mutex);
	kfree(ctrl);
}

@@ -812,6 +920,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)

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

	rc = hdcp_library_register(&ctrl->lib_ctx,
Loading