162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cadence MHDP8546 DP bridge driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020 Cadence Design Systems, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/io.h>
1062306a36Sopenharmony_ci#include <linux/iopoll.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <asm/unaligned.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <drm/display/drm_hdcp_helper.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "cdns-mhdp8546-hdcp.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic int cdns_mhdp_secure_mailbox_read(struct cdns_mhdp_device *mhdp)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	int ret, empty;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_EMPTY,
2562306a36Sopenharmony_ci				 empty, !empty, MAILBOX_RETRY_US,
2662306a36Sopenharmony_ci				 MAILBOX_TIMEOUT_US);
2762306a36Sopenharmony_ci	if (ret < 0)
2862306a36Sopenharmony_ci		return ret;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	return readl(mhdp->sapb_regs + CDNS_MAILBOX_RX_DATA) & 0xff;
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic int cdns_mhdp_secure_mailbox_write(struct cdns_mhdp_device *mhdp,
3462306a36Sopenharmony_ci					  u8 val)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	int ret, full;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_FULL,
4162306a36Sopenharmony_ci				 full, !full, MAILBOX_RETRY_US,
4262306a36Sopenharmony_ci				 MAILBOX_TIMEOUT_US);
4362306a36Sopenharmony_ci	if (ret < 0)
4462306a36Sopenharmony_ci		return ret;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	writel(val, mhdp->sapb_regs + CDNS_MAILBOX_TX_DATA);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return 0;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int cdns_mhdp_secure_mailbox_recv_header(struct cdns_mhdp_device *mhdp,
5262306a36Sopenharmony_ci						u8 module_id,
5362306a36Sopenharmony_ci						u8 opcode,
5462306a36Sopenharmony_ci						u16 req_size)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	u32 mbox_size, i;
5762306a36Sopenharmony_ci	u8 header[4];
5862306a36Sopenharmony_ci	int ret;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* read the header of the message */
6162306a36Sopenharmony_ci	for (i = 0; i < sizeof(header); i++) {
6262306a36Sopenharmony_ci		ret = cdns_mhdp_secure_mailbox_read(mhdp);
6362306a36Sopenharmony_ci		if (ret < 0)
6462306a36Sopenharmony_ci			return ret;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci		header[i] = ret;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	mbox_size = get_unaligned_be16(header + 2);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (opcode != header[0] || module_id != header[1] ||
7262306a36Sopenharmony_ci	    (opcode != HDCP_TRAN_IS_REC_ID_VALID && req_size != mbox_size)) {
7362306a36Sopenharmony_ci		for (i = 0; i < mbox_size; i++)
7462306a36Sopenharmony_ci			if (cdns_mhdp_secure_mailbox_read(mhdp) < 0)
7562306a36Sopenharmony_ci				break;
7662306a36Sopenharmony_ci		return -EINVAL;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return 0;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int cdns_mhdp_secure_mailbox_recv_data(struct cdns_mhdp_device *mhdp,
8362306a36Sopenharmony_ci					      u8 *buff, u16 buff_size)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	int ret;
8662306a36Sopenharmony_ci	u32 i;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	for (i = 0; i < buff_size; i++) {
8962306a36Sopenharmony_ci		ret = cdns_mhdp_secure_mailbox_read(mhdp);
9062306a36Sopenharmony_ci		if (ret < 0)
9162306a36Sopenharmony_ci			return ret;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		buff[i] = ret;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return 0;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_device *mhdp,
10062306a36Sopenharmony_ci					 u8 module_id,
10162306a36Sopenharmony_ci					 u8 opcode,
10262306a36Sopenharmony_ci					 u16 size,
10362306a36Sopenharmony_ci					 u8 *message)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	u8 header[4];
10662306a36Sopenharmony_ci	int ret;
10762306a36Sopenharmony_ci	u32 i;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	header[0] = opcode;
11062306a36Sopenharmony_ci	header[1] = module_id;
11162306a36Sopenharmony_ci	put_unaligned_be16(size, header + 2);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	for (i = 0; i < sizeof(header); i++) {
11462306a36Sopenharmony_ci		ret = cdns_mhdp_secure_mailbox_write(mhdp, header[i]);
11562306a36Sopenharmony_ci		if (ret)
11662306a36Sopenharmony_ci			return ret;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
12062306a36Sopenharmony_ci		ret = cdns_mhdp_secure_mailbox_write(mhdp, message[i]);
12162306a36Sopenharmony_ci		if (ret)
12262306a36Sopenharmony_ci			return ret;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_get_status(struct cdns_mhdp_device *mhdp,
12962306a36Sopenharmony_ci				     u16 *hdcp_port_status)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	u8 hdcp_status[HDCP_STATUS_SIZE];
13262306a36Sopenharmony_ci	int ret;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	mutex_lock(&mhdp->mbox_mutex);
13562306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
13662306a36Sopenharmony_ci					    HDCP_TRAN_STATUS_CHANGE, 0, NULL);
13762306a36Sopenharmony_ci	if (ret)
13862306a36Sopenharmony_ci		goto err_get_hdcp_status;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX,
14162306a36Sopenharmony_ci						   HDCP_TRAN_STATUS_CHANGE,
14262306a36Sopenharmony_ci						   sizeof(hdcp_status));
14362306a36Sopenharmony_ci	if (ret)
14462306a36Sopenharmony_ci		goto err_get_hdcp_status;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_status,
14762306a36Sopenharmony_ci						 sizeof(hdcp_status));
14862306a36Sopenharmony_ci	if (ret)
14962306a36Sopenharmony_ci		goto err_get_hdcp_status;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	*hdcp_port_status = ((u16)(hdcp_status[0] << 8) | hdcp_status[1]);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cierr_get_hdcp_status:
15462306a36Sopenharmony_ci	mutex_unlock(&mhdp->mbox_mutex);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return ret;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic u8 cdns_mhdp_hdcp_handle_status(struct cdns_mhdp_device *mhdp,
16062306a36Sopenharmony_ci				       u16 status)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	u8 err = GET_HDCP_PORT_STS_LAST_ERR(status);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (err)
16562306a36Sopenharmony_ci		dev_dbg(mhdp->dev, "HDCP Error = %d", err);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return err;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_rx_id_valid_response(struct cdns_mhdp_device *mhdp,
17162306a36Sopenharmony_ci					       u8 valid)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int ret;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	mutex_lock(&mhdp->mbox_mutex);
17662306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
17762306a36Sopenharmony_ci					    HDCP_TRAN_RESPOND_RECEIVER_ID_VALID,
17862306a36Sopenharmony_ci					    1, &valid);
17962306a36Sopenharmony_ci	mutex_unlock(&mhdp->mbox_mutex);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return ret;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_rx_id_valid(struct cdns_mhdp_device *mhdp,
18562306a36Sopenharmony_ci				      u8 *recv_num, u8 *hdcp_rx_id)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	u8 rec_id_hdr[2];
18862306a36Sopenharmony_ci	u8 status;
18962306a36Sopenharmony_ci	int ret;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	mutex_lock(&mhdp->mbox_mutex);
19262306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
19362306a36Sopenharmony_ci					    HDCP_TRAN_IS_REC_ID_VALID, 0, NULL);
19462306a36Sopenharmony_ci	if (ret)
19562306a36Sopenharmony_ci		goto err_rx_id_valid;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX,
19862306a36Sopenharmony_ci						   HDCP_TRAN_IS_REC_ID_VALID,
19962306a36Sopenharmony_ci						   sizeof(status));
20062306a36Sopenharmony_ci	if (ret)
20162306a36Sopenharmony_ci		goto err_rx_id_valid;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, rec_id_hdr, 2);
20462306a36Sopenharmony_ci	if (ret)
20562306a36Sopenharmony_ci		goto err_rx_id_valid;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	*recv_num = rec_id_hdr[0];
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_rx_id, 5 * *recv_num);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cierr_rx_id_valid:
21262306a36Sopenharmony_ci	mutex_unlock(&mhdp->mbox_mutex);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	return ret;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_km_stored_resp(struct cdns_mhdp_device *mhdp,
21862306a36Sopenharmony_ci					 u32 size, u8 *km)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	int ret;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	mutex_lock(&mhdp->mbox_mutex);
22362306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
22462306a36Sopenharmony_ci					    HDCP2X_TX_RESPOND_KM, size, km);
22562306a36Sopenharmony_ci	mutex_unlock(&mhdp->mbox_mutex);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return ret;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_tx_is_km_stored(struct cdns_mhdp_device *mhdp,
23162306a36Sopenharmony_ci					  u8 *resp, u32 size)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	int ret;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	mutex_lock(&mhdp->mbox_mutex);
23662306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
23762306a36Sopenharmony_ci					    HDCP2X_TX_IS_KM_STORED, 0, NULL);
23862306a36Sopenharmony_ci	if (ret)
23962306a36Sopenharmony_ci		goto err_is_km_stored;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX,
24262306a36Sopenharmony_ci						   HDCP2X_TX_IS_KM_STORED,
24362306a36Sopenharmony_ci						   size);
24462306a36Sopenharmony_ci	if (ret)
24562306a36Sopenharmony_ci		goto err_is_km_stored;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, resp, size);
24862306a36Sopenharmony_cierr_is_km_stored:
24962306a36Sopenharmony_ci	mutex_unlock(&mhdp->mbox_mutex);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return ret;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_tx_config(struct cdns_mhdp_device *mhdp,
25562306a36Sopenharmony_ci				    u8 hdcp_cfg)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	int ret;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	mutex_lock(&mhdp->mbox_mutex);
26062306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
26162306a36Sopenharmony_ci					    HDCP_TRAN_CONFIGURATION, 1, &hdcp_cfg);
26262306a36Sopenharmony_ci	mutex_unlock(&mhdp->mbox_mutex);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return ret;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_set_config(struct cdns_mhdp_device *mhdp,
26862306a36Sopenharmony_ci				     u8 hdcp_config, bool enable)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	u16 hdcp_port_status;
27162306a36Sopenharmony_ci	u32 ret_event;
27262306a36Sopenharmony_ci	u8 hdcp_cfg;
27362306a36Sopenharmony_ci	int ret;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	hdcp_cfg = hdcp_config | (enable ? 0x04 : 0) |
27662306a36Sopenharmony_ci		   (HDCP_CONTENT_TYPE_0 << 3);
27762306a36Sopenharmony_ci	cdns_mhdp_hdcp_tx_config(mhdp, hdcp_cfg);
27862306a36Sopenharmony_ci	ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS);
27962306a36Sopenharmony_ci	if (!ret_event)
28062306a36Sopenharmony_ci		return -1;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status);
28362306a36Sopenharmony_ci	if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status))
28462306a36Sopenharmony_ci		return -1;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return 0;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_auth_check(struct cdns_mhdp_device *mhdp)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	u16 hdcp_port_status;
29262306a36Sopenharmony_ci	u32 ret_event;
29362306a36Sopenharmony_ci	int ret;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS);
29662306a36Sopenharmony_ci	if (!ret_event)
29762306a36Sopenharmony_ci		return -1;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status);
30062306a36Sopenharmony_ci	if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status))
30162306a36Sopenharmony_ci		return -1;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (hdcp_port_status & 1) {
30462306a36Sopenharmony_ci		dev_dbg(mhdp->dev, "Authentication completed successfully!\n");
30562306a36Sopenharmony_ci		return 0;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	dev_dbg(mhdp->dev, "Authentication failed\n");
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return -1;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_check_receviers(struct cdns_mhdp_device *mhdp)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	u8 hdcp_rec_id[HDCP_MAX_RECEIVERS][HDCP_RECEIVER_ID_SIZE_BYTES];
31662306a36Sopenharmony_ci	u8 hdcp_num_rec;
31762306a36Sopenharmony_ci	u32 ret_event;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	ret_event = cdns_mhdp_wait_for_sw_event(mhdp,
32062306a36Sopenharmony_ci						CDNS_HDCP_TX_IS_RCVR_ID_VALID);
32162306a36Sopenharmony_ci	if (!ret_event)
32262306a36Sopenharmony_ci		return -1;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	hdcp_num_rec = 0;
32562306a36Sopenharmony_ci	memset(&hdcp_rec_id, 0, sizeof(hdcp_rec_id));
32662306a36Sopenharmony_ci	cdns_mhdp_hdcp_rx_id_valid(mhdp, &hdcp_num_rec, (u8 *)hdcp_rec_id);
32762306a36Sopenharmony_ci	cdns_mhdp_hdcp_rx_id_valid_response(mhdp, 1);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return 0;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_auth_22(struct cdns_mhdp_device *mhdp)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	u8 resp[HDCP_STATUS_SIZE];
33562306a36Sopenharmony_ci	u16 hdcp_port_status;
33662306a36Sopenharmony_ci	u32 ret_event;
33762306a36Sopenharmony_ci	int ret;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	dev_dbg(mhdp->dev, "HDCP: Start 2.2 Authentication\n");
34062306a36Sopenharmony_ci	ret_event = cdns_mhdp_wait_for_sw_event(mhdp,
34162306a36Sopenharmony_ci						CDNS_HDCP2_TX_IS_KM_STORED);
34262306a36Sopenharmony_ci	if (!ret_event)
34362306a36Sopenharmony_ci		return -1;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (ret_event & CDNS_HDCP_TX_STATUS) {
34662306a36Sopenharmony_ci		mhdp->sw_events &= ~CDNS_HDCP_TX_STATUS;
34762306a36Sopenharmony_ci		ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status);
34862306a36Sopenharmony_ci		if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status))
34962306a36Sopenharmony_ci			return -1;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	cdns_mhdp_hdcp_tx_is_km_stored(mhdp, resp, sizeof(resp));
35362306a36Sopenharmony_ci	cdns_mhdp_hdcp_km_stored_resp(mhdp, 0, NULL);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (cdns_mhdp_hdcp_check_receviers(mhdp))
35662306a36Sopenharmony_ci		return -1;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return 0;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic inline int cdns_mhdp_hdcp_auth_14(struct cdns_mhdp_device *mhdp)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	dev_dbg(mhdp->dev, "HDCP: Starting 1.4 Authentication\n");
36462306a36Sopenharmony_ci	return cdns_mhdp_hdcp_check_receviers(mhdp);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_auth(struct cdns_mhdp_device *mhdp,
36862306a36Sopenharmony_ci			       u8 hdcp_config)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	int ret;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	ret = cdns_mhdp_hdcp_set_config(mhdp, hdcp_config, true);
37362306a36Sopenharmony_ci	if (ret)
37462306a36Sopenharmony_ci		goto auth_failed;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (hdcp_config == HDCP_TX_1)
37762306a36Sopenharmony_ci		ret = cdns_mhdp_hdcp_auth_14(mhdp);
37862306a36Sopenharmony_ci	else
37962306a36Sopenharmony_ci		ret = cdns_mhdp_hdcp_auth_22(mhdp);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if (ret)
38262306a36Sopenharmony_ci		goto auth_failed;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	ret = cdns_mhdp_hdcp_auth_check(mhdp);
38562306a36Sopenharmony_ci	if (ret)
38662306a36Sopenharmony_ci		ret = cdns_mhdp_hdcp_auth_check(mhdp);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ciauth_failed:
38962306a36Sopenharmony_ci	return ret;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	int ret;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n",
39762306a36Sopenharmony_ci		mhdp->connector.name, mhdp->connector.base.id);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	return ret;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic int _cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	int ret = -EINVAL;
40762306a36Sopenharmony_ci	int tries = 3;
40862306a36Sopenharmony_ci	u32 i;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	for (i = 0; i < tries; i++) {
41162306a36Sopenharmony_ci		if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0 ||
41262306a36Sopenharmony_ci		    content_type == DRM_MODE_HDCP_CONTENT_TYPE1) {
41362306a36Sopenharmony_ci			ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_2);
41462306a36Sopenharmony_ci			if (!ret)
41562306a36Sopenharmony_ci				return 0;
41662306a36Sopenharmony_ci			_cdns_mhdp_hdcp_disable(mhdp);
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) {
42062306a36Sopenharmony_ci			ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_1);
42162306a36Sopenharmony_ci			if (!ret)
42262306a36Sopenharmony_ci				return 0;
42362306a36Sopenharmony_ci			_cdns_mhdp_hdcp_disable(mhdp);
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	dev_err(mhdp->dev, "HDCP authentication failed (%d tries/%d)\n",
42862306a36Sopenharmony_ci		tries, ret);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	return ret;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	u16 hdcp_port_status;
43662306a36Sopenharmony_ci	int ret = 0;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	mutex_lock(&mhdp->hdcp.mutex);
43962306a36Sopenharmony_ci	if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
44062306a36Sopenharmony_ci		goto out;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status);
44362306a36Sopenharmony_ci	if (!ret && hdcp_port_status & HDCP_PORT_STS_AUTH)
44462306a36Sopenharmony_ci		goto out;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	dev_err(mhdp->dev,
44762306a36Sopenharmony_ci		"[%s:%d] HDCP link failed, retrying authentication\n",
44862306a36Sopenharmony_ci		mhdp->connector.name, mhdp->connector.base.id);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	ret = _cdns_mhdp_hdcp_disable(mhdp);
45162306a36Sopenharmony_ci	if (ret) {
45262306a36Sopenharmony_ci		mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
45362306a36Sopenharmony_ci		schedule_work(&mhdp->hdcp.prop_work);
45462306a36Sopenharmony_ci		goto out;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	ret = _cdns_mhdp_hdcp_enable(mhdp, mhdp->hdcp.hdcp_content_type);
45862306a36Sopenharmony_ci	if (ret) {
45962306a36Sopenharmony_ci		mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
46062306a36Sopenharmony_ci		schedule_work(&mhdp->hdcp.prop_work);
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ciout:
46362306a36Sopenharmony_ci	mutex_unlock(&mhdp->hdcp.mutex);
46462306a36Sopenharmony_ci	return ret;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void cdns_mhdp_hdcp_check_work(struct work_struct *work)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct delayed_work *d_work = to_delayed_work(work);
47062306a36Sopenharmony_ci	struct cdns_mhdp_hdcp *hdcp = container_of(d_work,
47162306a36Sopenharmony_ci						   struct cdns_mhdp_hdcp,
47262306a36Sopenharmony_ci						   check_work);
47362306a36Sopenharmony_ci	struct cdns_mhdp_device *mhdp = container_of(hdcp,
47462306a36Sopenharmony_ci						     struct cdns_mhdp_device,
47562306a36Sopenharmony_ci						     hdcp);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (!cdns_mhdp_hdcp_check_link(mhdp))
47862306a36Sopenharmony_ci		schedule_delayed_work(&hdcp->check_work,
47962306a36Sopenharmony_ci				      DRM_HDCP_CHECK_PERIOD_MS);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic void cdns_mhdp_hdcp_prop_work(struct work_struct *work)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct cdns_mhdp_hdcp *hdcp = container_of(work,
48562306a36Sopenharmony_ci						   struct cdns_mhdp_hdcp,
48662306a36Sopenharmony_ci						   prop_work);
48762306a36Sopenharmony_ci	struct cdns_mhdp_device *mhdp = container_of(hdcp,
48862306a36Sopenharmony_ci						     struct cdns_mhdp_device,
48962306a36Sopenharmony_ci						     hdcp);
49062306a36Sopenharmony_ci	struct drm_device *dev = mhdp->connector.dev;
49162306a36Sopenharmony_ci	struct drm_connector_state *state;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
49462306a36Sopenharmony_ci	mutex_lock(&mhdp->hdcp.mutex);
49562306a36Sopenharmony_ci	if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
49662306a36Sopenharmony_ci		state = mhdp->connector.state;
49762306a36Sopenharmony_ci		state->content_protection = mhdp->hdcp.value;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci	mutex_unlock(&mhdp->hdcp.mutex);
50062306a36Sopenharmony_ci	drm_modeset_unlock(&dev->mode_config.connection_mutex);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ciint cdns_mhdp_hdcp_set_lc(struct cdns_mhdp_device *mhdp, u8 *val)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	int ret;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	mutex_lock(&mhdp->mbox_mutex);
50862306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_GENERAL,
50962306a36Sopenharmony_ci					    HDCP_GENERAL_SET_LC_128,
51062306a36Sopenharmony_ci					    16, val);
51162306a36Sopenharmony_ci	mutex_unlock(&mhdp->mbox_mutex);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	return ret;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ciint
51762306a36Sopenharmony_cicdns_mhdp_hdcp_set_public_key_param(struct cdns_mhdp_device *mhdp,
51862306a36Sopenharmony_ci				    struct cdns_hdcp_tx_public_key_param *val)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	int ret;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	mutex_lock(&mhdp->mbox_mutex);
52362306a36Sopenharmony_ci	ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX,
52462306a36Sopenharmony_ci					    HDCP2X_TX_SET_PUBLIC_KEY_PARAMS,
52562306a36Sopenharmony_ci					    sizeof(*val), (u8 *)val);
52662306a36Sopenharmony_ci	mutex_unlock(&mhdp->mbox_mutex);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return ret;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ciint cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	int ret;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	mutex_lock(&mhdp->hdcp.mutex);
53662306a36Sopenharmony_ci	ret = _cdns_mhdp_hdcp_enable(mhdp, content_type);
53762306a36Sopenharmony_ci	if (ret)
53862306a36Sopenharmony_ci		goto out;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	mhdp->hdcp.hdcp_content_type = content_type;
54162306a36Sopenharmony_ci	mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
54262306a36Sopenharmony_ci	schedule_work(&mhdp->hdcp.prop_work);
54362306a36Sopenharmony_ci	schedule_delayed_work(&mhdp->hdcp.check_work,
54462306a36Sopenharmony_ci			      DRM_HDCP_CHECK_PERIOD_MS);
54562306a36Sopenharmony_ciout:
54662306a36Sopenharmony_ci	mutex_unlock(&mhdp->hdcp.mutex);
54762306a36Sopenharmony_ci	return ret;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ciint cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	int ret = 0;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	mutex_lock(&mhdp->hdcp.mutex);
55562306a36Sopenharmony_ci	if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
55662306a36Sopenharmony_ci		mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
55762306a36Sopenharmony_ci		schedule_work(&mhdp->hdcp.prop_work);
55862306a36Sopenharmony_ci		ret = _cdns_mhdp_hdcp_disable(mhdp);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci	mutex_unlock(&mhdp->hdcp.mutex);
56162306a36Sopenharmony_ci	cancel_delayed_work_sync(&mhdp->hdcp.check_work);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return ret;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_civoid cdns_mhdp_hdcp_init(struct cdns_mhdp_device *mhdp)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	INIT_DELAYED_WORK(&mhdp->hdcp.check_work, cdns_mhdp_hdcp_check_work);
56962306a36Sopenharmony_ci	INIT_WORK(&mhdp->hdcp.prop_work, cdns_mhdp_hdcp_prop_work);
57062306a36Sopenharmony_ci	mutex_init(&mhdp->hdcp.mutex);
57162306a36Sopenharmony_ci}
572