xref: /openbmc/linux/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c (revision 3bf90eca)
197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c6a57a50Sjilai wang /* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
3c6a57a50Sjilai wang  */
4c6a57a50Sjilai wang 
5c6a57a50Sjilai wang #include "hdmi.h"
6*3bf90ecaSElliot Berman #include <linux/firmware/qcom/qcom_scm.h>
7c6a57a50Sjilai wang 
8c6a57a50Sjilai wang #define HDCP_REG_ENABLE 0x01
9c6a57a50Sjilai wang #define HDCP_REG_DISABLE 0x00
10c6a57a50Sjilai wang #define HDCP_PORT_ADDR 0x74
11c6a57a50Sjilai wang 
12c6a57a50Sjilai wang #define HDCP_INT_STATUS_MASK ( \
13c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_INT | \
14c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_FAIL_INT | \
15c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_XFER_REQ_INT | \
16c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_XFER_DONE_INT)
17c6a57a50Sjilai wang 
18c6a57a50Sjilai wang #define AUTH_WORK_RETRIES_TIME 100
19c6a57a50Sjilai wang #define AUTH_RETRIES_TIME 30
20c6a57a50Sjilai wang 
21c6a57a50Sjilai wang /* QFPROM Registers for HDMI/HDCP */
22c6a57a50Sjilai wang #define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB  0x000000F8
23c6a57a50Sjilai wang #define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB  0x000000FC
24c6a57a50Sjilai wang #define HDCP_KSV_LSB                     0x000060D8
25c6a57a50Sjilai wang #define HDCP_KSV_MSB                     0x000060DC
26c6a57a50Sjilai wang 
27c6a57a50Sjilai wang enum DS_TYPE {  /* type of downstream device */
28c6a57a50Sjilai wang 	DS_UNKNOWN,
29c6a57a50Sjilai wang 	DS_RECEIVER,
30c6a57a50Sjilai wang 	DS_REPEATER,
31c6a57a50Sjilai wang };
32c6a57a50Sjilai wang 
33c6a57a50Sjilai wang enum hdmi_hdcp_state {
34c6a57a50Sjilai wang 	HDCP_STATE_NO_AKSV,
35c6a57a50Sjilai wang 	HDCP_STATE_INACTIVE,
36c6a57a50Sjilai wang 	HDCP_STATE_AUTHENTICATING,
37c6a57a50Sjilai wang 	HDCP_STATE_AUTHENTICATED,
38c6a57a50Sjilai wang 	HDCP_STATE_AUTH_FAILED
39c6a57a50Sjilai wang };
40c6a57a50Sjilai wang 
41c6a57a50Sjilai wang struct hdmi_hdcp_reg_data {
42c6a57a50Sjilai wang 	u32 reg_id;
43c6a57a50Sjilai wang 	u32 off;
44c6a57a50Sjilai wang 	char *name;
45c6a57a50Sjilai wang 	u32 reg_val;
46c6a57a50Sjilai wang };
47c6a57a50Sjilai wang 
48c6a57a50Sjilai wang struct hdmi_hdcp_ctrl {
49c6a57a50Sjilai wang 	struct hdmi *hdmi;
50c6a57a50Sjilai wang 	u32 auth_retries;
51c6a57a50Sjilai wang 	bool tz_hdcp;
52c6a57a50Sjilai wang 	enum hdmi_hdcp_state hdcp_state;
53c6a57a50Sjilai wang 	struct work_struct hdcp_auth_work;
54c6a57a50Sjilai wang 	struct work_struct hdcp_reauth_work;
55c6a57a50Sjilai wang 
56c6a57a50Sjilai wang #define AUTH_ABORT_EV 1
57c6a57a50Sjilai wang #define AUTH_RESULT_RDY_EV 2
58c6a57a50Sjilai wang 	unsigned long auth_event;
59c6a57a50Sjilai wang 	wait_queue_head_t auth_event_queue;
60c6a57a50Sjilai wang 
61c6a57a50Sjilai wang 	u32 ksv_fifo_w_index;
62c6a57a50Sjilai wang 	/*
63c6a57a50Sjilai wang 	 * store aksv from qfprom
64c6a57a50Sjilai wang 	 */
65c6a57a50Sjilai wang 	u32 aksv_lsb;
66c6a57a50Sjilai wang 	u32 aksv_msb;
67c6a57a50Sjilai wang 	bool aksv_valid;
68c6a57a50Sjilai wang 	u32 ds_type;
69c6a57a50Sjilai wang 	u32 bksv_lsb;
70c6a57a50Sjilai wang 	u32 bksv_msb;
71c6a57a50Sjilai wang 	u8 dev_count;
72c6a57a50Sjilai wang 	u8 depth;
73c6a57a50Sjilai wang 	u8 ksv_list[5 * 127];
74c6a57a50Sjilai wang 	bool max_cascade_exceeded;
75c6a57a50Sjilai wang 	bool max_dev_exceeded;
76c6a57a50Sjilai wang };
77c6a57a50Sjilai wang 
msm_hdmi_ddc_read(struct hdmi * hdmi,u16 addr,u8 offset,u8 * data,u16 data_len)78fcda50c8SArnd Bergmann static int msm_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset,
79c6a57a50Sjilai wang 	u8 *data, u16 data_len)
80c6a57a50Sjilai wang {
81c6a57a50Sjilai wang 	int rc;
82c6a57a50Sjilai wang 	int retry = 5;
83c6a57a50Sjilai wang 	struct i2c_msg msgs[] = {
84c6a57a50Sjilai wang 		{
85c6a57a50Sjilai wang 			.addr	= addr >> 1,
86c6a57a50Sjilai wang 			.flags	= 0,
87c6a57a50Sjilai wang 			.len	= 1,
88c6a57a50Sjilai wang 			.buf	= &offset,
89c6a57a50Sjilai wang 		}, {
90c6a57a50Sjilai wang 			.addr	= addr >> 1,
91c6a57a50Sjilai wang 			.flags	= I2C_M_RD,
92c6a57a50Sjilai wang 			.len	= data_len,
93c6a57a50Sjilai wang 			.buf	= data,
94c6a57a50Sjilai wang 		}
95c6a57a50Sjilai wang 	};
96c6a57a50Sjilai wang 
97c6a57a50Sjilai wang 	DBG("Start DDC read");
98c6a57a50Sjilai wang retry:
99c6a57a50Sjilai wang 	rc = i2c_transfer(hdmi->i2c, msgs, 2);
100c6a57a50Sjilai wang 
101c6a57a50Sjilai wang 	retry--;
102c6a57a50Sjilai wang 	if (rc == 2)
103c6a57a50Sjilai wang 		rc = 0;
104c6a57a50Sjilai wang 	else if (retry > 0)
105c6a57a50Sjilai wang 		goto retry;
106c6a57a50Sjilai wang 	else
107c6a57a50Sjilai wang 		rc = -EIO;
108c6a57a50Sjilai wang 
109c6a57a50Sjilai wang 	DBG("End DDC read %d", rc);
110c6a57a50Sjilai wang 
111c6a57a50Sjilai wang 	return rc;
112c6a57a50Sjilai wang }
113c6a57a50Sjilai wang 
114c6a57a50Sjilai wang #define HDCP_DDC_WRITE_MAX_BYTE_NUM 32
115c6a57a50Sjilai wang 
msm_hdmi_ddc_write(struct hdmi * hdmi,u16 addr,u8 offset,u8 * data,u16 data_len)116fcda50c8SArnd Bergmann static int msm_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset,
117c6a57a50Sjilai wang 	u8 *data, u16 data_len)
118c6a57a50Sjilai wang {
119c6a57a50Sjilai wang 	int rc;
120c6a57a50Sjilai wang 	int retry = 10;
121c6a57a50Sjilai wang 	u8 buf[HDCP_DDC_WRITE_MAX_BYTE_NUM];
122c6a57a50Sjilai wang 	struct i2c_msg msgs[] = {
123c6a57a50Sjilai wang 		{
124c6a57a50Sjilai wang 			.addr	= addr >> 1,
125c6a57a50Sjilai wang 			.flags	= 0,
126c6a57a50Sjilai wang 			.len	= 1,
127c6a57a50Sjilai wang 		}
128c6a57a50Sjilai wang 	};
129c6a57a50Sjilai wang 
130c6a57a50Sjilai wang 	DBG("Start DDC write");
131c6a57a50Sjilai wang 	if (data_len > (HDCP_DDC_WRITE_MAX_BYTE_NUM - 1)) {
132c6a57a50Sjilai wang 		pr_err("%s: write size too big\n", __func__);
133c6a57a50Sjilai wang 		return -ERANGE;
134c6a57a50Sjilai wang 	}
135c6a57a50Sjilai wang 
136c6a57a50Sjilai wang 	buf[0] = offset;
137c6a57a50Sjilai wang 	memcpy(&buf[1], data, data_len);
138c6a57a50Sjilai wang 	msgs[0].buf = buf;
139c6a57a50Sjilai wang 	msgs[0].len = data_len + 1;
140c6a57a50Sjilai wang retry:
141c6a57a50Sjilai wang 	rc = i2c_transfer(hdmi->i2c, msgs, 1);
142c6a57a50Sjilai wang 
143c6a57a50Sjilai wang 	retry--;
144c6a57a50Sjilai wang 	if (rc == 1)
145c6a57a50Sjilai wang 		rc = 0;
146c6a57a50Sjilai wang 	else if (retry > 0)
147c6a57a50Sjilai wang 		goto retry;
148c6a57a50Sjilai wang 	else
149c6a57a50Sjilai wang 		rc = -EIO;
150c6a57a50Sjilai wang 
151c6a57a50Sjilai wang 	DBG("End DDC write %d", rc);
152c6a57a50Sjilai wang 
153c6a57a50Sjilai wang 	return rc;
154c6a57a50Sjilai wang }
155c6a57a50Sjilai wang 
msm_hdmi_hdcp_scm_wr(struct hdmi_hdcp_ctrl * hdcp_ctrl,u32 * preg,u32 * pdata,u32 count)156fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_scm_wr(struct hdmi_hdcp_ctrl *hdcp_ctrl, u32 *preg,
157c6a57a50Sjilai wang 	u32 *pdata, u32 count)
158c6a57a50Sjilai wang {
159c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
160c6a57a50Sjilai wang 	struct qcom_scm_hdcp_req scm_buf[QCOM_SCM_HDCP_MAX_REQ_CNT];
161c6a57a50Sjilai wang 	u32 resp, phy_addr, idx = 0;
162c6a57a50Sjilai wang 	int i, ret = 0;
163c6a57a50Sjilai wang 
164c6a57a50Sjilai wang 	WARN_ON(!pdata || !preg || (count == 0));
165c6a57a50Sjilai wang 
166c6a57a50Sjilai wang 	if (hdcp_ctrl->tz_hdcp) {
167c6a57a50Sjilai wang 		phy_addr = (u32)hdmi->mmio_phy_addr;
168c6a57a50Sjilai wang 
169c6a57a50Sjilai wang 		while (count) {
170c6a57a50Sjilai wang 			memset(scm_buf, 0, sizeof(scm_buf));
171c6a57a50Sjilai wang 			for (i = 0; i < count && i < QCOM_SCM_HDCP_MAX_REQ_CNT;
172c6a57a50Sjilai wang 				i++) {
173c6a57a50Sjilai wang 				scm_buf[i].addr = phy_addr + preg[idx];
174c6a57a50Sjilai wang 				scm_buf[i].val  = pdata[idx];
175c6a57a50Sjilai wang 				idx++;
176c6a57a50Sjilai wang 			}
177c6a57a50Sjilai wang 			ret = qcom_scm_hdcp_req(scm_buf, i, &resp);
178c6a57a50Sjilai wang 
179c6a57a50Sjilai wang 			if (ret || resp) {
180c6a57a50Sjilai wang 				pr_err("%s: error: scm_call ret=%d resp=%u\n",
181c6a57a50Sjilai wang 					__func__, ret, resp);
182c6a57a50Sjilai wang 				ret = -EINVAL;
183c6a57a50Sjilai wang 				break;
184c6a57a50Sjilai wang 			}
185c6a57a50Sjilai wang 
186c6a57a50Sjilai wang 			count -= i;
187c6a57a50Sjilai wang 		}
188c6a57a50Sjilai wang 	} else {
189c6a57a50Sjilai wang 		for (i = 0; i < count; i++)
190c6a57a50Sjilai wang 			hdmi_write(hdmi, preg[i], pdata[i]);
191c6a57a50Sjilai wang 	}
192c6a57a50Sjilai wang 
193c6a57a50Sjilai wang 	return ret;
194c6a57a50Sjilai wang }
195c6a57a50Sjilai wang 
msm_hdmi_hdcp_irq(struct hdmi_hdcp_ctrl * hdcp_ctrl)196fcda50c8SArnd Bergmann void msm_hdmi_hdcp_irq(struct hdmi_hdcp_ctrl *hdcp_ctrl)
197c6a57a50Sjilai wang {
198c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
199c6a57a50Sjilai wang 	u32 reg_val, hdcp_int_status;
200c6a57a50Sjilai wang 	unsigned long flags;
201c6a57a50Sjilai wang 
202c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
203c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_INT_CTRL);
204c6a57a50Sjilai wang 	hdcp_int_status = reg_val & HDCP_INT_STATUS_MASK;
205c6a57a50Sjilai wang 	if (!hdcp_int_status) {
206c6a57a50Sjilai wang 		spin_unlock_irqrestore(&hdmi->reg_lock, flags);
207c6a57a50Sjilai wang 		return;
208c6a57a50Sjilai wang 	}
209c6a57a50Sjilai wang 	/* Clear Interrupts */
210c6a57a50Sjilai wang 	reg_val |= hdcp_int_status << 1;
211c6a57a50Sjilai wang 	/* Clear AUTH_FAIL_INFO as well */
212c6a57a50Sjilai wang 	if (hdcp_int_status & HDMI_HDCP_INT_CTRL_AUTH_FAIL_INT)
213c6a57a50Sjilai wang 		reg_val |= HDMI_HDCP_INT_CTRL_AUTH_FAIL_INFO_ACK;
214c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL, reg_val);
215c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
216c6a57a50Sjilai wang 
217c6a57a50Sjilai wang 	DBG("hdcp irq %x", hdcp_int_status);
218c6a57a50Sjilai wang 
219c6a57a50Sjilai wang 	if (hdcp_int_status & HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_INT) {
220c6a57a50Sjilai wang 		pr_info("%s:AUTH_SUCCESS_INT received\n", __func__);
221c6a57a50Sjilai wang 		if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
222c6a57a50Sjilai wang 			set_bit(AUTH_RESULT_RDY_EV, &hdcp_ctrl->auth_event);
223c6a57a50Sjilai wang 			wake_up_all(&hdcp_ctrl->auth_event_queue);
224c6a57a50Sjilai wang 		}
225c6a57a50Sjilai wang 	}
226c6a57a50Sjilai wang 
227c6a57a50Sjilai wang 	if (hdcp_int_status & HDMI_HDCP_INT_CTRL_AUTH_FAIL_INT) {
228c6a57a50Sjilai wang 		reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
229c6a57a50Sjilai wang 		pr_info("%s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n",
230c6a57a50Sjilai wang 			__func__, reg_val);
231c6a57a50Sjilai wang 		if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state)
232c6a57a50Sjilai wang 			queue_work(hdmi->workq, &hdcp_ctrl->hdcp_reauth_work);
233c6a57a50Sjilai wang 		else if (HDCP_STATE_AUTHENTICATING ==
234c6a57a50Sjilai wang 				hdcp_ctrl->hdcp_state) {
235c6a57a50Sjilai wang 			set_bit(AUTH_RESULT_RDY_EV, &hdcp_ctrl->auth_event);
236c6a57a50Sjilai wang 			wake_up_all(&hdcp_ctrl->auth_event_queue);
237c6a57a50Sjilai wang 		}
238c6a57a50Sjilai wang 	}
239c6a57a50Sjilai wang }
240c6a57a50Sjilai wang 
msm_hdmi_hdcp_msleep(struct hdmi_hdcp_ctrl * hdcp_ctrl,u32 ms,u32 ev)241fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_msleep(struct hdmi_hdcp_ctrl *hdcp_ctrl, u32 ms, u32 ev)
242c6a57a50Sjilai wang {
243c6a57a50Sjilai wang 	int rc;
244c6a57a50Sjilai wang 
245c6a57a50Sjilai wang 	rc = wait_event_timeout(hdcp_ctrl->auth_event_queue,
246c6a57a50Sjilai wang 		!!test_bit(ev, &hdcp_ctrl->auth_event),
247c6a57a50Sjilai wang 		msecs_to_jiffies(ms));
248c6a57a50Sjilai wang 	if (rc) {
249c6a57a50Sjilai wang 		pr_info("%s: msleep is canceled by event %d\n",
250c6a57a50Sjilai wang 				__func__, ev);
251c6a57a50Sjilai wang 		clear_bit(ev, &hdcp_ctrl->auth_event);
252c6a57a50Sjilai wang 		return -ECANCELED;
253c6a57a50Sjilai wang 	}
254c6a57a50Sjilai wang 
255c6a57a50Sjilai wang 	return 0;
256c6a57a50Sjilai wang }
257c6a57a50Sjilai wang 
msm_hdmi_hdcp_read_validate_aksv(struct hdmi_hdcp_ctrl * hdcp_ctrl)258fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_read_validate_aksv(struct hdmi_hdcp_ctrl *hdcp_ctrl)
259c6a57a50Sjilai wang {
260c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
261c6a57a50Sjilai wang 
262c6a57a50Sjilai wang 	/* Fetch aksv from QFPROM, this info should be public. */
263c6a57a50Sjilai wang 	hdcp_ctrl->aksv_lsb = hdmi_qfprom_read(hdmi, HDCP_KSV_LSB);
264c6a57a50Sjilai wang 	hdcp_ctrl->aksv_msb = hdmi_qfprom_read(hdmi, HDCP_KSV_MSB);
265c6a57a50Sjilai wang 
266c6a57a50Sjilai wang 	/* check there are 20 ones in AKSV */
267c6a57a50Sjilai wang 	if ((hweight32(hdcp_ctrl->aksv_lsb) + hweight32(hdcp_ctrl->aksv_msb))
268c6a57a50Sjilai wang 			!= 20) {
269c6a57a50Sjilai wang 		pr_err("%s: AKSV QFPROM doesn't have 20 1's, 20 0's\n",
270c6a57a50Sjilai wang 			__func__);
271c6a57a50Sjilai wang 		pr_err("%s: QFPROM AKSV chk failed (AKSV=%02x%08x)\n",
272c6a57a50Sjilai wang 			__func__, hdcp_ctrl->aksv_msb,
273c6a57a50Sjilai wang 			hdcp_ctrl->aksv_lsb);
274c6a57a50Sjilai wang 		return -EINVAL;
275c6a57a50Sjilai wang 	}
276c6a57a50Sjilai wang 	DBG("AKSV=%02x%08x", hdcp_ctrl->aksv_msb, hdcp_ctrl->aksv_lsb);
277c6a57a50Sjilai wang 
278c6a57a50Sjilai wang 	return 0;
279c6a57a50Sjilai wang }
280c6a57a50Sjilai wang 
msm_reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl * hdcp_ctrl)281fcda50c8SArnd Bergmann static int msm_reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl *hdcp_ctrl)
282c6a57a50Sjilai wang {
283c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
284c6a57a50Sjilai wang 	u32 reg_val, failure, nack0;
285c6a57a50Sjilai wang 	int rc = 0;
286c6a57a50Sjilai wang 
287c6a57a50Sjilai wang 	/* Check for any DDC transfer failures */
288c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_STATUS);
289c6a57a50Sjilai wang 	failure = reg_val & HDMI_HDCP_DDC_STATUS_FAILED;
290c6a57a50Sjilai wang 	nack0 = reg_val & HDMI_HDCP_DDC_STATUS_NACK0;
291c6a57a50Sjilai wang 	DBG("HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d",
292c6a57a50Sjilai wang 		reg_val, failure, nack0);
293c6a57a50Sjilai wang 
294c6a57a50Sjilai wang 	if (failure) {
295c6a57a50Sjilai wang 		/*
296c6a57a50Sjilai wang 		 * Indicates that the last HDCP HW DDC transfer failed.
297c6a57a50Sjilai wang 		 * This occurs when a transfer is attempted with HDCP DDC
298c6a57a50Sjilai wang 		 * disabled (HDCP_DDC_DISABLE=1) or the number of retries
299c6a57a50Sjilai wang 		 * matches HDCP_DDC_RETRY_CNT.
300c6a57a50Sjilai wang 		 * Failure occurred,  let's clear it.
301c6a57a50Sjilai wang 		 */
302c6a57a50Sjilai wang 		DBG("DDC failure detected");
303c6a57a50Sjilai wang 
304c6a57a50Sjilai wang 		/* First, Disable DDC */
305c6a57a50Sjilai wang 		hdmi_write(hdmi, REG_HDMI_HDCP_DDC_CTRL_0,
306c6a57a50Sjilai wang 			HDMI_HDCP_DDC_CTRL_0_DISABLE);
307c6a57a50Sjilai wang 
308c6a57a50Sjilai wang 		/* ACK the Failure to Clear it */
309c6a57a50Sjilai wang 		reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_CTRL_1);
310c6a57a50Sjilai wang 		reg_val |= HDMI_HDCP_DDC_CTRL_1_FAILED_ACK;
311c6a57a50Sjilai wang 		hdmi_write(hdmi, REG_HDMI_HDCP_DDC_CTRL_1, reg_val);
312c6a57a50Sjilai wang 
313c6a57a50Sjilai wang 		/* Check if the FAILURE got Cleared */
314c6a57a50Sjilai wang 		reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_STATUS);
315c6a57a50Sjilai wang 		if (reg_val & HDMI_HDCP_DDC_STATUS_FAILED)
316c6a57a50Sjilai wang 			pr_info("%s: Unable to clear HDCP DDC Failure\n",
317c6a57a50Sjilai wang 				__func__);
318c6a57a50Sjilai wang 
319c6a57a50Sjilai wang 		/* Re-Enable HDCP DDC */
320c6a57a50Sjilai wang 		hdmi_write(hdmi, REG_HDMI_HDCP_DDC_CTRL_0, 0);
321c6a57a50Sjilai wang 	}
322c6a57a50Sjilai wang 
323c6a57a50Sjilai wang 	if (nack0) {
324c6a57a50Sjilai wang 		DBG("Before: HDMI_DDC_SW_STATUS=0x%08x",
325c6a57a50Sjilai wang 			hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS));
326c6a57a50Sjilai wang 		/* Reset HDMI DDC software status */
327c6a57a50Sjilai wang 		reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
328c6a57a50Sjilai wang 		reg_val |= HDMI_DDC_CTRL_SW_STATUS_RESET;
329c6a57a50Sjilai wang 		hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
330c6a57a50Sjilai wang 
331fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
332c6a57a50Sjilai wang 
333c6a57a50Sjilai wang 		reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
334c6a57a50Sjilai wang 		reg_val &= ~HDMI_DDC_CTRL_SW_STATUS_RESET;
335c6a57a50Sjilai wang 		hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
336c6a57a50Sjilai wang 
337c6a57a50Sjilai wang 		/* Reset HDMI DDC Controller */
338c6a57a50Sjilai wang 		reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
339c6a57a50Sjilai wang 		reg_val |= HDMI_DDC_CTRL_SOFT_RESET;
340c6a57a50Sjilai wang 		hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
341c6a57a50Sjilai wang 
342c6a57a50Sjilai wang 		/* If previous msleep is aborted, skip this msleep */
343c6a57a50Sjilai wang 		if (!rc)
344fcda50c8SArnd Bergmann 			rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
345c6a57a50Sjilai wang 
346c6a57a50Sjilai wang 		reg_val = hdmi_read(hdmi, REG_HDMI_DDC_CTRL);
347c6a57a50Sjilai wang 		reg_val &= ~HDMI_DDC_CTRL_SOFT_RESET;
348c6a57a50Sjilai wang 		hdmi_write(hdmi, REG_HDMI_DDC_CTRL, reg_val);
349c6a57a50Sjilai wang 		DBG("After: HDMI_DDC_SW_STATUS=0x%08x",
350c6a57a50Sjilai wang 			hdmi_read(hdmi, REG_HDMI_DDC_SW_STATUS));
351c6a57a50Sjilai wang 	}
352c6a57a50Sjilai wang 
353c6a57a50Sjilai wang 	return rc;
354c6a57a50Sjilai wang }
355c6a57a50Sjilai wang 
msm_hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl * hdcp_ctrl)356fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
357c6a57a50Sjilai wang {
358c6a57a50Sjilai wang 	int rc;
359c6a57a50Sjilai wang 	u32 hdcp_ddc_status, ddc_hw_status;
360c6a57a50Sjilai wang 	u32 xfer_done, xfer_req, hw_done;
361c6a57a50Sjilai wang 	bool hw_not_ready;
362c6a57a50Sjilai wang 	u32 timeout_count;
363c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
364c6a57a50Sjilai wang 
365c6a57a50Sjilai wang 	if (hdmi_read(hdmi, REG_HDMI_DDC_HW_STATUS) == 0)
366c6a57a50Sjilai wang 		return 0;
367c6a57a50Sjilai wang 
368c6a57a50Sjilai wang 	/* Wait to be clean on DDC HW engine */
369c6a57a50Sjilai wang 	timeout_count = 100;
370c6a57a50Sjilai wang 	do {
371c6a57a50Sjilai wang 		hdcp_ddc_status = hdmi_read(hdmi, REG_HDMI_HDCP_DDC_STATUS);
372c6a57a50Sjilai wang 		ddc_hw_status = hdmi_read(hdmi, REG_HDMI_DDC_HW_STATUS);
373c6a57a50Sjilai wang 
374c6a57a50Sjilai wang 		xfer_done = hdcp_ddc_status & HDMI_HDCP_DDC_STATUS_XFER_DONE;
375c6a57a50Sjilai wang 		xfer_req = hdcp_ddc_status & HDMI_HDCP_DDC_STATUS_XFER_REQ;
376c6a57a50Sjilai wang 		hw_done = ddc_hw_status & HDMI_DDC_HW_STATUS_DONE;
377c6a57a50Sjilai wang 		hw_not_ready = !xfer_done || xfer_req || !hw_done;
378c6a57a50Sjilai wang 
379c6a57a50Sjilai wang 		if (hw_not_ready)
380c6a57a50Sjilai wang 			break;
381c6a57a50Sjilai wang 
382c6a57a50Sjilai wang 		timeout_count--;
383c6a57a50Sjilai wang 		if (!timeout_count) {
384c6a57a50Sjilai wang 			pr_warn("%s: hw_ddc_clean failed\n", __func__);
385c6a57a50Sjilai wang 			return -ETIMEDOUT;
386c6a57a50Sjilai wang 		}
387c6a57a50Sjilai wang 
388fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
389c6a57a50Sjilai wang 		if (rc)
390c6a57a50Sjilai wang 			return rc;
391c6a57a50Sjilai wang 	} while (1);
392c6a57a50Sjilai wang 
393c6a57a50Sjilai wang 	return 0;
394c6a57a50Sjilai wang }
395c6a57a50Sjilai wang 
msm_hdmi_hdcp_reauth_work(struct work_struct * work)396fcda50c8SArnd Bergmann static void msm_hdmi_hdcp_reauth_work(struct work_struct *work)
397c6a57a50Sjilai wang {
398c6a57a50Sjilai wang 	struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(work,
399c6a57a50Sjilai wang 		struct hdmi_hdcp_ctrl, hdcp_reauth_work);
400c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
401c6a57a50Sjilai wang 	unsigned long flags;
402c6a57a50Sjilai wang 	u32 reg_val;
403c6a57a50Sjilai wang 
404c6a57a50Sjilai wang 	DBG("HDCP REAUTH WORK");
405c6a57a50Sjilai wang 	/*
406c6a57a50Sjilai wang 	 * Disable HPD circuitry.
407c6a57a50Sjilai wang 	 * This is needed to reset the HDCP cipher engine so that when we
408c6a57a50Sjilai wang 	 * attempt a re-authentication, HW would clear the AN0_READY and
409c6a57a50Sjilai wang 	 * AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
410c6a57a50Sjilai wang 	 */
411c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
412c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
413c6a57a50Sjilai wang 	reg_val &= ~HDMI_HPD_CTRL_ENABLE;
414c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
415c6a57a50Sjilai wang 
416c6a57a50Sjilai wang 	/* Disable HDCP interrupts */
417c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL, 0);
418c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
419c6a57a50Sjilai wang 
420c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_RESET,
421c6a57a50Sjilai wang 		HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE);
422c6a57a50Sjilai wang 
423c6a57a50Sjilai wang 	/* Wait to be clean on DDC HW engine */
424fcda50c8SArnd Bergmann 	if (msm_hdmi_hdcp_hw_ddc_clean(hdcp_ctrl)) {
425c6a57a50Sjilai wang 		pr_info("%s: reauth work aborted\n", __func__);
426c6a57a50Sjilai wang 		return;
427c6a57a50Sjilai wang 	}
428c6a57a50Sjilai wang 
429c6a57a50Sjilai wang 	/* Disable encryption and disable the HDCP block */
430c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_CTRL, 0);
431c6a57a50Sjilai wang 
432c6a57a50Sjilai wang 	/* Enable HPD circuitry */
433c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
434c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
435c6a57a50Sjilai wang 	reg_val |= HDMI_HPD_CTRL_ENABLE;
436c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
437c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
438c6a57a50Sjilai wang 
439c6a57a50Sjilai wang 	/*
440c6a57a50Sjilai wang 	 * Only retry defined times then abort current authenticating process
441c6a57a50Sjilai wang 	 */
442c6a57a50Sjilai wang 	if (++hdcp_ctrl->auth_retries == AUTH_RETRIES_TIME) {
443c6a57a50Sjilai wang 		hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
444c6a57a50Sjilai wang 		hdcp_ctrl->auth_retries = 0;
445c6a57a50Sjilai wang 		pr_info("%s: abort reauthentication!\n", __func__);
446c6a57a50Sjilai wang 
447c6a57a50Sjilai wang 		return;
448c6a57a50Sjilai wang 	}
449c6a57a50Sjilai wang 
450c6a57a50Sjilai wang 	DBG("Queue AUTH WORK");
451c6a57a50Sjilai wang 	hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
452c6a57a50Sjilai wang 	queue_work(hdmi->workq, &hdcp_ctrl->hdcp_auth_work);
453c6a57a50Sjilai wang }
454c6a57a50Sjilai wang 
msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl * hdcp_ctrl)455fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_auth_prepare(struct hdmi_hdcp_ctrl *hdcp_ctrl)
456c6a57a50Sjilai wang {
457c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
458c6a57a50Sjilai wang 	u32 link0_status;
459c6a57a50Sjilai wang 	u32 reg_val;
460c6a57a50Sjilai wang 	unsigned long flags;
461c6a57a50Sjilai wang 	int rc;
462c6a57a50Sjilai wang 
463c6a57a50Sjilai wang 	if (!hdcp_ctrl->aksv_valid) {
464fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_read_validate_aksv(hdcp_ctrl);
465c6a57a50Sjilai wang 		if (rc) {
466c6a57a50Sjilai wang 			pr_err("%s: ASKV validation failed\n", __func__);
467c6a57a50Sjilai wang 			hdcp_ctrl->hdcp_state = HDCP_STATE_NO_AKSV;
468c6a57a50Sjilai wang 			return -ENOTSUPP;
469c6a57a50Sjilai wang 		}
470c6a57a50Sjilai wang 		hdcp_ctrl->aksv_valid = true;
471c6a57a50Sjilai wang 	}
472c6a57a50Sjilai wang 
473c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
474c6a57a50Sjilai wang 	/* disable HDMI Encrypt */
475c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
476c6a57a50Sjilai wang 	reg_val &= ~HDMI_CTRL_ENCRYPTED;
477c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
478c6a57a50Sjilai wang 
479c6a57a50Sjilai wang 	/* Enabling Software DDC */
480c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_DDC_ARBITRATION);
481c6a57a50Sjilai wang 	reg_val &= ~HDMI_DDC_ARBITRATION_HW_ARBITRATION;
482c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_DDC_ARBITRATION, reg_val);
483c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
484c6a57a50Sjilai wang 
485c6a57a50Sjilai wang 	/*
486c6a57a50Sjilai wang 	 * Write AKSV read from QFPROM to the HDCP registers.
487c6a57a50Sjilai wang 	 * This step is needed for HDCP authentication and must be
488c6a57a50Sjilai wang 	 * written before enabling HDCP.
489c6a57a50Sjilai wang 	 */
490c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_SW_LOWER_AKSV, hdcp_ctrl->aksv_lsb);
491c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_SW_UPPER_AKSV, hdcp_ctrl->aksv_msb);
492c6a57a50Sjilai wang 
493c6a57a50Sjilai wang 	/*
494c6a57a50Sjilai wang 	 * HDCP setup prior to enabling HDCP_CTRL.
495c6a57a50Sjilai wang 	 * Setup seed values for random number An.
496c6a57a50Sjilai wang 	 */
497c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_ENTROPY_CTRL0, 0xB1FFB0FF);
498c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE);
499c6a57a50Sjilai wang 
500c6a57a50Sjilai wang 	/* Disable the RngCipher state */
501c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_DEBUG_CTRL);
502c6a57a50Sjilai wang 	reg_val &= ~HDMI_HDCP_DEBUG_CTRL_RNG_CIPHER;
503c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_DEBUG_CTRL, reg_val);
504c6a57a50Sjilai wang 	DBG("HDCP_DEBUG_CTRL=0x%08x",
505c6a57a50Sjilai wang 		hdmi_read(hdmi, REG_HDMI_HDCP_DEBUG_CTRL));
506c6a57a50Sjilai wang 
507c6a57a50Sjilai wang 	/*
508c6a57a50Sjilai wang 	 * Ensure that all register writes are completed before
509c6a57a50Sjilai wang 	 * enabling HDCP cipher
510c6a57a50Sjilai wang 	 */
511c6a57a50Sjilai wang 	wmb();
512c6a57a50Sjilai wang 
513c6a57a50Sjilai wang 	/*
514c6a57a50Sjilai wang 	 * Enable HDCP
515c6a57a50Sjilai wang 	 * This needs to be done as early as possible in order for the
516c6a57a50Sjilai wang 	 * hardware to make An available to read
517c6a57a50Sjilai wang 	 */
518c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_CTRL, HDMI_HDCP_CTRL_ENABLE);
519c6a57a50Sjilai wang 
520c6a57a50Sjilai wang 	/*
521c6a57a50Sjilai wang 	 * If we had stale values for the An ready bit, it should most
522c6a57a50Sjilai wang 	 * likely be cleared now after enabling HDCP cipher
523c6a57a50Sjilai wang 	 */
524c6a57a50Sjilai wang 	link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
525c6a57a50Sjilai wang 	DBG("After enabling HDCP Link0_Status=0x%08x", link0_status);
526c6a57a50Sjilai wang 	if (!(link0_status &
527c6a57a50Sjilai wang 		(HDMI_HDCP_LINK0_STATUS_AN_0_READY |
528c6a57a50Sjilai wang 		HDMI_HDCP_LINK0_STATUS_AN_1_READY)))
529c6a57a50Sjilai wang 		DBG("An not ready after enabling HDCP");
530c6a57a50Sjilai wang 
531c6a57a50Sjilai wang 	/* Clear any DDC failures from previous tries before enable HDCP*/
532fcda50c8SArnd Bergmann 	rc = msm_reset_hdcp_ddc_failures(hdcp_ctrl);
533c6a57a50Sjilai wang 
534c6a57a50Sjilai wang 	return rc;
535c6a57a50Sjilai wang }
536c6a57a50Sjilai wang 
msm_hdmi_hdcp_auth_fail(struct hdmi_hdcp_ctrl * hdcp_ctrl)537fcda50c8SArnd Bergmann static void msm_hdmi_hdcp_auth_fail(struct hdmi_hdcp_ctrl *hdcp_ctrl)
538c6a57a50Sjilai wang {
539c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
540c6a57a50Sjilai wang 	u32 reg_val;
541c6a57a50Sjilai wang 	unsigned long flags;
542c6a57a50Sjilai wang 
543c6a57a50Sjilai wang 	DBG("hdcp auth failed, queue reauth work");
544c6a57a50Sjilai wang 	/* clear HDMI Encrypt */
545c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
546c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
547c6a57a50Sjilai wang 	reg_val &= ~HDMI_CTRL_ENCRYPTED;
548c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
549c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
550c6a57a50Sjilai wang 
551c6a57a50Sjilai wang 	hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAILED;
552c6a57a50Sjilai wang 	queue_work(hdmi->workq, &hdcp_ctrl->hdcp_reauth_work);
553c6a57a50Sjilai wang }
554c6a57a50Sjilai wang 
msm_hdmi_hdcp_auth_done(struct hdmi_hdcp_ctrl * hdcp_ctrl)555fcda50c8SArnd Bergmann static void msm_hdmi_hdcp_auth_done(struct hdmi_hdcp_ctrl *hdcp_ctrl)
556c6a57a50Sjilai wang {
557c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
558c6a57a50Sjilai wang 	u32 reg_val;
559c6a57a50Sjilai wang 	unsigned long flags;
560c6a57a50Sjilai wang 
561c6a57a50Sjilai wang 	/*
562c6a57a50Sjilai wang 	 * Disable software DDC before going into part3 to make sure
563c6a57a50Sjilai wang 	 * there is no Arbitration between software and hardware for DDC
564c6a57a50Sjilai wang 	 */
565c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
566c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_DDC_ARBITRATION);
567c6a57a50Sjilai wang 	reg_val |= HDMI_DDC_ARBITRATION_HW_ARBITRATION;
568c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_DDC_ARBITRATION, reg_val);
569c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
570c6a57a50Sjilai wang 
571c6a57a50Sjilai wang 	/* enable HDMI Encrypt */
572c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
573c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
574c6a57a50Sjilai wang 	reg_val |= HDMI_CTRL_ENCRYPTED;
575c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
576c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
577c6a57a50Sjilai wang 
578c6a57a50Sjilai wang 	hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATED;
579c6a57a50Sjilai wang 	hdcp_ctrl->auth_retries = 0;
580c6a57a50Sjilai wang }
581c6a57a50Sjilai wang 
582c6a57a50Sjilai wang /*
583c6a57a50Sjilai wang  * hdcp authenticating part 1
584c6a57a50Sjilai wang  * Wait Key/An ready
585c6a57a50Sjilai wang  * Read BCAPS from sink
586c6a57a50Sjilai wang  * Write BCAPS and AKSV into HDCP engine
587c6a57a50Sjilai wang  * Write An and AKSV to sink
588c6a57a50Sjilai wang  * Read BKSV from sink and write into HDCP engine
589c6a57a50Sjilai wang  */
msm_hdmi_hdcp_wait_key_an_ready(struct hdmi_hdcp_ctrl * hdcp_ctrl)590fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_wait_key_an_ready(struct hdmi_hdcp_ctrl *hdcp_ctrl)
591c6a57a50Sjilai wang {
592c6a57a50Sjilai wang 	int rc;
593c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
594c6a57a50Sjilai wang 	u32 link0_status, keys_state;
595c6a57a50Sjilai wang 	u32 timeout_count;
596c6a57a50Sjilai wang 	bool an_ready;
597c6a57a50Sjilai wang 
598c6a57a50Sjilai wang 	/* Wait for HDCP keys to be checked and validated */
599c6a57a50Sjilai wang 	timeout_count = 100;
600c6a57a50Sjilai wang 	do {
601c6a57a50Sjilai wang 		link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
602c6a57a50Sjilai wang 		keys_state = (link0_status >> 28) & 0x7;
603c6a57a50Sjilai wang 		if (keys_state == HDCP_KEYS_STATE_VALID)
604c6a57a50Sjilai wang 			break;
605c6a57a50Sjilai wang 
606c6a57a50Sjilai wang 		DBG("Keys not ready(%d). s=%d, l0=%0x08x",
607c6a57a50Sjilai wang 			timeout_count, keys_state, link0_status);
608c6a57a50Sjilai wang 
609c6a57a50Sjilai wang 		timeout_count--;
610c6a57a50Sjilai wang 		if (!timeout_count) {
611c6a57a50Sjilai wang 			pr_err("%s: Wait key state timedout", __func__);
612c6a57a50Sjilai wang 			return -ETIMEDOUT;
613c6a57a50Sjilai wang 		}
614c6a57a50Sjilai wang 
615fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
616c6a57a50Sjilai wang 		if (rc)
617c6a57a50Sjilai wang 			return rc;
618c6a57a50Sjilai wang 	} while (1);
619c6a57a50Sjilai wang 
620c6a57a50Sjilai wang 	timeout_count = 100;
621c6a57a50Sjilai wang 	do {
622c6a57a50Sjilai wang 		link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
623c6a57a50Sjilai wang 		an_ready = (link0_status & HDMI_HDCP_LINK0_STATUS_AN_0_READY)
624c6a57a50Sjilai wang 			&& (link0_status & HDMI_HDCP_LINK0_STATUS_AN_1_READY);
625c6a57a50Sjilai wang 		if (an_ready)
626c6a57a50Sjilai wang 			break;
627c6a57a50Sjilai wang 
628c6a57a50Sjilai wang 		DBG("An not ready(%d). l0_status=0x%08x",
629c6a57a50Sjilai wang 			timeout_count, link0_status);
630c6a57a50Sjilai wang 
631c6a57a50Sjilai wang 		timeout_count--;
632c6a57a50Sjilai wang 		if (!timeout_count) {
633c6a57a50Sjilai wang 			pr_err("%s: Wait An timedout", __func__);
634c6a57a50Sjilai wang 			return -ETIMEDOUT;
635c6a57a50Sjilai wang 		}
636c6a57a50Sjilai wang 
637fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
638c6a57a50Sjilai wang 		if (rc)
639c6a57a50Sjilai wang 			return rc;
640c6a57a50Sjilai wang 	} while (1);
641c6a57a50Sjilai wang 
642c6a57a50Sjilai wang 	return 0;
643c6a57a50Sjilai wang }
644c6a57a50Sjilai wang 
msm_hdmi_hdcp_send_aksv_an(struct hdmi_hdcp_ctrl * hdcp_ctrl)645fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_send_aksv_an(struct hdmi_hdcp_ctrl *hdcp_ctrl)
646c6a57a50Sjilai wang {
647c6a57a50Sjilai wang 	int rc = 0;
648c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
649c6a57a50Sjilai wang 	u32 link0_aksv_0, link0_aksv_1;
650c6a57a50Sjilai wang 	u32 link0_an[2];
651c6a57a50Sjilai wang 	u8 aksv[5];
652c6a57a50Sjilai wang 
653c6a57a50Sjilai wang 	/* Read An0 and An1 */
654c6a57a50Sjilai wang 	link0_an[0] = hdmi_read(hdmi, REG_HDMI_HDCP_RCVPORT_DATA5);
655c6a57a50Sjilai wang 	link0_an[1] = hdmi_read(hdmi, REG_HDMI_HDCP_RCVPORT_DATA6);
656c6a57a50Sjilai wang 
657c6a57a50Sjilai wang 	/* Read AKSV */
658c6a57a50Sjilai wang 	link0_aksv_0 = hdmi_read(hdmi, REG_HDMI_HDCP_RCVPORT_DATA3);
659c6a57a50Sjilai wang 	link0_aksv_1 = hdmi_read(hdmi, REG_HDMI_HDCP_RCVPORT_DATA4);
660c6a57a50Sjilai wang 
661c6a57a50Sjilai wang 	DBG("Link ASKV=%08x%08x", link0_aksv_0, link0_aksv_1);
662c6a57a50Sjilai wang 	/* Copy An and AKSV to byte arrays for transmission */
663c6a57a50Sjilai wang 	aksv[0] =  link0_aksv_0        & 0xFF;
664c6a57a50Sjilai wang 	aksv[1] = (link0_aksv_0 >> 8)  & 0xFF;
665c6a57a50Sjilai wang 	aksv[2] = (link0_aksv_0 >> 16) & 0xFF;
666c6a57a50Sjilai wang 	aksv[3] = (link0_aksv_0 >> 24) & 0xFF;
667c6a57a50Sjilai wang 	aksv[4] =  link0_aksv_1        & 0xFF;
668c6a57a50Sjilai wang 
669c6a57a50Sjilai wang 	/* Write An to offset 0x18 */
670fcda50c8SArnd Bergmann 	rc = msm_hdmi_ddc_write(hdmi, HDCP_PORT_ADDR, 0x18, (u8 *)link0_an,
671c6a57a50Sjilai wang 		(u16)sizeof(link0_an));
672c6a57a50Sjilai wang 	if (rc) {
673c6a57a50Sjilai wang 		pr_err("%s:An write failed\n", __func__);
674c6a57a50Sjilai wang 		return rc;
675c6a57a50Sjilai wang 	}
676c6a57a50Sjilai wang 	DBG("Link0-An=%08x%08x", link0_an[0], link0_an[1]);
677c6a57a50Sjilai wang 
678c6a57a50Sjilai wang 	/* Write AKSV to offset 0x10 */
679fcda50c8SArnd Bergmann 	rc = msm_hdmi_ddc_write(hdmi, HDCP_PORT_ADDR, 0x10, aksv, 5);
680c6a57a50Sjilai wang 	if (rc) {
681c6a57a50Sjilai wang 		pr_err("%s:AKSV write failed\n", __func__);
682c6a57a50Sjilai wang 		return rc;
683c6a57a50Sjilai wang 	}
684c6a57a50Sjilai wang 	DBG("Link0-AKSV=%02x%08x", link0_aksv_1 & 0xFF, link0_aksv_0);
685c6a57a50Sjilai wang 
686c6a57a50Sjilai wang 	return 0;
687c6a57a50Sjilai wang }
688c6a57a50Sjilai wang 
msm_hdmi_hdcp_recv_bksv(struct hdmi_hdcp_ctrl * hdcp_ctrl)689fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_recv_bksv(struct hdmi_hdcp_ctrl *hdcp_ctrl)
690c6a57a50Sjilai wang {
691c6a57a50Sjilai wang 	int rc = 0;
692c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
693c6a57a50Sjilai wang 	u8 bksv[5];
694c6a57a50Sjilai wang 	u32 reg[2], data[2];
695c6a57a50Sjilai wang 
696c6a57a50Sjilai wang 	/* Read BKSV at offset 0x00 */
697fcda50c8SArnd Bergmann 	rc = msm_hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x00, bksv, 5);
698c6a57a50Sjilai wang 	if (rc) {
699c6a57a50Sjilai wang 		pr_err("%s:BKSV read failed\n", __func__);
700c6a57a50Sjilai wang 		return rc;
701c6a57a50Sjilai wang 	}
702c6a57a50Sjilai wang 
703c6a57a50Sjilai wang 	hdcp_ctrl->bksv_lsb = bksv[0] | (bksv[1] << 8) |
704c6a57a50Sjilai wang 		(bksv[2] << 16) | (bksv[3] << 24);
705c6a57a50Sjilai wang 	hdcp_ctrl->bksv_msb = bksv[4];
706c6a57a50Sjilai wang 	DBG(":BKSV=%02x%08x", hdcp_ctrl->bksv_msb, hdcp_ctrl->bksv_lsb);
707c6a57a50Sjilai wang 
708c6a57a50Sjilai wang 	/* check there are 20 ones in BKSV */
709c6a57a50Sjilai wang 	if ((hweight32(hdcp_ctrl->bksv_lsb) + hweight32(hdcp_ctrl->bksv_msb))
710c6a57a50Sjilai wang 			!= 20) {
711c6a57a50Sjilai wang 		pr_err(": BKSV doesn't have 20 1's and 20 0's\n");
712c6a57a50Sjilai wang 		pr_err(": BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n",
713c6a57a50Sjilai wang 			bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
714c6a57a50Sjilai wang 		return -EINVAL;
715c6a57a50Sjilai wang 	}
716c6a57a50Sjilai wang 
717c6a57a50Sjilai wang 	/* Write BKSV read from sink to HDCP registers */
718c6a57a50Sjilai wang 	reg[0] = REG_HDMI_HDCP_RCVPORT_DATA0;
719c6a57a50Sjilai wang 	data[0] = hdcp_ctrl->bksv_lsb;
720c6a57a50Sjilai wang 	reg[1] = REG_HDMI_HDCP_RCVPORT_DATA1;
721c6a57a50Sjilai wang 	data[1] = hdcp_ctrl->bksv_msb;
722fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_scm_wr(hdcp_ctrl, reg, data, 2);
723c6a57a50Sjilai wang 
724c6a57a50Sjilai wang 	return rc;
725c6a57a50Sjilai wang }
726c6a57a50Sjilai wang 
msm_hdmi_hdcp_recv_bcaps(struct hdmi_hdcp_ctrl * hdcp_ctrl)727fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_recv_bcaps(struct hdmi_hdcp_ctrl *hdcp_ctrl)
728c6a57a50Sjilai wang {
729c6a57a50Sjilai wang 	int rc = 0;
730c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
731c6a57a50Sjilai wang 	u32 reg, data;
732c6a57a50Sjilai wang 	u8 bcaps;
733c6a57a50Sjilai wang 
734fcda50c8SArnd Bergmann 	rc = msm_hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x40, &bcaps, 1);
735c6a57a50Sjilai wang 	if (rc) {
736c6a57a50Sjilai wang 		pr_err("%s:BCAPS read failed\n", __func__);
737c6a57a50Sjilai wang 		return rc;
738c6a57a50Sjilai wang 	}
739c6a57a50Sjilai wang 	DBG("BCAPS=%02x", bcaps);
740c6a57a50Sjilai wang 
741c6a57a50Sjilai wang 	/* receiver (0), repeater (1) */
742c6a57a50Sjilai wang 	hdcp_ctrl->ds_type = (bcaps & BIT(6)) ? DS_REPEATER : DS_RECEIVER;
743c6a57a50Sjilai wang 
744c6a57a50Sjilai wang 	/* Write BCAPS to the hardware */
745c6a57a50Sjilai wang 	reg = REG_HDMI_HDCP_RCVPORT_DATA12;
746c6a57a50Sjilai wang 	data = (u32)bcaps;
747fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_scm_wr(hdcp_ctrl, &reg, &data, 1);
748c6a57a50Sjilai wang 
749c6a57a50Sjilai wang 	return rc;
750c6a57a50Sjilai wang }
751c6a57a50Sjilai wang 
msm_hdmi_hdcp_auth_part1_key_exchange(struct hdmi_hdcp_ctrl * hdcp_ctrl)752fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_auth_part1_key_exchange(struct hdmi_hdcp_ctrl *hdcp_ctrl)
753c6a57a50Sjilai wang {
754c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
755c6a57a50Sjilai wang 	unsigned long flags;
756c6a57a50Sjilai wang 	int rc;
757c6a57a50Sjilai wang 
758c6a57a50Sjilai wang 	/* Wait for AKSV key and An ready */
759fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_wait_key_an_ready(hdcp_ctrl);
760c6a57a50Sjilai wang 	if (rc) {
761c6a57a50Sjilai wang 		pr_err("%s: wait key and an ready failed\n", __func__);
762c6a57a50Sjilai wang 		return rc;
763cccb9723SFengguang Wu 	}
764c6a57a50Sjilai wang 
765c6a57a50Sjilai wang 	/* Read BCAPS and send to HDCP engine */
766fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_recv_bcaps(hdcp_ctrl);
767c6a57a50Sjilai wang 	if (rc) {
768c6a57a50Sjilai wang 		pr_err("%s: read bcaps error, abort\n", __func__);
769c6a57a50Sjilai wang 		return rc;
770c6a57a50Sjilai wang 	}
771c6a57a50Sjilai wang 
772c6a57a50Sjilai wang 	/*
773c6a57a50Sjilai wang 	 * 1.1_Features turned off by default.
774c6a57a50Sjilai wang 	 * No need to write AInfo since 1.1_Features is disabled.
775c6a57a50Sjilai wang 	 */
776c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_RCVPORT_DATA4, 0);
777c6a57a50Sjilai wang 
778c6a57a50Sjilai wang 	/* Send AKSV and An to sink */
779fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_send_aksv_an(hdcp_ctrl);
780c6a57a50Sjilai wang 	if (rc) {
781c6a57a50Sjilai wang 		pr_err("%s:An/Aksv write failed\n", __func__);
782c6a57a50Sjilai wang 		return rc;
783c6a57a50Sjilai wang 	}
784c6a57a50Sjilai wang 
785c6a57a50Sjilai wang 	/* Read BKSV and send to HDCP engine*/
786fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_recv_bksv(hdcp_ctrl);
787c6a57a50Sjilai wang 	if (rc) {
788c6a57a50Sjilai wang 		pr_err("%s:BKSV Process failed\n", __func__);
789c6a57a50Sjilai wang 		return rc;
790c6a57a50Sjilai wang 	}
791c6a57a50Sjilai wang 
792c6a57a50Sjilai wang 	/* Enable HDCP interrupts and ack/clear any stale interrupts */
793c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
794c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL,
795c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_ACK |
796c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_MASK |
797c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_FAIL_ACK |
798c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_FAIL_MASK |
799c6a57a50Sjilai wang 		HDMI_HDCP_INT_CTRL_AUTH_FAIL_INFO_ACK);
800c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
801c6a57a50Sjilai wang 
802c6a57a50Sjilai wang 	return 0;
803c6a57a50Sjilai wang }
804c6a57a50Sjilai wang 
805c6a57a50Sjilai wang /* read R0' from sink and pass it to HDCP engine */
msm_hdmi_hdcp_auth_part1_recv_r0(struct hdmi_hdcp_ctrl * hdcp_ctrl)806fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_auth_part1_recv_r0(struct hdmi_hdcp_ctrl *hdcp_ctrl)
807c6a57a50Sjilai wang {
808c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
809c6a57a50Sjilai wang 	int rc = 0;
810c6a57a50Sjilai wang 	u8 buf[2];
811c6a57a50Sjilai wang 
812c6a57a50Sjilai wang 	/*
813c6a57a50Sjilai wang 	 * HDCP Compliance Test case 1A-01:
814c6a57a50Sjilai wang 	 * Wait here at least 100ms before reading R0'
815c6a57a50Sjilai wang 	 */
816fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 125, AUTH_ABORT_EV);
817c6a57a50Sjilai wang 	if (rc)
818c6a57a50Sjilai wang 		return rc;
819c6a57a50Sjilai wang 
820c6a57a50Sjilai wang 	/* Read R0' at offset 0x08 */
821fcda50c8SArnd Bergmann 	rc = msm_hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x08, buf, 2);
822c6a57a50Sjilai wang 	if (rc) {
823c6a57a50Sjilai wang 		pr_err("%s:R0' read failed\n", __func__);
824c6a57a50Sjilai wang 		return rc;
825c6a57a50Sjilai wang 	}
826c6a57a50Sjilai wang 	DBG("R0'=%02x%02x", buf[1], buf[0]);
827c6a57a50Sjilai wang 
828c6a57a50Sjilai wang 	/* Write R0' to HDCP registers and check to see if it is a match */
829c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_RCVPORT_DATA2_0,
830c6a57a50Sjilai wang 		(((u32)buf[1]) << 8) | buf[0]);
831c6a57a50Sjilai wang 
832c6a57a50Sjilai wang 	return 0;
833c6a57a50Sjilai wang }
834c6a57a50Sjilai wang 
835c6a57a50Sjilai wang /* Wait for authenticating result: R0/R0' are matched or not */
msm_hdmi_hdcp_auth_part1_verify_r0(struct hdmi_hdcp_ctrl * hdcp_ctrl)836fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_auth_part1_verify_r0(struct hdmi_hdcp_ctrl *hdcp_ctrl)
837c6a57a50Sjilai wang {
838c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
839c6a57a50Sjilai wang 	u32 link0_status;
840c6a57a50Sjilai wang 	int rc;
841c6a57a50Sjilai wang 
842c6a57a50Sjilai wang 	/* wait for hdcp irq, 10 sec should be long enough */
843fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 10000, AUTH_RESULT_RDY_EV);
844c6a57a50Sjilai wang 	if (!rc) {
845c6a57a50Sjilai wang 		pr_err("%s: Wait Auth IRQ timeout\n", __func__);
846c6a57a50Sjilai wang 		return -ETIMEDOUT;
847c6a57a50Sjilai wang 	}
848c6a57a50Sjilai wang 
849c6a57a50Sjilai wang 	link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
850c6a57a50Sjilai wang 	if (!(link0_status & HDMI_HDCP_LINK0_STATUS_RI_MATCHES)) {
851c6a57a50Sjilai wang 		pr_err("%s: Authentication Part I failed\n", __func__);
852c6a57a50Sjilai wang 		return -EINVAL;
853c6a57a50Sjilai wang 	}
854c6a57a50Sjilai wang 
855c6a57a50Sjilai wang 	/* Enable HDCP Encryption */
856c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_CTRL,
857c6a57a50Sjilai wang 		HDMI_HDCP_CTRL_ENABLE |
858c6a57a50Sjilai wang 		HDMI_HDCP_CTRL_ENCRYPTION_ENABLE);
859c6a57a50Sjilai wang 
860c6a57a50Sjilai wang 	return 0;
861c6a57a50Sjilai wang }
862c6a57a50Sjilai wang 
msm_hdmi_hdcp_recv_check_bstatus(struct hdmi_hdcp_ctrl * hdcp_ctrl,u16 * pbstatus)863fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_recv_check_bstatus(struct hdmi_hdcp_ctrl *hdcp_ctrl,
864c6a57a50Sjilai wang 	u16 *pbstatus)
865c6a57a50Sjilai wang {
866c6a57a50Sjilai wang 	int rc;
867c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
868c6a57a50Sjilai wang 	bool max_devs_exceeded = false, max_cascade_exceeded = false;
869c6a57a50Sjilai wang 	u32 repeater_cascade_depth = 0, down_stream_devices = 0;
870c6a57a50Sjilai wang 	u16 bstatus;
871c6a57a50Sjilai wang 	u8 buf[2];
872c6a57a50Sjilai wang 
873c6a57a50Sjilai wang 	/* Read BSTATUS at offset 0x41 */
874fcda50c8SArnd Bergmann 	rc = msm_hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x41, buf, 2);
875c6a57a50Sjilai wang 	if (rc) {
876c6a57a50Sjilai wang 		pr_err("%s: BSTATUS read failed\n", __func__);
877c6a57a50Sjilai wang 		goto error;
878c6a57a50Sjilai wang 	}
879c6a57a50Sjilai wang 	*pbstatus = bstatus = (buf[1] << 8) | buf[0];
880c6a57a50Sjilai wang 
881c6a57a50Sjilai wang 
882c6a57a50Sjilai wang 	down_stream_devices = bstatus & 0x7F;
883c6a57a50Sjilai wang 	repeater_cascade_depth = (bstatus >> 8) & 0x7;
884c6a57a50Sjilai wang 	max_devs_exceeded = (bstatus & BIT(7)) ? true : false;
885c6a57a50Sjilai wang 	max_cascade_exceeded = (bstatus & BIT(11)) ? true : false;
886c6a57a50Sjilai wang 
887c6a57a50Sjilai wang 	if (down_stream_devices == 0) {
888c6a57a50Sjilai wang 		/*
889c6a57a50Sjilai wang 		 * If no downstream devices are attached to the repeater
890c6a57a50Sjilai wang 		 * then part II fails.
891c6a57a50Sjilai wang 		 * todo: The other approach would be to continue PART II.
892c6a57a50Sjilai wang 		 */
893c6a57a50Sjilai wang 		pr_err("%s: No downstream devices\n", __func__);
894c6a57a50Sjilai wang 		rc = -EINVAL;
895c6a57a50Sjilai wang 		goto error;
896c6a57a50Sjilai wang 	}
897c6a57a50Sjilai wang 
898c6a57a50Sjilai wang 	/*
899c6a57a50Sjilai wang 	 * HDCP Compliance 1B-05:
900c6a57a50Sjilai wang 	 * Check if no. of devices connected to repeater
901c6a57a50Sjilai wang 	 * exceed max_devices_connected from bit 7 of Bstatus.
902c6a57a50Sjilai wang 	 */
903c6a57a50Sjilai wang 	if (max_devs_exceeded) {
904c6a57a50Sjilai wang 		pr_err("%s: no. of devs connected exceeds max allowed",
905c6a57a50Sjilai wang 			__func__);
906c6a57a50Sjilai wang 		rc = -EINVAL;
907c6a57a50Sjilai wang 		goto error;
908c6a57a50Sjilai wang 	}
909c6a57a50Sjilai wang 
910c6a57a50Sjilai wang 	/*
911c6a57a50Sjilai wang 	 * HDCP Compliance 1B-06:
912c6a57a50Sjilai wang 	 * Check if no. of cascade connected to repeater
913c6a57a50Sjilai wang 	 * exceed max_cascade_connected from bit 11 of Bstatus.
914c6a57a50Sjilai wang 	 */
915c6a57a50Sjilai wang 	if (max_cascade_exceeded) {
916c6a57a50Sjilai wang 		pr_err("%s: no. of cascade conn exceeds max allowed",
917c6a57a50Sjilai wang 			__func__);
918c6a57a50Sjilai wang 		rc = -EINVAL;
919c6a57a50Sjilai wang 		goto error;
920c6a57a50Sjilai wang 	}
921c6a57a50Sjilai wang 
922c6a57a50Sjilai wang error:
923c6a57a50Sjilai wang 	hdcp_ctrl->dev_count = down_stream_devices;
924c6a57a50Sjilai wang 	hdcp_ctrl->max_cascade_exceeded = max_cascade_exceeded;
925c6a57a50Sjilai wang 	hdcp_ctrl->max_dev_exceeded = max_devs_exceeded;
926c6a57a50Sjilai wang 	hdcp_ctrl->depth = repeater_cascade_depth;
927c6a57a50Sjilai wang 	return rc;
928c6a57a50Sjilai wang }
929c6a57a50Sjilai wang 
msm_hdmi_hdcp_auth_part2_wait_ksv_fifo_ready(struct hdmi_hdcp_ctrl * hdcp_ctrl)930fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_auth_part2_wait_ksv_fifo_ready(
931c6a57a50Sjilai wang 	struct hdmi_hdcp_ctrl *hdcp_ctrl)
932c6a57a50Sjilai wang {
933c6a57a50Sjilai wang 	int rc;
934c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
935c6a57a50Sjilai wang 	u32 reg, data;
936c6a57a50Sjilai wang 	u32 timeout_count;
937c6a57a50Sjilai wang 	u16 bstatus;
938c6a57a50Sjilai wang 	u8 bcaps;
939c6a57a50Sjilai wang 
940c6a57a50Sjilai wang 	/*
941c6a57a50Sjilai wang 	 * Wait until READY bit is set in BCAPS, as per HDCP specifications
942c6a57a50Sjilai wang 	 * maximum permitted time to check for READY bit is five seconds.
943c6a57a50Sjilai wang 	 */
944c6a57a50Sjilai wang 	timeout_count = 100;
945c6a57a50Sjilai wang 	do {
946c6a57a50Sjilai wang 		/* Read BCAPS at offset 0x40 */
947fcda50c8SArnd Bergmann 		rc = msm_hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x40, &bcaps, 1);
948c6a57a50Sjilai wang 		if (rc) {
949c6a57a50Sjilai wang 			pr_err("%s: BCAPS read failed\n", __func__);
950c6a57a50Sjilai wang 			return rc;
951c6a57a50Sjilai wang 		}
952c6a57a50Sjilai wang 
953c6a57a50Sjilai wang 		if (bcaps & BIT(5))
954c6a57a50Sjilai wang 			break;
955c6a57a50Sjilai wang 
956c6a57a50Sjilai wang 		timeout_count--;
957c6a57a50Sjilai wang 		if (!timeout_count) {
958c6a57a50Sjilai wang 			pr_err("%s: Wait KSV fifo ready timedout", __func__);
959c6a57a50Sjilai wang 			return -ETIMEDOUT;
960c6a57a50Sjilai wang 		}
961c6a57a50Sjilai wang 
962fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
963c6a57a50Sjilai wang 		if (rc)
964c6a57a50Sjilai wang 			return rc;
965c6a57a50Sjilai wang 	} while (1);
966c6a57a50Sjilai wang 
967fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_recv_check_bstatus(hdcp_ctrl, &bstatus);
968c6a57a50Sjilai wang 	if (rc) {
969c6a57a50Sjilai wang 		pr_err("%s: bstatus error\n", __func__);
970c6a57a50Sjilai wang 		return rc;
971c6a57a50Sjilai wang 	}
972c6a57a50Sjilai wang 
973c6a57a50Sjilai wang 	/* Write BSTATUS and BCAPS to HDCP registers */
974c6a57a50Sjilai wang 	reg = REG_HDMI_HDCP_RCVPORT_DATA12;
975c6a57a50Sjilai wang 	data = bcaps | (bstatus << 8);
976fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_scm_wr(hdcp_ctrl, &reg, &data, 1);
977c6a57a50Sjilai wang 	if (rc) {
978c6a57a50Sjilai wang 		pr_err("%s: BSTATUS write failed\n", __func__);
979c6a57a50Sjilai wang 		return rc;
980c6a57a50Sjilai wang 	}
981c6a57a50Sjilai wang 
982c6a57a50Sjilai wang 	return 0;
983c6a57a50Sjilai wang }
984c6a57a50Sjilai wang 
985c6a57a50Sjilai wang /*
986c6a57a50Sjilai wang  * hdcp authenticating part 2: 2nd
987c6a57a50Sjilai wang  * read ksv fifo from sink
988c6a57a50Sjilai wang  * transfer V' from sink to HDCP engine
989c6a57a50Sjilai wang  * reset SHA engine
990c6a57a50Sjilai wang  */
msm_hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl * hdcp_ctrl)991fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl)
992c6a57a50Sjilai wang {
993c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
994c6a57a50Sjilai wang 	int rc = 0;
995c6a57a50Sjilai wang 	struct hdmi_hdcp_reg_data reg_data[]  = {
996c6a57a50Sjilai wang 		{REG_HDMI_HDCP_RCVPORT_DATA7,  0x20, "V' H0"},
997c6a57a50Sjilai wang 		{REG_HDMI_HDCP_RCVPORT_DATA8,  0x24, "V' H1"},
998c6a57a50Sjilai wang 		{REG_HDMI_HDCP_RCVPORT_DATA9,  0x28, "V' H2"},
999c6a57a50Sjilai wang 		{REG_HDMI_HDCP_RCVPORT_DATA10, 0x2C, "V' H3"},
1000c6a57a50Sjilai wang 		{REG_HDMI_HDCP_RCVPORT_DATA11, 0x30, "V' H4"},
1001c6a57a50Sjilai wang 	};
1002c6a57a50Sjilai wang 	struct hdmi_hdcp_reg_data *rd;
1003c6a57a50Sjilai wang 	u32 size = ARRAY_SIZE(reg_data);
1004c6a57a50Sjilai wang 	u32 reg[ARRAY_SIZE(reg_data)];
1005c6a57a50Sjilai wang 	u32 data[ARRAY_SIZE(reg_data)];
1006c6a57a50Sjilai wang 	int i;
1007c6a57a50Sjilai wang 
1008c6a57a50Sjilai wang 	for (i = 0; i < size; i++) {
1009c6a57a50Sjilai wang 		rd = &reg_data[i];
1010fcda50c8SArnd Bergmann 		rc = msm_hdmi_ddc_read(hdmi, HDCP_PORT_ADDR,
1011c6a57a50Sjilai wang 			rd->off, (u8 *)&data[i], (u16)sizeof(data[i]));
1012c6a57a50Sjilai wang 		if (rc) {
1013c6a57a50Sjilai wang 			pr_err("%s: Read %s failed\n", __func__, rd->name);
1014c6a57a50Sjilai wang 			goto error;
1015c6a57a50Sjilai wang 		}
1016c6a57a50Sjilai wang 
1017c6a57a50Sjilai wang 		DBG("%s =%x", rd->name, data[i]);
1018c6a57a50Sjilai wang 		reg[i] = reg_data[i].reg_id;
1019c6a57a50Sjilai wang 	}
1020c6a57a50Sjilai wang 
1021fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_scm_wr(hdcp_ctrl, reg, data, size);
1022c6a57a50Sjilai wang 
1023c6a57a50Sjilai wang error:
1024c6a57a50Sjilai wang 	return rc;
1025c6a57a50Sjilai wang }
1026c6a57a50Sjilai wang 
msm_hdmi_hdcp_recv_ksv_fifo(struct hdmi_hdcp_ctrl * hdcp_ctrl)1027fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_recv_ksv_fifo(struct hdmi_hdcp_ctrl *hdcp_ctrl)
1028c6a57a50Sjilai wang {
1029c6a57a50Sjilai wang 	int rc;
1030c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
1031c6a57a50Sjilai wang 	u32 ksv_bytes;
1032c6a57a50Sjilai wang 
1033c6a57a50Sjilai wang 	ksv_bytes = 5 * hdcp_ctrl->dev_count;
1034c6a57a50Sjilai wang 
1035fcda50c8SArnd Bergmann 	rc = msm_hdmi_ddc_read(hdmi, HDCP_PORT_ADDR, 0x43,
1036c6a57a50Sjilai wang 		hdcp_ctrl->ksv_list, ksv_bytes);
1037c6a57a50Sjilai wang 	if (rc)
1038c6a57a50Sjilai wang 		pr_err("%s: KSV FIFO read failed\n", __func__);
1039c6a57a50Sjilai wang 
1040c6a57a50Sjilai wang 	return rc;
1041c6a57a50Sjilai wang }
1042c6a57a50Sjilai wang 
msm_hdmi_hdcp_reset_sha_engine(struct hdmi_hdcp_ctrl * hdcp_ctrl)1043fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_reset_sha_engine(struct hdmi_hdcp_ctrl *hdcp_ctrl)
1044c6a57a50Sjilai wang {
1045c6a57a50Sjilai wang 	u32 reg[2], data[2];
1046c6a57a50Sjilai wang 	u32 rc  = 0;
1047c6a57a50Sjilai wang 
1048c6a57a50Sjilai wang 	reg[0] = REG_HDMI_HDCP_SHA_CTRL;
1049c6a57a50Sjilai wang 	data[0] = HDCP_REG_ENABLE;
1050c6a57a50Sjilai wang 	reg[1] = REG_HDMI_HDCP_SHA_CTRL;
1051c6a57a50Sjilai wang 	data[1] = HDCP_REG_DISABLE;
1052c6a57a50Sjilai wang 
1053fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_scm_wr(hdcp_ctrl, reg, data, 2);
1054c6a57a50Sjilai wang 
1055c6a57a50Sjilai wang 	return rc;
1056c6a57a50Sjilai wang }
1057c6a57a50Sjilai wang 
msm_hdmi_hdcp_auth_part2_recv_ksv_fifo(struct hdmi_hdcp_ctrl * hdcp_ctrl)1058fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_auth_part2_recv_ksv_fifo(
1059c6a57a50Sjilai wang 	struct hdmi_hdcp_ctrl *hdcp_ctrl)
1060c6a57a50Sjilai wang {
1061c6a57a50Sjilai wang 	int rc;
1062c6a57a50Sjilai wang 	u32 timeout_count;
1063c6a57a50Sjilai wang 
1064c6a57a50Sjilai wang 	/*
1065c6a57a50Sjilai wang 	 * Read KSV FIFO over DDC
1066c6a57a50Sjilai wang 	 * Key Selection vector FIFO Used to pull downstream KSVs
1067c6a57a50Sjilai wang 	 * from HDCP Repeaters.
1068c6a57a50Sjilai wang 	 * All bytes (DEVICE_COUNT * 5) must be read in a single,
1069c6a57a50Sjilai wang 	 * auto incrementing access.
1070c6a57a50Sjilai wang 	 * All bytes read as 0x00 for HDCP Receivers that are not
1071c6a57a50Sjilai wang 	 * HDCP Repeaters (REPEATER == 0).
1072c6a57a50Sjilai wang 	 */
1073c6a57a50Sjilai wang 	timeout_count = 100;
1074c6a57a50Sjilai wang 	do {
1075fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_recv_ksv_fifo(hdcp_ctrl);
1076c6a57a50Sjilai wang 		if (!rc)
1077c6a57a50Sjilai wang 			break;
1078c6a57a50Sjilai wang 
1079c6a57a50Sjilai wang 		timeout_count--;
1080c6a57a50Sjilai wang 		if (!timeout_count) {
1081c6a57a50Sjilai wang 			pr_err("%s: Recv ksv fifo timedout", __func__);
1082c6a57a50Sjilai wang 			return -ETIMEDOUT;
1083c6a57a50Sjilai wang 		}
1084c6a57a50Sjilai wang 
1085fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 25, AUTH_ABORT_EV);
1086c6a57a50Sjilai wang 		if (rc)
1087c6a57a50Sjilai wang 			return rc;
1088c6a57a50Sjilai wang 	} while (1);
1089c6a57a50Sjilai wang 
1090fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_transfer_v_h(hdcp_ctrl);
1091c6a57a50Sjilai wang 	if (rc) {
1092c6a57a50Sjilai wang 		pr_err("%s: transfer V failed\n", __func__);
1093c6a57a50Sjilai wang 		return rc;
1094c6a57a50Sjilai wang 	}
1095c6a57a50Sjilai wang 
1096c6a57a50Sjilai wang 	/* reset SHA engine before write ksv fifo */
1097fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_reset_sha_engine(hdcp_ctrl);
1098c6a57a50Sjilai wang 	if (rc) {
1099c6a57a50Sjilai wang 		pr_err("%s: fail to reset sha engine\n", __func__);
1100c6a57a50Sjilai wang 		return rc;
1101c6a57a50Sjilai wang 	}
1102c6a57a50Sjilai wang 
1103c6a57a50Sjilai wang 	return 0;
1104c6a57a50Sjilai wang }
1105c6a57a50Sjilai wang 
1106c6a57a50Sjilai wang /*
1107c6a57a50Sjilai wang  * Write KSV FIFO to HDCP_SHA_DATA.
1108c6a57a50Sjilai wang  * This is done 1 byte at time starting with the LSB.
1109c6a57a50Sjilai wang  * Once 64 bytes have been written, we need to poll for
1110c6a57a50Sjilai wang  * HDCP_SHA_BLOCK_DONE before writing any further
1111c6a57a50Sjilai wang  * If the last byte is written, we need to poll for
1112c6a57a50Sjilai wang  * HDCP_SHA_COMP_DONE to wait until HW finish
1113c6a57a50Sjilai wang  */
msm_hdmi_hdcp_write_ksv_fifo(struct hdmi_hdcp_ctrl * hdcp_ctrl)1114fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_write_ksv_fifo(struct hdmi_hdcp_ctrl *hdcp_ctrl)
1115c6a57a50Sjilai wang {
1116c6a57a50Sjilai wang 	int i;
1117c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
1118c6a57a50Sjilai wang 	u32 ksv_bytes, last_byte = 0;
1119c6a57a50Sjilai wang 	u8 *ksv_fifo = NULL;
1120c6a57a50Sjilai wang 	u32 reg_val, data, reg;
1121c6a57a50Sjilai wang 	u32 rc  = 0;
1122c6a57a50Sjilai wang 
1123c6a57a50Sjilai wang 	ksv_bytes  = 5 * hdcp_ctrl->dev_count;
1124c6a57a50Sjilai wang 
1125c6a57a50Sjilai wang 	/* Check if need to wait for HW completion */
1126c6a57a50Sjilai wang 	if (hdcp_ctrl->ksv_fifo_w_index) {
1127c6a57a50Sjilai wang 		reg_val = hdmi_read(hdmi, REG_HDMI_HDCP_SHA_STATUS);
1128c6a57a50Sjilai wang 		DBG("HDCP_SHA_STATUS=%08x", reg_val);
1129c6a57a50Sjilai wang 		if (hdcp_ctrl->ksv_fifo_w_index == ksv_bytes) {
1130c6a57a50Sjilai wang 			/* check COMP_DONE if last write */
1131c6a57a50Sjilai wang 			if (reg_val & HDMI_HDCP_SHA_STATUS_COMP_DONE) {
1132c6a57a50Sjilai wang 				DBG("COMP_DONE");
1133c6a57a50Sjilai wang 				return 0;
1134c6a57a50Sjilai wang 			} else {
1135c6a57a50Sjilai wang 				return -EAGAIN;
1136c6a57a50Sjilai wang 			}
1137c6a57a50Sjilai wang 		} else {
1138c6a57a50Sjilai wang 			/* check BLOCK_DONE if not last write */
1139c6a57a50Sjilai wang 			if (!(reg_val & HDMI_HDCP_SHA_STATUS_BLOCK_DONE))
1140c6a57a50Sjilai wang 				return -EAGAIN;
1141c6a57a50Sjilai wang 
1142c6a57a50Sjilai wang 			DBG("BLOCK_DONE");
1143c6a57a50Sjilai wang 		}
1144c6a57a50Sjilai wang 	}
1145c6a57a50Sjilai wang 
1146c6a57a50Sjilai wang 	ksv_bytes  -= hdcp_ctrl->ksv_fifo_w_index;
1147c6a57a50Sjilai wang 	if (ksv_bytes <= 64)
1148c6a57a50Sjilai wang 		last_byte = 1;
1149c6a57a50Sjilai wang 	else
1150c6a57a50Sjilai wang 		ksv_bytes = 64;
1151c6a57a50Sjilai wang 
1152c6a57a50Sjilai wang 	ksv_fifo = hdcp_ctrl->ksv_list;
1153c6a57a50Sjilai wang 	ksv_fifo += hdcp_ctrl->ksv_fifo_w_index;
1154c6a57a50Sjilai wang 
1155c6a57a50Sjilai wang 	for (i = 0; i < ksv_bytes; i++) {
1156c6a57a50Sjilai wang 		/* Write KSV byte and set DONE bit[0] for last byte*/
1157c6a57a50Sjilai wang 		reg_val = ksv_fifo[i] << 16;
1158c6a57a50Sjilai wang 		if ((i == (ksv_bytes - 1)) && last_byte)
1159c6a57a50Sjilai wang 			reg_val |= HDMI_HDCP_SHA_DATA_DONE;
1160c6a57a50Sjilai wang 
1161c6a57a50Sjilai wang 		reg = REG_HDMI_HDCP_SHA_DATA;
1162c6a57a50Sjilai wang 		data = reg_val;
1163fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_scm_wr(hdcp_ctrl, &reg, &data, 1);
1164c6a57a50Sjilai wang 
1165c6a57a50Sjilai wang 		if (rc)
1166c6a57a50Sjilai wang 			return rc;
1167c6a57a50Sjilai wang 	}
1168c6a57a50Sjilai wang 
1169c6a57a50Sjilai wang 	hdcp_ctrl->ksv_fifo_w_index += ksv_bytes;
1170c6a57a50Sjilai wang 
1171c6a57a50Sjilai wang 	/*
1172c6a57a50Sjilai wang 	 *return -EAGAIN to notify caller to wait for COMP_DONE or BLOCK_DONE
1173c6a57a50Sjilai wang 	 */
1174c6a57a50Sjilai wang 	return -EAGAIN;
1175c6a57a50Sjilai wang }
1176c6a57a50Sjilai wang 
1177c6a57a50Sjilai wang /* write ksv fifo into HDCP engine */
msm_hdmi_hdcp_auth_part2_write_ksv_fifo(struct hdmi_hdcp_ctrl * hdcp_ctrl)1178fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_auth_part2_write_ksv_fifo(
1179c6a57a50Sjilai wang 	struct hdmi_hdcp_ctrl *hdcp_ctrl)
1180c6a57a50Sjilai wang {
1181c6a57a50Sjilai wang 	int rc;
1182c6a57a50Sjilai wang 	u32 timeout_count;
1183c6a57a50Sjilai wang 
1184c6a57a50Sjilai wang 	hdcp_ctrl->ksv_fifo_w_index = 0;
1185c6a57a50Sjilai wang 	timeout_count = 100;
1186c6a57a50Sjilai wang 	do {
1187fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_write_ksv_fifo(hdcp_ctrl);
1188c6a57a50Sjilai wang 		if (!rc)
1189c6a57a50Sjilai wang 			break;
1190c6a57a50Sjilai wang 
1191c6a57a50Sjilai wang 		if (rc != -EAGAIN)
1192c6a57a50Sjilai wang 			return rc;
1193c6a57a50Sjilai wang 
1194c6a57a50Sjilai wang 		timeout_count--;
1195c6a57a50Sjilai wang 		if (!timeout_count) {
1196c6a57a50Sjilai wang 			pr_err("%s: Write KSV fifo timedout", __func__);
1197c6a57a50Sjilai wang 			return -ETIMEDOUT;
1198c6a57a50Sjilai wang 		}
1199c6a57a50Sjilai wang 
1200fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
1201c6a57a50Sjilai wang 		if (rc)
1202c6a57a50Sjilai wang 			return rc;
1203c6a57a50Sjilai wang 	} while (1);
1204c6a57a50Sjilai wang 
1205c6a57a50Sjilai wang 	return 0;
1206c6a57a50Sjilai wang }
1207c6a57a50Sjilai wang 
msm_hdmi_hdcp_auth_part2_check_v_match(struct hdmi_hdcp_ctrl * hdcp_ctrl)1208fcda50c8SArnd Bergmann static int msm_hdmi_hdcp_auth_part2_check_v_match(struct hdmi_hdcp_ctrl *hdcp_ctrl)
1209c6a57a50Sjilai wang {
1210c6a57a50Sjilai wang 	int rc = 0;
1211c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
1212c6a57a50Sjilai wang 	u32 link0_status;
1213c6a57a50Sjilai wang 	u32 timeout_count = 100;
1214c6a57a50Sjilai wang 
1215c6a57a50Sjilai wang 	do {
1216c6a57a50Sjilai wang 		link0_status = hdmi_read(hdmi, REG_HDMI_HDCP_LINK0_STATUS);
1217c6a57a50Sjilai wang 		if (link0_status & HDMI_HDCP_LINK0_STATUS_V_MATCHES)
1218c6a57a50Sjilai wang 			break;
1219c6a57a50Sjilai wang 
1220c6a57a50Sjilai wang 		timeout_count--;
1221c6a57a50Sjilai wang 		if (!timeout_count) {
1222c6a57a50Sjilai wang 				pr_err("%s: HDCP V Match timedout", __func__);
1223c6a57a50Sjilai wang 				return -ETIMEDOUT;
1224c6a57a50Sjilai wang 		}
1225c6a57a50Sjilai wang 
1226fcda50c8SArnd Bergmann 		rc = msm_hdmi_hdcp_msleep(hdcp_ctrl, 20, AUTH_ABORT_EV);
1227c6a57a50Sjilai wang 		if (rc)
1228c6a57a50Sjilai wang 			return rc;
1229c6a57a50Sjilai wang 	} while (1);
1230c6a57a50Sjilai wang 
1231c6a57a50Sjilai wang 	return 0;
1232c6a57a50Sjilai wang }
1233c6a57a50Sjilai wang 
msm_hdmi_hdcp_auth_work(struct work_struct * work)1234fcda50c8SArnd Bergmann static void msm_hdmi_hdcp_auth_work(struct work_struct *work)
1235c6a57a50Sjilai wang {
1236c6a57a50Sjilai wang 	struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(work,
1237c6a57a50Sjilai wang 		struct hdmi_hdcp_ctrl, hdcp_auth_work);
1238c6a57a50Sjilai wang 	int rc;
1239c6a57a50Sjilai wang 
1240fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_auth_prepare(hdcp_ctrl);
1241c6a57a50Sjilai wang 	if (rc) {
1242c6a57a50Sjilai wang 		pr_err("%s: auth prepare failed %d\n", __func__, rc);
1243c6a57a50Sjilai wang 		goto end;
1244c6a57a50Sjilai wang 	}
1245c6a57a50Sjilai wang 
1246c6a57a50Sjilai wang 	/* HDCP PartI */
1247fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_auth_part1_key_exchange(hdcp_ctrl);
1248c6a57a50Sjilai wang 	if (rc) {
1249c6a57a50Sjilai wang 		pr_err("%s: key exchange failed %d\n", __func__, rc);
1250c6a57a50Sjilai wang 		goto end;
1251c6a57a50Sjilai wang 	}
1252c6a57a50Sjilai wang 
1253fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_auth_part1_recv_r0(hdcp_ctrl);
1254c6a57a50Sjilai wang 	if (rc) {
1255c6a57a50Sjilai wang 		pr_err("%s: receive r0 failed %d\n", __func__, rc);
1256c6a57a50Sjilai wang 		goto end;
1257c6a57a50Sjilai wang 	}
1258c6a57a50Sjilai wang 
1259fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_auth_part1_verify_r0(hdcp_ctrl);
1260c6a57a50Sjilai wang 	if (rc) {
1261c6a57a50Sjilai wang 		pr_err("%s: verify r0 failed %d\n", __func__, rc);
1262c6a57a50Sjilai wang 		goto end;
1263c6a57a50Sjilai wang 	}
1264c6a57a50Sjilai wang 	pr_info("%s: Authentication Part I successful\n", __func__);
1265c6a57a50Sjilai wang 	if (hdcp_ctrl->ds_type == DS_RECEIVER)
1266c6a57a50Sjilai wang 		goto end;
1267c6a57a50Sjilai wang 
1268c6a57a50Sjilai wang 	/* HDCP PartII */
1269fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_auth_part2_wait_ksv_fifo_ready(hdcp_ctrl);
1270c6a57a50Sjilai wang 	if (rc) {
1271c6a57a50Sjilai wang 		pr_err("%s: wait ksv fifo ready failed %d\n", __func__, rc);
1272c6a57a50Sjilai wang 		goto end;
1273c6a57a50Sjilai wang 	}
1274c6a57a50Sjilai wang 
1275fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_auth_part2_recv_ksv_fifo(hdcp_ctrl);
1276c6a57a50Sjilai wang 	if (rc) {
1277c6a57a50Sjilai wang 		pr_err("%s: recv ksv fifo failed %d\n", __func__, rc);
1278c6a57a50Sjilai wang 		goto end;
1279c6a57a50Sjilai wang 	}
1280c6a57a50Sjilai wang 
1281fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_auth_part2_write_ksv_fifo(hdcp_ctrl);
1282c6a57a50Sjilai wang 	if (rc) {
1283c6a57a50Sjilai wang 		pr_err("%s: write ksv fifo failed %d\n", __func__, rc);
1284c6a57a50Sjilai wang 		goto end;
1285c6a57a50Sjilai wang 	}
1286c6a57a50Sjilai wang 
1287fcda50c8SArnd Bergmann 	rc = msm_hdmi_hdcp_auth_part2_check_v_match(hdcp_ctrl);
1288c6a57a50Sjilai wang 	if (rc)
1289c6a57a50Sjilai wang 		pr_err("%s: check v match failed %d\n", __func__, rc);
1290c6a57a50Sjilai wang 
1291c6a57a50Sjilai wang end:
1292c6a57a50Sjilai wang 	if (rc == -ECANCELED) {
1293c6a57a50Sjilai wang 		pr_info("%s: hdcp authentication canceled\n", __func__);
1294c6a57a50Sjilai wang 	} else if (rc == -ENOTSUPP) {
1295c6a57a50Sjilai wang 		pr_info("%s: hdcp is not supported\n", __func__);
1296c6a57a50Sjilai wang 	} else if (rc) {
1297c6a57a50Sjilai wang 		pr_err("%s: hdcp authentication failed\n", __func__);
1298fcda50c8SArnd Bergmann 		msm_hdmi_hdcp_auth_fail(hdcp_ctrl);
1299c6a57a50Sjilai wang 	} else {
1300fcda50c8SArnd Bergmann 		msm_hdmi_hdcp_auth_done(hdcp_ctrl);
1301c6a57a50Sjilai wang 	}
1302c6a57a50Sjilai wang }
1303c6a57a50Sjilai wang 
msm_hdmi_hdcp_on(struct hdmi_hdcp_ctrl * hdcp_ctrl)1304fcda50c8SArnd Bergmann void msm_hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl)
1305c6a57a50Sjilai wang {
1306c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
1307c6a57a50Sjilai wang 	u32 reg_val;
1308c6a57a50Sjilai wang 	unsigned long flags;
1309c6a57a50Sjilai wang 
1310c6a57a50Sjilai wang 	if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) ||
1311c6a57a50Sjilai wang 		(HDCP_STATE_NO_AKSV == hdcp_ctrl->hdcp_state)) {
1312c6a57a50Sjilai wang 		DBG("still active or activating or no askv. returning");
1313c6a57a50Sjilai wang 		return;
1314c6a57a50Sjilai wang 	}
1315c6a57a50Sjilai wang 
1316c6a57a50Sjilai wang 	/* clear HDMI Encrypt */
1317c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
1318c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
1319c6a57a50Sjilai wang 	reg_val &= ~HDMI_CTRL_ENCRYPTED;
1320c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
1321c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
1322c6a57a50Sjilai wang 
1323c6a57a50Sjilai wang 	hdcp_ctrl->auth_event = 0;
1324c6a57a50Sjilai wang 	hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
1325c6a57a50Sjilai wang 	hdcp_ctrl->auth_retries = 0;
1326c6a57a50Sjilai wang 	queue_work(hdmi->workq, &hdcp_ctrl->hdcp_auth_work);
1327c6a57a50Sjilai wang }
1328c6a57a50Sjilai wang 
msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl * hdcp_ctrl)1329fcda50c8SArnd Bergmann void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl)
1330c6a57a50Sjilai wang {
1331c6a57a50Sjilai wang 	struct hdmi *hdmi = hdcp_ctrl->hdmi;
1332c6a57a50Sjilai wang 	unsigned long flags;
1333c6a57a50Sjilai wang 	u32 reg_val;
1334c6a57a50Sjilai wang 
1335c6a57a50Sjilai wang 	if ((HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) ||
1336c6a57a50Sjilai wang 		(HDCP_STATE_NO_AKSV == hdcp_ctrl->hdcp_state)) {
1337c6a57a50Sjilai wang 		DBG("hdcp inactive or no aksv. returning");
1338c6a57a50Sjilai wang 		return;
1339c6a57a50Sjilai wang 	}
1340c6a57a50Sjilai wang 
1341c6a57a50Sjilai wang 	/*
1342c6a57a50Sjilai wang 	 * Disable HPD circuitry.
1343c6a57a50Sjilai wang 	 * This is needed to reset the HDCP cipher engine so that when we
1344c6a57a50Sjilai wang 	 * attempt a re-authentication, HW would clear the AN0_READY and
1345c6a57a50Sjilai wang 	 * AN1_READY bits in HDMI_HDCP_LINK0_STATUS register
1346c6a57a50Sjilai wang 	 */
1347c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
1348c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
1349c6a57a50Sjilai wang 	reg_val &= ~HDMI_HPD_CTRL_ENABLE;
1350c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
1351c6a57a50Sjilai wang 
1352c6a57a50Sjilai wang 	/*
1353c6a57a50Sjilai wang 	 * Disable HDCP interrupts.
1354c6a57a50Sjilai wang 	 * Also, need to set the state to inactive here so that any ongoing
1355c6a57a50Sjilai wang 	 * reauth works will know that the HDCP session has been turned off.
1356c6a57a50Sjilai wang 	 */
1357c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_INT_CTRL, 0);
1358c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
1359c6a57a50Sjilai wang 
1360c6a57a50Sjilai wang 	/*
1361c6a57a50Sjilai wang 	 * Cancel any pending auth/reauth attempts.
1362c6a57a50Sjilai wang 	 * If one is ongoing, this will wait for it to finish.
1363c6a57a50Sjilai wang 	 * No more reauthentication attempts will be scheduled since we
1364c6a57a50Sjilai wang 	 * set the current state to inactive.
1365c6a57a50Sjilai wang 	 */
1366c6a57a50Sjilai wang 	set_bit(AUTH_ABORT_EV, &hdcp_ctrl->auth_event);
1367c6a57a50Sjilai wang 	wake_up_all(&hdcp_ctrl->auth_event_queue);
1368c6a57a50Sjilai wang 	cancel_work_sync(&hdcp_ctrl->hdcp_auth_work);
1369c6a57a50Sjilai wang 	cancel_work_sync(&hdcp_ctrl->hdcp_reauth_work);
1370c6a57a50Sjilai wang 
1371c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_RESET,
1372c6a57a50Sjilai wang 		HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE);
1373c6a57a50Sjilai wang 
1374c6a57a50Sjilai wang 	/* Disable encryption and disable the HDCP block */
1375c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HDCP_CTRL, 0);
1376c6a57a50Sjilai wang 
1377c6a57a50Sjilai wang 	spin_lock_irqsave(&hdmi->reg_lock, flags);
1378c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
1379c6a57a50Sjilai wang 	reg_val &= ~HDMI_CTRL_ENCRYPTED;
1380c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
1381c6a57a50Sjilai wang 
1382c6a57a50Sjilai wang 	/* Enable HPD circuitry */
1383c6a57a50Sjilai wang 	reg_val = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
1384c6a57a50Sjilai wang 	reg_val |= HDMI_HPD_CTRL_ENABLE;
1385c6a57a50Sjilai wang 	hdmi_write(hdmi, REG_HDMI_HPD_CTRL, reg_val);
1386c6a57a50Sjilai wang 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
1387c6a57a50Sjilai wang 
1388c6a57a50Sjilai wang 	hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
1389c6a57a50Sjilai wang 
1390c6a57a50Sjilai wang 	DBG("HDCP: Off");
1391c6a57a50Sjilai wang }
1392c6a57a50Sjilai wang 
msm_hdmi_hdcp_init(struct hdmi * hdmi)1393fcda50c8SArnd Bergmann struct hdmi_hdcp_ctrl *msm_hdmi_hdcp_init(struct hdmi *hdmi)
1394c6a57a50Sjilai wang {
1395c6a57a50Sjilai wang 	struct hdmi_hdcp_ctrl *hdcp_ctrl = NULL;
1396c6a57a50Sjilai wang 
1397c6a57a50Sjilai wang 	if (!hdmi->qfprom_mmio) {
1398c6a57a50Sjilai wang 		pr_err("%s: HDCP is not supported without qfprom\n",
1399c6a57a50Sjilai wang 			__func__);
1400c6a57a50Sjilai wang 		return ERR_PTR(-EINVAL);
1401c6a57a50Sjilai wang 	}
1402c6a57a50Sjilai wang 
1403c6a57a50Sjilai wang 	hdcp_ctrl = kzalloc(sizeof(*hdcp_ctrl), GFP_KERNEL);
1404c6a57a50Sjilai wang 	if (!hdcp_ctrl)
1405c6a57a50Sjilai wang 		return ERR_PTR(-ENOMEM);
1406c6a57a50Sjilai wang 
1407fcda50c8SArnd Bergmann 	INIT_WORK(&hdcp_ctrl->hdcp_auth_work, msm_hdmi_hdcp_auth_work);
1408fcda50c8SArnd Bergmann 	INIT_WORK(&hdcp_ctrl->hdcp_reauth_work, msm_hdmi_hdcp_reauth_work);
1409c6a57a50Sjilai wang 	init_waitqueue_head(&hdcp_ctrl->auth_event_queue);
1410c6a57a50Sjilai wang 	hdcp_ctrl->hdmi = hdmi;
1411c6a57a50Sjilai wang 	hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
1412c6a57a50Sjilai wang 	hdcp_ctrl->aksv_valid = false;
1413c6a57a50Sjilai wang 
1414c6a57a50Sjilai wang 	if (qcom_scm_hdcp_available())
1415c6a57a50Sjilai wang 		hdcp_ctrl->tz_hdcp = true;
1416c6a57a50Sjilai wang 	else
1417c6a57a50Sjilai wang 		hdcp_ctrl->tz_hdcp = false;
1418c6a57a50Sjilai wang 
1419c6a57a50Sjilai wang 	return hdcp_ctrl;
1420c6a57a50Sjilai wang }
1421c6a57a50Sjilai wang 
msm_hdmi_hdcp_destroy(struct hdmi * hdmi)1422fcda50c8SArnd Bergmann void msm_hdmi_hdcp_destroy(struct hdmi *hdmi)
1423c6a57a50Sjilai wang {
1424851dd75dSMarkus Elfring 	if (hdmi) {
1425c6a57a50Sjilai wang 		kfree(hdmi->hdcp_ctrl);
1426c6a57a50Sjilai wang 		hdmi->hdcp_ctrl = NULL;
1427c6a57a50Sjilai wang 	}
1428c6a57a50Sjilai wang }
1429