linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Add HDCP feature for DisplayPort
@ 2024-06-08 12:01 mac.shen
  2024-06-08 12:01 ` [PATCH v3 1/3] Subject: [PATCH] drm/mediatek/dp: Add tee client application for HDCP feature mac.shen
                   ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: mac.shen @ 2024-06-08 12:01 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, airlied, daniel, matthias.bgg,
	angelogioacchino.delregno, jitao.shi
  Cc: mac.shen, shuijing.li, linux-kernel, dri-devel, linux-mediatek,
	linux-arm-kernel

Add tee client application, HDCP 1.x and 2.x authentication for DisplayPort
to support the HDCP feature.

mac.shen (3):
  Subject: [PATCH] drm/mediatek/dp: Add tee client application for HDCP
    feature
  Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  Subject: [PATCH] drm/mediatek/dp: Add HDCP1.x feature for DisplayPort

 drivers/gpu/drm/mediatek/Makefile        |   7 +-
 drivers/gpu/drm/mediatek/mtk_dp.c        | 332 ++++++--
 drivers/gpu/drm/mediatek/mtk_dp.h        | 103 +++
 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c | 577 ++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h |  17 +
 drivers/gpu/drm/mediatek/mtk_dp_hdcp2.c  | 944 +++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dp_hdcp2.h  |  25 +
 drivers/gpu/drm/mediatek/mtk_dp_reg.h    |  11 +-
 drivers/gpu/drm/mediatek/mtk_dpi.c       |   3 +
 drivers/gpu/drm/mediatek/tci.h           | 143 ++++
 drivers/gpu/drm/mediatek/tlc_dp_hdcp.c   | 595 ++++++++++++++
 drivers/gpu/drm/mediatek/tlc_dp_hdcp.h   | 133 ++++
 12 files changed, 2805 insertions(+), 85 deletions(-)
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.h
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp2.c
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp2.h
 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

-- 
2.43.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v3 1/3] Subject: [PATCH] drm/mediatek/dp: Add tee client application for HDCP feature
  2024-06-08 12:01 [PATCH v3 0/3] Add HDCP feature for DisplayPort mac.shen
@ 2024-06-08 12:01 ` mac.shen
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
  2024-06-08 12:01 ` [PATCH v3 3/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP1.x " mac.shen
  2 siblings, 0 replies; 21+ messages in thread
From: mac.shen @ 2024-06-08 12:01 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, airlied, daniel, matthias.bgg,
	angelogioacchino.delregno, jitao.shi
  Cc: mac.shen, shuijing.li, linux-kernel, dri-devel, linux-mediatek,
	linux-arm-kernel

Add tee client application which will be used for
HDCP 1.x and 2.x authentication in DisplayPort.

Changes in v3:
- remove useless define
- refine the return value
- remove the define which control the log output
- remove the struct hdcp2_handler for HDCP 2.X
- refine the struct for the HDCP information
per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek
/patch/20240205055055.25340-2-mac.shen@mediatek.com/

Signed-off-by: mac.shen <mac.shen@mediatek.com>
---
 drivers/gpu/drm/mediatek/Makefile      |   5 +-
 drivers/gpu/drm/mediatek/tci.h         | 143 ++++++
 drivers/gpu/drm/mediatek/tlc_dp_hdcp.c | 595 +++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/tlc_dp_hdcp.h | 133 ++++++
 4 files changed, 875 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 32a2ed6c0cfe..f27ddfbd2e12 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -27,4 +27,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..48710ce5d391
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/tci.h
@@ -0,0 +1,143 @@
+/* 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.x */
+#define CMD_CALCULATE_LM        11
+#define CMD_COMPARE_R0          12
+#define CMD_COMPARE_V1          13
+#define CMD_GET_AKSV            14
+
+/* V2.x */
+#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_SKE_CAL_EKS         26
+#define CMD_COMPARE_V2          27
+#define CMD_COMPARE_M           28
+
+#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
+
+/* 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..8ae0548ae022
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.c
@@ -0,0 +1,595 @@
+// 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);
+
+/* Send dp commands through the TEE shared memory */
+static int dp_tee_op_send(struct dp_tee_private *dp_tee_priv, size_t len, u32 cmd_id)
+{
+	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) {
+		pr_err("[TLC_HDCP] Len %zd exceeds MAX_COMMAND_SIZE supported by dp TA\n", len);
+		return -EINVAL;
+	}
+
+	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) {
+		pr_err("[TLC_HDCP] rc:%d, invoke error:0x%x\n", rc, transceive_args.ret);
+		return -EBUSY;
+	}
+
+	temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs);
+	if (IS_ERR(temp_buf)) {
+		pr_err("[TLC_HDCP] tee_shm_get_va failed for receive\n");
+		return -ENOMEM;
+	}
+
+	/* 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.
+ *
+ * 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;
+}
+
+int tee_add_device(struct mtk_hdcp_info *hdcp_info, u32 version)
+{
+	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)
+		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)) {
+		pr_err("[TLC_HDCP] tee_client_open_context failed\n");
+		rc = PTR_ERR(dp_tee_priv->ctx);
+		goto free_priv;
+	}
+
+	/* 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) {
+		pr_err("[TLC_HDCP] 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)) {
+		pr_err("[TLC_HDCP] tee_shm_alloc_kernel_buf failed\n");
+		rc = -ENOMEM;
+		goto out_shm_alloc;
+	}
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error:%x\n", rc);
+		tee_remove_device(hdcp_info);
+		return rc;
+	}
+
+	hdcp_info->g_init = true;
+
+	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)
+{
+	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;
+
+	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)
+		pr_err("[TLC_HDCP] 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)
+{
+	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;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/* Write An to HW */
+int tee_hdcp1x_set_tx_an(struct mtk_hdcp_info *hdcp_info, u8 *an_code)
+{
+	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;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int tee_hdcp_enable_encrypt(struct mtk_hdcp_info *hdcp_info, bool enable, u8 version)
+{
+	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;
+
+	/* 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;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int tee_hdcp1x_soft_rst(struct mtk_hdcp_info *hdcp_info)
+{
+	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;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int tee_hdcp2_soft_rst(struct mtk_hdcp_info *hdcp_info)
+{
+	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;
+
+	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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/** V1.X **/
+int tee_get_aksv(struct mtk_hdcp_info *hdcp_info, u8 *aksv)
+{
+	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;
+	struct tci_t *tci_resp;
+	int rc;
+
+	/* Copy parameters */
+	tci->command_id = CMD_GET_AKSV;
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_GET_AKSV);
+	if (rc) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	tci_resp = (struct tci_t *)dp_tee_priv->resp_buf;
+	memcpy(aksv, tci_resp->cmd_body.cmd_hdcp_get_aksv.aksv, DRM_HDCP_KSV_LEN);
+
+	return 0;
+}
+
+/* Calculate Km base on Bksv and write it to HW */
+int tee_calculate_lm(struct mtk_hdcp_info *hdcp_info, u8 *bksv)
+{
+	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;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/*  Get r0 from HW and compare to rx_r0 */
+int tee_compare_r0(struct mtk_hdcp_info *hdcp_info, u8 *r0, u32 len)
+{
+	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;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/* Compute and compare v value */
+int tee_hdcp1x_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
+				 u8 *crypto_param, u32 param_len, u8 *rx_v)
+{
+	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;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/** V2.X **/
+int tee_ake_certificate(struct mtk_hdcp_info *hdcp_info,
+			u8 *certificate, bool *stored, u8 *out_m, u8 *out_ekm)
+{
+	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;
+	struct tci_t *tci_resp;
+	int rc;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	pr_info("[TLC_HDCP] verify signature: result %d\n", rc);
+	tci_resp = (struct tci_t *)dp_tee_priv->resp_buf;
+	*stored = tci_resp->cmd_body.cmd_hdcp_ake_certificate.stored;
+	memcpy(out_m, tci_resp->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_resp->cmd_body.cmd_hdcp_ake_certificate.ekm, HDCP_2_2_E_KH_KM_LEN);
+
+	return 0;
+}
+
+/* Encrypt km */
+int tee_enc_rsaes_oaep(struct mtk_hdcp_info *hdcp_info, u8 *ekm)
+{
+	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;
+	struct tci_t *tci_resp;
+	int rc;
+
+	/* Copy parameters */
+	tci->command_id = CMD_ENC_KM;
+
+	rc = dp_tee_op_send(dp_tee_priv, TCI_LENGTH, CMD_ENC_KM);
+	if (rc) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	tci_resp = (struct tci_t *)dp_tee_priv->resp_buf;
+	memcpy(ekm, tci_resp->cmd_body.cmd_hdcp_enc_km.enc_km, HDCP_2_2_E_KPUB_KM_LEN);
+
+	return 0;
+}
+
+/* Calculate h prime and compare to rx_h */
+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)
+{
+	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;
+	struct tci_t *tci_resp;
+	int rc;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	tci_resp = (struct tci_t *)dp_tee_priv->resp_buf;
+
+	return tci_resp->return_code;
+}
+
+/* Store paring info */
+int tee_ake_paring(struct mtk_hdcp_info *hdcp_info, u8 *rx_ekm)
+{
+	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;
+
+	/* 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)
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+
+	return 0;
+}
+
+/* Calculate l prime and compare */
+int tee_lc_l_prime(struct mtk_hdcp_info *hdcp_info, u8 *rn, u8 *rx_l, u32 len)
+{
+	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;
+	struct tci_t *tci_resp;
+	int rc;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+		return rc;
+	}
+
+	tci_resp = (struct tci_t *)dp_tee_priv->resp_buf;
+
+	return tci_resp->return_code;
+}
+
+int tee_ske_enc_ks(struct mtk_hdcp_info *hdcp_info, u8 *riv, u8 *eks)
+{
+	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;
+	int rc;
+
+	/* 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)
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+
+	share_buffer = (u8 *)dp_tee_priv->resp_buf;
+	memcpy(eks, share_buffer + TCI_LENGTH, 16);
+
+	return 0;
+}
+
+/* Calculate and compare v prime for repeater */
+int tee_hdcp2_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
+				u8 *crypto_param, u32 param_len, u8 *rx_v, u8 *tx_v)
+{
+	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;
+	int rc;
+
+	/* 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) {
+		pr_err("[TLC_HDCP] 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 0;
+}
+
+/* Calculate and compare m prime for repeater */
+int tee_hdcp2_compute_compare_m(struct mtk_hdcp_info *hdcp_info,
+				u8 *crypto_param, u32 param_len, u8 *rx_m)
+{
+	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;
+
+	/* 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)
+		pr_err("[TLC_HDCP] tee_op_send failed, error=%x\n", rc);
+
+	return 0;
+}
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..871d3fec5835
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/tlc_dp_hdcp.h
@@ -0,0 +1,133 @@
+/* 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"
+
+/* 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_3                0x5 /* HDCP version 2.3 Type 1 */
+
+/* Max buffer size supported by dp */
+#define MAX_COMMAND_SIZE       4096
+#define MAX_RESPONSE_SIZE      MAX_COMMAND_SIZE
+
+#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_INIT = 2,
+	AUTH_PASS = 3,
+	AUTH_FAIL = 4,
+};
+
+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 recvid_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 hdcp1x_info {
+	bool capable;
+	bool repeater;
+	u8 device_count;
+	u8 v[HDCP1X_V_LEN];
+	u8 b_ksv[DRM_HDCP_KSV_LEN];
+	u8 a_ksv[DRM_HDCP_KSV_LEN];
+	u8 b_info[HDCP1X_B_INFO_LEN];
+	u8 ksvfifo[DRM_HDCP_KSV_LEN * (HDCP1X_REP_MAXDEVS - 1)];
+};
+
+struct hdcp2_info {
+	bool capable;
+	bool repeater;
+	bool stored_km;
+	u8 device_count;
+	u8 stream_id_type;
+	u32 seq_num_v_cnt;
+	atomic_t cp_irq;
+	int cp_irq_cached;
+	wait_queue_head_t cp_irq_queue;
+	struct hdcp2_info_tx hdcp_tx;
+	struct hdcp2_info_rx hdcp_rx;
+	struct hdcp2_ake_stored_km ake_stored_km;
+};
+
+struct mtk_hdcp_info {
+	bool g_init;
+	u8 auth_status;
+	u8 auth_version;
+	u32 hdcp_content_type;
+	u32 content_protection;
+	struct hdcp2_info hdcp2_info;
+	struct hdcp1x_info hdcp1x_info;
+	struct dp_tee_private *g_dp_tee_priv;
+};
+
+int tee_add_device(struct mtk_hdcp_info *hdcp_info, u32 version);
+void tee_remove_device(struct mtk_hdcp_info *hdcp_info);
+int tee_clear_paring(struct mtk_hdcp_info *hdcp_info);
+int tee_calculate_lm(struct mtk_hdcp_info *hdcp_info, u8 *bksv);
+int tee_get_aksv(struct mtk_hdcp_info *hdcp_info, u8 *aksv);
+int tee_compare_r0(struct mtk_hdcp_info *hdcp_info, u8 *r0, u32 len);
+int tee_hdcp1x_compute_compare_v(struct mtk_hdcp_info *hdcp_info,
+				 u8 *crypto_param, u32 param_len, u8 *rx_v);
+int tee_hdcp1x_set_tx_an(struct mtk_hdcp_info *hdcp_info, u8 *an_code);
+int tee_hdcp1x_soft_rst(struct mtk_hdcp_info *hdcp_info);
+int tee_hdcp2_soft_rst(struct mtk_hdcp_info *hdcp_info);
+int tee_hdcp_enable_encrypt(struct mtk_hdcp_info *hdcp_info, bool enable, u8 version);
+int tee_ake_certificate(struct mtk_hdcp_info *hdcp_info,
+			u8 *certificate, bool *stored, u8 *out_m, u8 *out_ekm);
+int tee_enc_rsaes_oaep(struct mtk_hdcp_info *hdcp_info, u8 *ekm);
+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 tee_ake_paring(struct mtk_hdcp_info *hdcp_info, u8 *rx_ekm);
+int tee_lc_l_prime(struct mtk_hdcp_info *hdcp_info, u8 *rn, u8 *rx_l, u32 len);
+
+int tee_ske_enc_ks(struct mtk_hdcp_info *hdcp_info, u8 *riv, u8 *eks);
+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 tee_hdcp2_compute_compare_m(struct mtk_hdcp_info *hdcp_info,
+				u8 *crypto_param, u32 param_len, u8 *rx_m);
+#endif /* _TLC_DP_HDCP_H_ */
-- 
2.43.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 [PATCH v3 0/3] Add HDCP feature for DisplayPort mac.shen
  2024-06-08 12:01 ` [PATCH v3 1/3] Subject: [PATCH] drm/mediatek/dp: Add tee client application for HDCP feature mac.shen
