diff mbox series

[v2,1/3] Subject: [PATCH] drm/mediatek/dp: Add tee client application for HDCP feature

Message ID 20240205055055.25340-2-mac.shen@mediatek.com (mailing list archive)
State New, archived
Headers show
Series Add HDCP feature for DisplayPort | expand

Commit Message

mac.shen Feb. 5, 2024, 5:50 a.m. UTC
Add tee client application which will be used for
HDCP 1.x and 2.x authentication in DisplayPort.

Changes in v2:
- remove ca folder, and change file name with lower case
- refine the tci_t structure to make the data to tee can
  through this structure
- remove aux and regs from mtk_hdcp_info structure
- remove some definitions, and use the definitions in
  include/drm/drm_hdcp.h
- remove useless code
per suggestion from the previous thread:
https://lore.kernel.org/all/8fff59b5567449d8201dd1138c8fa
9218a545c46.camel@mediatek.com/

Signed-off-by: mac.shen <mac.shen@mediatek.com>
---
 drivers/gpu/drm/mediatek/Makefile      |   5 +-
 drivers/gpu/drm/mediatek/tci.h         | 156 +++++++
 drivers/gpu/drm/mediatek/tlc_dp_hdcp.c | 598 +++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/tlc_dp_hdcp.h | 414 +++++++++++++++++
 4 files changed, 1172 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/mediatek/tci.h
 create mode 100644 drivers/gpu/drm/mediatek/tlc_dp_hdcp.c
 create mode 100644 drivers/gpu/drm/mediatek/tlc_dp_hdcp.h

Comments

