brintos

brintos / linux-shallow public Read only

0
0
Text · 13.1 KiB · 31832ba Raw
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