@ 2024-06-08 12:01 ` mac.shen
  2024-07-18  5:41   ` CK Hu (胡俊光)
                     ` (14 more replies)
  2024-06-08 12:01 ` [PATCH v3 3/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP1.x " mac.shen
  2 siblings, 15 replies; 21+ messages in thread
From: mac.shen @ 2024-06-08 12:01 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, airlied, daniel, matthias.bgg,
	angelogioacchino.delregno, jitao.shi
  Cc: mac.shen, shuijing.li, linux-kernel, dri-devel, linux-mediatek,
	linux-arm-kernel

Changes in v3:
- refine the function to get system time
- refine the flow to do HDCP with content type and
  protection value which set by user space
- refine the flow to update content protection
- refine the flow to do HDCP2.x authentication
per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek
/patch/20240205055055.25340-3-mac.shen@mediatek.com/

Signed-off-by: mac.shen <mac.shen@mediatek.com>
---
 drivers/gpu/drm/mediatek/Makefile       |   1 +
 drivers/gpu/drm/mediatek/mtk_dp.c       | 321 +++++---
 drivers/gpu/drm/mediatek/mtk_dp.h       | 103 +++
 drivers/gpu/drm/mediatek/mtk_dp_hdcp2.c | 944 ++++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dp_hdcp2.h |  25 +
 drivers/gpu/drm/mediatek/mtk_dp_reg.h   |   8 +-
 drivers/gpu/drm/mediatek/mtk_dpi.c      |   3 +
 7 files changed, 1321 insertions(+), 84 deletions(-)
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp.h
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp2.c
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp2.h

diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index f27ddfbd2e12..19b7625ae573 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -28,6 +28,7 @@ mediatek-drm-hdmi-objs := mtk_cec.o \
 obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
 
 mtk-dp-objs := tlc_dp_hdcp.o \
+		  mtk_dp_hdcp2.o \
 		  mtk_dp.o
 
 obj-$(CONFIG_DRM_MEDIATEK_DP) += mtk-dp.o
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 536366956447..12854a04622f 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2019-2022 MediaTek Inc.
+ * Copyright (c) 2019-2024 MediaTek Inc.
  * Copyright (c) 2022 BayLibre
  */
 
@@ -8,13 +8,13 @@
 #include <drm/display/drm_dp.h>
 #include <drm/display/drm_dp_helper.h>
 #include <drm/drm_atomic_helper.h>
-#include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/display/drm_hdcp_helper.h>
 #include <linux/arm-smccc.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -30,10 +30,10 @@
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/soc/mediatek/mtk_sip_svc.h>
-#include <sound/hdmi-codec.h>
-#include <video/videomode.h>
 
+#include "mtk_dp.h"
 #include "mtk_dp_reg.h"
+#include "mtk_dp_hdcp2.h"
 
 #define MTK_DP_SIP_CONTROL_AARCH32	MTK_SIP_SMC_CMD(0x523)
 #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE	(BIT(0) | BIT(5))
@@ -52,43 +52,6 @@
 #define MTK_DP_VERSION 0x11
 #define MTK_DP_SDP_AUI 0x4
 
-enum {
-	MTK_DP_CAL_GLB_BIAS_TRIM = 0,
-	MTK_DP_CAL_CLKTX_IMPSE,
-	MTK_DP_CAL_LN_TX_IMPSEL_PMOS_0,
-	MTK_DP_CAL_LN_TX_IMPSEL_PMOS_1,
-	MTK_DP_CAL_LN_TX_IMPSEL_PMOS_2,
-	MTK_DP_CAL_LN_TX_IMPSEL_PMOS_3,
-	MTK_DP_CAL_LN_TX_IMPSEL_NMOS_0,
-	MTK_DP_CAL_LN_TX_IMPSEL_NMOS_1,
-	MTK_DP_CAL_LN_TX_IMPSEL_NMOS_2,
-	MTK_DP_CAL_LN_TX_IMPSEL_NMOS_3,
-	MTK_DP_CAL_MAX,
-};
-
-struct mtk_dp_train_info {
-	bool sink_ssc;
-	bool cable_plugged_in;
-	/* link_rate is in multiple of 0.27Gbps */
-	int link_rate;
-	int lane_count;
-	unsigned int channel_eq_pattern;
-};
-
-struct mtk_dp_audio_cfg {
-	bool detect_monitor;
-	int sad_count;
-	int sample_rate;
-	int word_length_bits;
-	int channels;
-};
-
-struct mtk_dp_info {
-	enum dp_pixelformat format;
-	struct videomode vm;
-	struct mtk_dp_audio_cfg audio_cur_cfg;
-};
-
 struct mtk_dp_efuse_fmt {
 	unsigned short idx;
 	unsigned short shift;
@@ -98,44 +61,6 @@ struct mtk_dp_efuse_fmt {
 	unsigned short default_val;
 };
 
-struct mtk_dp {
-	bool enabled;
-	bool need_debounce;
-	int irq;
-	u8 max_lanes;
-	u8 max_linkrate;
-	u8 rx_cap[DP_RECEIVER_CAP_SIZE];
-	u32 cal_data[MTK_DP_CAL_MAX];
-	u32 irq_thread_handle;
-	/* irq_thread_lock is used to protect irq_thread_handle */
-	spinlock_t irq_thread_lock;
-
-	struct device *dev;
-	struct drm_bridge bridge;
-	struct drm_bridge *next_bridge;
-	struct drm_connector *conn;
-	struct drm_device *drm_dev;
-	struct drm_dp_aux aux;
-
-	const struct mtk_dp_data *data;
-	struct mtk_dp_info info;
-	struct mtk_dp_train_info train_info;
-
-	struct platform_device *phy_dev;
-	struct phy *phy;
-	struct regmap *regs;
-	struct timer_list debounce_timer;
-
-	/* For audio */
-	bool audio_enable;
-	hdmi_codec_plugged_cb plugged_cb;
-	struct platform_device *audio_pdev;
-
-	struct device *codec_dev;
-	/* protect the plugged_cb as it's used in both bridge ops and audio */
-	struct mutex update_plugged_status_lock;
-};
-
 struct mtk_dp_data {
 	int bridge_type;
 	unsigned int smc_cmd;
@@ -319,12 +244,24 @@ static struct regmap_config mtk_dp_regmap_config = {
 	.name = "mtk-dp-registers",
 };
 
+u64 mtk_dp_get_system_time(void)
+{
+	return ktime_get_mono_fast_ns();
+}
+
+u64 mtk_dp_get_time_diff(u64 pre_time)
+{
+	u64 post_time = mtk_dp_get_system_time();
+
+	return (post_time - pre_time);
+}
+
 static struct mtk_dp *mtk_dp_from_bridge(struct drm_bridge *b)
 {
 	return container_of(b, struct mtk_dp, bridge);
 }
 
-static u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
+u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
 {
 	u32 read_val;
 	int ret;
@@ -350,8 +287,8 @@ static int mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
 	return ret;
 }
 
-static int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset,
-			      u32 val, u32 mask)
+int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset,
+		       u32 val, u32 mask)
 {
 	int ret = regmap_update_bits(mtk_dp->regs, offset, mask, val);
 
@@ -1865,11 +1802,200 @@ static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
 	mtk_dp_digital_sw_reset(mtk_dp);
 }
 
+static void mtk_dp_check_sink_esi(struct mtk_dp *mtk_dp)
+{
+	u8 clear_cp_irq = BIT(2);
+
+	/* hdcp 1.x do not need irq */
+	if (mtk_dp->hdcp_info.hdcp2_info.capable) {
+		dp_tx_hdcp2x_irq(&mtk_dp->hdcp_info);
+		drm_dp_dpcd_write(&mtk_dp->aux,
+				  DP_DEVICE_SERVICE_IRQ_VECTOR, &clear_cp_irq, 0x1);
+	}
+}
+
+static int mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
+{
+	ssize_t ret;
+	u8 sink_count;
+	u8 sink_count_200;
+
+	ret = drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT_ESI, &sink_count);
+	if (ret < 0) {
+		drm_info(mtk_dp->drm_dev, "Read sink count failed: %zd\n", ret);
+		return ret;
+	}
+
+	ret = drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT, &sink_count_200);
+	if (ret < 0) {
+		drm_info(mtk_dp->drm_dev,
+			 "Read DP_SINK_COUNT_ESI failed: %zd\n", ret);
+		return ret;
+	}
+
+	mtk_dp_check_sink_esi(mtk_dp);
+
+	return 0;
+}
+
+static void mtk_dp_hdcp_get_info(struct mtk_dp *mtk_dp)
+{
+	dp_tx_hdcp2x_get_info(&mtk_dp->hdcp_info);
+}
+
+static void mtk_dp_hdcp_disable(struct mtk_dp *mtk_dp)
+{
+	mutex_lock(&mtk_dp->hdcp_mutex);
+
+	if (mtk_dp->hdcp_info.auth_status == AUTH_ZERO)
+		goto end;
+
+	if (mtk_dp->hdcp_info.auth_version == HDCP_VERSION_2X)
+		dp_tx_hdcp2x_disabel(&mtk_dp->hdcp_info);
+
+end:
+	cancel_delayed_work_sync(&mtk_dp->check_work);
+	mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_DESIRED);
+
+	mutex_unlock(&mtk_dp->hdcp_mutex);
+}
+
+static void mtk_dp_hdcp_check_work(struct work_struct *work)
+{
+	struct mtk_dp *mtk_dp = container_of(to_delayed_work(work),
+		struct mtk_dp, check_work);
+
+	if (mtk_dp->hdcp_info.auth_version == HDCP_VERSION_2X &&
+	    (!dp_tx_hdcp2x_check_link(&mtk_dp->hdcp_info))) {
+		schedule_delayed_work(&mtk_dp->check_work, DRM_HDCP2_CHECK_PERIOD_MS);
+	}
+}
+
+static void mtk_dp_hdcp_handle(struct work_struct *data)
+{
+	struct mtk_dp *mtk_dp = container_of(data, struct mtk_dp, hdcp_work);
+	unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
+	int ret = -EINVAL;
+
+	mutex_lock(&mtk_dp->hdcp_mutex);
+
+	if (mtk_dp->hdcp_info.auth_status == AUTH_PASS)
+		goto end;
+
+	mtk_dp_hdcp_get_info(mtk_dp);
+
+	if (mtk_dp->hdcp_info.hdcp2_info.capable) {
+		ret = dp_tx_hdcp2x_enable(&mtk_dp->hdcp_info);
+		if (!ret)
+			check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
+	}
+
+	if (!ret) {
+		schedule_delayed_work(&mtk_dp->check_work, check_link_interval);
+		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_ENABLED);
+	}
+
+end:
+	mutex_unlock(&mtk_dp->hdcp_mutex);
+}
+
+static void mtk_dp_hdcp_enable(struct mtk_dp *mtk_dp)
+{
+	if (!mtk_dp->train_info.cable_plugged_in || !mtk_dp->enabled)
+		return;
+
+	dev_info(mtk_dp->dev, "[HDCP] dp start HDCP work\n");
+	queue_work(mtk_dp->hdcp_workqueue, &mtk_dp->hdcp_work);
+}
+
+static void mtk_dp_hdcp_prop_work(struct work_struct *work)
+{
+	struct mtk_dp *mtk_dp;
+	struct drm_device *drm_dev;
+
+	mtk_dp = container_of(work, struct mtk_dp, prop_work);
+
+	if (!mtk_dp->conn) {
+		dev_err(mtk_dp->dev, "[HDCP] Connector is null\n");
+		return;
+	}
+
+	drm_dev = mtk_dp->conn->dev;
+
+	drm_modeset_lock(&drm_dev->mode_config.connection_mutex, NULL);
+
+	if (mtk_dp->hdcp_info.content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+		dev_info(mtk_dp->dev, "[HDCP] Update CP, content protection: %d, auth status:%d\n",
+			 mtk_dp->hdcp_info.content_protection, mtk_dp->hdcp_info.auth_status);
+
+		/* only update between ENABLED/DESIRED */
+		drm_hdcp_update_content_protection(mtk_dp->conn,
+						   mtk_dp->hdcp_info.content_protection);
+	}
+
+	drm_modeset_unlock(&drm_dev->mode_config.connection_mutex);
+}
+
+void mtk_dp_hdcp_update_value(struct mtk_dp *mtk_dp, u32 value)
+{
+	if (mtk_dp->hdcp_info.content_protection == value)
+		return;
+
+	mtk_dp->hdcp_info.content_protection = value;
+	if (mtk_dp->hdcp_info.content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+		return;
+
+	schedule_work(&mtk_dp->prop_work);
+}
+
+static void mtk_dp_hdcp_atomic_check(struct mtk_dp *mtk_dp, struct drm_connector_state *state)
+{
+	unsigned int current_protection = mtk_dp->hdcp_info.content_protection;
+	unsigned int new_protection = state->content_protection;
+	bool type_changed = state->hdcp_content_type != mtk_dp->hdcp_info.hdcp_content_type;
+	bool protection_changed = current_protection != new_protection;
+	bool disable = false;
+	bool enable = false;
+
+	dev_dbg(mtk_dp->dev, "[HDCP] atomic check, old[%d, %d], new[%d, %d]\n",
+		mtk_dp->hdcp_info.content_protection, mtk_dp->hdcp_info.hdcp_content_type,
+		state->content_protection, state->hdcp_content_type);
+
+	if (type_changed) {
+		/*
+		 * With the current protection as ENABLED/DESIRED,
+		 * re-authenticate with new content type if the content type changed.
+		 */
+		mtk_dp->hdcp_info.hdcp_content_type = state->hdcp_content_type;
+		mtk_dp->hdcp_info.hdcp2_info.stream_id_type = state->hdcp_content_type;
+
+		if (current_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+			disable = true;
+
+		if (new_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+			enable = true;
+	} else if (protection_changed) {
+		if (new_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+			disable = true;
+		else
+			enable = true;
+	}
+
+	if (disable)
+		mtk_dp_hdcp_disable(mtk_dp);
+
+	if (enable) {
+		mtk_dp->hdcp_info.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		mtk_dp_hdcp_enable(mtk_dp);
+	}
+}
+
 static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
 {
 	struct mtk_dp *mtk_dp = dev;
 	unsigned long flags;
 	u32 status;
+	int ret;
 
 	if (mtk_dp->need_debounce && mtk_dp->train_info.cable_plugged_in)
 		msleep(100);
@@ -1894,8 +2020,13 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
 		}
 	}
 
-	if (status & MTK_DP_THREAD_HPD_EVENT)
+	if (status & MTK_DP_THREAD_HPD_EVENT) {
 		dev_dbg(mtk_dp->dev, "Receive IRQ from sink devices\n");
+		/* check if need clear hpd irq */
+		ret = mtk_dp_hpd_sink_event(mtk_dp);
+		if (ret)
+			dev_err(mtk_dp->dev, "Fail to process hpd sink event\n");
+	}
 
 	return IRQ_HANDLED;
 }
@@ -2242,6 +2373,7 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 					struct drm_bridge_state *old_state)
 {
 	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
+	struct drm_connector_state *connector_state;
 	int ret;
 
 	mtk_dp->conn = drm_atomic_get_new_connector_for_encoder(old_state->base.state,
@@ -2252,6 +2384,8 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 		return;
 	}
 
+	connector_state = drm_atomic_get_connector_state(old_state->base.state, mtk_dp->conn);
+
 	mtk_dp_aux_panel_poweron(mtk_dp, true);
 
 	/* Training */
@@ -2281,6 +2415,14 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 	mtk_dp->enabled = true;
 	mtk_dp_update_plugged_status(mtk_dp);
 
+	/* Enable hdcp if it's desired */
+	dev_dbg(mtk_dp->dev, "hdcp_content_type:%d, content protection: %d",
+		connector_state->hdcp_content_type, connector_state->content_protection);
+	if (connector_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
+		mtk_dp->hdcp_info.hdcp_content_type = connector_state->hdcp_content_type;
+		mtk_dp_hdcp_enable(mtk_dp);
+	}
+
 	return;
 power_off_aux:
 	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
@@ -2427,6 +2569,8 @@ static int mtk_dp_bridge_atomic_check(struct drm_bridge *bridge,
 
 	drm_display_mode_to_videomode(&crtc_state->adjusted_mode, &mtk_dp->info.vm);
 
+	mtk_dp_hdcp_atomic_check(mtk_dp, conn_state);
+
 	return 0;
 }
 
@@ -2666,6 +2810,17 @@ static int mtk_dp_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	mutex_init(&mtk_dp->hdcp_mutex);
+	init_waitqueue_head(&mtk_dp->hdcp_info.hdcp2_info.cp_irq_queue);
+	INIT_WORK(&mtk_dp->hdcp_work, mtk_dp_hdcp_handle);
+	INIT_WORK(&mtk_dp->prop_work, mtk_dp_hdcp_prop_work);
+	INIT_DELAYED_WORK(&mtk_dp->check_work, mtk_dp_hdcp_check_work);
+	mtk_dp->hdcp_workqueue = create_workqueue("mtk_dp_hdcp_work");
+	if (!mtk_dp->hdcp_workqueue) {
+		dev_err(mtk_dp->dev, "failed to create hdcp work queue");
+		return -ENOMEM;
+	}
+
 	mtk_dp->bridge.funcs = &mtk_dp_bridge_funcs;
 	mtk_dp->bridge.of_node = dev->of_node;
 	mtk_dp->bridge.type = mtk_dp->data->bridge_type;
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.h b/drivers/gpu/drm/mediatek/mtk_dp.h
new file mode 100644
index 000000000000..dfeaf12c7d58
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019-2024 MediaTek Inc.
+ */
+
+#ifndef _MTK_DP_H_
+#define _MTK_DP_H_
+
+#include "tlc_dp_hdcp.h"
+#include <drm/drm_bridge.h>
+#include <sound/hdmi-codec.h>
+#include <video/videomode.h>
+
+#define MS_TO_NS(x)        ((x) * NSEC_PER_MSEC)
+
+enum {
+	MTK_DP_CAL_GLB_BIAS_TRIM = 0,
+	MTK_DP_CAL_CLKTX_IMPSE,
+	MTK_DP_CAL_LN_TX_IMPSEL_PMOS_0,
+	MTK_DP_CAL_LN_TX_IMPSEL_PMOS_1,
+	MTK_DP_CAL_LN_TX_IMPSEL_PMOS_2,
+	MTK_DP_CAL_LN_TX_IMPSEL_PMOS_3,
+	MTK_DP_CAL_LN_TX_IMPSEL_NMOS_0,
+	MTK_DP_CAL_LN_TX_IMPSEL_NMOS_1,
+	MTK_DP_CAL_LN_TX_IMPSEL_NMOS_2,
+	MTK_DP_CAL_LN_TX_IMPSEL_NMOS_3,
+	MTK_DP_CAL_MAX,
+};
+
+struct mtk_dp_audio_cfg {
+	bool detect_monitor;
+	int sad_count;
+	int sample_rate;
+	int word_length_bits;
+	int channels;
+};
+
+struct mtk_dp_info {
+	enum dp_pixelformat format;
+	struct videomode vm;
+	struct mtk_dp_audio_cfg audio_cur_cfg;
+};
+
+struct mtk_dp_train_info {
+	bool sink_ssc;
+	bool cable_plugged_in;
+	/* link_rate is in multiple of 0.27Gbps */
+	int link_rate;
+	int lane_count;
+	unsigned int channel_eq_pattern;
+};
+
+struct mtk_dp {
+	bool enabled;
+	bool need_debounce;
+	int irq;
+	u8 max_lanes;
+	u8 max_linkrate;
+	u8 rx_cap[DP_RECEIVER_CAP_SIZE];
+	u32 cal_data[MTK_DP_CAL_MAX];
+	u32 irq_thread_handle;
+	/* irq_thread_lock is used to protect irq_thread_handle */
+	spinlock_t irq_thread_lock;
+
+	struct device *dev;
+	struct drm_bridge bridge;
+	struct drm_bridge *next_bridge;
+	struct drm_connector *conn;
+	struct drm_device *drm_dev;
+	struct drm_dp_aux aux;
+
+	const struct mtk_dp_data *data;
+	struct mtk_dp_info info;
+	struct mtk_dp_train_info train_info;
+	struct mtk_hdcp_info hdcp_info;
+	struct work_struct hdcp_work;
+	struct work_struct prop_work;
+	struct delayed_work check_work;
+	struct workqueue_struct *hdcp_workqueue;
+	/* This mutex is used to synchronize HDCP operations in the driver */
+	struct mutex hdcp_mutex;
+
+	struct platform_device *phy_dev;
+	struct phy *phy;
+	struct regmap *regs;
+	struct timer_list debounce_timer;
+
+	/* For audio */
+	bool audio_enable;
+	hdmi_codec_plugged_cb plugged_cb;
+	struct platform_device *audio_pdev;
+
+	struct device *codec_dev;
+	/* protect the plugged_cb as it's used in both bridge ops and audio */
+	struct mutex update_plugged_status_lock;
+};
+
+u64 mtk_dp_get_system_time(void);
+u64 mtk_dp_get_time_diff(u64 pre_time);
+u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset);
+int mtk_dp_update_bits(struct mtk_dp *mtk_dp, u32 offset, u32 val, u32 mask);
+void mtk_dp_hdcp_update_value(struct mtk_dp *mtk_dp, u32 value);
+#endif /* _MTK_DP_H_ */
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_hdcp2.c b/drivers/gpu/drm/mediatek/mtk_dp_hdcp2.c
new file mode 100644
index 000000000000..e8affa4343c1
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp_hdcp2.c
@@ -0,0 +1,944 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019-2024 MediaTek Inc.
+ */
+
+#include <drm/display/drm_hdcp_helper.h>
+
+#include "mtk_dp_hdcp2.h"
+#include "mtk_dp_reg.h"
+#include "mtk_dp.h"
+
+#define HDCP2_LC_RETRY_CNT			3
+
+static u8 t_rtx[HDCP_2_2_RTX_LEN] = {
+	0x18, 0xfa, 0xe4, 0x20, 0x6a, 0xfb, 0x51, 0x49
+};
+
+static u8 t_tx_caps[HDCP_2_2_TXCAPS_LEN] = {
+	0x02, 0x00, 0x00
+};
+
+static u8 t_rn[HDCP_2_2_RN_LEN] = {
+	0x32, 0x75, 0x3e, 0xa8, 0x78, 0xa6, 0x38, 0x1c
+};
+
+static u8 t_riv[HDCP_2_2_RIV_LEN] = {
+	0x40, 0x2b, 0x6b, 0x43, 0xc5, 0xe8, 0x86, 0xd8
+};
+
+static void dp_tx_hdcp2x_fill_stream_type(struct mtk_hdcp_info *hdcp_info, u8 uc_type)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+
+	mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_34D0, uc_type, 0xff);
+}
+
+static void dp_tx_hdcp2x_set_auth_pass(struct mtk_hdcp_info *hdcp_info, bool enable)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+
+	if (enable) {
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3400,
+				   HDCP_SEL_DP_TRANS_P0_MASK, HDCP_SEL_DP_TRANS_P0_MASK);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_34A4,
+				   HDCP22_AUTH_DONE_DP_TRANS_P0_MASK,
+				   HDCP22_AUTH_DONE_DP_TRANS_P0_MASK);
+	} else {
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3400, 0, HDCP_SEL_DP_TRANS_P0_MASK);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_34A4, 0,
+				   HDCP22_AUTH_DONE_DP_TRANS_P0_MASK);
+	}
+}
+
+static int dp_tx_hdcp2x_enable_auth(struct mtk_hdcp_info *hdcp_info, bool enable)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u32 version;
+	int ret;
+
+	dp_tx_hdcp2x_set_auth_pass(hdcp_info, enable);
+	if (!enable) {
+		ret = tee_hdcp_enable_encrypt(hdcp_info, enable, HDCP_NONE);
+		if (ret)
+			return ret;
+		mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, 0, HDCP_FRAME_EN_DP_ENC0_P0);
+
+		return 0;
+	}
+
+	if (HDCP_2_2_HDCP1_DEVICE_CONNECTED(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[1]))
+		version = HDCP_V1;
+	else if (HDCP_2_2_HDCP_2_0_REP_CONNECTED
+		(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[1]))
+		version = HDCP_V2;
+	else
+		version = HDCP_V2_3;
+
+	ret = tee_hdcp_enable_encrypt(hdcp_info, enable, version);
+	if (ret)
+		return ret;
+	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
+			   HDCP_FRAME_EN_DP_ENC0_P0, HDCP_FRAME_EN_DP_ENC0_P0);
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_init(struct mtk_hdcp_info *hdcp_info)
+{
+	int ret;
+
+	memset(&hdcp_info->hdcp2_info.hdcp_tx, 0, sizeof(struct hdcp2_info_tx));
+	memset(&hdcp_info->hdcp2_info.hdcp_rx, 0, sizeof(struct hdcp2_info_rx));
+	memset(&hdcp_info->hdcp2_info.ake_stored_km, 0, sizeof(struct hdcp2_ake_stored_km));
+	memcpy(hdcp_info->hdcp2_info.hdcp_tx.ake_init.r_tx, t_rtx, HDCP_2_2_RTX_LEN);
+	memcpy(&hdcp_info->hdcp2_info.hdcp_tx.tx_caps, t_tx_caps, HDCP_2_2_TXCAPS_LEN);
+	memcpy(hdcp_info->hdcp2_info.hdcp_tx.lc_init.r_n, t_rn, HDCP_2_2_RN_LEN);
+	memcpy(hdcp_info->hdcp2_info.hdcp_tx.send_eks.riv, t_riv, HDCP_2_2_RIV_LEN);
+
+	ret = dp_tx_hdcp2x_enable_auth(hdcp_info, false);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_inc_seq_num_m(struct mtk_hdcp_info *hdcp_info)
+{
+	u32 tmp = drm_hdcp_be24_to_cpu(hdcp_info->hdcp2_info.hdcp_tx.stream_manage.seq_num_m);
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+
+	if (tmp == HDCP_2_2_SEQ_NUM_MAX) {
+		dev_err(mtk_dp->dev, "[HDCP2.X] With seq num max\n");
+		return -EINVAL;
+	}
+
+	tmp++;
+
+	drm_hdcp_cpu_to_be24(hdcp_info->hdcp2_info.hdcp_tx.stream_manage.seq_num_m, tmp);
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_process_rep_auth_stream_manage(struct mtk_hdcp_info *hdcp_info)
+{
+	hdcp_info->hdcp2_info.hdcp_tx.k[0] = 0x00;
+	hdcp_info->hdcp2_info.hdcp_tx.k[1] = 0x01;
+
+	hdcp_info->hdcp2_info.hdcp_tx.stream_id_type[0] = 0x00; /* Payload ID */
+	hdcp_info->hdcp2_info.hdcp_tx.stream_id_type[1] = hdcp_info->hdcp2_info.stream_id_type;
+
+	return dp_tx_hdcp2x_inc_seq_num_m(hdcp_info);
+}
+
+static int dp_tx_hdcp2x_recv_rep_auth_send_recv_id_list(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u32 len = 0, len_recv_id_list = 0;
+	u8 *buffer = NULL;
+	int ret = 0;
+
+	len_recv_id_list = hdcp_info->hdcp2_info.device_count * HDCP_2_2_RECEIVER_ID_LEN;
+	len = len_recv_id_list + HDCP_2_2_RXINFO_LEN + HDCP_2_2_SEQ_NUM_LEN;
+	buffer = kmalloc(len, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(mtk_dp->dev, "[HDCP2.X] Out of memory\n");
+		return -ENOMEM;
+	}
+
+	memcpy(buffer, hdcp_info->hdcp2_info.hdcp_rx.recvid_list.receiver_ids,
+	       len_recv_id_list);
+	memcpy(buffer + len_recv_id_list,
+	       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info, HDCP_2_2_RXINFO_LEN);
+	memcpy(buffer + len_recv_id_list + HDCP_2_2_RXINFO_LEN,
+	       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.seq_num_v, HDCP_2_2_SEQ_NUM_LEN);
+
+	ret = tee_hdcp2_compute_compare_v(hdcp_info, buffer, len,
+					  hdcp_info->hdcp2_info.hdcp_rx.recvid_list.v_prime,
+		hdcp_info->hdcp2_info.hdcp_tx.send_ack.v);
+
+	kfree(buffer);
+
+	return ret;
+}
+
+static int dp_tx_hdcp2x_recv_rep_auth_stream_ready(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 *buffer = NULL;
+	u32 len = 0;
+	int ret = 0;
+
+	len = HDCP2_STREAMID_TYPE_LEN + HDCP_2_2_SEQ_NUM_LEN;
+	buffer = kmalloc(len, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(mtk_dp->dev, "[HDCP2.X] Out of memory\n");
+		return -ENOMEM;
+	}
+
+	memcpy(buffer, hdcp_info->hdcp2_info.hdcp_tx.stream_id_type, HDCP2_STREAMID_TYPE_LEN);
+	memcpy(buffer + HDCP2_STREAMID_TYPE_LEN,
+	       hdcp_info->hdcp2_info.hdcp_tx.stream_manage.seq_num_m,
+	       HDCP_2_2_SEQ_NUM_LEN);
+	ret = tee_hdcp2_compute_compare_m(hdcp_info, buffer, len,
+					  hdcp_info->hdcp2_info.hdcp_rx.stream_ready.m_prime);
+
+	kfree(buffer);
+
+	return ret;
+}
+
+static void dp_tx_hdcp2x_wait_for_cp_irq(struct mtk_hdcp_info *hdcp_info, int timeout)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	long ret;
+
+#define C (hdcp_info->hdcp2_info.cp_irq_cached != atomic_read(&hdcp_info->hdcp2_info.cp_irq))
+	ret = wait_event_interruptible_timeout(hdcp_info->hdcp2_info.cp_irq_queue, C,
+					       msecs_to_jiffies(timeout));
+	if (!ret)
+		dev_dbg(mtk_dp->dev, "[HDCP2.X] Timedout at waiting for CP_IRQ\n");
+}
+
+static int dp_tx_hdcp2x_read_ake_send_cert(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ktime_t msg_end;
+	bool msg_expired;
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_SEND_CERT\n");
+
+	mdelay(HDCP_2_2_CERT_TIMEOUT_MS);
+
+	msg_end = ktime_add_ms(ktime_get_raw(), HDCP_2_2_DP_CERT_READ_TIMEOUT_MS);
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_AKE_SEND_CERT_OFFSET,
+			       (void *)&hdcp_info->hdcp2_info.hdcp_rx.cert_rx, HDCP2_CERTRX_LEN);
+	if (ret < 0)
+		return ret;
+
+	msg_expired = ktime_after(ktime_get_raw(), msg_end);
+	if (msg_expired)
+		dev_dbg(mtk_dp->dev, "[HDCP2.X] Timeout to read Ake send cert\n");
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RRX_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.send_cert.r_rx, HDCP_2_2_RRX_LEN);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.send_cert.rx_caps,
+		HDCP_2_2_RXCAPS_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_read_ake_send_hprime(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ktime_t msg_end;
+	bool msg_expired;
+	u8 rx_status = 0;
+	int timeout;
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_SEND_HPRIME\n");
+
+	timeout = hdcp_info->hdcp2_info.stored_km ?
+		HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS : HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS;
+
+	dp_tx_hdcp2x_wait_for_cp_irq(hdcp_info, timeout);
+	hdcp_info->hdcp2_info.cp_irq_cached = atomic_read(&hdcp_info->hdcp2_info.cp_irq);
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
+			       HDCP_2_2_DP_RXSTATUS_LEN);
+	if (ret != HDCP_2_2_DP_RXSTATUS_LEN)
+		return ret >= 0 ? -EIO : ret;
+
+	if (!HDCP_2_2_DP_RXSTATUS_H_PRIME(rx_status))
+		return -EAGAIN;
+
+	msg_end = ktime_add_ms(ktime_get_raw(), HDCP_2_2_DP_HPRIME_READ_TIMEOUT_MS);
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.send_hprime.h_prime,
+		HDCP_2_2_H_PRIME_LEN);
+	if (ret < 0)
+		return ret;
+
+	msg_expired = ktime_after(ktime_get_raw(), msg_end);
+	if (msg_expired)
+		dev_dbg(mtk_dp->dev, "[HDCP2.X] Timeout to read AKE hprime\n");
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_read_ake_send_pairing_info(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ktime_t msg_end;
+	bool msg_expired;
+	u8 rx_status = 0;
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_SEND_PAIRING_INFO\n");
+
+	dp_tx_hdcp2x_wait_for_cp_irq(hdcp_info, HDCP_2_2_PAIRING_TIMEOUT_MS);
+	hdcp_info->hdcp2_info.cp_irq_cached = atomic_read(&hdcp_info->hdcp2_info.cp_irq);
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
+			       HDCP_2_2_DP_RXSTATUS_LEN);
+	if (ret != HDCP_2_2_DP_RXSTATUS_LEN)
+		return ret >= 0 ? -EIO : ret;
+
+	if (!HDCP_2_2_DP_RXSTATUS_PAIRING(rx_status))
+		return -EAGAIN;
+
+	msg_end = ktime_add_ms(ktime_get_raw(), HDCP_2_2_DP_PAIRING_READ_TIMEOUT_MS);
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.pairing_info.e_kh_km,
+		HDCP_2_2_E_KH_KM_LEN);
+	if (ret < 0)
+		return ret;
+
+	msg_expired = ktime_after(ktime_get_raw(), msg_end);
+	if (msg_expired)
+		dev_err(mtk_dp->dev, "[HDCP2.X] Timeout to read pairing info\n");
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_read_lc_send_lprime(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_LC_SEND_LPRIME\n");
+
+	mdelay(HDCP_2_2_DP_LPRIME_TIMEOUT_MS);
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.send_lprime.l_prime,
+		HDCP_2_2_L_PRIME_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_read_rep_send_recvid_list(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 rx_status = 0;
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_REP_SEND_RECVID_LIST\n");
+
+	dp_tx_hdcp2x_wait_for_cp_irq(hdcp_info, HDCP_2_2_RECVID_LIST_TIMEOUT_MS);
+	hdcp_info->hdcp2_info.cp_irq_cached = atomic_read(&hdcp_info->hdcp2_info.cp_irq);
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
+			       HDCP_2_2_DP_RXSTATUS_LEN);
+	if (ret != HDCP_2_2_DP_RXSTATUS_LEN)
+		return ret >= 0 ? -EIO : ret;
+
+	if (!HDCP_2_2_DP_RXSTATUS_READY(rx_status)) {
+		dev_err(mtk_dp->dev, "[HDCP2.X] RX status no ready\n");
+		return -EAGAIN;
+	}
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info,
+		HDCP_2_2_RXINFO_LEN);
+	if (ret < 0)
+		return ret;
+
+	hdcp_info->hdcp2_info.device_count =
+	(HDCP_2_2_DEV_COUNT_HI(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[0]) << 4 |
+	HDCP_2_2_DEV_COUNT_LO(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[1]));
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.seq_num_v,
+		HDCP_2_2_SEQ_NUM_LEN);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_VPRIME_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.v_prime,
+		HDCP_2_2_V_PRIME_HALF_LEN);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.receiver_ids,
+		hdcp_info->hdcp2_info.device_count * HDCP_2_2_RECEIVER_ID_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_read_rep_stream_ready(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_REP_STREAM_READY\n");
+
+	mdelay(HDCP_2_2_STREAM_READY_TIMEOUT_MS);
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REP_STREAM_READY_OFFSET,
+			       hdcp_info->hdcp2_info.hdcp_rx.stream_ready.m_prime,
+		HDCP_2_2_MPRIME_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_write_ake_init(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_Init\n");
+
+	ret = tee_hdcp2_soft_rst(hdcp_info);
+	if (ret)
+		return ret;
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_AKE_INIT_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.ake_init.r_tx, HDCP_2_2_RTX_LEN);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_TXCAPS_OFFSET,
+				(void *)&hdcp_info->hdcp2_info.hdcp_tx.tx_caps,
+			  HDCP_2_2_TXCAPS_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_write_ake_no_stored_km(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_NO_STORED_KM\n");
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.no_stored_km.e_kpub_km,
+		HDCP_2_2_E_KPUB_KM_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_write_ake_stored_km(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_STORED_KM\n");
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_AKE_STORED_KM_OFFSET,
+				hdcp_info->hdcp2_info.ake_stored_km.e_kh_km_m,
+		HDCP_2_2_E_KH_KM_LEN);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_M_OFFSET,
+				hdcp_info->hdcp2_info.ake_stored_km.e_kh_km_m +
+		HDCP_2_2_E_KH_KM_LEN,
+		HDCP_2_2_E_KH_KM_M_LEN - HDCP_2_2_E_KH_KM_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_write_lc_init(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_LC_INIT\n");
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_LC_INIT_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.lc_init.r_n, HDCP_2_2_RN_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_write_ske_send_eks(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_SKE_SEND_EKS\n");
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_SKE_SEND_EKS_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.send_eks.e_dkey_ks,
+		HDCP_2_2_E_DKEY_KS_LEN);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_RIV_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.send_eks.riv, HDCP_2_2_RIV_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_write_stream_type(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] Write stream type\n");
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.stream_id_type, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_write_send_ack(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_SEND_ACK\n");
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REP_SEND_ACK_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.send_ack.v,
+		HDCP_2_2_V_PRIME_HALF_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_write_stream_manage(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	ssize_t ret;
+
+	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_STREAM_MANAGE\n");
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.stream_manage.seq_num_m,
+		HDCP_2_2_SEQ_NUM_LEN);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_K_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.k, HDCP2_K_LEN);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_STREAM_ID_TYPE_OFFSET,
+				hdcp_info->hdcp2_info.hdcp_tx.stream_id_type,
+		HDCP2_STREAMID_TYPE_LEN);
+	if (ret < 0)
+		return ret;
+
+	dp_tx_hdcp2x_fill_stream_type(hdcp_info, hdcp_info->hdcp2_info.stream_id_type);
+
+	return 0;
+}
+
+/* Authentication flow starts from here */
+static int dp_tx_hdcp2x_key_exchange(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	bool stored;
+	int ret;
+
+	if (!hdcp_info->hdcp2_info.capable)
+		return -EAGAIN;
+
+	ret = dp_tx_hdcp2x_init(hdcp_info);
+	if (ret)
+		return ret;
+
+	ret = dp_tx_hdcp2x_write_ake_init(hdcp_info);
+	if (ret)
+		return ret;
+
+	ret = dp_tx_hdcp2x_read_ake_send_cert(hdcp_info);
+	if (ret)
+		return ret;
+
+	hdcp_info->hdcp2_info.repeater =
+		HDCP_2_2_RX_REPEATER(hdcp_info->hdcp2_info.hdcp_rx.send_cert.rx_caps[2]);
+
+	if (drm_hdcp_check_ksvs_revoked(mtk_dp->drm_dev,
+					hdcp_info->hdcp2_info.hdcp_rx.send_cert.cert_rx.receiver_id,
+					1) > 0) {
+		dev_err(mtk_dp->dev, "[HDCP2.X] Receiver ID is revoked\n");
+		return -EPERM;
+	}
+
+	ret = tee_ake_certificate(hdcp_info,
+				  (u8 *)&hdcp_info->hdcp2_info.hdcp_rx.cert_rx, &stored,
+		hdcp_info->hdcp2_info.ake_stored_km.e_kh_km_m +
+		HDCP_2_2_E_KH_KM_LEN,
+		hdcp_info->hdcp2_info.ake_stored_km.e_kh_km_m);
+	if (ret)
+		return ret;
+
+	hdcp_info->hdcp2_info.stored_km = stored;
+
+	if (!hdcp_info->hdcp2_info.stored_km) {
+		ret = tee_enc_rsaes_oaep(hdcp_info,
+					 hdcp_info->hdcp2_info.hdcp_tx.no_stored_km.e_kpub_km);
+		if (ret)
+			return ret;
+
+		ret = dp_tx_hdcp2x_write_ake_no_stored_km(hdcp_info);
+		if (ret)
+			return ret;
+
+	} else {
+		ret = dp_tx_hdcp2x_write_ake_stored_km(hdcp_info);
+		if (ret)
+			return ret;
+	}
+
+	ret = dp_tx_hdcp2x_read_ake_send_hprime(hdcp_info);
+	if (ret)
+		return ret;
+
+	ret = tee_ake_h_prime(hdcp_info,
+			      hdcp_info->hdcp2_info.hdcp_tx.ake_init.r_tx,
+		hdcp_info->hdcp2_info.hdcp_rx.send_cert.r_rx,
+		hdcp_info->hdcp2_info.hdcp_rx.send_cert.rx_caps,
+		(u8 *)&hdcp_info->hdcp2_info.hdcp_tx.tx_caps,
+		hdcp_info->hdcp2_info.hdcp_rx.send_hprime.h_prime,
+		HDCP_2_2_H_PRIME_LEN);
+	if (ret) {
+		if (hdcp_info->hdcp2_info.stored_km)
+			tee_clear_paring(hdcp_info);
+		return ret;
+	}
+
+	if (!hdcp_info->hdcp2_info.stored_km) {
+		ret = dp_tx_hdcp2x_read_ake_send_pairing_info(hdcp_info);
+		if (ret)
+			return ret;
+
+		/* Store m, km, Ekh(km) */
+		ret = tee_ake_paring(hdcp_info,
+				     hdcp_info->hdcp2_info.hdcp_rx.pairing_info.e_kh_km);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_locality_check(struct mtk_hdcp_info *hdcp_info)
+{
+	int ret, i, tries = HDCP2_LC_RETRY_CNT;
+
+	for (i = 0; i < tries; i++) {
+		ret = dp_tx_hdcp2x_write_lc_init(hdcp_info);
+		if (ret)
+			continue;
+
+		ret = dp_tx_hdcp2x_read_lc_send_lprime(hdcp_info);
+		if (ret)
+			continue;
+
+		ret = tee_lc_l_prime(hdcp_info, hdcp_info->hdcp2_info.hdcp_tx.lc_init.r_n,
+				     hdcp_info->hdcp2_info.hdcp_rx.send_lprime.l_prime,
+				     HDCP_2_2_L_PRIME_LEN);
+		if (!ret)
+			return 0;
+	}
+
+	return ret;
+}
+
+static int dp_tx_hdcp2x_session_key_exchange(struct mtk_hdcp_info *hdcp_info)
+{
+	int ret;
+
+	ret = tee_ske_enc_ks(hdcp_info, hdcp_info->hdcp2_info.hdcp_tx.send_eks.riv,
+			     hdcp_info->hdcp2_info.hdcp_tx.send_eks.e_dkey_ks);
+	if (ret)
+		return ret;
+
+	ret = dp_tx_hdcp2x_write_ske_send_eks(hdcp_info);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static
+int dp_tx_hdcp2x_authenticate_repeater(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 *rx_info;
+	int ret;
+
+	ret = dp_tx_hdcp2x_read_rep_send_recvid_list(hdcp_info);
+	if (ret)
+		return ret;
+
+	rx_info = hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info;
+
+	if (HDCP_2_2_MAX_CASCADE_EXCEEDED(rx_info[1]) ||
+	    HDCP_2_2_MAX_DEVS_EXCEEDED(rx_info[1])) {
+		dev_err(mtk_dp->dev, "[HDCP2.X] Topology max size exceeded\n");
+		return -EINVAL;
+	}
+
+	if (drm_hdcp_check_ksvs_revoked(mtk_dp->drm_dev,
+					hdcp_info->hdcp2_info.hdcp_rx.recvid_list.receiver_ids,
+					hdcp_info->hdcp2_info.device_count) > 0) {
+		dev_err(mtk_dp->dev, "[HDCP2.X] Revoked receiver ID(s) is in list\n");
+		return -EPERM;
+	}
+
+	ret = dp_tx_hdcp2x_recv_rep_auth_send_recv_id_list(hdcp_info);
+	if (ret)
+		return -EINVAL;
+
+	ret = dp_tx_hdcp2x_write_send_ack(hdcp_info);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp2x_authenticate(struct mtk_hdcp_info *hdcp_info)
+{
+	int ret;
+
+	ret = dp_tx_hdcp2x_key_exchange(hdcp_info);
+	if (ret)
+		return ret;
+
+	ret = dp_tx_hdcp2x_locality_check(hdcp_info);
+	if (ret)
+		return ret;
+
+	ret = dp_tx_hdcp2x_session_key_exchange(hdcp_info);
+	if (ret)
+		return ret;
+
+	if (!hdcp_info->hdcp2_info.repeater) {
+		ret = dp_tx_hdcp2x_write_stream_type(hdcp_info);
+		if (ret)
+			return ret;
+	}
+
+	if (hdcp_info->hdcp2_info.repeater) {
+		ret = dp_tx_hdcp2x_authenticate_repeater(hdcp_info);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static
+int dp_tx_hdcp2x_propagate_stream_management_info(struct mtk_hdcp_info *hdcp_info)
+{
+	int i, ret, tries = 3;
+
+	if (!hdcp_info->hdcp2_info.repeater)
+		return 0;
+
+	for (i = 0; i < tries; i++) {
+		ret = dp_tx_hdcp2x_process_rep_auth_stream_manage(hdcp_info);
+		if (ret)
+			continue;
+
+		ret = dp_tx_hdcp2x_write_stream_manage(hdcp_info);
+		if (ret)
+			continue;
+
+		ret = dp_tx_hdcp2x_read_rep_stream_ready(hdcp_info);
+		if (ret)
+			continue;
+
+		ret = dp_tx_hdcp2x_recv_rep_auth_stream_ready(hdcp_info);
+		if (!ret)
+			return 0;
+	}
+
+	return ret;
+}
+
+void dp_tx_hdcp2x_get_info(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 tmp[3];
+	ssize_t ret;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux,
+			       DP_HDCP_2_2_REG_RX_CAPS_OFFSET, tmp, HDCP_2_2_RXCAPS_LEN);
+	if (ret < 0)
+		return;
+
+	if (!HDCP_2_2_DP_HDCP_CAPABLE(tmp[2]) || tmp[0] != HDCP_2_2_RX_CAPS_VERSION_VAL) {
+		hdcp_info->hdcp2_info.capable = false;
+	} else {
+		hdcp_info->hdcp2_info.capable = true;
+		hdcp_info->hdcp2_info.repeater = HDCP_2_2_RX_REPEATER(tmp[2]);
+	}
+
+	dev_info(mtk_dp->dev, "[HDCP2.X] Capable: %d, Reapeater: %d\n",
+		 hdcp_info->hdcp2_info.capable,
+		 hdcp_info->hdcp2_info.repeater);
+}
+
+int dp_tx_hdcp2x_enable(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	int ret, i, tries = 3;
+
+	hdcp_info->auth_status = AUTH_INIT;
+
+	ret = tee_add_device(hdcp_info, HDCP_VERSION_2X);
+	if (ret)
+		goto fail2;
+
+	for (i = 0; i < tries; i++) {
+		ret = dp_tx_hdcp2x_authenticate(hdcp_info);
+		if (ret)
+			continue;
+
+		ret = dp_tx_hdcp2x_propagate_stream_management_info(hdcp_info);
+		if (!ret) {
+			dev_dbg(mtk_dp->dev, "[HDCP2.X] Stream management done\n");
+			break;
+		}
+	}
+	if (i == tries)
+		goto fail1;
+
+	msleep(HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN);
+	ret = dp_tx_hdcp2x_enable_auth(hdcp_info, true);
+	if (!ret) {
+		hdcp_info->auth_version = HDCP_VERSION_2X;
+		hdcp_info->auth_status = AUTH_PASS;
+		dev_info(mtk_dp->dev, "[HDCP2.X] Authentication done\n");
+
+		return 0;
+	}
+
+fail1:
+	tee_remove_device(hdcp_info);
+
+fail2:
+	hdcp_info->auth_status = AUTH_FAIL;
+	dev_err(mtk_dp->dev, "[HDCP2.X] Authentication fail\n");
+
+	return ret;
+}
+
+int dp_tx_hdcp2x_disabel(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	int ret;
+
+	if (hdcp_info->auth_status == AUTH_PASS) {
+		ret = dp_tx_hdcp2x_enable_auth(hdcp_info, false);
+		if (ret)
+			return ret;
+	}
+
+	tee_remove_device(hdcp_info);
+
+	hdcp_info->auth_version = HDCP_NONE;
+	hdcp_info->auth_status = AUTH_ZERO;
+	dev_info(mtk_dp->dev, "[HDCP2.X] Disable Authentication\n");
+
+	return 0;
+}
+
+int dp_tx_hdcp2x_check_link(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 rx_status;
+	int ret = -EINVAL;
+	int tmp = 0;
+
+	mutex_lock(&mtk_dp->hdcp_mutex);
+
+	if (mtk_dp->hdcp_info.auth_status != AUTH_PASS)
+		goto end;
+
+	if (!mtk_dp->train_info.cable_plugged_in || !mtk_dp->enabled)
+		goto disable;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
+			       HDCP_2_2_DP_RXSTATUS_LEN);
+	if (ret != HDCP_2_2_DP_RXSTATUS_LEN) {
+		dev_dbg(mtk_dp->dev, "[HDCP2.X] Read bstatus failed, reauth\n");
+		goto disable;
+	}
+
+	if (HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(rx_status))
+		tmp = REAUTH_REQUEST;
+	else if (HDCP_2_2_DP_RXSTATUS_LINK_FAILED(rx_status))
+		tmp = LINK_INTEGRITY_FAILURE;
+	else if (HDCP_2_2_DP_RXSTATUS_READY(rx_status))
+		tmp = TOPOLOGY_CHANGE;
+
+	if (tmp == LINK_PROTECTED) {
+		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_ENABLED);
+		ret = 0;
+		goto end;
+	}
+
+	if (tmp == TOPOLOGY_CHANGE) {
+		ret = dp_tx_hdcp2x_authenticate_repeater(hdcp_info);
+		if (!ret) {
+			mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_ENABLED);
+			goto end;
+		}
+	} else {
+		dev_info(mtk_dp->dev, "[HDCP2.X] link failed with:0x%x, retrying auth\n", tmp);
+	}
+
+disable:
+	ret = dp_tx_hdcp2x_disabel(hdcp_info);
+	if (ret || !mtk_dp->train_info.cable_plugged_in || !mtk_dp->enabled) {
+		ret = -EAGAIN;
+		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_DESIRED);
+		goto end;
+	}
+
+	ret = dp_tx_hdcp2x_enable(hdcp_info);
+	if (ret)
+		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_DESIRED);
+
+end:
+	mutex_unlock(&mtk_dp->hdcp_mutex);
+
+	return ret;
+}
+
+void dp_tx_hdcp2x_irq(struct mtk_hdcp_info *hdcp_info)
+{
+	atomic_inc(&hdcp_info->hdcp2_info.cp_irq);
+	wake_up_all(&hdcp_info->hdcp2_info.cp_irq_queue);
+}
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_hdcp2.h b/drivers/gpu/drm/mediatek/mtk_dp_hdcp2.h
new file mode 100644
index 000000000000..0532bcb9958b
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp_hdcp2.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019-2024 MediaTek Inc.
+ */
+
+#ifndef _MTK_dp_HDCP2_H_
+#define _MTK_dp_HDCP2_H_
+
+#include "tlc_dp_hdcp.h"
+
+#define HDCP_VERSION_2X 2
+
+enum check_link {
+	LINK_PROTECTED	= 0,
+	TOPOLOGY_CHANGE,
+	LINK_INTEGRITY_FAILURE,
+	REAUTH_REQUEST
+};
+
+void dp_tx_hdcp2x_get_info(struct mtk_hdcp_info *hdcp_info);
+int dp_tx_hdcp2x_enable(struct mtk_hdcp_info *hdcp_info);
+int dp_tx_hdcp2x_disabel(struct mtk_hdcp_info *hdcp_info);
+int dp_tx_hdcp2x_check_link(struct mtk_hdcp_info *hdcp_info);
+void dp_tx_hdcp2x_irq(struct mtk_hdcp_info *hdcp_info);
+#endif /* _MTK_dp_HDCP2_H_ */
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index 709b79480693..8c60983a26ed 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (c) 2019-2022 MediaTek Inc.
+ * Copyright (c) 2019-2024 MediaTek Inc.
  * Copyright (c) 2022 BayLibre
  */
 #ifndef _MTK_DP_REG_H_
@@ -83,6 +83,7 @@
 #define VIDEO_MUTE_SW_DP_ENC0_P0			BIT(2)
 #define VIDEO_MUTE_SEL_DP_ENC0_P0			BIT(3)
 #define ENHANCED_FRAME_EN_DP_ENC0_P0			BIT(4)
+#define HDCP_FRAME_EN_DP_ENC0_P0			BIT(5)
 #define MTK_DP_ENC0_P0_3004			0x3004
 #define VIDEO_M_CODE_SEL_DP_ENC0_P0_MASK		BIT(8)
 #define DP_TX_ENCODER_4P_RESET_SW_DP_ENC0_P0		BIT(9)
@@ -245,6 +246,7 @@
 
 /* offset: TRANS_OFFSET (0x3400) */
 #define MTK_DP_TRANS_P0_3400				0x3400
+#define HDCP_SEL_DP_TRANS_P0_MASK				BIT(11)
 #define PATTERN1_EN_DP_TRANS_P0_MASK				BIT(12)
 #define PATTERN2_EN_DP_TRANS_P0_MASK				BIT(13)
 #define PATTERN3_EN_DP_TRANS_P0_MASK				BIT(14)
@@ -276,7 +278,11 @@
 #define HPD_INT_THD_ECO_DP_TRANS_P0_MASK			GENMASK(1, 0)
 #define HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT		BIT(1)
 #define MTK_DP_TRANS_P0_34A4				0x34a4
+#define HDCP22_AUTH_DONE_DP_TRANS_P0_MASK		BIT(4)
+#define R0_AVAILABLE_DP_TRANS_P0		BIT(12)
+#define REPEATER_I_DP_TRANS_P0_MASK		BIT(15)
 #define LANE_NUM_DP_TRANS_P0_MASK				GENMASK(3, 2)
+#define MTK_DP_TRANS_P0_34D0                0x34D0
 #define MTK_DP_TRANS_P0_3540				0x3540
 #define FEC_EN_DP_TRANS_P0_MASK					BIT(0)
 #define FEC_CLOCK_EN_MODE_DP_TRANS_P0				BIT(3)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index bfe8653005db..6f85753c0c82 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -25,6 +25,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_of.h>
 #include <drm/drm_simple_kms_helper.h>
+#include <drm/display/drm_hdcp_helper.h>
 
 #include "mtk_ddp_comp.h"
 #include "mtk_disp_drv.h"
@@ -820,6 +821,8 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
 	}
 	drm_connector_attach_encoder(dpi->connector, &dpi->encoder);
 