kernel test robot Feb. 5, 2024, 4:17 p.m. UTC | #1
Hi mac.shen,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on pza/reset/next linus/master v6.8-rc3 next-20240205]
[cannot apply to pza/imx-drm/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/mac-shen/Subject-PATCH-drm-mediatek-dp-Add-tee-client-application-for-HDCP-feature/20240205-163727
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20240205055055.25340-2-mac.shen%40mediatek.com
patch subject: [PATCH v2 1/3] Subject: [PATCH] drm/mediatek/dp: Add tee client application for HDCP feature
config: arm64-defconfig (https://download.01.org/0day-ci/archive/20240205/202402052342.Y5awT1T2-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240205/202402052342.Y5awT1T2-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202402052342.Y5awT1T2-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/gpu/drm/mediatek/tlc_dp_hdcp.c:34: warning: Function parameter or struct member 'dp_tee_priv' not described in 'dp_tee_op_send'
>> drivers/gpu/drm/mediatek/tlc_dp_hdcp.c:34: warning: Function parameter or struct member 'cmd_id' not described in 'dp_tee_op_send'


vim +34 drivers/gpu/drm/mediatek/tlc_dp_hdcp.c

    13	
    14	/*
    15	 * TA_FTPM_UUID: 99975014-3c7c-54ea-8487-a80d215ea92c
    16	 *
    17	 * Randomly generated, and must correspond to the GUID on the TA side.
    18	 * Defined here in the reference implementation:
    19	 * https://github.com/microsoft/ms-tpm-20-ref/blob/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM/include/fTPM.h#L42
    20	 */
    21	static const uuid_t dp_ta_uuid =
    22		UUID_INIT(0x99975014, 0x3c7c, 0x54ea,
    23			  0x84, 0x87, 0xa8, 0x0d, 0x21, 0x5e, 0xa9, 0x2c);
    24	
    25	/**
    26	 * dp_tee_op_send() - send dp commands through the TEE shared memory.
    27	 * @len:	the number of bytes to send.
    28	 *
    29	 * Return:
    30	 *	In case of success, returns 0.
    31	 *	On failure, -errno
    32	 */
    33	static int dp_tee_op_send(struct dp_tee_private *dp_tee_priv, size_t len, u32 cmd_id)
  > 34	{
    35		int rc;
    36		u8 *temp_buf;
    37		struct tee_ioctl_invoke_arg transceive_args;
    38		struct tee_param command_params[4];
    39		struct tee_shm *shm = dp_tee_priv->shm;
    40	
    41		if (len > MAX_COMMAND_SIZE) {
    42			TLCERR("%s: len=%zd exceeds MAX_COMMAND_SIZE supported by dp TA\n", __func__, len);
    43			return -EIO;
    44		}
    45	
    46		memset(&transceive_args, 0, sizeof(transceive_args));
    47		memset(command_params, 0, sizeof(command_params));
    48		dp_tee_priv->resp_len = 0;
    49	
    50		/* Invoke FTPM_OPTEE_TA_SUBMIT_COMMAND function of dp TA */
    51		transceive_args = (struct tee_ioctl_invoke_arg) {
    52			.func = cmd_id,
    53			.session = dp_tee_priv->session,
    54			.num_params = 4,
    55		};
    56	
    57		/* Fill FTPM_OPTEE_TA_SUBMIT_COMMAND parameters */
    58		command_params[0] = (struct tee_param) {
    59			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
    60			.u.memref = {
    61				.shm = shm,
    62				.size = len,
    63				.shm_offs = 0,
    64			},
    65		};
    66	
    67		command_params[1] = (struct tee_param) {
    68			.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
    69			.u.memref = {
    70				.shm = shm,
    71				.size = MAX_RESPONSE_SIZE,
    72				.shm_offs = MAX_COMMAND_SIZE,
    73			},
    74		};
    75	
    76		rc = tee_client_invoke_func(dp_tee_priv->ctx, &transceive_args, command_params);
    77		if (rc < 0 || transceive_args.ret != 0) {
    78			TLCERR("%s: invoke error: 0x%x\n", __func__, transceive_args.ret);
    79			return (rc < 0) ? rc : transceive_args.ret;
    80		}
    81	
    82		temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs);
    83		if (IS_ERR(temp_buf)) {
    84			TLCERR("%s: tee_shm_get_va failed for receive\n", __func__);
    85			return PTR_ERR(temp_buf);
    86		}
    87	
    88		/* Sanity checks look good, cache the response */
    89		memcpy(dp_tee_priv->resp_buf, temp_buf, MAX_RESPONSE_SIZE / 2);
    90		dp_tee_priv->resp_len = MAX_RESPONSE_SIZE / 2;
    91	
    92		return 0;
    93	}
    94
AngeloGioacchino Del Regno Feb. 6, 2024, 3:34 p.m. UTC | #2
Il 05/02/24 06:50, mac.shen ha scritto:
> Add tee client application which will be used for
> HDCP 1.x and 2.x authentication in DisplayPort.
> 
> Changes in v2:
> - remove ca folder, and change file name with lower case
> - refine the tci_t structure to make the data to tee can
>    through this structure
> - remove aux and regs from mtk_hdcp_info structure
> - remove some definitions, and use the definitions in
>    include/drm/drm_hdcp.h
> - remove useless code
> per suggestion from the previous thread:
> https://lore.kernel.org/all/8fff59b5567449d8201dd1138c8fa
> 9218a545c46.camel@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---
>   drivers/gpu/drm/mediatek/Makefile      |   5 +-
>   drivers/gpu/drm/mediatek/tci.h         | 156 +++++++
>   drivers/gpu/drm/mediatek/tlc_dp_hdcp.c | 598 +++++++++++++++++++++++++
>   drivers/gpu/drm/mediatek/tlc_dp_hdcp.h | 414 +++++++++++++++++
>   4 files changed, 1172 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/mediatek/tci.h
>   create mode 100644 drivers/gpu/drm/mediatek/tlc_dp_hdcp.c
>   create mode 100644 drivers/gpu/drm/mediatek/tlc_dp_hdcp.h
> 
> diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
> index d4d193f60271..c80e6c2f9336 100644
> --- a/drivers/gpu/drm/mediatek/Makefile
> +++ b/drivers/gpu/drm/mediatek/Makefile
> @@ -26,4 +26,7 @@ mediatek-drm-hdmi-objs := mtk_cec.o \
>   
>   obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
>   
> -obj-$(CONFIG_DRM_MEDIATEK_DP) += mtk_dp.o
> +mtk-dp-objs := tlc_dp_hdcp.o \
> +		  mtk_dp.o
> +
> +obj-$(CONFIG_DRM_MEDIATEK_DP) += mtk-dp.o
> diff --git a/drivers/gpu/drm/mediatek/tci.h b/drivers/gpu/drm/mediatek/tci.h
> new file mode 100644
> index 000000000000..f2239ea3ffbf
> --- /dev/null
> +++ b/drivers/gpu/drm/mediatek/tci.h
> @@ -0,0 +1,156 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2019-2024 MediaTek Inc.
> + */
> +
> +#ifndef _TCI_H_
> +#define _TCI_H_
> +
> +#include <drm/display/drm_hdcp.h>
> +
> +#define CMD_DEVICE_ADDED        1
> +#define CMD_DEVICE_REMOVE       2
> +#define CMD_WRITE_VAL           3
> +#define CMD_DEVICE_CLEAN        4
> +#define CMD_ENABLE_ENCRYPT      5
> +
> +/* V1.3 */
> +#define CMD_CALCULATE_LM        11
> +#define CMD_COMPARE_R0          12
> +#define CMD_COMPARE_V1          13
> +#define CMD_GET_AKSV            14
> +
> +/* V2.2 */
> +#define CMD_AKE_CERTIFICATE     20
> +#define CMD_ENC_KM              21
> +#define CMD_AKE_H_PRIME         22
> +#define CMD_AKE_PARING          23
> +#define CMD_LC_L_PRIME          24
> +#define CMD_COMPARE_L           25
> +#define CMD_SKE_CAL_EKS         26
> +
> +#define CMD_COMPARE_V2          27
> +#define CMD_COMPARE_M           28
> +
> +/* Need remove in furture */
> +#define CMD_LOAD_KEY            50
> +
> +#define RET_COMPARE_PASS 0
> +#define RET_COMPARE_FAIL 1
> +#define RET_NEW_DEVICE 2
> +#define RET_STORED_DEVICE 3
> +
> +#define TYPE_HDCP_PARAM_AN 10
> +#define TYPE_HDCP_PARAM_RST_1 11
> +#define TYPE_HDCP_PARAM_RST_2 12
> +#define TYPE_HDCP_ENABLE_ENCRYPT 13
> +#define TYPE_HDCP_DISABLE_ENCRYPT 14
> +
> +#define TYPE_HDCP13_KEY 20
> +#define TYPE_HDCP22_KEY 21
> +
> +// reserved:2

Please, C-style comments only.

> +#define HDCP2_CERTRX_LEN (HDCP_2_2_RECEIVER_ID_LEN + HDCP_2_2_K_PUB_RX_LEN + \
> +	2 + HDCP_2_2_DCP_LLC_SIG_LEN)
> +// version:1
> +#define HDCP_2_2_TXCAPS_LEN (HDCP_2_2_TXCAP_MASK_LEN + 1)
> +#define PARAM_LEN 1024
> +
> +#define TCI_LENGTH sizeof(struct tci_t)
> +
> +struct cmd_hdcp_init_for_verion_t {
> +	u32 version;
> +	bool need_load_key;
> +};
> +
> +struct cmd_hdcp_write_val_t {
> +	u8 type;
> +	u8 len;
> +	u8 val[DRM_HDCP_AN_LEN];
> +};
> +
> +struct cmd_hdcp_calculate_lm_t {
> +	u8 bksv[DRM_HDCP_KSV_LEN];
> +};
> +
> +struct cmd_hdcp_get_aksv_t {
> +	u8 aksv[DRM_HDCP_KSV_LEN];
> +};
> +
> +struct cmd_hdcp_ake_certificate_t {
> +	u8 certification[HDCP2_CERTRX_LEN];
> +	bool stored;
> +	u8 m[HDCP_2_2_E_KH_KM_M_LEN - HDCP_2_2_E_KH_KM_LEN];
> +	u8 ekm[HDCP_2_2_E_KH_KM_LEN];
> +};
> +
> +struct cmd_hdcp_ake_paring_t {
> +	u8 ekm[HDCP_2_2_E_KH_KM_LEN];
> +};
> +
> +struct cmd_hdcp_enc_km_t {
> +	u8 enc_km[HDCP_2_2_E_KPUB_KM_LEN];
> +};
> +
> +struct cmd_hdcp_ake_h_prime_t {
> +	u8 rtx[HDCP_2_2_RTX_LEN];
> +	u8 rrx[HDCP_2_2_RRX_LEN];
> +	u8 rx_caps[HDCP_2_2_RXCAPS_LEN];
> +	u8 tx_caps[HDCP_2_2_TXCAPS_LEN];
> +	u32 rx_h_len;
> +	u8 rx_h[HDCP_2_2_H_PRIME_LEN];
> +};
> +
> +struct cmd_hdcp_lc_l_prime_t {
> +	u8 rn[HDCP_2_2_RN_LEN];
> +	u32 rx_l_len;
> +	u8 rx_l[HDCP_2_2_L_PRIME_LEN];
> +};
> +
> +struct cmd_hdcp_ske_eks_t {
> +	u8 riv[HDCP_2_2_RIV_LEN];
> +	u32 eks_len;
> +	u32 eks;
> +};
> +
> +struct cmd_hdcp_compare_t {
> +	u32 rx_val_len;
> +	u8 rx_val[HDCP_2_2_MPRIME_LEN];
> +	u32 param_len;
> +	u8 param[PARAM_LEN];
> +	u32 out_len;
> +	u32 out;
> +};
> +
> +union tci_cmd_body_t {
> +	/* Init with special HDCP version */
> +	struct cmd_hdcp_init_for_verion_t cmd_hdcp_init_for_verion;
> +	/* Write uint32 data to hw */
> +	struct cmd_hdcp_write_val_t cmd_hdcp_write_val;
> +	/* Get aksv */
> +	struct cmd_hdcp_get_aksv_t cmd_hdcp_get_aksv;
> +	/* Calculate r0 */
> +	struct cmd_hdcp_calculate_lm_t cmd_hdcp_calculate_lm;
> +	/* Generate signature for certificate */
> +	struct cmd_hdcp_ake_certificate_t cmd_hdcp_ake_certificate;
> +	/* To store ekm */
> +	struct cmd_hdcp_ake_paring_t cmd_hdcp_ake_paring;
> +	/* Encrypt km for V2.2 */
> +	struct cmd_hdcp_enc_km_t cmd_hdcp_enc_km;
> +	/* Compute H prime */
> +	struct cmd_hdcp_ake_h_prime_t cmd_hdcp_ake_h_prime;
> +	/* Compute L prime */
> +	struct cmd_hdcp_lc_l_prime_t cmd_hdcp_lc_l_prime;
> +	/* Compute eks */
> +	struct cmd_hdcp_ske_eks_t cmd_hdcp_ske_eks;
> +	/* Compare */
> +	struct cmd_hdcp_compare_t cmd_hdcp_compare;
> +} __packed;
> +
> +struct tci_t {
> +	u32 command_id;
> +	u32 return_code;
> +	union tci_cmd_body_t cmd_body;
> +};
> +
> +#endif /* _TCI_H_ */
> diff --git a/drivers/gpu/drm/mediatek/tlc_dp_hdcp.c b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.c
> new file mode 100644
> index 000000000000..147329324648
> --- /dev/null
> +++ b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.c
> @@ -0,0 +1,598 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2019-2024 MediaTek Inc.
> + */
> +
> +#include <linux/types.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +#include "tlc_dp_hdcp.h"
> +
> +#define DEFAULT_WRITE_VAL_LEN 1
> +#define DEFAULT_WRITE_VAL 0
> +
> +/*
> + * TA_FTPM_UUID: 99975014-3c7c-54ea-8487-a80d215ea92c
> + *
> + * Randomly generated, and must correspond to the GUID on the TA side.
> + * Defined here in the reference implementation:
> + * https://github.com/microsoft/ms-tpm-20-ref/blob/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM/include/fTPM.h#L42
> + */
> +static const uuid_t dp_ta_uuid =
> +	UUID_INIT(0x99975014, 0x3c7c, 0x54ea,
> +		  0x84, 0x87, 0xa8, 0x0d, 0x21, 0x5e, 0xa9, 0x2c);
> +
> +/**
> + * dp_tee_op_send() - send dp commands through the TEE shared memory.
> + * @len:	the number of bytes to send.
> + *
> + * Return:
> + *	In case of success, returns 0.
> + *	On failure, -errno

I think that's not what you want as final format, please check the documentation.

https://docs.kernel.org/doc-guide/kernel-doc.html#return-values

> + */
> +static int dp_tee_op_send(struct dp_tee_private *dp_tee_priv, size_t len, u32 cmd_id)
> +{
> +	int rc;
> +	u8 *temp_buf;
> +	struct tee_ioctl_invoke_arg transceive_args;
> +	struct tee_param command_params[4];
> +	struct tee_shm *shm = dp_tee_priv->shm;

Please reorder:

	struct tee_ioctl_invoke_arg transceive_args;
	struct tee_shm *shm = dp_tee_priv->shm;
	struct tee_param command_params[4];
	u8 *temp_buf;
	int rc;

> +
> +	if (len > MAX_COMMAND_SIZE) {
> +		TLCERR("%s: len=%zd exceeds MAX_COMMAND_SIZE supported by dp TA\n", __func__, len);
> +		return -EIO;
> +	}
> +
> +	memset(&transceive_args, 0, sizeof(transceive_args));
> +	memset(command_params, 0, sizeof(command_params));
> +	dp_tee_priv->resp_len = 0;
> +
> +	/* Invoke FTPM_OPTEE_TA_SUBMIT_COMMAND function of dp TA */
> +	transceive_args = (struct tee_ioctl_invoke_arg) {
> +		.func = cmd_id,
> +		.session = dp_tee_priv->session,
> +		.num_params = 4,
> +	};
> +
> +	/* Fill FTPM_OPTEE_TA_SUBMIT_COMMAND parameters */
> +	command_params[0] = (struct tee_param) {
> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
> +		.u.memref = {
> +			.shm = shm,
> +			.size = len,
> +			.shm_offs = 0,
> +		},
> +	};
> +
> +	command_params[1] = (struct tee_param) {
> +		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
> +		.u.memref = {
> +			.shm = shm,
> +			.size = MAX_RESPONSE_SIZE,
> +			.shm_offs = MAX_COMMAND_SIZE,
> +		},
> +	};
> +
> +	rc = tee_client_invoke_func(dp_tee_priv->ctx, &transceive_args, command_params);
> +	if (rc < 0 || transceive_args.ret != 0) {
> +		TLCERR("%s: invoke error: 0x%x\n", __func__, transceive_args.ret);
> +		return (rc < 0) ? rc : transceive_args.ret;
> +	}
> +
> +	temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs);
> +	if (IS_ERR(temp_buf)) {
> +		TLCERR("%s: tee_shm_get_va failed for receive\n", __func__);
> +		return PTR_ERR(temp_buf);
> +	}
> +
> +	/* Sanity checks look good, cache the response */
> +	memcpy(dp_tee_priv->resp_buf, temp_buf, MAX_RESPONSE_SIZE / 2);
> +	dp_tee_priv->resp_len = MAX_RESPONSE_SIZE / 2;
> +
> +	return 0;
> +}
> +
> +/*
> + * Check whether this driver supports the dp TA in the TEE instance
> + * represented by the params (ver/data) to this function.
> + */
> +static int dp_tee_match(struct tee_ioctl_version_data *ver, const void *data)
> +{
> +	/*
> +	 * Currently this driver only support GP Complaint OPTEE based dp TA
> +	 */
> +	if (ver->impl_id == TEE_IMPL_ID_OPTEE && ver->gen_caps & TEE_GEN_CAP_GP)
> +		return 1;
> +	else
> +		return 0;

/*
  * Check whether this driver supports the dp TA in the TEE instance
  * represented by the params (ver/data) to this function.
  *
  * Note that currently this driver only supports GP Compliant OPTEE
  * based dp TA.
  */
static int dp_tee_match(struct tee_ioctl_version_data *ver, const void *data)
{
	return ver->impl_id == TEE_IMPL_ID_OPTEE &&
	       ver->gen_caps & TEE_GEN_CAP_GP
}

That's shorter :-)

> +}
> +
> +int tee_add_device(struct mtk_hdcp_info *hdcp_info, u32 version)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = NULL;

You don't need this NULL assignment...

> +	struct tee_ioctl_open_session_arg sess_arg;
> +	struct tci_t *tci;

	struct tee_ioctl_open_session_arg sess_arg;
	struct dp_tee_private *dp_tee_priv;
	struct tci_t *tci;
	int rc;


> +
> +	if (hdcp_info->g_init)
> +		tee_remove_device(hdcp_info);
> +
> +	dp_tee_priv = kzalloc(sizeof(*dp_tee_priv), GFP_KERNEL);
> +	if (!dp_tee_priv) {
> +		kfree(dp_tee_priv);

There's no need to kfree something that couldn't be allocated.

> +		TLCERR("%s: tee_alloc_memory failed\n", __func__);
> +		return -ENOMEM;
> +	}
> +	hdcp_info->g_dp_tee_priv = dp_tee_priv;
> +
> +	/* Open context with TEE driver */
> +	dp_tee_priv->ctx = tee_client_open_context(NULL, dp_tee_match, NULL, NULL);
> +	if (IS_ERR(dp_tee_priv->ctx)) {

		/* We return -EPROBE_DEFER because ... why?!
		 * does it even make any sense to override this
		 * return value? I don't think so.
		 */
		if (PTR_ERR(dp_tee_priv->ctx) == -ENOENT)
			rc = -EPROBE_DEFER;
		else
			rc = PTR_ERR(dp_tee_priv->ctx);

		goto free_priv;
	}

