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

Commit e24d78b4 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: hdcp2.2: use strict timeouts as per standard"

parents 5b742b56 985edcd0
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -332,6 +332,7 @@ struct hdcp_lib_handle {
	uint32_t msglen;
	uint32_t tz_ctxhandle;
	uint32_t hdcp_timeout;
	uint32_t timeout_left;
	bool no_stored_km_flag;
	bool feature_supported;
	void *client_ctx;
@@ -842,7 +843,11 @@ 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));
	handle->timeout_left = data->timeout;

	pr_debug("%s, timeout left: %dms\n",
		hdcp_lib_cmd_to_str(handle->wakeup_cmd),
		handle->timeout_left);

	rc = hdcp_lib_check_valid_state(handle);
	if (rc)
@@ -874,6 +879,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
		handle->no_stored_km_flag = 0;
		handle->repeater_flag = 0;
		handle->last_msg_sent = 0;
		handle->hdcp_timeout = 0;
		handle->timeout_left = 0;
		atomic_set(&handle->hdcp_off, 0);
		handle->hdcp_state = HDCP_STATE_INIT;

@@ -949,7 +956,7 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work)
		break;
	default:
		cdata.cmd = HDMI_HDCP_WKUP_CMD_RECV_MESSAGE;
		cdata.timeout = handle->hdcp_timeout;
		cdata.timeout = handle->timeout_left;
	}

	mutex_unlock(&handle->hdcp_lock);
+87 −34
Original line number Diff line number Diff line
@@ -34,11 +34,12 @@
#define HDCP_SINK_DDC_HDCP2_RXSTATUS 0x70        /* RxStatus, 2 bytes */
#define HDCP_SINK_DDC_HDCP2_READ_MESSAGE 0x80    /* HDCP Tx reads here */

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

#define HDCP2P2_SEC_TO_US 1000000
#define HDCP2P2_MS_TO_US  1000
#define HDCP2P2_KHZ_TO_HZ 1000
#define HDCP2P2_DEFAULT_TIMEOUT 500