+	drm_connector_attach_content_protection_property(dpi->connector, true);
+
 	return 0;
 
 err_cleanup:
-- 
2.43.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 3/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP1.x feature for DisplayPort
  2024-06-08 12:01 [PATCH v3 0/3] Add HDCP feature for DisplayPort mac.shen
  2024-06-08 12:01 ` [PATCH v3 1/3] Subject: [PATCH] drm/mediatek/dp: Add tee client application for HDCP feature mac.shen
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
@ 2024-06-08 12:01 ` mac.shen
  2024-08-30  9:03   ` CK Hu (胡俊光)
  2 siblings, 1 reply; 21+ messages in thread
From: mac.shen @ 2024-06-08 12:01 UTC (permalink / raw)
  To: chunkuang.hu, p.zabel, airlied, daniel, matthias.bgg,
	angelogioacchino.delregno, jitao.shi
  Cc: mac.shen, shuijing.li, linux-kernel, dri-devel, linux-mediatek,
	linux-arm-kernel

Changes in v3:
- remove useless code
- remove magic number
- refine the flow to do HDCP1.x authentication
per suggestion from the previous thread:
https://patchwork.kernel.org/project/linux-mediatek
/patch/20240205055055.25340-4-mac.shen@mediatek.com/

Signed-off-by: mac.shen <mac.shen@mediatek.com>
---
 drivers/gpu/drm/mediatek/Makefile        |   1 +
 drivers/gpu/drm/mediatek/mtk_dp.c        |  11 +
 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c | 577 +++++++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h |  17 +
 drivers/gpu/drm/mediatek/mtk_dp_reg.h    |   3 +
 5 files changed, 609 insertions(+)
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c
 create mode 100644 drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h

diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 19b7625ae573..a90c3294bfbe 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -28,6 +28,7 @@ mediatek-drm-hdmi-objs := mtk_cec.o \
 obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o
 
 mtk-dp-objs := tlc_dp_hdcp.o \
+		  mtk_dp_hdcp1x.o \
 		  mtk_dp_hdcp2.o \
 		  mtk_dp.o
 
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 12854a04622f..3925eb2be064 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -33,6 +33,7 @@
 
 #include "mtk_dp.h"
 #include "mtk_dp_reg.h"
+#include "mtk_dp_hdcp1x.h"
 #include "mtk_dp_hdcp2.h"
 
 #define MTK_DP_SIP_CONTROL_AARCH32	MTK_SIP_SMC_CMD(0x523)
@@ -1841,6 +1842,7 @@ static int mtk_dp_hpd_sink_event(struct mtk_dp *mtk_dp)
 static void mtk_dp_hdcp_get_info(struct mtk_dp *mtk_dp)
 {
 	dp_tx_hdcp2x_get_info(&mtk_dp->hdcp_info);
+	dp_tx_hdcp1x_get_info(&mtk_dp->hdcp_info);
 }
 
 static void mtk_dp_hdcp_disable(struct mtk_dp *mtk_dp)
@@ -1852,6 +1854,8 @@ static void mtk_dp_hdcp_disable(struct mtk_dp *mtk_dp)
 
 	if (mtk_dp->hdcp_info.auth_version == HDCP_VERSION_2X)
 		dp_tx_hdcp2x_disabel(&mtk_dp->hdcp_info);
+	else if (mtk_dp->hdcp_info.auth_version == HDCP_VERSION_1X)
+		dp_tx_hdcp1x_disabel(&mtk_dp->hdcp_info);
 
 end:
 	cancel_delayed_work_sync(&mtk_dp->check_work);
@@ -1868,6 +1872,9 @@ static void mtk_dp_hdcp_check_work(struct work_struct *work)
 	if (mtk_dp->hdcp_info.auth_version == HDCP_VERSION_2X &&
 	    (!dp_tx_hdcp2x_check_link(&mtk_dp->hdcp_info))) {
 		schedule_delayed_work(&mtk_dp->check_work, DRM_HDCP2_CHECK_PERIOD_MS);
+	} else if (mtk_dp->hdcp_info.auth_version == HDCP_VERSION_1X &&
+		(!dp_tx_hdcp1x_check_link(&mtk_dp->hdcp_info))) {
+		schedule_delayed_work(&mtk_dp->check_work, DRM_HDCP_CHECK_PERIOD_MS);
 	}
 }
 
@@ -1890,6 +1897,10 @@ static void mtk_dp_hdcp_handle(struct work_struct *data)
 			check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
 	}
 
+	if (ret && mtk_dp->hdcp_info.hdcp1x_info.capable &&
+	    mtk_dp->hdcp_info.hdcp_content_type != DRM_MODE_HDCP_CONTENT_TYPE1)
+		ret = dp_tx_hdcp1x_enable(&mtk_dp->hdcp_info);
+
 	if (!ret) {
 		schedule_delayed_work(&mtk_dp->check_work, check_link_interval);
 		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_ENABLED);
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c b/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c
new file mode 100644
index 000000000000..0fcf23c378df
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.c
@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019-2024 MediaTek Inc.
+ */
+
+#include <drm/display/drm_hdcp_helper.h>
+
+#include "mtk_dp_hdcp1x.h"
+#include "mtk_dp_reg.h"
+#include "mtk_dp.h"
+
+#define HDCP1X_R0_WDT			100
+#define HDCP1X_REP_RDY_WDT		5000
+
+static void dp_tx_hdcp1x_start_cipher(struct mtk_hdcp_info *hdcp_info, bool enable)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+
+	if (enable) {
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3480, REQ_BLOCK_CIPHER_AUTH,
+				   REQ_BLOCK_CIPHER_AUTH);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3480, KM_GENERATED, KM_GENERATED);
+	} else {
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3480, 0, KM_GENERATED);
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_3480, 0, REQ_BLOCK_CIPHER_AUTH);
+	}
+}
+
+static bool dp_tx_hdcp1x_get_r0_available(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	bool R0_available;
+	u32 ret;
+
+	ret = mtk_dp_read(mtk_dp, MTK_DP_TRANS_P0_34A4);
+	if (ret & R0_AVAILABLE_DP_TRANS_P0)
+		R0_available = true;
+	else
+		R0_available = false;
+
+	return R0_available;
+}
+
+static void dp_tx_hdcp1x_set_repeater(struct mtk_hdcp_info *hdcp_info, bool enable)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+
+	if (enable)
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_34A4,
+				   REPEATER_I_DP_TRANS_P0_MASK, REPEATER_I_DP_TRANS_P0_MASK);
+	else
+		mtk_dp_update_bits(mtk_dp, MTK_DP_TRANS_P0_34A4, 0,  REPEATER_I_DP_TRANS_P0_MASK);
+}
+
+static int dp_tx_hdcp1x_init(struct mtk_hdcp_info *hdcp_info)
+{
+	int ret;
+	u8 i;
+
+	for (i = 0; i < 5; i++) {
+		hdcp_info->hdcp1x_info.b_ksv[i] = 0x00;
+		hdcp_info->hdcp1x_info.a_ksv[i] = 0x00;
+	}
+
+	for (i = 0; i < 5; i++)
+		hdcp_info->hdcp1x_info.v[i] = 0x00;
+
+	hdcp_info->hdcp1x_info.b_info[0] = 0x00;
+	hdcp_info->hdcp1x_info.b_info[1] = 0x00;
+	hdcp_info->hdcp1x_info.device_count = 0x00;
+
+	ret = tee_hdcp_enable_encrypt(hdcp_info, false, HDCP_NONE);
+	if (ret)
+		return ret;
+
+	dp_tx_hdcp1x_start_cipher(hdcp_info, false);
+
+	ret = tee_hdcp1x_soft_rst(hdcp_info);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int dp_tx_hdcp1x_read_sink_b_ksv(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 read_buffer[DRM_HDCP_KSV_LEN], i;
+	ssize_t ret;
+
+	if (hdcp_info->hdcp1x_info.capable) {
+		ret = drm_dp_dpcd_read(&mtk_dp->aux,
+				       DP_AUX_HDCP_BKSV, read_buffer, DRM_HDCP_KSV_LEN);
+		if (ret < 0)
+			return ret;
+
+		for (i = 0; i < DRM_HDCP_KSV_LEN; i++) {
+			hdcp_info->hdcp1x_info.b_ksv[i] = read_buffer[i];
+			dev_dbg(mtk_dp->dev, "[HDCP1.X] Bksv:0x%x\n", read_buffer[i]);
+		}
+	}
+
+	return 0;
+}
+
+static int dp_tx_hdcp1x_check_sink_ksv_ready(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 read_buffer;
+	ssize_t ret;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BSTATUS, &read_buffer, 1);
+	if (ret < 0)
+		return ret;
+
+	return (read_buffer & DP_BSTATUS_READY)  ? 0 : -EAGAIN;
+}
+
+static int dp_tx_hdcp1x_read_sink_b_info(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 read_buffer[DRM_HDCP_BSTATUS_LEN];
+	ssize_t ret;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BINFO, read_buffer, DRM_HDCP_BSTATUS_LEN);
+	if (ret < 0)
+		return ret;
+
+	hdcp_info->hdcp1x_info.b_info[0] = read_buffer[0];
+	hdcp_info->hdcp1x_info.b_info[1] = read_buffer[1];
+	hdcp_info->hdcp1x_info.device_count = DRM_HDCP_NUM_DOWNSTREAM(read_buffer[0]);
+
+	dev_dbg(mtk_dp->dev, "[HDCP1.X] Binfo max_cascade_EXCEEDED:%lu\n",
+		DRM_HDCP_MAX_CASCADE_EXCEEDED(read_buffer[1]));
+	dev_dbg(mtk_dp->dev, "[HDCP1.X] Binfo DEPTH:%d\n", read_buffer[1] & 0x07);
+	dev_dbg(mtk_dp->dev, "[HDCP1.X] Binfo max_devs_EXCEEDED:%lu\n",
+		DRM_HDCP_MAX_DEVICE_EXCEEDED(read_buffer[0]));
+	dev_dbg(mtk_dp->dev, "[HDCP1.X] Binfo device_count:%d\n",
+		hdcp_info->hdcp1x_info.device_count);
+
+	return 0;
+}
+
+static int dp_tx_hdcp1x_read_sink_ksv(struct mtk_hdcp_info *hdcp_info, u8 dev_count)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 times = dev_count / 3;
+	u8 remain = dev_count % 3;
+	ssize_t ret;
+	u8 i;
+
+	if (times > 0) {
+		for (i = 0; i < times; i++) {
+			ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_KSV_FIFO,
+					       hdcp_info->hdcp1x_info.ksvfifo + i * 15, 15);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	if (remain > 0) {
+		ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_KSV_FIFO,
+				       hdcp_info->hdcp1x_info.ksvfifo + times * 15, remain * 5);
+		if (ret < 0)
+			return ret;
+	}
+
+	dev_dbg(mtk_dp->dev, "[HDCP1.X] Read ksvfifo:0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+		hdcp_info->hdcp1x_info.ksvfifo[0],
+		hdcp_info->hdcp1x_info.ksvfifo[1],
+		hdcp_info->hdcp1x_info.ksvfifo[2],
+		hdcp_info->hdcp1x_info.ksvfifo[3],
+		hdcp_info->hdcp1x_info.ksvfifo[4]);
+
+	return 0;
+}
+
+static int dp_tx_hdcp1x_read_sink_sha_v(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 read_buffer[4], i, j;
+	ssize_t ret;
+
+	for (i = 0; i < 5; i++) {
+		ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_V_PRIME(i), read_buffer, 4);
+		if (ret < 0)
+			return ret;
+
+		for (j = 0; j < 4; j++) {
+			hdcp_info->hdcp1x_info.v[(i * 4) + j] = read_buffer[3 - j];
+			dev_dbg(mtk_dp->dev, "[HDCP1.X] Read sink V:0x%x\n",
+				hdcp_info->hdcp1x_info.v[(i * 4) + j]);
+		}
+	}
+
+	return 0;
+}
+
+static int dp_tx_hdcp1x_auth_with_repeater(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 *buffer;
+	u32 len;
+	int ret;
+
+	if (hdcp_info->hdcp1x_info.device_count > HDCP1X_REP_MAXDEVS) {
+		dev_err(mtk_dp->dev, "[HDCP1.X] Repeater:%d exceed max devs\n",
+			hdcp_info->hdcp1x_info.device_count);
+		return -EINVAL;
+	}
+
+	ret = dp_tx_hdcp1x_read_sink_ksv(hdcp_info, hdcp_info->hdcp1x_info.device_count);
+	if (ret)
+		return ret;
+
+	ret = dp_tx_hdcp1x_read_sink_sha_v(hdcp_info);
+	if (ret)
+		return ret;
+
+	len = hdcp_info->hdcp1x_info.device_count * DRM_HDCP_KSV_LEN + HDCP1X_B_INFO_LEN;
+	buffer = kmalloc(len, GFP_KERNEL);
+	if (!buffer) {
+		dev_err(mtk_dp->dev, "[HDCP1.X] Out of Memory\n");
+		return -ENOMEM;
+	}
+
+	memcpy(buffer, hdcp_info->hdcp1x_info.ksvfifo, len - HDCP1X_B_INFO_LEN);
+	memcpy(buffer + (len - HDCP1X_B_INFO_LEN), hdcp_info->hdcp1x_info.b_info,
+	       HDCP1X_B_INFO_LEN);
+	ret = tee_hdcp1x_compute_compare_v(hdcp_info, buffer, len, hdcp_info->hdcp1x_info.v);
+	if (!ret)
+		dev_dbg(mtk_dp->dev, "[HDCP1.X] Check V' pass\n");
+	else
+		dev_err(mtk_dp->dev, "[HDCP1.X] Check V' fail\n");
+
+	kfree(buffer);
+
+	return ret;
+}
+
+static int dp_tx_hdcp1x_verify_b_ksv(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	int i, j, k = 0;
+	u8 ksv;
+
+	for (i = 0; i < DRM_HDCP_KSV_LEN; i++) {
+		ksv = hdcp_info->hdcp1x_info.b_ksv[i];
+		for (j = 0; j < 8; j++)
+			k += (ksv >> j) & 0x01;
+	}
+
+	if (k != 20) {
+		dev_err(mtk_dp->dev, "[HDCP1.X] Check BKSV 20'1' 20'0' fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dp_tx_hdcp1x_write_a_ksv(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	int i, k, j;
+	ssize_t ret;
+	u8 tmp;
+
+	ret = tee_get_aksv(hdcp_info, hdcp_info->hdcp1x_info.a_ksv);
+	if (ret)
+		return ret;
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_AUX_HDCP_AKSV, hdcp_info->hdcp1x_info.a_ksv,
+				DRM_HDCP_KSV_LEN);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0, k = 0; i < DRM_HDCP_KSV_LEN; i++) {
+		tmp = hdcp_info->hdcp1x_info.a_ksv[i];
+
+		for (j = 0; j < 8; j++)
+			k += (tmp >> j) & 0x01;
+		dev_dbg(mtk_dp->dev, "[HDCP1.X] Aksv:0x%x\n", tmp);
+	}
+
+	if (k != 20) {
+		dev_err(mtk_dp->dev, "[HDCP1.X] Check AKSV 20'1' 20'0' fail\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dp_tx_hdcp1x_write_an(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 an_value[DRM_HDCP_AN_LEN] = { /* on DP Spec p99 */
+		0x03, 0x04, 0x07, 0x0C, 0x13, 0x1C, 0x27, 0x34};
+	int ret;
+
+	ret = tee_hdcp1x_set_tx_an(hdcp_info, an_value);
+	if (ret)
+		return ret;
+
+	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_AUX_HDCP_AN, an_value, DRM_HDCP_AN_LEN);
+	if (ret < 0)
+		return ret;
+
+	mdelay(5);
+
+	return 0;
+}
+
+static int dp_tx_hdcp1x_check_r0(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 value[DRM_HDCP_BSTATUS_LEN];
+	bool sink_R0_available = false;
+	int i, tries;
+	ssize_t ret;
+	bool tmp;
+
+	tmp = dp_tx_hdcp1x_get_r0_available(hdcp_info);
+	if (!tmp) {
+		dev_err(mtk_dp->dev, "[HDCP1.X] Fail to get R0 available\n");
+		return -EINVAL;
+	}
+
+	tries = 2;
+	for (i = 0; i < tries; i++) {
+		ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BSTATUS, value, 1);
+		if (ret < 0)
+			continue;
+
+		sink_R0_available = (value[0x0] & DP_BSTATUS_R0_PRIME_READY) ? true : false;
+		if (sink_R0_available)
+			break;
+	}
+
+	if (i == tries) {
+		dev_err(mtk_dp->dev, "[HDCP1.X] R0 no available\n");
+		return -EINVAL;
+	}
+
+	tries = 3;
+	while (i < tries) {
+		ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_RI_PRIME, value, DRM_HDCP_RI_LEN);
+		if (ret < 0)
+			return ret;
+
+		ret = tee_compare_r0(hdcp_info, value, DRM_HDCP_RI_LEN);
+		if (!ret)
+			return ret;
+
+		dev_dbg(mtk_dp->dev, "[HDCP1.X] R0 check FAIL, Rx_R0:0x%x, 0x%x, retry\n",
+			value[0x1], value[0x0]);
+		mdelay(5);
+
+		i++;
+	}
+
+	dev_err(mtk_dp->dev, "[HDCP1.X] R0 check fail\n");
+	return -EINVAL;
+}
+
+/* Implements Part 1 of the HDCP authorization procedure */
+static int dp_tx_hdcp1x_auth(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	int ret, i, tries = 2;
+	bool expired;
+	ktime_t end;
+
+	if (!hdcp_info->hdcp1x_info.capable)
+		return -EAGAIN;
+
+	ret = dp_tx_hdcp1x_init(hdcp_info);
+	if (ret)
+		return ret;
+
+	ret = dp_tx_hdcp1x_write_an(hdcp_info);
+	if (ret)
+		return ret;
+	ret = dp_tx_hdcp1x_write_a_ksv(hdcp_info);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < tries; i++) {
+		ret = dp_tx_hdcp1x_read_sink_b_ksv(hdcp_info);
+		if (ret)
+			continue;
+
+		ret = dp_tx_hdcp1x_verify_b_ksv(hdcp_info);
+		if (!ret)
+			break;
+	}
+	if (i == tries)
+		return -ENODEV;
+	if (drm_hdcp_check_ksvs_revoked(mtk_dp->drm_dev, hdcp_info->hdcp1x_info.b_ksv, 1) > 0) {
+		dev_err(mtk_dp->dev, "[HDCP1.X] BKSV is revoked\n");
+		return -EPERM;
+	}
+
+	dp_tx_hdcp1x_set_repeater(hdcp_info, hdcp_info->hdcp1x_info.repeater);
+
+	ret = tee_calculate_lm(hdcp_info, hdcp_info->hdcp1x_info.b_ksv);
+	if (ret)
+		return ret;
+	dp_tx_hdcp1x_start_cipher(hdcp_info, true);
+
+	/* Wait 100ms(at least) before check R0 */
+	msleep(HDCP1X_R0_WDT);
+	ret = dp_tx_hdcp1x_check_r0(hdcp_info);
+	if (ret)
+		return ret;
+	ret = tee_hdcp_enable_encrypt(hdcp_info, true, HDCP_V1);
+	if (ret)
+		return ret;
+
+	if (!hdcp_info->hdcp1x_info.repeater)
+		return 0;
+
+	/* Check ksv ready (defined max time as 5s in spec) */
+	end = ktime_add_ms(ktime_get_raw(), HDCP1X_REP_RDY_WDT);
+	for (;;) {
+		ret = dp_tx_hdcp1x_check_sink_ksv_ready(hdcp_info);
+		if (!ret)
+			break;
+
+		expired = ktime_after(ktime_get_raw(), end);
+		if (expired) {
+			ret = -ETIMEDOUT;
+			dev_err(mtk_dp->dev, "[HDCP1.X] Check sink ksv ready timeout\n");
+			goto fail;
+		}
+
+		msleep(100);
+	}
+
+	ret = dp_tx_hdcp1x_check_sink_ksv_ready(hdcp_info);
+	if (ret)
+		goto fail;
+
+	ret = dp_tx_hdcp1x_read_sink_b_info(hdcp_info);
+	if (ret)
+		goto fail;
+
+	ret = dp_tx_hdcp1x_auth_with_repeater(hdcp_info);
+	if (ret)
+		goto fail;
+
+	return 0;
+
+fail:
+	tee_hdcp_enable_encrypt(hdcp_info, false, HDCP_NONE);
+
+	return ret;
+}
+
+void dp_tx_hdcp1x_get_info(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	u8 tmp[2];
+	ssize_t ret;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BCAPS, tmp, 0x1);
+	if (ret < 0)
+		return;
+
+	hdcp_info->hdcp1x_info.capable = tmp[0x0] & DP_BCAPS_HDCP_CAPABLE;
+	hdcp_info->hdcp1x_info.repeater = tmp[0x0] & DP_BCAPS_REPEATER_PRESENT;
+
+	dev_info(mtk_dp->dev, "[HDCP1.X] Capable:%d, Reapeater:%d\n",
+		 hdcp_info->hdcp1x_info.capable,
+		hdcp_info->hdcp1x_info.repeater);
+}
+
+int dp_tx_hdcp1x_enable(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	int ret = 0, i, tries = 3;
+
+	hdcp_info->auth_status = AUTH_INIT;
+
+	ret = tee_add_device(hdcp_info, HDCP_VERSION_1X);
+	if (ret)
+		goto fail;
+
+	for (i = 0; i < tries; i++) {
+		ret = dp_tx_hdcp1x_auth(hdcp_info);
+		if (!ret) {
+			hdcp_info->auth_version = HDCP_VERSION_1X;
+			hdcp_info->auth_status = AUTH_PASS;
+			dev_info(mtk_dp->dev, "[HDCP1.X] Authentication done\n");
+
+			return 0;
+		}
+	}
+
+	tee_remove_device(hdcp_info);
+
+fail:
+	hdcp_info->auth_status = AUTH_FAIL;
+	dev_err(mtk_dp->dev, "[HDCP1.X] Authentication fail\n");
+
+	return ret;
+}
+
+int dp_tx_hdcp1x_disabel(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	int ret;
+
+	if (hdcp_info->auth_status == AUTH_PASS) {
+		ret = tee_hdcp_enable_encrypt(hdcp_info, false, HDCP_NONE);
+		if (ret)
+			return ret;
+
+		dp_tx_hdcp1x_start_cipher(hdcp_info, false);
+
+		ret = tee_hdcp1x_soft_rst(hdcp_info);
+		if (ret)
+			return ret;
+	}
+
+	tee_remove_device(hdcp_info);
+
+	hdcp_info->auth_version = HDCP_NONE;
+	hdcp_info->auth_status = AUTH_ZERO;
+	dev_info(mtk_dp->dev, "[HDCP1.X] Disable Authentication\n");
+
+	return 0;
+}
+
+int dp_tx_hdcp1x_check_link(struct mtk_hdcp_info *hdcp_info)
+{
+	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
+	int ret = -EINVAL;
+	u8 bstatus;
+
+	mutex_lock(&mtk_dp->hdcp_mutex);
+
+	if (mtk_dp->hdcp_info.auth_status != AUTH_PASS)
+		goto end;
+
+	if (!mtk_dp->train_info.cable_plugged_in || !mtk_dp->enabled)
+		goto disable;
+
+	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_AUX_HDCP_BSTATUS, &bstatus, 1);
+	if (ret != 1) {
+		dev_dbg(mtk_dp->dev, "[HDCP1.X] Read bstatus failed, reauth\n");
+		goto disable;
+	}
+
+	ret = bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ);
+
+	if (!ret) {
+		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_ENABLED);
+		goto end;
+	}
+
+disable:
+	ret = dp_tx_hdcp1x_disabel(hdcp_info);
+	if (ret || !mtk_dp->train_info.cable_plugged_in || !mtk_dp->enabled) {
+		ret = -EAGAIN;
+		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_DESIRED);
+		goto end;
+	}
+
+	ret = dp_tx_hdcp1x_enable(hdcp_info);
+	if (ret)
+		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_DESIRED);
+
+end:
+	mutex_unlock(&mtk_dp->hdcp_mutex);
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h b/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h
new file mode 100644
index 000000000000..f0a19c491791
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dp_hdcp1x.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019-2024 MediaTek Inc.
+ */
+
+#ifndef _MTK_DP_HDCP1X_H_
+#define _MTK_DP_HDCP1X_H_
+
+#include "tlc_dp_hdcp.h"
+
+#define HDCP_VERSION_1X 1
+
+void dp_tx_hdcp1x_get_info(struct mtk_hdcp_info *hdcp_info);
+int dp_tx_hdcp1x_enable(struct mtk_hdcp_info *hdcp_info);
+int dp_tx_hdcp1x_disabel(struct mtk_hdcp_info *hdcp_info);
+int dp_tx_hdcp1x_check_link(struct mtk_hdcp_info *hdcp_info);
+#endif /* _MTK_DP_HDCP1X_H_ */
diff --git a/drivers/gpu/drm/mediatek/mtk_dp_reg.h b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
index 8c60983a26ed..c04ea5dda6bd 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp_reg.h
+++ b/drivers/gpu/drm/mediatek/mtk_dp_reg.h
@@ -277,6 +277,9 @@
 #define MTK_DP_TRANS_P0_3430				0x3430
 #define HPD_INT_THD_ECO_DP_TRANS_P0_MASK			GENMASK(1, 0)
 #define HPD_INT_THD_ECO_DP_TRANS_P0_HIGH_BOUND_EXT		BIT(1)
+#define MTK_DP_TRANS_P0_3480                0x3480
+#define REQ_BLOCK_CIPHER_AUTH                           BIT(12)
+#define KM_GENERATED                                    BIT(4)
 #define MTK_DP_TRANS_P0_34A4				0x34a4
 #define HDCP22_AUTH_DONE_DP_TRANS_P0_MASK		BIT(4)
 #define R0_AVAILABLE_DP_TRANS_P0		BIT(12)
-- 
2.43.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
@ 2024-07-18  5:41   ` CK Hu (胡俊光)
  2024-07-18  6:23   ` CK Hu (胡俊光)
                     ` (13 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-07-18  5:41 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +static void mtk_dp_hdcp_get_info(struct mtk_dp *mtk_dp)
> +{
> +	dp_tx_hdcp2x_get_info(&mtk_dp->hdcp_info);

dp_tx_hdcp2x_get_info() is only called by mtk_dp_hdcp_get_info() and mtk_dp_hdcp_get_info() only call mtk_dp_hdcp_get_info(),
so merge these two function.

Regards,
CK

> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
  2024-07-18  5:41   ` CK Hu (胡俊光)
@ 2024-07-18  6:23   ` CK Hu (胡俊光)
  2024-07-18  7:48   ` CK Hu (胡俊光)
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-07-18  6:23 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +/* Authentication flow starts from here */
> +static int dp_tx_hdcp2x_key_exchange(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	bool stored;
> +	int ret;
> +
> +	if (!hdcp_info->hdcp2_info.capable)
> +		return -EAGAIN;
> +
> +	ret = dp_tx_hdcp2x_init(hdcp_info);
> +	if (ret)
> +		return ret;
> +
> +	ret = dp_tx_hdcp2x_write_ake_init(hdcp_info);
> +	if (ret)
> +		return ret;
> +
> +	ret = dp_tx_hdcp2x_read_ake_send_cert(hdcp_info);
> +	if (ret)
> +		return ret;
> +
> +	hdcp_info->hdcp2_info.repeater =
> +		HDCP_2_2_RX_REPEATER(hdcp_info->hdcp2_info.hdcp_rx.send_cert.rx_caps[2]);
> +
> +	if (drm_hdcp_check_ksvs_revoked(mtk_dp->drm_dev,
> +					hdcp_info->hdcp2_info.hdcp_rx.send_cert.cert_rx.receiver_id,
> +					1) > 0) {
> +		dev_err(mtk_dp->dev, "[HDCP2.X] Receiver ID is revoked\n");
> +		return -EPERM;
> +	}
> +
> +	ret = tee_ake_certificate(hdcp_info,
> +				  (u8 *)&hdcp_info->hdcp2_info.hdcp_rx.cert_rx, &stored,
> +		hdcp_info->hdcp2_info.ake_stored_km.e_kh_km_m +
> +		HDCP_2_2_E_KH_KM_LEN,
> +		hdcp_info->hdcp2_info.ake_stored_km.e_kh_km_m);
> +	if (ret)
> +		return ret;
> +
> +	hdcp_info->hdcp2_info.stored_km = stored;
> +
> +	if (!hdcp_info->hdcp2_info.stored_km) {
> +		ret = tee_enc_rsaes_oaep(hdcp_info,
> +					 hdcp_info->hdcp2_info.hdcp_tx.no_stored_km.e_kpub_km);
> +		if (ret)
> +			return ret;
> +
> +		ret = dp_tx_hdcp2x_write_ake_no_stored_km(hdcp_info);
> +		if (ret)
> +			return ret;
> +
> +	} else {
> +		ret = dp_tx_hdcp2x_write_ake_stored_km(hdcp_info);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = dp_tx_hdcp2x_read_ake_send_hprime(hdcp_info);
> +	if (ret)
> +		return ret;
> +
> +	ret = tee_ake_h_prime(hdcp_info,
> +			      hdcp_info->hdcp2_info.hdcp_tx.ake_init.r_tx,
> +		hdcp_info->hdcp2_info.hdcp_rx.send_cert.r_rx,
> +		hdcp_info->hdcp2_info.hdcp_rx.send_cert.rx_caps,
> +		(u8 *)&hdcp_info->hdcp2_info.hdcp_tx.tx_caps,
> +		hdcp_info->hdcp2_info.hdcp_rx.send_hprime.h_prime,
> +		HDCP_2_2_H_PRIME_LEN);

hdcp_info->hdcp2_info.hdcp_tx.ake_init,
hdcp_info->hdcp2_info.hdcp_rx.send_cert,
hdcp_info->hdcp2_info.hdcp_rx.send_hprime,
hdcp_info->hdcp2_info.hdcp_tx.no_stored_km,
hdcp_info->hdcp2_info.stored_km,
hdcp_info->hdcp2_info.hdcp_rx.pairing_info

are used only in dp_tx_hdcp2x_key_exchange(), so make them as local variable in dp_tx_hdcp2x_key_exchange().

hdcp_info->hdcp2_info.hdcp_tx.tx_caps is constant value, so use t_tx_caps[] directly instead of using hdcp_info->hdcp2_info.hdcp_tx.tx_caps.

Regards,
CK

> +	if (ret) {
> +		if (hdcp_info->hdcp2_info.stored_km)
> +			tee_clear_paring(hdcp_info);
> +		return ret;
> +	}
> +
> +	if (!hdcp_info->hdcp2_info.stored_km) {
> +		ret = dp_tx_hdcp2x_read_ake_send_pairing_info(hdcp_info);
> +		if (ret)
> +			return ret;
> +
> +		/* Store m, km, Ekh(km) */
> +		ret = tee_ake_paring(hdcp_info,
> +				     hdcp_info->hdcp2_info.hdcp_rx.pairing_info.e_kh_km);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
  2024-07-18  5:41   ` CK Hu (胡俊光)
  2024-07-18  6:23   ` CK Hu (胡俊光)
@ 2024-07-18  7:48   ` CK Hu (胡俊光)
  2024-07-19  4:05   ` CK Hu (胡俊光)
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-07-18  7:48 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +static int dp_tx_hdcp2x_write_ake_no_stored_km(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_NO_STORED_KM\n");
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET,
> +				hdcp_info->hdcp2_info.hdcp_tx.no_stored_km.e_kpub_km,
> +		HDCP_2_2_E_KPUB_KM_LEN);
> +	if (ret < 0)

Directly return ret here.

> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int dp_tx_hdcp2x_write_ake_stored_km(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_STORED_KM\n");
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_AKE_STORED_KM_OFFSET,
> +				hdcp_info->hdcp2_info.ake_stored_km.e_kh_km_m,
> +		HDCP_2_2_E_KH_KM_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_M_OFFSET,
> +				hdcp_info->hdcp2_info.ake_stored_km.e_kh_km_m +
> +		HDCP_2_2_E_KH_KM_LEN,
> +		HDCP_2_2_E_KH_KM_M_LEN - HDCP_2_2_E_KH_KM_LEN);
> +	if (ret < 0)

Ditto.

Regards,
CK

> +		return ret;
> +
> +	return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (2 preceding siblings ...)
  2024-07-18  7:48   ` CK Hu (胡俊光)
@ 2024-07-19  4:05   ` CK Hu (胡俊光)
  2024-07-23  7:16   ` CK Hu (胡俊光)
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-07-19  4:05 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +static int dp_tx_hdcp2x_enable_auth(struct mtk_hdcp_info *hdcp_info, bool enable)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	u32 version;
> +	int ret;
> +
> +	dp_tx_hdcp2x_set_auth_pass(hdcp_info, enable);
> +	if (!enable) {
> +		ret = tee_hdcp_enable_encrypt(hdcp_info, enable, HDCP_NONE);
> +		if (ret)
> +			return ret;
> +		mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000, 0, HDCP_FRAME_EN_DP_ENC0_P0);
> +
> +		return 0;
> +	}
> +
> +	if (HDCP_2_2_HDCP1_DEVICE_CONNECTED(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[1]))
> +		version = HDCP_V1;

dp_tx_hdcp2x_enable_auth() is called only when HDCP 2.x, but here detect that version is 1.
I don't know the specification of HDCP, is this is an error case?
Or if this is a normal case, please add some comment here to explain for someone who don't know HDCP specification.

Regards,
CK

> +	else if (HDCP_2_2_HDCP_2_0_REP_CONNECTED
> +		(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[1]))
> +		version = HDCP_V2;
> +	else
> +		version = HDCP_V2_3;
> +
> +	ret = tee_hdcp_enable_encrypt(hdcp_info, enable, version);
> +	if (ret)
> +		return ret;
> +	mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_3000,
> +			   HDCP_FRAME_EN_DP_ENC0_P0, HDCP_FRAME_EN_DP_ENC0_P0);
> +
> +	return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (3 preceding siblings ...)
  2024-07-19  4:05   ` CK Hu (胡俊光)
@ 2024-07-23  7:16   ` CK Hu (胡俊光)
  2024-08-12  7:05   ` CK Hu (胡俊光)
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-07-23  7:16 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +static int dp_tx_hdcp2x_init(struct mtk_hdcp_info *hdcp_info)
> +{
> +	int ret;
> +
> +	memset(&hdcp_info->hdcp2_info.hdcp_tx, 0, sizeof(struct hdcp2_info_tx));
> +	memset(&hdcp_info->hdcp2_info.hdcp_rx, 0, sizeof(struct hdcp2_info_rx));
> +	memset(&hdcp_info->hdcp2_info.ake_stored_km, 0, sizeof(struct hdcp2_ake_stored_km));
> +	memcpy(hdcp_info->hdcp2_info.hdcp_tx.ake_init.r_tx, t_rtx, HDCP_2_2_RTX_LEN);
> +	memcpy(&hdcp_info->hdcp2_info.hdcp_tx.tx_caps, t_tx_caps, HDCP_2_2_TXCAPS_LEN);
> +	memcpy(hdcp_info->hdcp2_info.hdcp_tx.lc_init.r_n, t_rn, HDCP_2_2_RN_LEN);
> +	memcpy(hdcp_info->hdcp2_info.hdcp_tx.send_eks.riv, t_riv, HDCP_2_2_RIV_LEN);
> +
> +	ret = dp_tx_hdcp2x_enable_auth(hdcp_info, false);

By default, auth is disabled. So this is redundant.

Regards,
CK

> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (4 preceding siblings ...)
  2024-07-23  7:16   ` CK Hu (胡俊光)
