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