/*
 * HDCP 2.2 encryption requires the data encryption block that is present in
@@ -66,6 +67,7 @@ struct hdmi_hdcp2p2_ctrl {
	char *send_msg_buf;
	uint32_t send_msg_len;
	uint32_t timeout;
	uint32_t timeout_left;

	struct task_struct *thread;
	struct kthread_worker worker;
@@ -78,6 +80,45 @@ struct hdmi_hdcp2p2_ctrl {
	struct delayed_work link_check_work;
};

static inline bool hdmi_hdcp2p2_is_valid_state(struct hdmi_hdcp2p2_ctrl *ctrl)
{
	if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE)
		return true;

	if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
		return true;

	return false;
}

static int hdmi_hdcp2p2_copy_buf(struct hdmi_hdcp2p2_ctrl *ctrl,
	struct hdmi_hdcp_wakeup_data *data)
{
	mutex_lock(&ctrl->msg_lock);

	if (!data->send_msg_len) {
		mutex_unlock(&ctrl->msg_lock);
		return 0;
	}

	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) {
		mutex_unlock(&ctrl->msg_lock);
		return -ENOMEM;
	}

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

	mutex_unlock(&ctrl->msg_lock);

	return 0;
}

static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
{
	struct hdmi_hdcp2p2_ctrl *ctrl;
@@ -95,42 +136,34 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)

	mutex_lock(&ctrl->wakeup_mutex);

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

	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 (data->timeout)
		ctrl->timeout = data->timeout;
	else
		ctrl->timeout = HDCP2P2_DEFAULT_TIMEOUT;

		if (!ctrl->send_msg_buf) {
			mutex_unlock(&ctrl->msg_lock);
	if (!hdmi_hdcp2p2_is_valid_state(ctrl)) {
		pr_err("invalid state\n");
		goto exit;
	}

		memcpy(ctrl->send_msg_buf, data->send_msg_buf,
			ctrl->send_msg_len);
	}
	mutex_unlock(&ctrl->msg_lock);
	if (hdmi_hdcp2p2_copy_buf(ctrl, data))
		goto exit;

	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:
@@ -366,6 +399,7 @@ static int hdmi_hdcp2p2_ddc_read_message(struct hdmi_hdcp2p2_ctrl *ctrl,
		pr_err("hdcp is off\n");
		return -EINVAL;
	}

	memset(&ddc_data, 0, sizeof(ddc_data));
	ddc_data.dev_addr = HDCP_SINK_DDC_SLAVE_ADDR;
	ddc_data.offset = HDCP_SINK_DDC_HDCP2_READ_MESSAGE;
@@ -378,9 +412,14 @@ static int hdmi_hdcp2p2_ddc_read_message(struct hdmi_hdcp2p2_ctrl *ctrl,

	ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;

	pr_debug("read msg timeout %dms\n", timeout);

	rc = hdmi_ddc_read(ctrl->init_data.ddc_ctrl);
	if (rc)
		pr_err("Cannot read HDCP message register\n");

	ctrl->timeout_left = ctrl->init_data.ddc_ctrl->ddc_data.timeout_left;

	return rc;
}

@@ -396,6 +435,7 @@ static int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl,
	ddc_data.data_buf = buf;
	ddc_data.data_len = size;
	ddc_data.retry = 1;
	ddc_data.hard_timeout = ctrl->timeout;
	ddc_data.what = "HDCP2WriteMessage";

	ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
@@ -403,6 +443,9 @@ static int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl,
	rc = hdmi_ddc_write(ctrl->init_data.ddc_ctrl);
	if (rc)
		pr_err("Cannot write HDCP message register\n");

	ctrl->timeout_left = ctrl->init_data.ddc_ctrl->ddc_data.timeout_left;

	return rc;
}

@@ -545,6 +588,7 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED;
	} else {
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS;
		cdata.timeout = ctrl->timeout_left;
	}
exit:
	kzfree(msg);
@@ -605,10 +649,13 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
	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);
	pr_debug("timeout for rxstatus %dms, %d hsyncs\n",
		ctrl->timeout, lines_needed_for_given_time);

	ddc_data->intr_mask = RXSTATUS_MESSAGE_SIZE;
	ddc_data->timer_delay_lines = lines_needed_for_given_time;
	ddc_data->timeout_ms = ctrl->timeout;
	ddc_data->timeout_hsync = lines_needed_for_given_time;
	ddc_data->periodic_timer_hsync = lines_needed_for_given_time / 20;
	ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER;

	rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, true);
@@ -617,26 +664,30 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
		goto exit;
	}

	ctrl->timeout_left = ddc_data->timeout_left;

	pr_debug("timeout left after rxstatus %dms, msg size %d\n",
		ctrl->timeout_left, ddc_data->message_size);

	if (!ddc_data->message_size) {
		pr_err("recvd invalid message size\n");
		rc = -EINVAL;
		goto exit;
	}

	pr_debug("rxstatus msg size %d\n", ddc_data->message_size);

	recvd_msg_buf = kzalloc(ddc_data->message_size, GFP_KERNEL);
	if (!recvd_msg_buf)
		goto exit;

	rc = hdmi_hdcp2p2_ddc_read_message(ctrl, recvd_msg_buf,
		ddc_data->message_size, ctrl->timeout);
		ddc_data->message_size, ctrl->timeout_left);
	if (rc)
		pr_err("error reading message %d\n", rc);

	cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS;
	cdata.recvd_msg_buf = recvd_msg_buf;
	cdata.recvd_msg_len = ddc_data->message_size;
	cdata.timeout = ctrl->timeout_left;
exit:
	if (rc == -ETIMEDOUT)
		cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT;
@@ -672,14 +723,16 @@ static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl)
	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) *
	lines_needed_for_given_time = (jiffies_to_msecs((HZ / 2) + (HZ / 4)) *
		HDCP2P2_MS_TO_US) / time_taken_by_one_line_us;

	pr_debug("timeout for rxstatus %d\n", lines_needed_for_given_time);
	pr_debug("timeout for rxstatus %d hsyncs\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->timeout_hsync = lines_needed_for_given_time;
	ddc_data->periodic_timer_hsync = lines_needed_for_given_time;
	ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER;

	return hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, false);
@@ -788,7 +841,7 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
		}

		rc = hdmi_hdcp2p2_ddc_read_message(ctrl, recvd_msg_buf,
			ddc_data->message_size, ctrl->timeout);
			ddc_data->message_size, HDCP2P2_DEFAULT_TIMEOUT);
		if (rc) {
			cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
			pr_err("error reading message %d\n", rc);
+43 −22
Original line number Diff line number Diff line
@@ -515,23 +515,22 @@ static int hdmi_ddc_clear_irq(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
		return -EINVAL;
	}

	/* clear and enable interrutps */
	ddc_int_ctrl = sw_done_mask | sw_done_ack | hw_done_mask | hw_done_ack;

	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, ddc_int_ctrl);

	/* wait until DDC HW is free */
	timeout = 100;
	do {
		--timeout;
		ddc_status = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_HW_STATUS);
		in_use = ddc_status & (in_use_by_sw | in_use_by_hw);
		if (in_use) {
			pr_debug("ddc is in use by %s\n",
				ddc_status & in_use_by_sw ? "sw" : "hw");
			msleep(20);
			udelay(100);
		}
	} while (in_use && timeout);

	/* clear and enable interrutps */
	ddc_int_ctrl = sw_done_mask | sw_done_ack | hw_done_mask | hw_done_ack;

	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, ddc_int_ctrl);
	} while (in_use && --timeout);

	if (!timeout) {
		pr_err("%s: timedout\n", what);
@@ -652,10 +651,14 @@ again:
		&ddc_ctrl->ddc_sw_done, wait_time);
	pr_debug("ddc read done at %dms\n", jiffies_to_msecs(jiffies));

	ddc_data->timeout_left = jiffies_to_msecs(time_out_count);

	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, BIT(1));
	if (!time_out_count) {
		if (ddc_data->retry-- > 0) {
			pr_debug("failed timout, retry=%d\n", ddc_data->retry);

			if (!ddc_data->hard_timeout)
				goto again;
		}
		status = -ETIMEDOUT;
@@ -809,8 +812,7 @@ static int hdmi_ddc_hdcp2p2_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
	intr2 = DSS_REG_R(io, HDMI_HDCP_INT_CTRL2);
	intr0 = DSS_REG_R(io, HDMI_DDC_INT_CTRL0);

	pr_debug("INT_CTRL0 :0x%x\n", intr0);
	pr_debug("INT_CTRL2 :0x%x\n", intr2);
	pr_debug("ctl0: 0x%x, ctl1: 0x%x\n", intr0, intr2);

	/* check for encryption ready interrupt */
	if (intr2 & BIT(2)) {
@@ -1204,6 +1206,7 @@ int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
	int status = 0, retry = 10;
	u32 time_out_count;
	struct hdmi_tx_ddc_data *ddc_data;
	u32 wait_time;

	if (!ddc_ctrl || !ddc_ctrl->io) {
		pr_err("invalid input\n");
@@ -1286,8 +1289,19 @@ again:
	reinit_completion(&ddc_ctrl->ddc_sw_done);
	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0));

	if (ddc_data->hard_timeout) {
		pr_debug("using hard_timeout %dms\n", ddc_data->hard_timeout);
		wait_time = msecs_to_jiffies(ddc_data->hard_timeout);
	} else {
		wait_time = HZ/2;
	}

	pr_debug("timeout for ddc write %d jiffies\n", wait_time);

	time_out_count = wait_for_completion_timeout(
		&ddc_ctrl->ddc_sw_done, HZ/2);
		&ddc_ctrl->ddc_sw_done, wait_time);

	ddc_data->timeout_left = jiffies_to_msecs(time_out_count);

	pr_debug("DDC write done at %dms\n", jiffies_to_msecs(jiffies));

