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