1*6a3608eaSParshuram Thombare // SPDX-License-Identifier: GPL-2.0 2*6a3608eaSParshuram Thombare /* 3*6a3608eaSParshuram Thombare * Cadence MHDP8546 DP bridge driver. 4*6a3608eaSParshuram Thombare * 5*6a3608eaSParshuram Thombare * Copyright (C) 2020 Cadence Design Systems, Inc. 6*6a3608eaSParshuram Thombare * 7*6a3608eaSParshuram Thombare */ 8*6a3608eaSParshuram Thombare 9*6a3608eaSParshuram Thombare #include <linux/io.h> 10*6a3608eaSParshuram Thombare #include <linux/iopoll.h> 11*6a3608eaSParshuram Thombare 12*6a3608eaSParshuram Thombare #include <asm/unaligned.h> 13*6a3608eaSParshuram Thombare 14*6a3608eaSParshuram Thombare #include <drm/drm_hdcp.h> 15*6a3608eaSParshuram Thombare 16*6a3608eaSParshuram Thombare #include "cdns-mhdp8546-hdcp.h" 17*6a3608eaSParshuram Thombare 18*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_read(struct cdns_mhdp_device *mhdp) 19*6a3608eaSParshuram Thombare { 20*6a3608eaSParshuram Thombare int ret, empty; 21*6a3608eaSParshuram Thombare 22*6a3608eaSParshuram Thombare WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex)); 23*6a3608eaSParshuram Thombare 24*6a3608eaSParshuram Thombare ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_EMPTY, 25*6a3608eaSParshuram Thombare empty, !empty, MAILBOX_RETRY_US, 26*6a3608eaSParshuram Thombare MAILBOX_TIMEOUT_US); 27*6a3608eaSParshuram Thombare if (ret < 0) 28*6a3608eaSParshuram Thombare return ret; 29*6a3608eaSParshuram Thombare 30*6a3608eaSParshuram Thombare return readl(mhdp->sapb_regs + CDNS_MAILBOX_RX_DATA) & 0xff; 31*6a3608eaSParshuram Thombare } 32*6a3608eaSParshuram Thombare 33*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_write(struct cdns_mhdp_device *mhdp, 34*6a3608eaSParshuram Thombare u8 val) 35*6a3608eaSParshuram Thombare { 36*6a3608eaSParshuram Thombare int ret, full; 37*6a3608eaSParshuram Thombare 38*6a3608eaSParshuram Thombare WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex)); 39*6a3608eaSParshuram Thombare 40*6a3608eaSParshuram Thombare ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_FULL, 41*6a3608eaSParshuram Thombare full, !full, MAILBOX_RETRY_US, 42*6a3608eaSParshuram Thombare MAILBOX_TIMEOUT_US); 43*6a3608eaSParshuram Thombare if (ret < 0) 44*6a3608eaSParshuram Thombare return ret; 45*6a3608eaSParshuram Thombare 46*6a3608eaSParshuram Thombare writel(val, mhdp->sapb_regs + CDNS_MAILBOX_TX_DATA); 47*6a3608eaSParshuram Thombare 48*6a3608eaSParshuram Thombare return 0; 49*6a3608eaSParshuram Thombare } 50*6a3608eaSParshuram Thombare 51*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_recv_header(struct cdns_mhdp_device *mhdp, 52*6a3608eaSParshuram Thombare u8 module_id, 53*6a3608eaSParshuram Thombare u8 opcode, 54*6a3608eaSParshuram Thombare u16 req_size) 55*6a3608eaSParshuram Thombare { 56*6a3608eaSParshuram Thombare u32 mbox_size, i; 57*6a3608eaSParshuram Thombare u8 header[4]; 58*6a3608eaSParshuram Thombare int ret; 59*6a3608eaSParshuram Thombare 60*6a3608eaSParshuram Thombare /* read the header of the message */ 61*6a3608eaSParshuram Thombare for (i = 0; i < sizeof(header); i++) { 62*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_read(mhdp); 63*6a3608eaSParshuram Thombare if (ret < 0) 64*6a3608eaSParshuram Thombare return ret; 65*6a3608eaSParshuram Thombare 66*6a3608eaSParshuram Thombare header[i] = ret; 67*6a3608eaSParshuram Thombare } 68*6a3608eaSParshuram Thombare 69*6a3608eaSParshuram Thombare mbox_size = get_unaligned_be16(header + 2); 70*6a3608eaSParshuram Thombare 71*6a3608eaSParshuram Thombare if (opcode != header[0] || module_id != header[1] || 72*6a3608eaSParshuram Thombare (opcode != HDCP_TRAN_IS_REC_ID_VALID && req_size != mbox_size)) { 73*6a3608eaSParshuram Thombare for (i = 0; i < mbox_size; i++) 74*6a3608eaSParshuram Thombare if (cdns_mhdp_secure_mailbox_read(mhdp) < 0) 75*6a3608eaSParshuram Thombare break; 76*6a3608eaSParshuram Thombare return -EINVAL; 77*6a3608eaSParshuram Thombare } 78*6a3608eaSParshuram Thombare 79*6a3608eaSParshuram Thombare return 0; 80*6a3608eaSParshuram Thombare } 81*6a3608eaSParshuram Thombare 82*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_recv_data(struct cdns_mhdp_device *mhdp, 83*6a3608eaSParshuram Thombare u8 *buff, u16 buff_size) 84*6a3608eaSParshuram Thombare { 85*6a3608eaSParshuram Thombare int ret; 86*6a3608eaSParshuram Thombare u32 i; 87*6a3608eaSParshuram Thombare 88*6a3608eaSParshuram Thombare for (i = 0; i < buff_size; i++) { 89*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_read(mhdp); 90*6a3608eaSParshuram Thombare if (ret < 0) 91*6a3608eaSParshuram Thombare return ret; 92*6a3608eaSParshuram Thombare 93*6a3608eaSParshuram Thombare buff[i] = ret; 94*6a3608eaSParshuram Thombare } 95*6a3608eaSParshuram Thombare 96*6a3608eaSParshuram Thombare return 0; 97*6a3608eaSParshuram Thombare } 98*6a3608eaSParshuram Thombare 99*6a3608eaSParshuram Thombare static int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_device *mhdp, 100*6a3608eaSParshuram Thombare u8 module_id, 101*6a3608eaSParshuram Thombare u8 opcode, 102*6a3608eaSParshuram Thombare u16 size, 103*6a3608eaSParshuram Thombare u8 *message) 104*6a3608eaSParshuram Thombare { 105*6a3608eaSParshuram Thombare u8 header[4]; 106*6a3608eaSParshuram Thombare int ret; 107*6a3608eaSParshuram Thombare u32 i; 108*6a3608eaSParshuram Thombare 109*6a3608eaSParshuram Thombare header[0] = opcode; 110*6a3608eaSParshuram Thombare header[1] = module_id; 111*6a3608eaSParshuram Thombare put_unaligned_be16(size, header + 2); 112*6a3608eaSParshuram Thombare 113*6a3608eaSParshuram Thombare for (i = 0; i < sizeof(header); i++) { 114*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_write(mhdp, header[i]); 115*6a3608eaSParshuram Thombare if (ret) 116*6a3608eaSParshuram Thombare return ret; 117*6a3608eaSParshuram Thombare } 118*6a3608eaSParshuram Thombare 119*6a3608eaSParshuram Thombare for (i = 0; i < size; i++) { 120*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_write(mhdp, message[i]); 121*6a3608eaSParshuram Thombare if (ret) 122*6a3608eaSParshuram Thombare return ret; 123*6a3608eaSParshuram Thombare } 124*6a3608eaSParshuram Thombare 125*6a3608eaSParshuram Thombare return 0; 126*6a3608eaSParshuram Thombare } 127*6a3608eaSParshuram Thombare 128*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_get_status(struct cdns_mhdp_device *mhdp, 129*6a3608eaSParshuram Thombare u16 *hdcp_port_status) 130*6a3608eaSParshuram Thombare { 131*6a3608eaSParshuram Thombare u8 hdcp_status[HDCP_STATUS_SIZE]; 132*6a3608eaSParshuram Thombare int ret; 133*6a3608eaSParshuram Thombare 134*6a3608eaSParshuram Thombare mutex_lock(&mhdp->mbox_mutex); 135*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, 136*6a3608eaSParshuram Thombare HDCP_TRAN_STATUS_CHANGE, 0, NULL); 137*6a3608eaSParshuram Thombare if (ret) 138*6a3608eaSParshuram Thombare goto err_get_hdcp_status; 139*6a3608eaSParshuram Thombare 140*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, 141*6a3608eaSParshuram Thombare HDCP_TRAN_STATUS_CHANGE, 142*6a3608eaSParshuram Thombare sizeof(hdcp_status)); 143*6a3608eaSParshuram Thombare if (ret) 144*6a3608eaSParshuram Thombare goto err_get_hdcp_status; 145*6a3608eaSParshuram Thombare 146*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_status, 147*6a3608eaSParshuram Thombare sizeof(hdcp_status)); 148*6a3608eaSParshuram Thombare if (ret) 149*6a3608eaSParshuram Thombare goto err_get_hdcp_status; 150*6a3608eaSParshuram Thombare 151*6a3608eaSParshuram Thombare *hdcp_port_status = ((u16)(hdcp_status[0] << 8) | hdcp_status[1]); 152*6a3608eaSParshuram Thombare 153*6a3608eaSParshuram Thombare err_get_hdcp_status: 154*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->mbox_mutex); 155*6a3608eaSParshuram Thombare 156*6a3608eaSParshuram Thombare return ret; 157*6a3608eaSParshuram Thombare } 158*6a3608eaSParshuram Thombare 159*6a3608eaSParshuram Thombare static u8 cdns_mhdp_hdcp_handle_status(struct cdns_mhdp_device *mhdp, 160*6a3608eaSParshuram Thombare u16 status) 161*6a3608eaSParshuram Thombare { 162*6a3608eaSParshuram Thombare u8 err = GET_HDCP_PORT_STS_LAST_ERR(status); 163*6a3608eaSParshuram Thombare 164*6a3608eaSParshuram Thombare if (err) 165*6a3608eaSParshuram Thombare dev_dbg(mhdp->dev, "HDCP Error = %d", err); 166*6a3608eaSParshuram Thombare 167*6a3608eaSParshuram Thombare return err; 168*6a3608eaSParshuram Thombare } 169*6a3608eaSParshuram Thombare 170*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_rx_id_valid_response(struct cdns_mhdp_device *mhdp, 171*6a3608eaSParshuram Thombare u8 valid) 172*6a3608eaSParshuram Thombare { 173*6a3608eaSParshuram Thombare int ret; 174*6a3608eaSParshuram Thombare 175*6a3608eaSParshuram Thombare mutex_lock(&mhdp->mbox_mutex); 176*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, 177*6a3608eaSParshuram Thombare HDCP_TRAN_RESPOND_RECEIVER_ID_VALID, 178*6a3608eaSParshuram Thombare 1, &valid); 179*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->mbox_mutex); 180*6a3608eaSParshuram Thombare 181*6a3608eaSParshuram Thombare return ret; 182*6a3608eaSParshuram Thombare } 183*6a3608eaSParshuram Thombare 184*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_rx_id_valid(struct cdns_mhdp_device *mhdp, 185*6a3608eaSParshuram Thombare u8 *recv_num, u8 *hdcp_rx_id) 186*6a3608eaSParshuram Thombare { 187*6a3608eaSParshuram Thombare u8 rec_id_hdr[2]; 188*6a3608eaSParshuram Thombare u8 status; 189*6a3608eaSParshuram Thombare int ret; 190*6a3608eaSParshuram Thombare 191*6a3608eaSParshuram Thombare mutex_lock(&mhdp->mbox_mutex); 192*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, 193*6a3608eaSParshuram Thombare HDCP_TRAN_IS_REC_ID_VALID, 0, NULL); 194*6a3608eaSParshuram Thombare if (ret) 195*6a3608eaSParshuram Thombare goto err_rx_id_valid; 196*6a3608eaSParshuram Thombare 197*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, 198*6a3608eaSParshuram Thombare HDCP_TRAN_IS_REC_ID_VALID, 199*6a3608eaSParshuram Thombare sizeof(status)); 200*6a3608eaSParshuram Thombare if (ret) 201*6a3608eaSParshuram Thombare goto err_rx_id_valid; 202*6a3608eaSParshuram Thombare 203*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, rec_id_hdr, 2); 204*6a3608eaSParshuram Thombare if (ret) 205*6a3608eaSParshuram Thombare goto err_rx_id_valid; 206*6a3608eaSParshuram Thombare 207*6a3608eaSParshuram Thombare *recv_num = rec_id_hdr[0]; 208*6a3608eaSParshuram Thombare 209*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_rx_id, 5 * *recv_num); 210*6a3608eaSParshuram Thombare 211*6a3608eaSParshuram Thombare err_rx_id_valid: 212*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->mbox_mutex); 213*6a3608eaSParshuram Thombare 214*6a3608eaSParshuram Thombare return ret; 215*6a3608eaSParshuram Thombare } 216*6a3608eaSParshuram Thombare 217*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_km_stored_resp(struct cdns_mhdp_device *mhdp, 218*6a3608eaSParshuram Thombare u32 size, u8 *km) 219*6a3608eaSParshuram Thombare { 220*6a3608eaSParshuram Thombare int ret; 221*6a3608eaSParshuram Thombare 222*6a3608eaSParshuram Thombare mutex_lock(&mhdp->mbox_mutex); 223*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, 224*6a3608eaSParshuram Thombare HDCP2X_TX_RESPOND_KM, size, km); 225*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->mbox_mutex); 226*6a3608eaSParshuram Thombare 227*6a3608eaSParshuram Thombare return ret; 228*6a3608eaSParshuram Thombare } 229*6a3608eaSParshuram Thombare 230*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_tx_is_km_stored(struct cdns_mhdp_device *mhdp, 231*6a3608eaSParshuram Thombare u8 *resp, u32 size) 232*6a3608eaSParshuram Thombare { 233*6a3608eaSParshuram Thombare int ret; 234*6a3608eaSParshuram Thombare 235*6a3608eaSParshuram Thombare mutex_lock(&mhdp->mbox_mutex); 236*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, 237*6a3608eaSParshuram Thombare HDCP2X_TX_IS_KM_STORED, 0, NULL); 238*6a3608eaSParshuram Thombare if (ret) 239*6a3608eaSParshuram Thombare goto err_is_km_stored; 240*6a3608eaSParshuram Thombare 241*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, 242*6a3608eaSParshuram Thombare HDCP2X_TX_IS_KM_STORED, 243*6a3608eaSParshuram Thombare size); 244*6a3608eaSParshuram Thombare if (ret) 245*6a3608eaSParshuram Thombare goto err_is_km_stored; 246*6a3608eaSParshuram Thombare 247*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, resp, size); 248*6a3608eaSParshuram Thombare err_is_km_stored: 249*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->mbox_mutex); 250*6a3608eaSParshuram Thombare 251*6a3608eaSParshuram Thombare return ret; 252*6a3608eaSParshuram Thombare } 253*6a3608eaSParshuram Thombare 254*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_tx_config(struct cdns_mhdp_device *mhdp, 255*6a3608eaSParshuram Thombare u8 hdcp_cfg) 256*6a3608eaSParshuram Thombare { 257*6a3608eaSParshuram Thombare int ret; 258*6a3608eaSParshuram Thombare 259*6a3608eaSParshuram Thombare mutex_lock(&mhdp->mbox_mutex); 260*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, 261*6a3608eaSParshuram Thombare HDCP_TRAN_CONFIGURATION, 1, &hdcp_cfg); 262*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->mbox_mutex); 263*6a3608eaSParshuram Thombare 264*6a3608eaSParshuram Thombare return ret; 265*6a3608eaSParshuram Thombare } 266*6a3608eaSParshuram Thombare 267*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_set_config(struct cdns_mhdp_device *mhdp, 268*6a3608eaSParshuram Thombare u8 hdcp_config, bool enable) 269*6a3608eaSParshuram Thombare { 270*6a3608eaSParshuram Thombare u16 hdcp_port_status; 271*6a3608eaSParshuram Thombare u32 ret_event; 272*6a3608eaSParshuram Thombare u8 hdcp_cfg; 273*6a3608eaSParshuram Thombare int ret; 274*6a3608eaSParshuram Thombare 275*6a3608eaSParshuram Thombare hdcp_cfg = hdcp_config | (enable ? 0x04 : 0) | 276*6a3608eaSParshuram Thombare (HDCP_CONTENT_TYPE_0 << 3); 277*6a3608eaSParshuram Thombare cdns_mhdp_hdcp_tx_config(mhdp, hdcp_cfg); 278*6a3608eaSParshuram Thombare ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS); 279*6a3608eaSParshuram Thombare if (!ret_event) 280*6a3608eaSParshuram Thombare return -1; 281*6a3608eaSParshuram Thombare 282*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); 283*6a3608eaSParshuram Thombare if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) 284*6a3608eaSParshuram Thombare return -1; 285*6a3608eaSParshuram Thombare 286*6a3608eaSParshuram Thombare return 0; 287*6a3608eaSParshuram Thombare } 288*6a3608eaSParshuram Thombare 289*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_auth_check(struct cdns_mhdp_device *mhdp) 290*6a3608eaSParshuram Thombare { 291*6a3608eaSParshuram Thombare u16 hdcp_port_status; 292*6a3608eaSParshuram Thombare u32 ret_event; 293*6a3608eaSParshuram Thombare int ret; 294*6a3608eaSParshuram Thombare 295*6a3608eaSParshuram Thombare ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS); 296*6a3608eaSParshuram Thombare if (!ret_event) 297*6a3608eaSParshuram Thombare return -1; 298*6a3608eaSParshuram Thombare 299*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); 300*6a3608eaSParshuram Thombare if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) 301*6a3608eaSParshuram Thombare return -1; 302*6a3608eaSParshuram Thombare 303*6a3608eaSParshuram Thombare if (hdcp_port_status & 1) { 304*6a3608eaSParshuram Thombare dev_dbg(mhdp->dev, "Authentication completed successfully!\n"); 305*6a3608eaSParshuram Thombare return 0; 306*6a3608eaSParshuram Thombare } 307*6a3608eaSParshuram Thombare 308*6a3608eaSParshuram Thombare dev_dbg(mhdp->dev, "Authentication failed\n"); 309*6a3608eaSParshuram Thombare 310*6a3608eaSParshuram Thombare return -1; 311*6a3608eaSParshuram Thombare } 312*6a3608eaSParshuram Thombare 313*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_check_receviers(struct cdns_mhdp_device *mhdp) 314*6a3608eaSParshuram Thombare { 315*6a3608eaSParshuram Thombare u8 hdcp_rec_id[HDCP_MAX_RECEIVERS][HDCP_RECEIVER_ID_SIZE_BYTES]; 316*6a3608eaSParshuram Thombare u8 hdcp_num_rec; 317*6a3608eaSParshuram Thombare u32 ret_event; 318*6a3608eaSParshuram Thombare 319*6a3608eaSParshuram Thombare ret_event = cdns_mhdp_wait_for_sw_event(mhdp, 320*6a3608eaSParshuram Thombare CDNS_HDCP_TX_IS_RCVR_ID_VALID); 321*6a3608eaSParshuram Thombare if (!ret_event) 322*6a3608eaSParshuram Thombare return -1; 323*6a3608eaSParshuram Thombare 324*6a3608eaSParshuram Thombare hdcp_num_rec = 0; 325*6a3608eaSParshuram Thombare memset(&hdcp_rec_id, 0, sizeof(hdcp_rec_id)); 326*6a3608eaSParshuram Thombare cdns_mhdp_hdcp_rx_id_valid(mhdp, &hdcp_num_rec, (u8 *)hdcp_rec_id); 327*6a3608eaSParshuram Thombare cdns_mhdp_hdcp_rx_id_valid_response(mhdp, 1); 328*6a3608eaSParshuram Thombare 329*6a3608eaSParshuram Thombare return 0; 330*6a3608eaSParshuram Thombare } 331*6a3608eaSParshuram Thombare 332*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_auth_22(struct cdns_mhdp_device *mhdp) 333*6a3608eaSParshuram Thombare { 334*6a3608eaSParshuram Thombare u8 resp[HDCP_STATUS_SIZE]; 335*6a3608eaSParshuram Thombare u16 hdcp_port_status; 336*6a3608eaSParshuram Thombare u32 ret_event; 337*6a3608eaSParshuram Thombare int ret; 338*6a3608eaSParshuram Thombare 339*6a3608eaSParshuram Thombare dev_dbg(mhdp->dev, "HDCP: Start 2.2 Authentication\n"); 340*6a3608eaSParshuram Thombare ret_event = cdns_mhdp_wait_for_sw_event(mhdp, 341*6a3608eaSParshuram Thombare CDNS_HDCP2_TX_IS_KM_STORED); 342*6a3608eaSParshuram Thombare if (!ret_event) 343*6a3608eaSParshuram Thombare return -1; 344*6a3608eaSParshuram Thombare 345*6a3608eaSParshuram Thombare if (ret_event & CDNS_HDCP_TX_STATUS) { 346*6a3608eaSParshuram Thombare mhdp->sw_events &= ~CDNS_HDCP_TX_STATUS; 347*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); 348*6a3608eaSParshuram Thombare if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) 349*6a3608eaSParshuram Thombare return -1; 350*6a3608eaSParshuram Thombare } 351*6a3608eaSParshuram Thombare 352*6a3608eaSParshuram Thombare cdns_mhdp_hdcp_tx_is_km_stored(mhdp, resp, sizeof(resp)); 353*6a3608eaSParshuram Thombare cdns_mhdp_hdcp_km_stored_resp(mhdp, 0, NULL); 354*6a3608eaSParshuram Thombare 355*6a3608eaSParshuram Thombare if (cdns_mhdp_hdcp_check_receviers(mhdp)) 356*6a3608eaSParshuram Thombare return -1; 357*6a3608eaSParshuram Thombare 358*6a3608eaSParshuram Thombare return 0; 359*6a3608eaSParshuram Thombare } 360*6a3608eaSParshuram Thombare 361*6a3608eaSParshuram Thombare static inline int cdns_mhdp_hdcp_auth_14(struct cdns_mhdp_device *mhdp) 362*6a3608eaSParshuram Thombare { 363*6a3608eaSParshuram Thombare dev_dbg(mhdp->dev, "HDCP: Starting 1.4 Authentication\n"); 364*6a3608eaSParshuram Thombare return cdns_mhdp_hdcp_check_receviers(mhdp); 365*6a3608eaSParshuram Thombare } 366*6a3608eaSParshuram Thombare 367*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_auth(struct cdns_mhdp_device *mhdp, 368*6a3608eaSParshuram Thombare u8 hdcp_config) 369*6a3608eaSParshuram Thombare { 370*6a3608eaSParshuram Thombare int ret; 371*6a3608eaSParshuram Thombare 372*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_set_config(mhdp, hdcp_config, true); 373*6a3608eaSParshuram Thombare if (ret) 374*6a3608eaSParshuram Thombare goto auth_failed; 375*6a3608eaSParshuram Thombare 376*6a3608eaSParshuram Thombare if (hdcp_config == HDCP_TX_1) 377*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_auth_14(mhdp); 378*6a3608eaSParshuram Thombare else 379*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_auth_22(mhdp); 380*6a3608eaSParshuram Thombare 381*6a3608eaSParshuram Thombare if (ret) 382*6a3608eaSParshuram Thombare goto auth_failed; 383*6a3608eaSParshuram Thombare 384*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_auth_check(mhdp); 385*6a3608eaSParshuram Thombare if (ret) 386*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_auth_check(mhdp); 387*6a3608eaSParshuram Thombare 388*6a3608eaSParshuram Thombare auth_failed: 389*6a3608eaSParshuram Thombare return ret; 390*6a3608eaSParshuram Thombare } 391*6a3608eaSParshuram Thombare 392*6a3608eaSParshuram Thombare static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) 393*6a3608eaSParshuram Thombare { 394*6a3608eaSParshuram Thombare int ret; 395*6a3608eaSParshuram Thombare 396*6a3608eaSParshuram Thombare dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", 397*6a3608eaSParshuram Thombare mhdp->connector.name, mhdp->connector.base.id); 398*6a3608eaSParshuram Thombare 399*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); 400*6a3608eaSParshuram Thombare 401*6a3608eaSParshuram Thombare return ret; 402*6a3608eaSParshuram Thombare } 403*6a3608eaSParshuram Thombare 404*6a3608eaSParshuram Thombare static int _cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) 405*6a3608eaSParshuram Thombare { 406*6a3608eaSParshuram Thombare int ret, tries = 3; 407*6a3608eaSParshuram Thombare u32 i; 408*6a3608eaSParshuram Thombare 409*6a3608eaSParshuram Thombare for (i = 0; i < tries; i++) { 410*6a3608eaSParshuram Thombare if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0 || 411*6a3608eaSParshuram Thombare content_type == DRM_MODE_HDCP_CONTENT_TYPE1) { 412*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_2); 413*6a3608eaSParshuram Thombare if (!ret) 414*6a3608eaSParshuram Thombare return 0; 415*6a3608eaSParshuram Thombare _cdns_mhdp_hdcp_disable(mhdp); 416*6a3608eaSParshuram Thombare } 417*6a3608eaSParshuram Thombare 418*6a3608eaSParshuram Thombare if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) { 419*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_1); 420*6a3608eaSParshuram Thombare if (!ret) 421*6a3608eaSParshuram Thombare return 0; 422*6a3608eaSParshuram Thombare _cdns_mhdp_hdcp_disable(mhdp); 423*6a3608eaSParshuram Thombare } 424*6a3608eaSParshuram Thombare } 425*6a3608eaSParshuram Thombare 426*6a3608eaSParshuram Thombare dev_err(mhdp->dev, "HDCP authentication failed (%d tries/%d)\n", 427*6a3608eaSParshuram Thombare tries, ret); 428*6a3608eaSParshuram Thombare 429*6a3608eaSParshuram Thombare return ret; 430*6a3608eaSParshuram Thombare } 431*6a3608eaSParshuram Thombare 432*6a3608eaSParshuram Thombare static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) 433*6a3608eaSParshuram Thombare { 434*6a3608eaSParshuram Thombare u16 hdcp_port_status; 435*6a3608eaSParshuram Thombare int ret = 0; 436*6a3608eaSParshuram Thombare 437*6a3608eaSParshuram Thombare mutex_lock(&mhdp->hdcp.mutex); 438*6a3608eaSParshuram Thombare if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) 439*6a3608eaSParshuram Thombare goto out; 440*6a3608eaSParshuram Thombare 441*6a3608eaSParshuram Thombare ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); 442*6a3608eaSParshuram Thombare if (!ret && hdcp_port_status & HDCP_PORT_STS_AUTH) 443*6a3608eaSParshuram Thombare goto out; 444*6a3608eaSParshuram Thombare 445*6a3608eaSParshuram Thombare dev_err(mhdp->dev, 446*6a3608eaSParshuram Thombare "[%s:%d] HDCP link failed, retrying authentication\n", 447*6a3608eaSParshuram Thombare mhdp->connector.name, mhdp->connector.base.id); 448*6a3608eaSParshuram Thombare 449*6a3608eaSParshuram Thombare ret = _cdns_mhdp_hdcp_disable(mhdp); 450*6a3608eaSParshuram Thombare if (ret) { 451*6a3608eaSParshuram Thombare mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; 452*6a3608eaSParshuram Thombare schedule_work(&mhdp->hdcp.prop_work); 453*6a3608eaSParshuram Thombare goto out; 454*6a3608eaSParshuram Thombare } 455*6a3608eaSParshuram Thombare 456*6a3608eaSParshuram Thombare ret = _cdns_mhdp_hdcp_enable(mhdp, mhdp->hdcp.hdcp_content_type); 457*6a3608eaSParshuram Thombare if (ret) { 458*6a3608eaSParshuram Thombare mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; 459*6a3608eaSParshuram Thombare schedule_work(&mhdp->hdcp.prop_work); 460*6a3608eaSParshuram Thombare } 461*6a3608eaSParshuram Thombare out: 462*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->hdcp.mutex); 463*6a3608eaSParshuram Thombare return ret; 464*6a3608eaSParshuram Thombare } 465*6a3608eaSParshuram Thombare 466*6a3608eaSParshuram Thombare static void cdns_mhdp_hdcp_check_work(struct work_struct *work) 467*6a3608eaSParshuram Thombare { 468*6a3608eaSParshuram Thombare struct delayed_work *d_work = to_delayed_work(work); 469*6a3608eaSParshuram Thombare struct cdns_mhdp_hdcp *hdcp = container_of(d_work, 470*6a3608eaSParshuram Thombare struct cdns_mhdp_hdcp, 471*6a3608eaSParshuram Thombare check_work); 472*6a3608eaSParshuram Thombare struct cdns_mhdp_device *mhdp = container_of(hdcp, 473*6a3608eaSParshuram Thombare struct cdns_mhdp_device, 474*6a3608eaSParshuram Thombare hdcp); 475*6a3608eaSParshuram Thombare 476*6a3608eaSParshuram Thombare if (!cdns_mhdp_hdcp_check_link(mhdp)) 477*6a3608eaSParshuram Thombare schedule_delayed_work(&hdcp->check_work, 478*6a3608eaSParshuram Thombare DRM_HDCP_CHECK_PERIOD_MS); 479*6a3608eaSParshuram Thombare } 480*6a3608eaSParshuram Thombare 481*6a3608eaSParshuram Thombare static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) 482*6a3608eaSParshuram Thombare { 483*6a3608eaSParshuram Thombare struct cdns_mhdp_hdcp *hdcp = container_of(work, 484*6a3608eaSParshuram Thombare struct cdns_mhdp_hdcp, 485*6a3608eaSParshuram Thombare prop_work); 486*6a3608eaSParshuram Thombare struct cdns_mhdp_device *mhdp = container_of(hdcp, 487*6a3608eaSParshuram Thombare struct cdns_mhdp_device, 488*6a3608eaSParshuram Thombare hdcp); 489*6a3608eaSParshuram Thombare struct drm_device *dev = mhdp->connector.dev; 490*6a3608eaSParshuram Thombare struct drm_connector_state *state; 491*6a3608eaSParshuram Thombare 492*6a3608eaSParshuram Thombare drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 493*6a3608eaSParshuram Thombare mutex_lock(&mhdp->hdcp.mutex); 494*6a3608eaSParshuram Thombare if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { 495*6a3608eaSParshuram Thombare state = mhdp->connector.state; 496*6a3608eaSParshuram Thombare state->content_protection = mhdp->hdcp.value; 497*6a3608eaSParshuram Thombare } 498*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->hdcp.mutex); 499*6a3608eaSParshuram Thombare drm_modeset_unlock(&dev->mode_config.connection_mutex); 500*6a3608eaSParshuram Thombare } 501*6a3608eaSParshuram Thombare 502*6a3608eaSParshuram Thombare int cdns_mhdp_hdcp_set_lc(struct cdns_mhdp_device *mhdp, u8 *val) 503*6a3608eaSParshuram Thombare { 504*6a3608eaSParshuram Thombare int ret; 505*6a3608eaSParshuram Thombare 506*6a3608eaSParshuram Thombare mutex_lock(&mhdp->mbox_mutex); 507*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_GENERAL, 508*6a3608eaSParshuram Thombare HDCP_GENERAL_SET_LC_128, 509*6a3608eaSParshuram Thombare 16, val); 510*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->mbox_mutex); 511*6a3608eaSParshuram Thombare 512*6a3608eaSParshuram Thombare return ret; 513*6a3608eaSParshuram Thombare } 514*6a3608eaSParshuram Thombare 515*6a3608eaSParshuram Thombare int 516*6a3608eaSParshuram Thombare cdns_mhdp_hdcp_set_public_key_param(struct cdns_mhdp_device *mhdp, 517*6a3608eaSParshuram Thombare struct cdns_hdcp_tx_public_key_param *val) 518*6a3608eaSParshuram Thombare { 519*6a3608eaSParshuram Thombare int ret; 520*6a3608eaSParshuram Thombare 521*6a3608eaSParshuram Thombare mutex_lock(&mhdp->mbox_mutex); 522*6a3608eaSParshuram Thombare ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, 523*6a3608eaSParshuram Thombare HDCP2X_TX_SET_PUBLIC_KEY_PARAMS, 524*6a3608eaSParshuram Thombare sizeof(*val), (u8 *)val); 525*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->mbox_mutex); 526*6a3608eaSParshuram Thombare 527*6a3608eaSParshuram Thombare return ret; 528*6a3608eaSParshuram Thombare } 529*6a3608eaSParshuram Thombare 530*6a3608eaSParshuram Thombare int cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) 531*6a3608eaSParshuram Thombare { 532*6a3608eaSParshuram Thombare int ret; 533*6a3608eaSParshuram Thombare 534*6a3608eaSParshuram Thombare mutex_lock(&mhdp->hdcp.mutex); 535*6a3608eaSParshuram Thombare ret = _cdns_mhdp_hdcp_enable(mhdp, content_type); 536*6a3608eaSParshuram Thombare if (ret) 537*6a3608eaSParshuram Thombare goto out; 538*6a3608eaSParshuram Thombare 539*6a3608eaSParshuram Thombare mhdp->hdcp.hdcp_content_type = content_type; 540*6a3608eaSParshuram Thombare mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_ENABLED; 541*6a3608eaSParshuram Thombare schedule_work(&mhdp->hdcp.prop_work); 542*6a3608eaSParshuram Thombare schedule_delayed_work(&mhdp->hdcp.check_work, 543*6a3608eaSParshuram Thombare DRM_HDCP_CHECK_PERIOD_MS); 544*6a3608eaSParshuram Thombare out: 545*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->hdcp.mutex); 546*6a3608eaSParshuram Thombare return ret; 547*6a3608eaSParshuram Thombare } 548*6a3608eaSParshuram Thombare 549*6a3608eaSParshuram Thombare int cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) 550*6a3608eaSParshuram Thombare { 551*6a3608eaSParshuram Thombare int ret = 0; 552*6a3608eaSParshuram Thombare 553*6a3608eaSParshuram Thombare mutex_lock(&mhdp->hdcp.mutex); 554*6a3608eaSParshuram Thombare if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { 555*6a3608eaSParshuram Thombare mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; 556*6a3608eaSParshuram Thombare schedule_work(&mhdp->hdcp.prop_work); 557*6a3608eaSParshuram Thombare ret = _cdns_mhdp_hdcp_disable(mhdp); 558*6a3608eaSParshuram Thombare } 559*6a3608eaSParshuram Thombare mutex_unlock(&mhdp->hdcp.mutex); 560*6a3608eaSParshuram Thombare cancel_delayed_work_sync(&mhdp->hdcp.check_work); 561*6a3608eaSParshuram Thombare 562*6a3608eaSParshuram Thombare return ret; 563*6a3608eaSParshuram Thombare } 564*6a3608eaSParshuram Thombare 565*6a3608eaSParshuram Thombare void cdns_mhdp_hdcp_init(struct cdns_mhdp_device *mhdp) 566*6a3608eaSParshuram Thombare { 567*6a3608eaSParshuram Thombare INIT_DELAYED_WORK(&mhdp->hdcp.check_work, cdns_mhdp_hdcp_check_work); 568*6a3608eaSParshuram Thombare INIT_WORK(&mhdp->hdcp.prop_work, cdns_mhdp_hdcp_prop_work); 569*6a3608eaSParshuram Thombare mutex_init(&mhdp->hdcp.mutex); 570*6a3608eaSParshuram Thombare } 571