@ 2024-08-12  7:05   ` CK Hu (胡俊光)
  2024-08-12  7:25   ` CK Hu (胡俊光)
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-08-12  7:05 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +int dp_tx_hdcp2x_check_link(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	u8 rx_status;
> +	int ret = -EINVAL;
> +	int tmp = 0;
> +
> +	mutex_lock(&mtk_dp->hdcp_mutex);
> +
> +	if (mtk_dp->hdcp_info.auth_status != AUTH_PASS)
> +		goto end;
> +
> +	if (!mtk_dp->train_info.cable_plugged_in || !mtk_dp->enabled)
> +		goto disable;
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
> +			       HDCP_2_2_DP_RXSTATUS_LEN);
> +	if (ret != HDCP_2_2_DP_RXSTATUS_LEN) {
> +		dev_dbg(mtk_dp->dev, "[HDCP2.X] Read bstatus failed, reauth\n");
> +		goto disable;
> +	}
> +
> +	if (HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(rx_status))
> +		tmp = REAUTH_REQUEST;
> +	else if (HDCP_2_2_DP_RXSTATUS_LINK_FAILED(rx_status))
> +		tmp = LINK_INTEGRITY_FAILURE;
> +	else if (HDCP_2_2_DP_RXSTATUS_READY(rx_status))
> +		tmp = TOPOLOGY_CHANGE;
> +
> +	if (tmp == LINK_PROTECTED) {
> +		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_ENABLED);
> +		ret = 0;
> +		goto end;
> +	}
> +
> +	if (tmp == TOPOLOGY_CHANGE) {
> +		ret = dp_tx_hdcp2x_authenticate_repeater(hdcp_info);
> +		if (!ret) {
> +			mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_ENABLED);
> +			goto end;
> +		}
> +	} else {
> +		dev_info(mtk_dp->dev, "[HDCP2.X] link failed with:0x%x, retrying auth\n", tmp);
> +	}
> +
> +disable:
> +	ret = dp_tx_hdcp2x_disabel(hdcp_info);
> +	if (ret || !mtk_dp->train_info.cable_plugged_in || !mtk_dp->enabled) {
> +		ret = -EAGAIN;
> +		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_DESIRED);
> +		goto end;
> +	}
> +
> +	ret = dp_tx_hdcp2x_enable(hdcp_info);

