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, ®, &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, ®, &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 = ®_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, ®, &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