> +		if (PTR_ERR(dp_tee_priv->ctx) == -ENOENT) {
> +			kfree(dp_tee_priv);
> +			return -EPROBE_DEFER;
> +		}
> +		kfree(dp_tee_priv);
> +		TLCERR("%s: tee_client_open_context failed\n", __func__);
> +		return PTR_ERR(dp_tee_priv->ctx);
> +	}
> +
> +	/* Open a session with dp TA */
> +	memset(&sess_arg, 0, sizeof(sess_arg));
> +	export_uuid(sess_arg.uuid, &dp_ta_uuid);
> +	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
> +	sess_arg.num_params = 0;
> +
> +	rc = tee_client_open_session(dp_tee_priv->ctx, &sess_arg, NULL);
> +	if (rc < 0 || sess_arg.ret != 0) {
> +		kfree(dp_tee_priv);

We don't kfree here because the goto will take care of that already...
P.S.: same for the other instances

> +		TLCERR("tee_client_open_session failed, err=%x\n", sess_arg.ret);
> +		rc = -EINVAL;
> +		goto out_tee_session;
> +	}
> +	dp_tee_priv->session = sess_arg.session;
> +
> +	/* Allocate dynamic shared memory with dp TA */
> +	dp_tee_priv->shm = tee_shm_alloc_kernel_buf(dp_tee_priv->ctx, MAX_COMMAND_SIZE
> +	 + MAX_RESPONSE_SIZE);
> +	if (IS_ERR(dp_tee_priv->shm)) {
> +		kfree(dp_tee_priv);
> +		TLCERR("%s: tee_shm_alloc_kernel_buf failed\n", __func__);
> +		rc = -ENOMEM;
> +		goto out_shm_alloc;
> +	}
> +	TLCINFO("Register 8k share memory successfully, (%p)",
> +		dp_tee_priv->shm->kaddr);

Don't print pointer addresses, it won't mean anything for most people as there will
be randomization and - if not - could be used for a vulnerability.

Please, just don't.

> +
> +	/* Copy parameter for add new device */
> +	tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +	memset(tci, 0, TCI_LENGTH);
> +	tci->command_id = CMD_DEVICE_ADDED;
> +	tci->cmd_body.cmd_hdcp_init_for_verion.version = version;
> +	tci->cmd_body.cmd_hdcp_init_for_verion.need_load_key = true;
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_DEVICE_ADDED);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		tee_remove_device(hdcp_info);
> +		return rc;
> +	}
> +
> +	hdcp_info->g_init = true;
> +
> +	return rc;

If you intend to pass on a result of dp_tee_op_send, then pass that to a pointer
in the function param.

Here, you shall return 0.

> +
> +out_shm_alloc:
> +	tee_client_close_session(dp_tee_priv->ctx, dp_tee_priv->session);
> +out_tee_session:
> +	tee_client_close_context(dp_tee_priv->ctx);

free_priv:
	kfree(dp_tee_priv);

> +
> +	return rc;
> +}
> +
> +void tee_remove_device(struct mtk_hdcp_info *hdcp_info)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;

int rc goes here

> +
> +	if (!hdcp_info->g_init)
> +		return;
> +
> +	hdcp_info->g_init = false;
> +	memset(tci, 0, TCI_LENGTH);
> +	tci->command_id = CMD_DEVICE_REMOVE;
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_DEVICE_REMOVE);
> +	if (rc != 0)
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +
> +	/* Free the shared memory pool */
> +	tee_shm_free(dp_tee_priv->shm);
> +
> +	/* Close the existing session with fTPM TA */
> +	tee_client_close_session(dp_tee_priv->ctx, dp_tee_priv->session);
> +
> +	/* Close the context with TEE driver */
> +	tee_client_close_context(dp_tee_priv->ctx);
> +
> +	/* Free the memory */
> +	kfree(dp_tee_priv);
> +}
> +
> +int tee_clear_paring(struct mtk_hdcp_info *hdcp_info)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;

int rc goes here

> +
> +	/* Copy parameters */
> +	memset(tci, 0, TCI_LENGTH);
> +	tci->command_id = CMD_DEVICE_CLEAN;
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_DEVICE_CLEAN);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	return rc;

return 0;

> +}
> +
> +int tee_hdcp1x_set_tx_an(struct mtk_hdcp_info *hdcp_info, u8 *an_code)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_WRITE_VAL;
> +	tci->cmd_body.cmd_hdcp_write_val.len = DRM_HDCP_AN_LEN;
> +	tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_PARAM_AN;
> +	memcpy(tci->cmd_body.cmd_hdcp_write_val.val, an_code, DRM_HDCP_AN_LEN);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_WRITE_VAL);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +int tee_hdcp_enable_encrypt(struct mtk_hdcp_info *hdcp_info, bool enable, u8 version)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_ENABLE_ENCRYPT;

	tci->cmd_body.cmd_hdcp_write_val.type = enable ? TYPE_HDCP_ENABLE_ENCRYPT : 
TYPE_HDCP_DISABLE_ENCRYPT;

> +	if (enable)
> +		tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_ENABLE_ENCRYPT;
> +	else
> +		tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_DISABLE_ENCRYPT;
> +
> +	/* Set HDCP version supportted by device */
> +	tci->cmd_body.cmd_hdcp_write_val.len = 1;
> +	tci->cmd_body.cmd_hdcp_write_val.val[0] = version;
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_ENABLE_ENCRYPT);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +

return 0.... here and everywhere else.

> +	return rc;
> +}
> +
> +int tee_hdcp1x_soft_rst(struct mtk_hdcp_info *hdcp_info)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_WRITE_VAL;
> +	tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_PARAM_RST_1;
> +	/* No need input. Set default value 0 for check */
> +	tci->cmd_body.cmd_hdcp_write_val.len = DEFAULT_WRITE_VAL_LEN;
> +	memset(tci->cmd_body.cmd_hdcp_write_val.val, DEFAULT_WRITE_VAL, DEFAULT_WRITE_VAL_LEN);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_WRITE_VAL);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +int tee_hdcp2_soft_rst(struct mtk_hdcp_info *hdcp_info)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	tci->command_id = CMD_WRITE_VAL;
> +	tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_PARAM_RST_2;
> +	/* No need input. Set default value 0 for check */

> +	tci->cmd_body.cmd_hdcp_write_val.len =
> +		DEFAULT_WRITE_VAL_LEN;

Fits in one line.

> +	memset(tci->cmd_body.cmd_hdcp_write_val.val, DEFAULT_WRITE_VAL, DEFAULT_WRITE_VAL_LEN);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_WRITE_VAL);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +/** V1.X **/
> +int tee_get_aksv(struct mtk_hdcp_info *hdcp_info, u8 *aksv)
> +{

Reorder the variables, here and everywhere else.

> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_GET_AKSV;
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_GET_AKSV);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	tci = (struct tci_t *)dp_tee_priv->resp_buf;

Use a different variable, otherwise this adds up confusion.