When something error then go here. Why enable hdcp?

Regards,
CK

> +	if (ret)
> +		mtk_dp_hdcp_update_value(mtk_dp, DRM_MODE_CONTENT_PROTECTION_DESIRED);
> +
> +end:
> +	mutex_unlock(&mtk_dp->hdcp_mutex);
> +
> +	return ret;
> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (5 preceding siblings ...)
  2024-08-12  7:05   ` CK Hu (胡俊光)
@ 2024-08-12  7:25   ` CK Hu (胡俊光)
  2024-08-22  5:39   ` CK Hu (胡俊光)
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-08-12  7:25 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> @@ -2242,6 +2373,7 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
>  					struct drm_bridge_state *old_state)
>  {
>  	struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
> +	struct drm_connector_state *connector_state;
>  	int ret;
>  
>  	mtk_dp->conn = drm_atomic_get_new_connector_for_encoder(old_state->base.state,
> @@ -2252,6 +2384,8 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
>  		return;
>  	}
>  
> +	connector_state = drm_atomic_get_connector_state(old_state->base.state, mtk_dp->conn);
> +
>  	mtk_dp_aux_panel_poweron(mtk_dp, true);
>  
>  	/* Training */
> @@ -2281,6 +2415,14 @@ static void mtk_dp_bridge_atomic_enable(struct drm_bridge *bridge,
>  	mtk_dp->enabled = true;
>  	mtk_dp_update_plugged_status(mtk_dp);
>  
> +	/* Enable hdcp if it's desired */
> +	dev_dbg(mtk_dp->dev, "hdcp_content_type:%d, content protection: %d",
> +		connector_state->hdcp_content_type, connector_state->content_protection);
> +	if (connector_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
> +		mtk_dp->hdcp_info.hdcp_content_type = connector_state->hdcp_content_type;
> +		mtk_dp_hdcp_enable(mtk_dp);
> +	}
> +
>  	return;
>  power_off_aux:
>  	mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
> @@ -2427,6 +2569,8 @@ static int mtk_dp_bridge_atomic_check(struct drm_bridge *bridge,
>  
>  	drm_display_mode_to_videomode(&crtc_state->adjusted_mode, &mtk_dp->info.vm);
>  
> +	mtk_dp_hdcp_atomic_check(mtk_dp, conn_state);
> +
>  	return 0;
>  }

In mtk_dp_bridge_atomic_enable(), you enable hdcp.
So in mtk_dp_bridge_atomic_disable(), you should disable hdcp.

Regards,
CK

>  

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (6 preceding siblings ...)
  2024-08-12  7:25   ` CK Hu (胡俊光)