@@ -1297,6 +1311,8 @@ again:
		if (retry-- > 0) {
			pr_debug("%s: failed timout, retry=%d\n",
				ddc_data->what, retry);

			if (!ddc_data->hard_timeout)
				goto again;
		}
		status = -ETIMEDOUT;
@@ -1635,6 +1651,7 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait)
	u32 reg_val;
	u32 intr_en_mask;
	u32 timeout;
	u32 timer;
	int rc = 0;
	struct hdmi_tx_hdcp2p2_ddc_data *data;

@@ -1674,9 +1691,11 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait)
	 * 3. DDC_TIMEOUT_TIMER: Timeout in hsyncs which starts counting when
	 *	a request is made and stops when it is accepted by DDC arbiter
	 */
	timeout = data->timer_delay_lines;
	pr_debug("timeout: %d\n", timeout);
	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_TIMER_CTRL, timeout);
	timeout = data->timeout_hsync;
	timer = data->periodic_timer_hsync;
	pr_debug("timeout: %d hsyncs, timer %d hsync\n", timeout, timer);

	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_TIMER_CTRL, timer);

	/* Set both urgent and hw-timeout fields to the same value */
	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_TIMER_CTRL2,
@@ -1711,8 +1730,6 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait)
	reg_val = DSS_REG_R(ctrl->io, HDMI_HW_DDC_CTRL);
	reg_val &= ~(BIT(1) | BIT(0));

	pr_debug("data->read_method %d\n", data->read_method);

	if (data->read_method == HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER)
		reg_val |= BIT(1) | BIT(0);
	else
@@ -1725,16 +1742,20 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait)
		DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_SW_TRIGGER, 1);

		if (wait) {
			u32 wait_timeout;

			reinit_completion(&ctrl->rxstatus_completion);
			/* max timeout as per hdcp 2.2 std is 1 sec */
			timeout = wait_for_completion_timeout(

			wait_timeout = wait_for_completion_timeout(
					&ctrl->rxstatus_completion,
					msecs_to_jiffies(HDMI_SEC_TO_MS));
			if (!timeout) {
					msecs_to_jiffies(data->timeout_ms));
			if (!wait_timeout) {
				pr_err("sw ddc rxstatus timeout\n");
				rc = -ETIMEDOUT;
			}

			data->timeout_left = jiffies_to_msecs(wait_timeout);

			rc = hdmi_ddc_check_status(ctrl);

			hdmi_hdcp2p2_ddc_disable(ctrl);
+5 −1
Original line number Diff line number Diff line
@@ -405,6 +405,7 @@ struct hdmi_tx_ddc_data {
	u32 request_len;
	u32 no_align;
	u32 hard_timeout;
	u32 timeout_left;
	int retry;
};

@@ -416,7 +417,10 @@ enum hdmi_tx_hdcp2p2_rxstatus_intr_mask {

struct hdmi_tx_hdcp2p2_ddc_data {
	enum hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask;
	u32 timer_delay_lines;
	u32 timeout_ms;
	u32 timeout_hsync;
	u32 periodic_timer_hsync;
	u32 timeout_left;
	u32 read_method;
	u32 message_size;
	bool encryption_ready;