> +	memcpy(aksv, tci->cmd_body.cmd_hdcp_get_aksv.aksv, DRM_HDCP_KSV_LEN);
> +
> +	return rc;
> +}
> +
> +int tee_calculate_lm(struct mtk_hdcp_info *hdcp_info, u8 *bksv)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_CALCULATE_LM;
> +	memcpy(tci->cmd_body.cmd_hdcp_calculate_lm.bksv, bksv, DRM_HDCP_KSV_LEN);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_CALCULATE_LM);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +int tee_compare_r0(struct mtk_hdcp_info *hdcp_info, u8 *r0, u32 len)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_COMPARE_R0;
> +	tci->cmd_body.cmd_hdcp_compare.rx_val_len = len;
> +	memcpy(tci->cmd_body.cmd_hdcp_compare.rx_val, r0, len);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_COMPARE_R0);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +int tee_hdcp1x_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
> +				 u8 *crypto_param, u32 param_len, u8 *rx_v)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_COMPARE_V1;
> +	tci->cmd_body.cmd_hdcp_compare.rx_val_len = 20;
> +	tci->cmd_body.cmd_hdcp_compare.param_len = param_len;
> +	memcpy(tci->cmd_body.cmd_hdcp_compare.rx_val, rx_v, 20);
> +	memcpy(tci->cmd_body.cmd_hdcp_compare.param, crypto_param, param_len);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_COMPARE_V1);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +/** V2.X **/
> +int tee_ake_certificate(struct mtk_hdcp_info *hdcp_info,
> +			u8 *certificate, bool *stored, u8 *out_m, u8 *out_ekm)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_AKE_CERTIFICATE;
> +	memcpy(tci->cmd_body.cmd_hdcp_ake_certificate.certification,
> +	       certificate, HDCP2_CERTRX_LEN);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_AKE_CERTIFICATE);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	TLCINFO("verify signature: result %d", rc);
> +	tci = (struct tci_t *)dp_tee_priv->resp_buf;
> +	*stored = tci->cmd_body.cmd_hdcp_ake_certificate.stored;
> +	memcpy(out_m, tci->cmd_body.cmd_hdcp_ake_certificate.m,
> +	       HDCP_2_2_E_KH_KM_M_LEN - HDCP_2_2_E_KH_KM_LEN);
> +	memcpy(out_ekm, tci->cmd_body.cmd_hdcp_ake_certificate.ekm, HDCP_2_2_E_KH_KM_LEN);
> +
> +	return rc;
> +}
> +
> +int tee_enc_rsaes_oaep(struct mtk_hdcp_info *hdcp_info, u8 *ekm)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_ENC_KM;
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_ENC_KM);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	tci = (struct tci_t *)dp_tee_priv->resp_buf;
> +	memcpy(ekm, tci->cmd_body.cmd_hdcp_enc_km.enc_km, HDCP_2_2_E_KPUB_KM_LEN);
> +
> +	return rc;
> +}
> +
> +int tee_ake_h_prime(struct mtk_hdcp_info *hdcp_info,
> +		    u8 *rtx, u8 *rrx, u8 *rx_caps, u8 *tx_caps, u8 *rx_h, u32 rx_h_len)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_AKE_H_PRIME;
> +	tci->cmd_body.cmd_hdcp_ake_h_prime.rx_h_len = rx_h_len;
> +
> +	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.rtx, rtx, HDCP_2_2_RTX_LEN);
> +	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.rrx, rrx, HDCP_2_2_RRX_LEN);
> +	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.rx_caps, rx_caps, HDCP_2_2_RXCAPS_LEN);
> +	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.tx_caps, tx_caps, HDCP_2_2_TXCAPS_LEN);
> +	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.rx_h, rx_h, rx_h_len);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_AKE_H_PRIME);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	tci = (struct tci_t *)dp_tee_priv->resp_buf;
> +	return tci->return_code;
> +}
> +
> +int tee_ake_paring(struct mtk_hdcp_info *hdcp_info, u8 *rx_ekm)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_AKE_PARING;
> +	memcpy(tci->cmd_body.cmd_hdcp_ake_paring.ekm, rx_ekm, HDCP_2_2_E_KH_KM_LEN);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_AKE_PARING);
> +	if (rc != 0)
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +
> +	return rc;
> +}
> +
> +int tee_lc_l_prime(struct mtk_hdcp_info *hdcp_info, u8 *rn, u8 *rx_l, u32 len)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_LC_L_PRIME;
> +	memcpy(tci->cmd_body.cmd_hdcp_lc_l_prime.rn, rn, HDCP_2_2_RN_LEN);
> +	tci->cmd_body.cmd_hdcp_lc_l_prime.rx_l_len = len;
> +	memcpy(tci->cmd_body.cmd_hdcp_lc_l_prime.rx_l, rx_l, len);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_LC_L_PRIME);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	tci = (struct tci_t *)dp_tee_priv->resp_buf;
> +	return tci->return_code;
> +}
> +
> +int tee_ske_enc_ks(struct mtk_hdcp_info *hdcp_info, u8 *riv, u8 *eks)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +	u8 *share_buffer = NULL;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_SKE_CAL_EKS;
> +	memcpy(tci->cmd_body.cmd_hdcp_ske_eks.riv, riv, HDCP_2_2_RIV_LEN);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH + 16, CMD_SKE_CAL_EKS);
> +	if (rc != 0)
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +
> +	share_buffer = (u8 *)dp_tee_priv->resp_buf;
> +	memcpy(eks, share_buffer + TCI_LENGTH, 16);
> +
> +	return rc;
> +}
> +
> +int tee_hdcp2_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
> +				u8 *crypto_param, u32 param_len, u8 *rx_v, u8 *tx_v)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +	u8 *share_buffer = NULL;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_COMPARE_V2;
> +	tci->cmd_body.cmd_hdcp_compare.rx_val_len = 16;
> +	tci->cmd_body.cmd_hdcp_compare.param_len = param_len;
> +	memcpy(tci->cmd_body.cmd_hdcp_compare.rx_val, rx_v, 16);
> +	memcpy(tci->cmd_body.cmd_hdcp_compare.param, crypto_param, param_len);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_COMPARE_V2);
> +	if (rc != 0) {
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +		return rc;
> +	}
> +
> +	share_buffer = (u8 *)dp_tee_priv->resp_buf;
> +	memcpy(tx_v, share_buffer + TCI_LENGTH, 16);
> +
> +	return rc;
> +}
> +
> +int tee_hdcp2_compute_compare_m(struct mtk_hdcp_info *hdcp_info,
> +				u8 *crypto_param, u32 param_len, u8 *rx_m)
> +{
> +	int rc;
> +	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
> +	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
> +
> +	/* Copy parameters */
> +	tci->command_id = CMD_COMPARE_M;
> +	tci->cmd_body.cmd_hdcp_compare.rx_val_len = HDCP_2_2_MPRIME_LEN;
> +	tci->cmd_body.cmd_hdcp_compare.param_len = param_len;
> +	memcpy(tci->cmd_body.cmd_hdcp_compare.rx_val, rx_m, HDCP_2_2_MPRIME_LEN);
> +	memcpy(tci->cmd_body.cmd_hdcp_compare.param, crypto_param, param_len);
> +
> +	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_COMPARE_M);
> +	if (rc != 0)
> +		TLCERR("tee_op_send failed, error=%x\n", rc);
> +
> +	return rc;
> +}
> diff --git a/drivers/gpu/drm/mediatek/tlc_dp_hdcp.h b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.h
> new file mode 100644
> index 000000000000..493d3c51a7a0
> --- /dev/null
> +++ b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.h
> @@ -0,0 +1,414 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2019-2024 MediaTek Inc.
> + */
> +
> +#ifndef _TLC_DP_HDCP_H_
> +#define _TLC_DP_HDCP_H_
> +
> +#include <linux/printk.h>
> +#include <linux/tee_drv.h>
> +#include <linux/uuid.h>
> +#include <linux/types.h>
> +#include <linux/sched/clock.h>
> +#include <drm/display/drm_dp_helper.h>
> +#include "tci.h"
> +
> +#define TLCINFO(string, args...) pr_info("[TLC_HDCP]info: "string, ##args)
> +#define TLCERR(string, args...) pr_info("[TLC_HDCP]line:%d,err:%s:"string,\
> +	__LINE__, __func__, ##args)
> +
> +#define DPTXHDCPFUNC(fmt, arg...)		\
> +	pr_info("[DPTXHDCP][%s line:%d]"pr_fmt(fmt), __func__, __LINE__, ##arg)
> +#define DPTXHDCPMSG(fmt, arg...)                                  \
> +		pr_info("[DPTXHDCP]"pr_fmt(fmt), ##arg)
> +#define DPTXHDCPERR(fmt, arg...)                                  \
> +		pr_err("[DPTXHDCP]"pr_fmt(fmt), ##arg)

You don't need those print wrappers and you can just use pr_{info,err} where
needed in the code.
Also, dev_info/dev_err would be preferred.

> +
> +#define RET_SUCCESS 0

Unused (and anyway unneeded) definition: please remove.

> +
> +/**
> + * hdcp version definitions
> + */
> +#define HDCP_NONE                0x0 // No HDCP supported, no secure data path
> +#define HDCP_V1                  0x1 // HDCP version 1.0
> +#define HDCP_V2                  0x2 // HDCP version 2.0 Type 1
> +#define HDCP_V2_1                0x3 // HDCP version 2.1 Type 1
> +#define HDCP_V2_2                0x4 // HDCP version 2.2 Type 1
> +#define HDCP_V2_3                0x5 // HDCP version 2.3 Type 1

Please introduce definitions in the same commits where you use them.
Also, C-style comments please.

> +
> +/* Local display only(content required version use only) */
> +#define HDCP_LOCAL_DISPLAY_ONLY  0xf
> +#define HDCP_NO_DIGITAL_OUTPUT   0xff // No digital output
> +#define HDCP_DEFAULT             HDCP_NO_DIGITAL_OUTPUT // Default value
> +
> +#define HDCP_VERSION_1X 1
> +#define HDCP_VERSION_2X 2
> +
> +/* max. buffer size supported by dp  */
> +#define MAX_COMMAND_SIZE       4096
> +#define MAX_RESPONSE_SIZE      4096
> +
> +#define HDCP1X_REP_MAXDEVS 128
> +#define HDCP1X_V_LEN 20
> +#define HDCP1X_B_INFO_LEN 2
> +
> +#define HDCP2_K_LEN 2
> +#define HDCP2_STREAMID_TYPE_LEN 2
> +
> +enum HDCP_RESULT {
> +	AUTH_ZERO = 0,
> +	AUTH_PREPARE = 1,
> +	AUTH_INIT = 2,
> +	AUTH_PASS = 3,
> +	AUTH_FAIL = 4,
> +};
> +
> +struct dp_header {
> +	__be16 tag;
> +	__be32 length;
> +	union {
> +		__be32 ordinal;
> +		__be32 return_code;
> +	};
> +} __packed;
> +
> +/**
> + * struct dp_tee_private - fTPM's private data
> + * @session:  dp TA session identifier.
> + * @resp_len: cached response buffer length.
> + * @resp_buf: cached response buffer.
> + * @ctx:      TEE context handler.
> + * @shm:      Memory pool shared with fTPM TA in TEE.
> + */
> +struct dp_tee_private {
> +	u32 session;
> +	size_t resp_len;
> +	u8 resp_buf[MAX_RESPONSE_SIZE];
> +	struct tee_context *ctx;
> +	struct tee_shm *shm;
> +};
> +
> +struct hdcp2_info_tx {
> +	struct hdcp2_ake_init ake_init;
> +	struct hdcp2_ake_no_stored_km no_stored_km;
> +	struct hdcp2_ske_send_eks send_eks;
> +	struct hdcp2_lc_init lc_init;
> +	struct hdcp2_rep_stream_manage stream_manage;
> +	struct hdcp2_rep_send_ack send_ack;
> +	struct hdcp2_tx_caps tx_caps;
> +	u8 k[HDCP2_K_LEN];
> +	u8 stream_id_type[HDCP2_STREAMID_TYPE_LEN];
> +};
> +
> +struct hdcp2_info_rx {
> +	struct hdcp2_cert_rx cert_rx;
> +	struct hdcp2_ake_send_cert send_cert;
> +	struct hdcp2_rep_send_receiverid_list receiverid_list;
> +	struct hdcp2_ake_send_pairing_info pairing_info;
> +	struct hdcp2_rep_stream_ready stream_ready;
> +	struct hdcp2_ake_send_hprime send_hprime;
> +	struct hdcp2_lc_send_lprime send_lprime;
> +};
> +
> +struct hdcp2_handler {
> +	u8 main_state;
> +	u8 sub_state;
> +	u8 down_stream_dev_cnt;
> +	u8 hdcp_rx_ver;
> +	bool send_ake_init:1;
> +	bool get_recv_id_list:1;
> +	bool stored_km:1;
> +	bool send_lc_init:1;
> +	bool send_ack:1;
> +	bool sink_is_repeater:1;
> +	bool recv_msg:1;
> +	bool send_pair:1;
> +	u32 seq_num_v_cnt;
> +	u32 retry_cnt;
> +};
> +
> +struct hdcp1x_info {
> +	bool enable;
> +	bool repeater;
> +	bool r0_read;
> +	bool ksv_ready;
> +	bool max_cascade;
> +	bool max_devs;
> +	u8 b_status;
> +	u8 b_ksv[DRM_HDCP_KSV_LEN];
> +	u8 a_ksv[DRM_HDCP_KSV_LEN];
> +	u8 v[HDCP1X_V_LEN];
> +	u8 b_info[HDCP1X_B_INFO_LEN];
> +	u8 ksvfifo[DRM_HDCP_KSV_LEN * (HDCP1X_REP_MAXDEVS - 1)];
> +	u8 device_count;
> +	u8 retry_count;
> +	int main_states;
> +	int sub_states;
> +};
> +
> +struct hdcp2_info {
> +	struct hdcp2_info_tx hdcp_tx;
> +	struct hdcp2_info_rx hdcp_rx;
> +	struct hdcp2_ake_stored_km ake_stored_km;
> +	struct hdcp2_handler hdcp_handler;
> +	bool enable;
> +	bool repeater;
> +	bool read_certrx;
> +	bool read_h_prime;
> +	bool read_pairing;
> +	bool read_l_prime;
> +	bool ks_exchange_done;
> +	bool read_v_prime;
> +	u8 retry_count;
> +	u8 device_count;
> +	u8 stream_id_type;
> +};
> +
> +struct mtk_hdcp_info {
> +	u8 auth_status;
> +	bool g_init;
> +	u32 hdcp_content_type;
> +	u32 content_protection;
> +	struct dp_tee_private *g_dp_tee_priv;
> +	struct hdcp1x_info hdcp1x_info;
> +	struct hdcp2_info hdcp2_info;
> +};
> +
> +#ifdef __cplusplus
> +extern "C"

cplusplus?! This is the kernel, this is not a UAPI header and will never be, and
you don't need this ifdef at all.

> +{
> +#endif
> +
> +/*

Please use valid kerneldoc; here and everywhere else.

> + *Description:
> + *  A device connect and do some initializations.
> + *
> + *Input:
> + *  version: HDCP version
> + *
> + *Returns:
> + *  TEEC_SUCCESS success*
> + */
> +int tee_add_device(struct mtk_hdcp_info *hdcp_info, u32 version);
> +

Regards,
Angelo
CK Hu (胡俊光) Feb. 20, 2024, 1:37 a.m. UTC | #3
Hi, Mac:

On Mon, 2024-02-05 at 13:50 +0800, mac.shen wrote:
> Add tee client application which will be used for
> HDCP 1.x and 2.x authentication in DisplayPort.
> 
> Changes in v2:
> - remove ca folder, and change file name with lower case
> - refine the tci_t structure to make the data to tee can
>   through this structure
> - remove aux and regs from mtk_hdcp_info structure
> - remove some definitions, and use the definitions in
>   include/drm/drm_hdcp.h
> - remove useless code
> per suggestion from the previous thread:
> https://lore.kernel.org/all/8fff59b5567449d8201dd1138c8fa
> 9218a545c46.camel@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +#define RET_COMPARE_PASS 0
> +#define RET_COMPARE_FAIL 1
> +#define RET_NEW_DEVICE 2
> +#define RET_STORED_DEVICE 3

These definition are useless, so drop them.

Regards,
CK

> +
CK Hu (胡俊光) Feb. 20, 2024, 7:53 a.m. UTC | #4
Hi, Mac:

On Mon, 2024-02-05 at 13:50 +0800, mac.shen wrote:
> Add tee client application which will be used for
> HDCP 1.x and 2.x authentication in DisplayPort.
> 
> Changes in v2:
> - remove ca folder, and change file name with lower case
> - refine the tci_t structure to make the data to tee can
>   through this structure
> - remove aux and regs from mtk_hdcp_info structure
> - remove some definitions, and use the definitions in
>   include/drm/drm_hdcp.h
> - remove useless code
> per suggestion from the previous thread:
> https://lore.kernel.org/all/8fff59b5567449d8201dd1138c8fa
> 9218a545c46.camel@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +struct hdcp2_handler {
> +	u8 main_state;
> +	u8 sub_state;
> +	u8 down_stream_dev_cnt;

Useless, drop it.

> +	u8 hdcp_rx_ver;

Ditto.

> +	bool send_ake_init:1;

You set send_ake_init to ture, but never check it, so it's useless,
drop it.

> +	bool get_recv_id_list:1;

Useless, drop it.

> +	bool stored_km:1;
> +	bool send_lc_init:1;

You set send_lc_init to ture, but never check it, so it's useless, drop
it.

> +	bool send_ack:1;

Useless, drop it.

> +	bool sink_is_repeater:1;

Ditto.

> +	bool recv_msg:1;
> +	bool send_pair:1;

You set send_pair to ture, but never check it, so it's useless, drop
it.

Regards,
CK

> +	u32 seq_num_v_cnt;
> +	u32 retry_cnt;
> +};
> +
diff mbox series

Patch

diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index d4d193f60271..c80e6c2f9336 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -26,4 +26,7 @@  mediatek-drm-hdmi-objs := mtk_cec.o \
 
 obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
 
-obj-$(CONFIG_DRM_MEDIATEK_DP) += mtk_dp.o
+mtk-dp-objs := tlc_dp_hdcp.o \
+		  mtk_dp.o
+
+obj-$(CONFIG_DRM_MEDIATEK_DP) += mtk-dp.o
diff --git a/drivers/gpu/drm/mediatek/tci.h b/drivers/gpu/drm/mediatek/tci.h
new file mode 100644
index 000000000000..f2239ea3ffbf
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/tci.h
@@ -0,0 +1,156 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019-2024 MediaTek Inc.
+ */
+
+#ifndef _TCI_H_
+#define _TCI_H_
+
+#include <drm/display/drm_hdcp.h>
+
+#define CMD_DEVICE_ADDED        1
+#define CMD_DEVICE_REMOVE       2
+#define CMD_WRITE_VAL           3
+#define CMD_DEVICE_CLEAN        4
+#define CMD_ENABLE_ENCRYPT      5
+
+/* V1.3 */
+#define CMD_CALCULATE_LM        11
+#define CMD_COMPARE_R0          12
+#define CMD_COMPARE_V1          13
+#define CMD_GET_AKSV            14
+
+/* V2.2 */
+#define CMD_AKE_CERTIFICATE     20
+#define CMD_ENC_KM              21
+#define CMD_AKE_H_PRIME         22
+#define CMD_AKE_PARING          23
+#define CMD_LC_L_PRIME          24
+#define CMD_COMPARE_L           25
+#define CMD_SKE_CAL_EKS         26
+
+#define CMD_COMPARE_V2          27
+#define CMD_COMPARE_M           28
+
+/* Need remove in furture */
+#define CMD_LOAD_KEY            50
+
+#define RET_COMPARE_PASS 0
+#define RET_COMPARE_FAIL 1
+#define RET_NEW_DEVICE 2
+#define RET_STORED_DEVICE 3
+
+#define TYPE_HDCP_PARAM_AN 10
+#define TYPE_HDCP_PARAM_RST_1 11
+#define TYPE_HDCP_PARAM_RST_2 12
+#define TYPE_HDCP_ENABLE_ENCRYPT 13
+#define TYPE_HDCP_DISABLE_ENCRYPT 14
+
+#define TYPE_HDCP13_KEY 20
+#define TYPE_HDCP22_KEY 21
+
+// reserved:2
+#define HDCP2_CERTRX_LEN (HDCP_2_2_RECEIVER_ID_LEN + HDCP_2_2_K_PUB_RX_LEN + \
+	2 + HDCP_2_2_DCP_LLC_SIG_LEN)
+// version:1
+#define HDCP_2_2_TXCAPS_LEN (HDCP_2_2_TXCAP_MASK_LEN + 1)
+#define PARAM_LEN 1024
+
+#define TCI_LENGTH sizeof(struct tci_t)
+
+struct cmd_hdcp_init_for_verion_t {
+	u32 version;
+	bool need_load_key;
+};
+
+struct cmd_hdcp_write_val_t {
+	u8 type;
+	u8 len;
+	u8 val[DRM_HDCP_AN_LEN];
+};
+
+struct cmd_hdcp_calculate_lm_t {
+	u8 bksv[DRM_HDCP_KSV_LEN];
+};
+
+struct cmd_hdcp_get_aksv_t {
+	u8 aksv[DRM_HDCP_KSV_LEN];
+};
+
+struct cmd_hdcp_ake_certificate_t {
+	u8 certification[HDCP2_CERTRX_LEN];
+	bool stored;
+	u8 m[HDCP_2_2_E_KH_KM_M_LEN - HDCP_2_2_E_KH_KM_LEN];
+	u8 ekm[HDCP_2_2_E_KH_KM_LEN];
+};
+
+struct cmd_hdcp_ake_paring_t {
+	u8 ekm[HDCP_2_2_E_KH_KM_LEN];
+};
+
+struct cmd_hdcp_enc_km_t {
+	u8 enc_km[HDCP_2_2_E_KPUB_KM_LEN];
+};
+
+struct cmd_hdcp_ake_h_prime_t {
+	u8 rtx[HDCP_2_2_RTX_LEN];
+	u8 rrx[HDCP_2_2_RRX_LEN];
+	u8 rx_caps[HDCP_2_2_RXCAPS_LEN];
+	u8 tx_caps[HDCP_2_2_TXCAPS_LEN];
+	u32 rx_h_len;
+	u8 rx_h[HDCP_2_2_H_PRIME_LEN];
+};
+
+struct cmd_hdcp_lc_l_prime_t {
+	u8 rn[HDCP_2_2_RN_LEN];
+	u32 rx_l_len;
+	u8 rx_l[HDCP_2_2_L_PRIME_LEN];
+};
+
+struct cmd_hdcp_ske_eks_t {
+	u8 riv[HDCP_2_2_RIV_LEN];
+	u32 eks_len;
+	u32 eks;
+};
+
+struct cmd_hdcp_compare_t {
+	u32 rx_val_len;
+	u8 rx_val[HDCP_2_2_MPRIME_LEN];
+	u32 param_len;
+	u8 param[PARAM_LEN];
+	u32 out_len;
+	u32 out;
+};
+
+union tci_cmd_body_t {
+	/* Init with special HDCP version */
+	struct cmd_hdcp_init_for_verion_t cmd_hdcp_init_for_verion;
+	/* Write uint32 data to hw */
+	struct cmd_hdcp_write_val_t cmd_hdcp_write_val;
+	/* Get aksv */
+	struct cmd_hdcp_get_aksv_t cmd_hdcp_get_aksv;
+	/* Calculate r0 */
+	struct cmd_hdcp_calculate_lm_t cmd_hdcp_calculate_lm;
+	/* Generate signature for certificate */
+	struct cmd_hdcp_ake_certificate_t cmd_hdcp_ake_certificate;
+	/* To store ekm */
+	struct cmd_hdcp_ake_paring_t cmd_hdcp_ake_paring;
+	/* Encrypt km for V2.2 */
+	struct cmd_hdcp_enc_km_t cmd_hdcp_enc_km;
+	/* Compute H prime */
+	struct cmd_hdcp_ake_h_prime_t cmd_hdcp_ake_h_prime;
+	/* Compute L prime */
+	struct cmd_hdcp_lc_l_prime_t cmd_hdcp_lc_l_prime;
+	/* Compute eks */
+	struct cmd_hdcp_ske_eks_t cmd_hdcp_ske_eks;
+	/* Compare */
+	struct cmd_hdcp_compare_t cmd_hdcp_compare;
+} __packed;
+
+struct tci_t {
+	u32 command_id;
+	u32 return_code;
+	union tci_cmd_body_t cmd_body;
+};
+
+#endif /* _TCI_H_ */
diff --git a/drivers/gpu/drm/mediatek/tlc_dp_hdcp.c b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.c
new file mode 100644
index 000000000000..147329324648
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.c
@@ -0,0 +1,598 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019-2024 MediaTek Inc.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "tlc_dp_hdcp.h"
+
+#define DEFAULT_WRITE_VAL_LEN 1
+#define DEFAULT_WRITE_VAL 0
+
+/*
+ * TA_FTPM_UUID: 99975014-3c7c-54ea-8487-a80d215ea92c
+ *
+ * Randomly generated, and must correspond to the GUID on the TA side.
+ * Defined here in the reference implementation:
+ * https://github.com/microsoft/ms-tpm-20-ref/blob/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM/include/fTPM.h#L42
+ */
+static const uuid_t dp_ta_uuid =
+	UUID_INIT(0x99975014, 0x3c7c, 0x54ea,
+		  0x84, 0x87, 0xa8, 0x0d, 0x21, 0x5e, 0xa9, 0x2c);
+
+/**
+ * dp_tee_op_send() - send dp commands through the TEE shared memory.
+ * @len:	the number of bytes to send.
+ *
+ * Return:
+ *	In case of success, returns 0.
+ *	On failure, -errno
+ */
+static int dp_tee_op_send(struct dp_tee_private *dp_tee_priv, size_t len, u32 cmd_id)
+{
+	int rc;
+	u8 *temp_buf;
+	struct tee_ioctl_invoke_arg transceive_args;
+	struct tee_param command_params[4];
+	struct tee_shm *shm = dp_tee_priv->shm;
+
+	if (len > MAX_COMMAND_SIZE) {
+		TLCERR("%s: len=%zd exceeds MAX_COMMAND_SIZE supported by dp TA\n", __func__, len);
+		return -EIO;
+	}
+
+	memset(&transceive_args, 0, sizeof(transceive_args));
+	memset(command_params, 0, sizeof(command_params));
+	dp_tee_priv->resp_len = 0;
+
+	/* Invoke FTPM_OPTEE_TA_SUBMIT_COMMAND function of dp TA */
+	transceive_args = (struct tee_ioctl_invoke_arg) {
+		.func = cmd_id,
+		.session = dp_tee_priv->session,
+		.num_params = 4,
+	};
+
+	/* Fill FTPM_OPTEE_TA_SUBMIT_COMMAND parameters */
+	command_params[0] = (struct tee_param) {
+		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+		.u.memref = {
+			.shm = shm,
+			.size = len,
+			.shm_offs = 0,
+		},
+	};
+
+	command_params[1] = (struct tee_param) {
+		.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+		.u.memref = {
+			.shm = shm,
+			.size = MAX_RESPONSE_SIZE,
+			.shm_offs = MAX_COMMAND_SIZE,
+		},
+	};
+
+	rc = tee_client_invoke_func(dp_tee_priv->ctx, &transceive_args, command_params);
+	if (rc < 0 || transceive_args.ret != 0) {
+		TLCERR("%s: invoke error: 0x%x\n", __func__, transceive_args.ret);
+		return (rc < 0) ? rc : transceive_args.ret;
+	}
+
+	temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs);
+	if (IS_ERR(temp_buf)) {
+		TLCERR("%s: tee_shm_get_va failed for receive\n", __func__);
+		return PTR_ERR(temp_buf);
+	}
+
+	/* Sanity checks look good, cache the response */
+	memcpy(dp_tee_priv->resp_buf, temp_buf, MAX_RESPONSE_SIZE / 2);
+	dp_tee_priv->resp_len = MAX_RESPONSE_SIZE / 2;
+
+	return 0;
+}
+
+/*
+ * Check whether this driver supports the dp TA in the TEE instance
+ * represented by the params (ver/data) to this function.
+ */
+static int dp_tee_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+	/*
+	 * Currently this driver only support GP Complaint OPTEE based dp TA
+	 */
+	if (ver->impl_id == TEE_IMPL_ID_OPTEE && ver->gen_caps & TEE_GEN_CAP_GP)
+		return 1;
+	else
+		return 0;
+}
+
+int tee_add_device(struct mtk_hdcp_info *hdcp_info, u32 version)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = NULL;
+	struct tee_ioctl_open_session_arg sess_arg;
+	struct tci_t *tci;
+
+	if (hdcp_info->g_init)
+		tee_remove_device(hdcp_info);
+
+	dp_tee_priv = kzalloc(sizeof(*dp_tee_priv), GFP_KERNEL);
+	if (!dp_tee_priv) {
+		kfree(dp_tee_priv);
+		TLCERR("%s: tee_alloc_memory failed\n", __func__);
+		return -ENOMEM;
+	}
+	hdcp_info->g_dp_tee_priv = dp_tee_priv;
+
+	/* Open context with TEE driver */
+	dp_tee_priv->ctx = tee_client_open_context(NULL, dp_tee_match, NULL, NULL);
+	if (IS_ERR(dp_tee_priv->ctx)) {
+		if (PTR_ERR(dp_tee_priv->ctx) == -ENOENT) {
+			kfree(dp_tee_priv);
+			return -EPROBE_DEFER;
+		}
+		kfree(dp_tee_priv);
+		TLCERR("%s: tee_client_open_context failed\n", __func__);
+		return PTR_ERR(dp_tee_priv->ctx);
+	}
+
+	/* Open a session with dp TA */
+	memset(&sess_arg, 0, sizeof(sess_arg));
+	export_uuid(sess_arg.uuid, &dp_ta_uuid);
+	sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+	sess_arg.num_params = 0;
+
+	rc = tee_client_open_session(dp_tee_priv->ctx, &sess_arg, NULL);
+	if (rc < 0 || sess_arg.ret != 0) {
+		kfree(dp_tee_priv);
+		TLCERR("tee_client_open_session failed, err=%x\n", sess_arg.ret);
+		rc = -EINVAL;
+		goto out_tee_session;
+	}
+	dp_tee_priv->session = sess_arg.session;
+
+	/* Allocate dynamic shared memory with dp TA */
+	dp_tee_priv->shm = tee_shm_alloc_kernel_buf(dp_tee_priv->ctx, MAX_COMMAND_SIZE
+	 + MAX_RESPONSE_SIZE);
+	if (IS_ERR(dp_tee_priv->shm)) {
+		kfree(dp_tee_priv);
+		TLCERR("%s: tee_shm_alloc_kernel_buf failed\n", __func__);
+		rc = -ENOMEM;
+		goto out_shm_alloc;
+	}
+	TLCINFO("Register 8k share memory successfully, (%p)",
+		dp_tee_priv->shm->kaddr);
+
+	/* Copy parameter for add new device */
+	tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+	memset(tci, 0, TCI_LENGTH);
+	tci->command_id = CMD_DEVICE_ADDED;
+	tci->cmd_body.cmd_hdcp_init_for_verion.version = version;
+	tci->cmd_body.cmd_hdcp_init_for_verion.need_load_key = true;
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_DEVICE_ADDED);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		tee_remove_device(hdcp_info);
+		return rc;
+	}
+
+	hdcp_info->g_init = true;
+
+	return rc;
+
+out_shm_alloc:
+	tee_client_close_session(dp_tee_priv->ctx, dp_tee_priv->session);
+out_tee_session:
+	tee_client_close_context(dp_tee_priv->ctx);
+
+	return rc;
+}
+
+void tee_remove_device(struct mtk_hdcp_info *hdcp_info)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	if (!hdcp_info->g_init)
+		return;
+
+	hdcp_info->g_init = false;
+	memset(tci, 0, TCI_LENGTH);
+	tci->command_id = CMD_DEVICE_REMOVE;
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_DEVICE_REMOVE);
+	if (rc != 0)
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+
+	/* Free the shared memory pool */
+	tee_shm_free(dp_tee_priv->shm);
+
+	/* Close the existing session with fTPM TA */
+	tee_client_close_session(dp_tee_priv->ctx, dp_tee_priv->session);
+
+	/* Close the context with TEE driver */
+	tee_client_close_context(dp_tee_priv->ctx);
+
+	/* Free the memory */
+	kfree(dp_tee_priv);
+}
+
+int tee_clear_paring(struct mtk_hdcp_info *hdcp_info)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	memset(tci, 0, TCI_LENGTH);
+	tci->command_id = CMD_DEVICE_CLEAN;
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_DEVICE_CLEAN);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int tee_hdcp1x_set_tx_an(struct mtk_hdcp_info *hdcp_info, u8 *an_code)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_WRITE_VAL;
+	tci->cmd_body.cmd_hdcp_write_val.len = DRM_HDCP_AN_LEN;
+	tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_PARAM_AN;
+	memcpy(tci->cmd_body.cmd_hdcp_write_val.val, an_code, DRM_HDCP_AN_LEN);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_WRITE_VAL);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int tee_hdcp_enable_encrypt(struct mtk_hdcp_info *hdcp_info, bool enable, u8 version)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_ENABLE_ENCRYPT;
+	if (enable)
+		tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_ENABLE_ENCRYPT;
+	else
+		tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_DISABLE_ENCRYPT;
+
+	/* Set HDCP version supportted by device */
+	tci->cmd_body.cmd_hdcp_write_val.len = 1;
+	tci->cmd_body.cmd_hdcp_write_val.val[0] = version;
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_ENABLE_ENCRYPT);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int tee_hdcp1x_soft_rst(struct mtk_hdcp_info *hdcp_info)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_WRITE_VAL;
+	tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_PARAM_RST_1;
+	/* No need input. Set default value 0 for check */
+	tci->cmd_body.cmd_hdcp_write_val.len = DEFAULT_WRITE_VAL_LEN;
+	memset(tci->cmd_body.cmd_hdcp_write_val.val, DEFAULT_WRITE_VAL, DEFAULT_WRITE_VAL_LEN);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_WRITE_VAL);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int tee_hdcp2_soft_rst(struct mtk_hdcp_info *hdcp_info)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	tci->command_id = CMD_WRITE_VAL;
+	tci->cmd_body.cmd_hdcp_write_val.type = TYPE_HDCP_PARAM_RST_2;
+	/* No need input. Set default value 0 for check */
+	tci->cmd_body.cmd_hdcp_write_val.len =
+		DEFAULT_WRITE_VAL_LEN;
+	memset(tci->cmd_body.cmd_hdcp_write_val.val, DEFAULT_WRITE_VAL, DEFAULT_WRITE_VAL_LEN);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_WRITE_VAL);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/** V1.X **/
+int tee_get_aksv(struct mtk_hdcp_info *hdcp_info, u8 *aksv)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_GET_AKSV;
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_GET_AKSV);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	tci = (struct tci_t *)dp_tee_priv->resp_buf;
+	memcpy(aksv, tci->cmd_body.cmd_hdcp_get_aksv.aksv, DRM_HDCP_KSV_LEN);
+
+	return rc;
+}
+
+int tee_calculate_lm(struct mtk_hdcp_info *hdcp_info, u8 *bksv)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_CALCULATE_LM;
+	memcpy(tci->cmd_body.cmd_hdcp_calculate_lm.bksv, bksv, DRM_HDCP_KSV_LEN);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_CALCULATE_LM);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int tee_compare_r0(struct mtk_hdcp_info *hdcp_info, u8 *r0, u32 len)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_COMPARE_R0;
+	tci->cmd_body.cmd_hdcp_compare.rx_val_len = len;
+	memcpy(tci->cmd_body.cmd_hdcp_compare.rx_val, r0, len);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_COMPARE_R0);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int tee_hdcp1x_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
+				 u8 *crypto_param, u32 param_len, u8 *rx_v)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_COMPARE_V1;
+	tci->cmd_body.cmd_hdcp_compare.rx_val_len = 20;
+	tci->cmd_body.cmd_hdcp_compare.param_len = param_len;
+	memcpy(tci->cmd_body.cmd_hdcp_compare.rx_val, rx_v, 20);
+	memcpy(tci->cmd_body.cmd_hdcp_compare.param, crypto_param, param_len);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_COMPARE_V1);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/** V2.X **/
+int tee_ake_certificate(struct mtk_hdcp_info *hdcp_info,
+			u8 *certificate, bool *stored, u8 *out_m, u8 *out_ekm)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_AKE_CERTIFICATE;
+	memcpy(tci->cmd_body.cmd_hdcp_ake_certificate.certification,
+	       certificate, HDCP2_CERTRX_LEN);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_AKE_CERTIFICATE);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	TLCINFO("verify signature: result %d", rc);
+	tci = (struct tci_t *)dp_tee_priv->resp_buf;
+	*stored = tci->cmd_body.cmd_hdcp_ake_certificate.stored;
+	memcpy(out_m, tci->cmd_body.cmd_hdcp_ake_certificate.m,
+	       HDCP_2_2_E_KH_KM_M_LEN - HDCP_2_2_E_KH_KM_LEN);
+	memcpy(out_ekm, tci->cmd_body.cmd_hdcp_ake_certificate.ekm, HDCP_2_2_E_KH_KM_LEN);
+
+	return rc;
+}
+
+int tee_enc_rsaes_oaep(struct mtk_hdcp_info *hdcp_info, u8 *ekm)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_ENC_KM;
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_ENC_KM);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	tci = (struct tci_t *)dp_tee_priv->resp_buf;
+	memcpy(ekm, tci->cmd_body.cmd_hdcp_enc_km.enc_km, HDCP_2_2_E_KPUB_KM_LEN);
+
+	return rc;
+}
+
+int tee_ake_h_prime(struct mtk_hdcp_info *hdcp_info,
+		    u8 *rtx, u8 *rrx, u8 *rx_caps, u8 *tx_caps, u8 *rx_h, u32 rx_h_len)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_AKE_H_PRIME;
+	tci->cmd_body.cmd_hdcp_ake_h_prime.rx_h_len = rx_h_len;
+
+	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.rtx, rtx, HDCP_2_2_RTX_LEN);
+	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.rrx, rrx, HDCP_2_2_RRX_LEN);
+	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.rx_caps, rx_caps, HDCP_2_2_RXCAPS_LEN);
+	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.tx_caps, tx_caps, HDCP_2_2_TXCAPS_LEN);
+	memcpy(tci->cmd_body.cmd_hdcp_ake_h_prime.rx_h, rx_h, rx_h_len);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_AKE_H_PRIME);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	tci = (struct tci_t *)dp_tee_priv->resp_buf;
+	return tci->return_code;
+}
+
+int tee_ake_paring(struct mtk_hdcp_info *hdcp_info, u8 *rx_ekm)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_AKE_PARING;
+	memcpy(tci->cmd_body.cmd_hdcp_ake_paring.ekm, rx_ekm, HDCP_2_2_E_KH_KM_LEN);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_AKE_PARING);
+	if (rc != 0)
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+
+	return rc;
+}
+
+int tee_lc_l_prime(struct mtk_hdcp_info *hdcp_info, u8 *rn, u8 *rx_l, u32 len)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_LC_L_PRIME;
+	memcpy(tci->cmd_body.cmd_hdcp_lc_l_prime.rn, rn, HDCP_2_2_RN_LEN);
+	tci->cmd_body.cmd_hdcp_lc_l_prime.rx_l_len = len;
+	memcpy(tci->cmd_body.cmd_hdcp_lc_l_prime.rx_l, rx_l, len);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_LC_L_PRIME);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	tci = (struct tci_t *)dp_tee_priv->resp_buf;
+	return tci->return_code;
+}
+
+int tee_ske_enc_ks(struct mtk_hdcp_info *hdcp_info, u8 *riv, u8 *eks)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+	u8 *share_buffer = NULL;
+
+	/* Copy parameters */
+	tci->command_id = CMD_SKE_CAL_EKS;
+	memcpy(tci->cmd_body.cmd_hdcp_ske_eks.riv, riv, HDCP_2_2_RIV_LEN);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH + 16, CMD_SKE_CAL_EKS);
+	if (rc != 0)
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+
+	share_buffer = (u8 *)dp_tee_priv->resp_buf;
+	memcpy(eks, share_buffer + TCI_LENGTH, 16);
+
+	return rc;
+}
+
+int tee_hdcp2_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
+				u8 *crypto_param, u32 param_len, u8 *rx_v, u8 *tx_v)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+	u8 *share_buffer = NULL;
+
+	/* Copy parameters */
+	tci->command_id = CMD_COMPARE_V2;
+	tci->cmd_body.cmd_hdcp_compare.rx_val_len = 16;
+	tci->cmd_body.cmd_hdcp_compare.param_len = param_len;
+	memcpy(tci->cmd_body.cmd_hdcp_compare.rx_val, rx_v, 16);
+	memcpy(tci->cmd_body.cmd_hdcp_compare.param, crypto_param, param_len);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_COMPARE_V2);
+	if (rc != 0) {
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	share_buffer = (u8 *)dp_tee_priv->resp_buf;
+	memcpy(tx_v, share_buffer + TCI_LENGTH, 16);
+
+	return rc;
+}
+
+int tee_hdcp2_compute_compare_m(struct mtk_hdcp_info *hdcp_info,
+				u8 *crypto_param, u32 param_len, u8 *rx_m)
+{
+	int rc;
+	struct dp_tee_private *dp_tee_priv = hdcp_info->g_dp_tee_priv;
+	struct tci_t *tci = (struct tci_t *)dp_tee_priv->shm->kaddr;
+
+	/* Copy parameters */
+	tci->command_id = CMD_COMPARE_M;
+	tci->cmd_body.cmd_hdcp_compare.rx_val_len = HDCP_2_2_MPRIME_LEN;
+	tci->cmd_body.cmd_hdcp_compare.param_len = param_len;
+	memcpy(tci->cmd_body.cmd_hdcp_compare.rx_val, rx_m, HDCP_2_2_MPRIME_LEN);
+	memcpy(tci->cmd_body.cmd_hdcp_compare.param, crypto_param, param_len);
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_COMPARE_M);
+	if (rc != 0)
+		TLCERR("tee_op_send failed, error=%x\n", rc);
+
+	return rc;
+}
diff --git a/drivers/gpu/drm/mediatek/tlc_dp_hdcp.h b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.h
new file mode 100644
index 000000000000..493d3c51a7a0
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.h
@@ -0,0 +1,414 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019-2024 MediaTek Inc.
+ */
+
+#ifndef _TLC_DP_HDCP_H_
+#define _TLC_DP_HDCP_H_
+
+#include <linux/printk.h>
+#include <linux/tee_drv.h>
+#include <linux/uuid.h>
+#include <linux/types.h>
+#include <linux/sched/clock.h>
+#include <drm/display/drm_dp_helper.h>
+#include "tci.h"
+
+#define TLCINFO(string, args...) pr_info("[TLC_HDCP]info: "string, ##args)
+#define TLCERR(string, args...) pr_info("[TLC_HDCP]line:%d,err:%s:"string,\
+	__LINE__, __func__, ##args)
+
+#define DPTXHDCPFUNC(fmt, arg...)		\
+	pr_info("[DPTXHDCP][%s line:%d]"pr_fmt(fmt), __func__, __LINE__, ##arg)
+#define DPTXHDCPMSG(fmt, arg...)                                  \
+		pr_info("[DPTXHDCP]"pr_fmt(fmt), ##arg)
+#define DPTXHDCPERR(fmt, arg...)                                  \
+		pr_err("[DPTXHDCP]"pr_fmt(fmt), ##arg)
+
+#define RET_SUCCESS 0
+
+/**
+ * hdcp version definitions
+ */
+#define HDCP_NONE                0x0 // No HDCP supported, no secure data path
+#define HDCP_V1                  0x1 // HDCP version 1.0
+#define HDCP_V2                  0x2 // HDCP version 2.0 Type 1
+#define HDCP_V2_1                0x3 // HDCP version 2.1 Type 1
+#define HDCP_V2_2                0x4 // HDCP version 2.2 Type 1
+#define HDCP_V2_3                0x5 // HDCP version 2.3 Type 1
+
+/* Local display only(content required version use only) */
+#define HDCP_LOCAL_DISPLAY_ONLY  0xf
+#define HDCP_NO_DIGITAL_OUTPUT   0xff // No digital output
+#define HDCP_DEFAULT             HDCP_NO_DIGITAL_OUTPUT // Default value
+
+#define HDCP_VERSION_1X 1
+#define HDCP_VERSION_2X 2
+
+/* max. buffer size supported by dp  */
+#define MAX_COMMAND_SIZE       4096
+#define MAX_RESPONSE_SIZE      4096
+
+#define HDCP1X_REP_MAXDEVS 128
+#define HDCP1X_V_LEN 20
+#define HDCP1X_B_INFO_LEN 2
+
+#define HDCP2_K_LEN 2
+#define HDCP2_STREAMID_TYPE_LEN 2
+
+enum HDCP_RESULT {
+	AUTH_ZERO = 0,
+	AUTH_PREPARE = 1,
+	AUTH_INIT = 2,
+	AUTH_PASS = 3,
+	AUTH_FAIL = 4,
+};
+
+struct dp_header {
+	__be16 tag;
+	__be32 length;
+	union {
+		__be32 ordinal;
+		__be32 return_code;
+	};
+} __packed;
+
+/**
+ * struct dp_tee_private - fTPM's private data
+ * @session:  dp TA session identifier.
+ * @resp_len: cached response buffer length.
+ * @resp_buf: cached response buffer.
+ * @ctx:      TEE context handler.
+ * @shm:      Memory pool shared with fTPM TA in TEE.
+ */
+struct dp_tee_private {
+	u32 session;
+	size_t resp_len;
+	u8 resp_buf[MAX_RESPONSE_SIZE];
+	struct tee_context *ctx;
+	struct tee_shm *shm;
+};
+
+struct hdcp2_info_tx {
+	struct hdcp2_ake_init ake_init;
+	struct hdcp2_ake_no_stored_km no_stored_km;
+	struct hdcp2_ske_send_eks send_eks;
+	struct hdcp2_lc_init lc_init;
+	struct hdcp2_rep_stream_manage stream_manage;
+	struct hdcp2_rep_send_ack send_ack;
+	struct hdcp2_tx_caps tx_caps;
+	u8 k[HDCP2_K_LEN];
+	u8 stream_id_type[HDCP2_STREAMID_TYPE_LEN];
+};
+
+struct hdcp2_info_rx {
+	struct hdcp2_cert_rx cert_rx;
+	struct hdcp2_ake_send_cert send_cert;
+	struct hdcp2_rep_send_receiverid_list receiverid_list;
+	struct hdcp2_ake_send_pairing_info pairing_info;
+	struct hdcp2_rep_stream_ready stream_ready;
+	struct hdcp2_ake_send_hprime send_hprime;
+	struct hdcp2_lc_send_lprime send_lprime;
+};
+
+struct hdcp2_handler {
+	u8 main_state;
+	u8 sub_state;
+	u8 down_stream_dev_cnt;
+	u8 hdcp_rx_ver;
+	bool send_ake_init:1;
+	bool get_recv_id_list:1;
+	bool stored_km:1;
+	bool send_lc_init:1;
+	bool send_ack:1;
+	bool sink_is_repeater:1;
+	bool recv_msg:1;
+	bool send_pair:1;
+	u32 seq_num_v_cnt;
+	u32 retry_cnt;
+};
+
+struct hdcp1x_info {
+	bool enable;
+	bool repeater;
+	bool r0_read;
+	bool ksv_ready;
+	bool max_cascade;
+	bool max_devs;
+	u8 b_status;
+	u8 b_ksv[DRM_HDCP_KSV_LEN];
+	u8 a_ksv[DRM_HDCP_KSV_LEN];
+	u8 v[HDCP1X_V_LEN];
+	u8 b_info[HDCP1X_B_INFO_LEN];
+	u8 ksvfifo[DRM_HDCP_KSV_LEN * (HDCP1X_REP_MAXDEVS - 1)];
+	u8 device_count;
+	u8 retry_count;
+	int main_states;
+	int sub_states;
+};
+
+struct hdcp2_info {
+	struct hdcp2_info_tx hdcp_tx;
+	struct hdcp2_info_rx hdcp_rx;
+	struct hdcp2_ake_stored_km ake_stored_km;
+	struct hdcp2_handler hdcp_handler;
+	bool enable;
+	bool repeater;
+	bool read_certrx;
+	bool read_h_prime;
+	bool read_pairing;
+	bool read_l_prime;
+	bool ks_exchange_done;
+	bool read_v_prime;
+	u8 retry_count;
+	u8 device_count;
+	u8 stream_id_type;
+};
+
+struct mtk_hdcp_info {
+	u8 auth_status;
+	bool g_init;
+	u32 hdcp_content_type;
+	u32 content_protection;
+	struct dp_tee_private *g_dp_tee_priv;
+	struct hdcp1x_info hdcp1x_info;
+	struct hdcp2_info hdcp2_info;
+};
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ *Description:
+ *  A device connect and do some initializations.
+ *
+ *Input:
+ *  version: HDCP version
+ *
+ *Returns:
+ *  TEEC_SUCCESS success*
+ */
+int tee_add_device(struct mtk_hdcp_info *hdcp_info, u32 version);
+
+/*
+ *Description:
+ *  Device disconnect.
+ *
+ *Returns:
+ *  N/A
+ */
+void tee_remove_device(struct mtk_hdcp_info *hdcp_info);
+
+/*
+ *Description:
+ *  Clearing paring info.
+ *
+ *Returns:
+ *  TEEC_SUCCESS success*
+ */
+int tee_clear_paring(struct mtk_hdcp_info *hdcp_info);
+
+/*
+ *Description:
+ *  Calculate Km base on Bksv and write it to HW.
+ *
+ *Input:
+ *  bksv[5] input
+ *
+ *Returns:
+ *  TEEC_SUCCESS success
+ */
+int tee_calculate_lm(struct mtk_hdcp_info *hdcp_info, u8 *bksv);
+
+/*
+ *Description:
+ *  Get Aksv from TEE.
+ *
+ *Output:
+ *  aksv[5]
+ *
+ *Returns:
+ *  TEEC_SUCCESS success
+ */
+int tee_get_aksv(struct mtk_hdcp_info *hdcp_info, u8 *aksv);
+
+/*
+ *Description:
+ *  Get r0 from HW and compare to rx_r0.
+ *
+ *Parameters:
+ *  r0[len] input
+ *
+ *Returns:
+ *  TEEC_SUCCESS success
+ */
+int tee_compare_r0(struct mtk_hdcp_info *hdcp_info, u8 *r0, u32 len);
+
+/*
+ *Description:
+ *  Compute and compare v value.
+ *
+ *Input:
+ *  crypto_param[param_len] params used to calculate
+ *  rx_v[20] v value from rx
+ *
+ *Returns:
+ *  RET_COMPARE_PASS verify pass
+ */
+int tee_hdcp1x_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
+				 u8 *crypto_param, u32 param_len, u8 *rx_v);
+
+/*
+ *Description:
+ *  Write An to HW.
+ *
+ *Input:
+ *  an_code[8]
+ *
+ *Returns:
+ *  TEEC_SUCCESS success
+ */
+int tee_hdcp1x_set_tx_an(struct mtk_hdcp_info *hdcp_info, u8 *an_code);
+
+/*
+ *Description:
+ *  Write RST to HW.
+ *
+ *Returns:
+ *  TEEC_SUCCESS success
+ */
+int tee_hdcp1x_soft_rst(struct mtk_hdcp_info *hdcp_info);
+int tee_hdcp2_soft_rst(struct mtk_hdcp_info *hdcp_info);
+
+/*
+ *Description:
+ *  Set enable or disable to HW.
+ *
+ *Returns:
+ *  TEEC_SUCCESS success
+ */
+int tee_hdcp_enable_encrypt(struct mtk_hdcp_info *hdcp_info, bool enable, u8 version);
+
+/*
+ *Description:
+ *  AKE cetificate verify.
+ *
+ *Input:
+ *  certificate[522]: cert use to calculate
+ *output:
+ *  stored: whether be stored before
+ *  out_m[16]
+ *  out_ekm[16]
+ *
+ *Returns:
+ *  TEEC_SUCCESS success*
+ */
+int tee_ake_certificate(struct mtk_hdcp_info *hdcp_info,
+			u8 *certificate, bool *stored, u8 *out_m, u8 *out_ekm);
+
+/*
+ *Description:
+ *  Encrypt km.
+ *
+ *Output:
+ *  ekm[128]: encrypted km
+ *
+ *Returns:
+ *  TEEC_SUCCESS success*
+ */
+int tee_enc_rsaes_oaep(struct mtk_hdcp_info *hdcp_info, u8 *ekm);
+
+/*
+ *Description:
+ *  Calculate h prime and compare to rx_h
+ *
+ *Input:
+ *  rtx[8]
+ *  rrx[8]
+ *  rx_caps[3]
+ *  tx_caps[3]
+ *  rx_h[rx_h_len]
+ *
+ *Returns:
+ *  RET_COMPARE_PASS: compare pass
+ */
+int tee_ake_h_prime(struct mtk_hdcp_info *hdcp_info,
+		    u8 *rtx, u8 *rrx, u8 *rx_caps, u8 *tx_caps, u8 *rx_h, u32 rx_h_len);
+
+/*
+ *Description:
+ *  Store paring info.
+ *
+ *Input:
+ *  rx_ekm[16]
+ *
+ *Returns:
+ *  TEEC_SUCCESS success*
+ */
+int tee_ake_paring(struct mtk_hdcp_info *hdcp_info, u8 *rx_ekm);
+
+/*
+ *Description:
+ *  Calculate l prime and compare.
+ *
+ *Input:
+ *  rn[8]
+ *  rx_l[len]
+ *
+ *Returns:
+ *  RET_COMPARE_PASS compare pass
+ */
+int tee_lc_l_prime(struct mtk_hdcp_info *hdcp_info, u8 *rn, u8 *rx_l, u32 len);
+
+/*
+ *Description:
+ *  Encrypt ks
+ *  Write contentkey and riv to hw
+ *
+ *Input:
+ *  riv[8]
+ *Output:
+ *  eks[16]
+ *
+ *Returns:
+ *  TEEC_SUCCESS success*
+ */
+int tee_ske_enc_ks(struct mtk_hdcp_info *hdcp_info, u8 *riv, u8 *eks);
+
+/*
+ *Description:
+ *  Calculate and compare v prime for repeater.
+ *
+ *Input:
+ *  crypto_param[param_len] params used to calculate
+ *  rx_v[16] v value from rx
+ *Output:
+ *  tx_v[16]
+ *
+ *Returns:
+ *  TEEC_SUCCESS success*
+ */
+int tee_hdcp2_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
+				u8 *crypto_param, u32 param_len, u8 *rx_v, u8 *tx_v);
+
+/*
+ *Description:
+ *  Calculate and compare m prime for repeater.
+ *
+ *Input:
+ *  crypto_param[param_len] params used to calculate
+ *  rx_m[32] m value from rx
+ *
+ *Returns:
+ *  RET_COMPARE_PASS verify pass
+ */
+int tee_hdcp2_compute_compare_m(struct mtk_hdcp_info *hdcp_info,
+				u8 *crypto_param, u32 param_len, u8 *rx_m);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TLC_DP_HDCP_H_ */