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