@ 2024-08-22  5:39   ` CK Hu (胡俊光)
  2024-08-22  6:20   ` CK Hu (胡俊光)
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-08-22  5:39 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +static int dp_tx_hdcp2x_write_lc_init(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_LC_INIT\n");
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_LC_INIT_OFFSET,
> +				hdcp_info->hdcp2_info.hdcp_tx.lc_init.r_n, HDCP_2_2_RN_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;

This function is called only by dp_tx_hdcp2x_locality_check() and this function just does one thing.
So merge this function into dp_tx_hdcp2x_locality_check().

Regards,
CK

> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (7 preceding siblings ...)
  2024-08-22  5:39   ` CK Hu (胡俊光)
@ 2024-08-22  6:20   ` CK Hu (胡俊光)
  2024-08-23  1:07   ` CK Hu (胡俊光)
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-08-22  6:20 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +static int dp_tx_hdcp2x_read_lc_send_lprime(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_LC_SEND_LPRIME\n");
> +
> +	mdelay(HDCP_2_2_DP_LPRIME_TIMEOUT_MS);
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.send_lprime.l_prime,
> +		HDCP_2_2_L_PRIME_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;

This function is called only by dp_tx_hdcp2x_locality_check(), and this function just does two things.
So merge this function into dp_tx_hdcp2x_locality_check().

Regards,
CK

> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (8 preceding siblings ...)
  2024-08-22  6:20   ` CK Hu (胡俊光)
@ 2024-08-23  1:07   ` CK Hu (胡俊光)
  2024-08-23  2:44   ` CK Hu (胡俊光)
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-08-23  1:07 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +static int dp_tx_hdcp2x_write_ske_send_eks(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_SKE_SEND_EKS\n");
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_SKE_SEND_EKS_OFFSET,
> +				hdcp_info->hdcp2_info.hdcp_tx.send_eks.e_dkey_ks,
> +		HDCP_2_2_E_DKEY_KS_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_RIV_OFFSET,
> +				hdcp_info->hdcp2_info.hdcp_tx.send_eks.riv, HDCP_2_2_RIV_LEN);

riv is constant, so remove hdcp_info->hdcp2_info.hdcp_tx.send_eks.riv and use t_riv directly.

> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int dp_tx_hdcp2x_session_key_exchange(struct mtk_hdcp_info *hdcp_info)
> +{
> +	int ret;
> +
> +	ret = tee_ske_enc_ks(hdcp_info, hdcp_info->hdcp2_info.hdcp_tx.send_eks.riv,
> +			     hdcp_info->hdcp2_info.hdcp_tx.send_eks.e_dkey_ks);

Ditto.

Regards,
CK

> +	if (ret)
> +		return ret;
> +
> +	ret = dp_tx_hdcp2x_write_ske_send_eks(hdcp_info);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (9 preceding siblings ...)
  2024-08-23  1:07   ` CK Hu (胡俊光)
@ 2024-08-23  2:44   ` CK Hu (胡俊光)
  2024-08-23  7:30   ` CK Hu (胡俊光)
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-08-23  2:44 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +static int dp_tx_hdcp2x_write_ske_send_eks(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_SKE_SEND_EKS\n");
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_SKE_SEND_EKS_OFFSET,
> +				hdcp_info->hdcp2_info.hdcp_tx.send_eks.e_dkey_ks,
> +		HDCP_2_2_E_DKEY_KS_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REG_RIV_OFFSET,
> +				hdcp_info->hdcp2_info.hdcp_tx.send_eks.riv, HDCP_2_2_RIV_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;

This function is called only by dp_tx_hdcp2x_session_key_exchange() and only does two things.
So merge this function into dp_tx_hdcp2x_session_key_exchange().

Regards,
CK

> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (10 preceding siblings ...)
  2024-08-23  2:44   ` CK Hu (胡俊光)
@ 2024-08-23  7:30   ` CK Hu (胡俊光)
  2024-10-30  8:20   ` CK Hu (胡俊光)
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-08-23  7:30 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +static int dp_tx_hdcp2x_read_ake_send_hprime(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	ktime_t msg_end;
> +	bool msg_expired;
> +	u8 rx_status = 0;
> +	int timeout;
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_AKE_SEND_HPRIME\n");
> +
> +	timeout = hdcp_info->hdcp2_info.stored_km ?
> +		HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS : HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS;
> +
> +	dp_tx_hdcp2x_wait_for_cp_irq(hdcp_info, timeout);
> +	hdcp_info->hdcp2_info.cp_irq_cached = atomic_read(&hdcp_info->hdcp2_info.cp_irq);

cp_irq_cached is updated always after dp_tx_hdcp2x_wait_for_cp_irq(),
and  cp_irq_cached is only used in dp_tx_hdcp2x_wait_for_cp_irq(),
so move this update into dp_tx_hdcp2x_wait_for_cp_irq().

Regards,
CK

> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
> +			       HDCP_2_2_DP_RXSTATUS_LEN);
> +	if (ret != HDCP_2_2_DP_RXSTATUS_LEN)
> +		return ret >= 0 ? -EIO : ret;
> +
> +	if (!HDCP_2_2_DP_RXSTATUS_H_PRIME(rx_status))
> +		return -EAGAIN;
> +
> +	msg_end = ktime_add_ms(ktime_get_raw(), HDCP_2_2_DP_HPRIME_READ_TIMEOUT_MS);
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.send_hprime.h_prime,
> +		HDCP_2_2_H_PRIME_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	msg_expired = ktime_after(ktime_get_raw(), msg_end);
> +	if (msg_expired)
> +		dev_dbg(mtk_dp->dev, "[HDCP2.X] Timeout to read AKE hprime\n");
> +
> +	return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 3/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP1.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 3/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP1.x " mac.shen
@ 2024-08-30  9:03   ` CK Hu (胡俊光)
  0 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-08-30  9:03 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	angelogioacchino.delregno@collabora.com
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - remove useless code
> - remove magic number
> - refine the flow to do HDCP1.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!l3mVePuKN038rd5XoCuION0zP40BtWBb7148hHsXs7hCWDTRgESIkfNHuEtPQ1Rb4P9MOpJZstgE4j2LJg$ 
> /patch/20240205055055.25340-4-mac.shen@mediatek.com/

Move the version change information after '---'.

In here, describe HDCP1.x.
Does MediaTek DP has some limitation? If so, describe it.

I would like to HDCP1.x patch in front of HDCP2.x because the spec development is from 1.x to 2.x.
So move this patch before HDCP2.x patch.

Regards,
CK

> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (11 preceding siblings ...)
  2024-08-23  7:30   ` CK Hu (胡俊光)
@ 2024-10-30  8:20   ` CK Hu (胡俊光)
  2024-11-01  7:18   ` CK Hu (胡俊光)
  2024-11-01  9:01   ` CK Hu (胡俊光)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-10-30  8:20 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	AngeloGioacchino Del Regno
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +static int dp_tx_hdcp2x_read_rep_send_recvid_list(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	u8 rx_status = 0;
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_REP_SEND_RECVID_LIST\n");
> +
> +	dp_tx_hdcp2x_wait_for_cp_irq(hdcp_info, HDCP_2_2_RECVID_LIST_TIMEOUT_MS);
> +	hdcp_info->hdcp2_info.cp_irq_cached = atomic_read(&hdcp_info->hdcp2_info.cp_irq);
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
> +			       HDCP_2_2_DP_RXSTATUS_LEN);
> +	if (ret != HDCP_2_2_DP_RXSTATUS_LEN)
> +		return ret >= 0 ? -EIO : ret;
> +
> +	if (!HDCP_2_2_DP_RXSTATUS_READY(rx_status)) {
> +		dev_err(mtk_dp->dev, "[HDCP2.X] RX status no ready\n");
> +		return -EAGAIN;

In [1], intel return -ETIMEOUT and not retry. Maybe return -ETIMEOUT is better?

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/i915/display/intel_dp_hdcp.c?h=v6.12-rc5#n428

Regards,
CK

> +	}
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info,
> +		HDCP_2_2_RXINFO_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	hdcp_info->hdcp2_info.device_count =
> +	(HDCP_2_2_DEV_COUNT_HI(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[0]) << 4 |
> +	HDCP_2_2_DEV_COUNT_LO(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[1]));
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.seq_num_v,
> +		HDCP_2_2_SEQ_NUM_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_VPRIME_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.v_prime,
> +		HDCP_2_2_V_PRIME_HALF_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.receiver_ids,
> +		hdcp_info->hdcp2_info.device_count * HDCP_2_2_RECEIVER_ID_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (12 preceding siblings ...)
  2024-10-30  8:20   ` CK Hu (胡俊光)
@ 2024-11-01  7:18   ` CK Hu (胡俊光)
  2024-11-07  7:05     ` CK Hu (胡俊光)
  2024-11-01  9:01   ` CK Hu (胡俊光)
  14 siblings, 1 reply; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-11-01  7:18 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	AngeloGioacchino Del Regno
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +
> +static int dp_tx_hdcp2x_read_rep_send_recvid_list(struct mtk_hdcp_info *hdcp_info)
> +{
> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	u8 rx_status = 0;
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_REP_SEND_RECVID_LIST\n");
> +
> +	dp_tx_hdcp2x_wait_for_cp_irq(hdcp_info, HDCP_2_2_RECVID_LIST_TIMEOUT_MS);
> +	hdcp_info->hdcp2_info.cp_irq_cached = atomic_read(&hdcp_info->hdcp2_info.cp_irq);
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
> +			       HDCP_2_2_DP_RXSTATUS_LEN);
> +	if (ret != HDCP_2_2_DP_RXSTATUS_LEN)
> +		return ret >= 0 ? -EIO : ret;
> +
> +	if (!HDCP_2_2_DP_RXSTATUS_READY(rx_status)) {
> +		dev_err(mtk_dp->dev, "[HDCP2.X] RX status no ready\n");
> +		return -EAGAIN;
> +	}
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info,
> +		HDCP_2_2_RXINFO_LEN);

In [1], intel use DP_HDCP_2_2_REG_RXINFO_OFFSET to get device count.
But here you use DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET to get device count.
So both command can get device count? Or something wrong?

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/i915/display/intel_dp_hdcp.c?h=v6.12-rc5#n497

Regards,
CK

> +	if (ret < 0)
> +		return ret;
> +
> +	hdcp_info->hdcp2_info.device_count =
> +	(HDCP_2_2_DEV_COUNT_HI(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[0]) << 4 |
> +	HDCP_2_2_DEV_COUNT_LO(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[1]));
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.seq_num_v,
> +		HDCP_2_2_SEQ_NUM_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_VPRIME_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.v_prime,
> +		HDCP_2_2_V_PRIME_HALF_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET,
> +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.receiver_ids,
> +		hdcp_info->hdcp2_info.device_count * HDCP_2_2_RECEIVER_ID_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
                     ` (13 preceding siblings ...)
  2024-11-01  7:18   ` CK Hu (胡俊光)
@ 2024-11-01  9:01   ` CK Hu (胡俊光)
  14 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-11-01  9:01 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	AngeloGioacchino Del Regno
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> Changes in v3:
> - refine the function to get system time
> - refine the flow to do HDCP with content type and
>   protection value which set by user space
> - refine the flow to update content protection
> - refine the flow to do HDCP2.x authentication
> per suggestion from the previous thread:
> https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> 
> Signed-off-by: mac.shen <mac.shen@mediatek.com>
> ---

[snip]

> +static int dp_tx_hdcp2x_write_send_ack(struct mtk_hdcp_info *hdcp_info)
> +{

This function is only called by one place and this function just does one thing, so merge this function into caller function.

Regards,
CK

> +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> +	ssize_t ret;
> +
> +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_SEND_ACK\n");
> +
> +	ret = drm_dp_dpcd_write(&mtk_dp->aux, DP_HDCP_2_2_REP_SEND_ACK_OFFSET,
> +				hdcp_info->hdcp2_info.hdcp_tx.send_ack.v,
> +		HDCP_2_2_V_PRIME_HALF_LEN);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort
  2024-11-01  7:18   ` CK Hu (胡俊光)
@ 2024-11-07  7:05     ` CK Hu (胡俊光)
  0 siblings, 0 replies; 21+ messages in thread
From: CK Hu (胡俊光) @ 2024-11-07  7:05 UTC (permalink / raw)
  To: Mac Shen (沈俊), chunkuang.hu@kernel.org,
	Jitao Shi (石记涛), daniel@ffwll.ch,
	p.zabel@pengutronix.de, airlied@gmail.com, matthias.bgg@gmail.com,
	AngeloGioacchino Del Regno
  Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	Shuijing Li (李水静)

Hi, Mac:

On Fri, 2024-11-01 at 15:18 +0800, CK Hu wrote:
> Hi, Mac:
> 
> On Sat, 2024-06-08 at 20:01 +0800, mac.shen wrote:
> > Changes in v3:
> > - refine the function to get system time
> > - refine the flow to do HDCP with content type and
> >   protection value which set by user space
> > - refine the flow to update content protection
> > - refine the flow to do HDCP2.x authentication
> > per suggestion from the previous thread:
> > https://urldefense.com/v3/__https://patchwork.kernel.org/project/linux-mediatek__;!!CTRNKA9wMg0ARbw!md6xUiYN88D2YmETs8FQgaExM2zH8S1SmAEU9GRchwpNsXOyDFul3ziVKhRpCJaj8Rcn-gvM-801runjwA$ 
> > /patch/20240205055055.25340-3-mac.shen@mediatek.com/
> > 
> > Signed-off-by: mac.shen <mac.shen@mediatek.com>
> > ---
> 
> [snip]
> 
> > +
> > +static int dp_tx_hdcp2x_read_rep_send_recvid_list(struct mtk_hdcp_info *hdcp_info)
> > +{
> > +	struct mtk_dp *mtk_dp = container_of(hdcp_info, struct mtk_dp, hdcp_info);
> > +	u8 rx_status = 0;
> > +	ssize_t ret;
> > +
> > +	dev_dbg(mtk_dp->dev, "[HDCP2.X] HDCP_2_2_REP_SEND_RECVID_LIST\n");
> > +
> > +	dp_tx_hdcp2x_wait_for_cp_irq(hdcp_info, HDCP_2_2_RECVID_LIST_TIMEOUT_MS);
> > +	hdcp_info->hdcp2_info.cp_irq_cached = atomic_read(&hdcp_info->hdcp2_info.cp_irq);
> > +
> > +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, &rx_status,
> > +			       HDCP_2_2_DP_RXSTATUS_LEN);
> > +	if (ret != HDCP_2_2_DP_RXSTATUS_LEN)
> > +		return ret >= 0 ? -EIO : ret;
> > +
> > +	if (!HDCP_2_2_DP_RXSTATUS_READY(rx_status)) {
> > +		dev_err(mtk_dp->dev, "[HDCP2.X] RX status no ready\n");
> > +		return -EAGAIN;
> > +	}
> > +
> > +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET,
> > +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info,
> > +		HDCP_2_2_RXINFO_LEN);
> 
> In [1], intel use DP_HDCP_2_2_REG_RXINFO_OFFSET to get device count.
> But here you use DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET to get device count.
> So both command can get device count? Or something wrong?

Forget my previous comment. In [2], intel use DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET to get device count.

[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/i915/display/intel_hdcp.c?h=v6.12-rc6#n1749

Regards,
CK

> 
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/i915/display/intel_dp_hdcp.c?h=v6.12-rc5#n497
> 
> Regards,
> CK
> 
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	hdcp_info->hdcp2_info.device_count =
> > +	(HDCP_2_2_DEV_COUNT_HI(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[0]) << 4 |
> > +	HDCP_2_2_DEV_COUNT_LO(hdcp_info->hdcp2_info.hdcp_rx.recvid_list.rx_info[1]));
> > +
> > +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET,
> > +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.seq_num_v,
> > +		HDCP_2_2_SEQ_NUM_LEN);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_VPRIME_OFFSET,
> > +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.v_prime,
> > +		HDCP_2_2_V_PRIME_HALF_LEN);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = drm_dp_dpcd_read(&mtk_dp->aux, DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET,
> > +			       hdcp_info->hdcp2_info.hdcp_rx.recvid_list.receiver_ids,
> > +		hdcp_info->hdcp2_info.device_count * HDCP_2_2_RECEIVER_ID_LEN);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	return 0;
> > +}
> > +
> 
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2024-11-07  7:07 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-08 12:01 [PATCH v3 0/3] Add HDCP feature for DisplayPort mac.shen
2024-06-08 12:01 ` [PATCH v3 1/3] Subject: [PATCH] drm/mediatek/dp: Add tee client application for HDCP feature mac.shen
2024-06-08 12:01 ` [PATCH v3 2/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP2.x feature for DisplayPort mac.shen
2024-07-18  5:41   ` CK Hu (胡俊光)
2024-07-18  6:23   ` CK Hu (胡俊光)
2024-07-18  7:48   ` CK Hu (胡俊光)
2024-07-19  4:05   ` CK Hu (胡俊光)
2024-07-23  7:16   ` CK Hu (胡俊光)
2024-08-12  7:05   ` CK Hu (胡俊光)
2024-08-12  7:25   ` CK Hu (胡俊光)
2024-08-22  5:39   ` CK Hu (胡俊光)
2024-08-22  6:20   ` CK Hu (胡俊光)
2024-08-23  1:07   ` CK Hu (胡俊光)
2024-08-23  2:44   ` CK Hu (胡俊光)
2024-08-23  7:30   ` CK Hu (胡俊光)
2024-10-30  8:20   ` CK Hu (胡俊光)
2024-11-01  7:18   ` CK Hu (胡俊光)
2024-11-07  7:05     ` CK Hu (胡俊光)
2024-11-01  9:01   ` CK Hu (胡俊光)
2024-06-08 12:01 ` [PATCH v3 3/3] Subject: [PATCH] drm/mediatek/dp: Add HDCP1.x " mac.shen
2024-08-30  9:03   ` CK Hu (胡俊光)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).