Prechádzať zdrojové kódy

securemsm-kernel : Enable hdcp_qseecom module compilation

1. enable hdcp_qseecom.ko module compilation.
2. removed duplicated files in crypto-qti and smcInvoke folder.

Change-Id: I18c14000756484aa3d4723a58814ba8350d12927
Sheik Anwar Shabic Y 3 rokov pred
rodič
commit
49142cbffe

+ 10 - 4
Android.mk

@@ -3,16 +3,12 @@
 LOCAL_PATH := $(call my-dir)
 DLKM_DIR := $(TOP)/device/qcom/common/dlkm
 
-
-
-
 SSG_SRC_FILES := \
 	$(wildcard $(LOCAL_PATH)/*) \
  	$(wildcard $(LOCAL_PATH)/*/*) \
  	$(wildcard $(LOCAL_PATH)/*/*/*) \
  	$(wildcard $(LOCAL_PATH)/*/*/*/*)
 
-
 #$(error $(SSG_SRC_FILES))
 include $(CLEAR_VARS)
 #LOCAL_SRC_FILES           := $(SSG_SRC_FILES)
@@ -63,3 +59,13 @@ LOCAL_MODULE_DEBUG_ENABLE := true
 LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
 include $(DLKM_DIR)/Build_external_kernelmodule.mk
 #################################################
+#################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES           := $(SSG_SRC_FILES)
+LOCAL_MODULE              := hdcp_qseecom_dlkm.ko
+LOCAL_MODULE_KBUILD_NAME  := hdcp_qseecom_dlkm.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+#################################################

+ 13 - 6
Kbuild

@@ -1,17 +1,24 @@
-include  $(SSG_MODULE_ROOT)/config/ssg_smcinvoke.conf
+include $(SSG_MODULE_ROOT)/config/ssg_smcinvoke.conf
 
-obj-m += smcinvoke_dlkm.o
+LINUXINCLUDE += -I$(SSG_MODULE_ROOT)/ \
+                -I$(SSG_MODULE_ROOT)/linux/
+
+KBUILD_CPPFLAGS += -DCONFIG_HDCP_QSEECOM
+
+obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke_dlkm.o
 smcinvoke_dlkm-objs := smcinvoke/smcinvoke_kernel.o smcinvoke/smcinvoke.o
 
-obj-m += tz_log_dlkm.o
+obj-$(CONFIG_QTI_TZ_LOG) += tz_log_dlkm.o
 tz_log_dlkm-objs := tz_log/tz_log.o
 
-obj-m += qce50_dlkm.o
+obj-$(CONFIG_CRYPTO_DEV_QCEDEV) += qce50_dlkm.o
 qce50_dlkm-objs := crypto-qti/qce50.o
 
-obj-m += qcedev-mod_dlkm.o
+obj-$(CONFIG_CRYPTO_DEV_QCOM_MSM_QCE) += qcedev-mod_dlkm.o
 qcedev-mod_dlkm-objs := crypto-qti/qcedev.o crypto-qti/qcedev_smmu.o crypto-qti/compat_qcedev.o
 
-obj-m += qcrypto-msm_dlkm.o
+obj-$(CONFIG_CRYPTO_DEV_QCRYPTO) += qcrypto-msm_dlkm.o
 qcrypto-msm_dlkm-objs := crypto-qti/qcrypto.o 
 
+obj-$(CONFIG_HDCP_QSEECOM) += hdcp_qseecom_dlkm.o
+hdcp_qseecom_dlkm-objs := hdcp/hdcp_qseecom.o

+ 3 - 4
Makefile

@@ -1,7 +1,7 @@
 M=$(PWD)
 SSG_MODULE_ROOT=$(KERNEL_SRC)/$(M)
-
-KBUILD_OPTIONS+=  SSG_MODULE_ROOT=$(SSG_MODULE_ROOT)
+INC=-I/$(M)/linux/*
+KBUILD_OPTIONS+=SSG_MODULE_ROOT=$(SSG_MODULE_ROOT)
 
 all: modules
 
@@ -9,5 +9,4 @@ clean:
 	$(MAKE) -C $(KERNEL_SRC) M=$(M) clean
 
 %:
-	$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
-
+	$(MAKE) -C $(KERNEL_SRC) M=$(M) $(INC) $@ $(KBUILD_OPTIONS)

+ 1 - 0
config/ssg_smcinvoke.conf

@@ -5,3 +5,4 @@ export CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=m
 export CONFIG_CRYPTO_DEV_QCRYPTO=m
 export CONFIG_SCSI_UFS_CRYPTO=m
 export CONFIG_SCSI_UFS_CRYPTO_QTI=m
+export CONFIG_HDCP_QSEECOM=m

+ 0 - 38
crypto-qti/linux/fips_status.h

@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
-/*
- * Copyright (c) 2019, The Linux Foundation. All rights reserved.
- */
-
-#ifndef _FIPS_STATUS__H
-#define _FIPS_STATUS__H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-/**
- * fips_status: global FIPS140-2 status
- * @FIPS140_STATUS_NA:
- *					Not a FIPS140-2 compliant Build.
- *					The flag status won't
- *					change throughout
- *					the lifetime
- * @FIPS140_STATUS_PASS_CRYPTO:
- *					KAT self tests are passed.
- * @FIPS140_STATUS_QCRYPTO_ALLOWED:
- *					Integrity test is passed.
- * @FIPS140_STATUS_PASS:
- *					All tests are passed and build
- *					is in FIPS140-2 mode
- * @FIPS140_STATUS_FAIL:
- *					One of the test is failed.
- *					This will block all requests
- *					to crypto modules
- */
-enum fips_status {
-		FIPS140_STATUS_NA				= 0,
-		FIPS140_STATUS_PASS_CRYPTO		= 1,
-		FIPS140_STATUS_QCRYPTO_ALLOWED	= 2,
-		FIPS140_STATUS_PASS				= 3,
-		FIPS140_STATUS_FAIL				= 0xFF
-};
-#endif /* _FIPS_STATUS__H */

+ 0 - 18
crypto-qti/linux/platform_data/qcom_crypto_device.h

@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved.
- */
-
-#ifndef __QCOM_CRYPTO_DEVICE__H
-#define __QCOM_CRYPTO_DEVICE__H
-
-#include <linux/types.h>
-
-struct msm_ce_hw_support {
-	uint32_t ce_shared;
-	uint32_t shared_ce_resource;
-	uint32_t hw_key_support;
-	uint32_t sha_hmac;
-};
-
-#endif /* __QCOM_CRYPTO_DEVICE__H */

+ 0 - 289
crypto-qti/linux/qcedev.h

@@ -1,289 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
-/*
- * Copyright (c) 2019, The Linux Foundation. All rights reserved.
- */
-
-#ifndef _QCEDEV__H
-#define _QCEDEV__H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include "fips_status.h"
-
-#define QCEDEV_MAX_SHA_BLOCK_SIZE	64
-#define QCEDEV_MAX_BEARER	31
-#define QCEDEV_MAX_KEY_SIZE	64
-#define QCEDEV_MAX_IV_SIZE	32
-
-#define QCEDEV_MAX_BUFFERS      16
-#define QCEDEV_MAX_SHA_DIGEST	32
-
-#define QCEDEV_USE_PMEM		1
-#define QCEDEV_NO_PMEM		0
-
-#define QCEDEV_AES_KEY_128	16
-#define QCEDEV_AES_KEY_192	24
-#define QCEDEV_AES_KEY_256	32
-/**
- *qcedev_oper_enum: Operation types
- * @QCEDEV_OPER_ENC:		Encrypt
- * @QCEDEV_OPER_DEC:		Decrypt
- * @QCEDEV_OPER_ENC_NO_KEY:	Encrypt. Do not need key to be specified by
- *				user. Key already set by an external processor.
- * @QCEDEV_OPER_DEC_NO_KEY:	Decrypt. Do not need the key to be specified by
- *				user. Key already set by an external processor.
- */
-enum qcedev_oper_enum {
-	QCEDEV_OPER_DEC		= 0,
-	QCEDEV_OPER_ENC		= 1,
-	QCEDEV_OPER_DEC_NO_KEY	= 2,
-	QCEDEV_OPER_ENC_NO_KEY	= 3,
-	QCEDEV_OPER_LAST
-};
-
-/**
- *qcedev_oper_enum: Cipher algorithm types
- * @QCEDEV_ALG_DES:		DES
- * @QCEDEV_ALG_3DES:		3DES
- * @QCEDEV_ALG_AES:		AES
- */
-enum qcedev_cipher_alg_enum {
-	QCEDEV_ALG_DES		= 0,
-	QCEDEV_ALG_3DES		= 1,
-	QCEDEV_ALG_AES		= 2,
-	QCEDEV_ALG_LAST
-};
-
-/**
- *qcedev_cipher_mode_enum : AES mode
- * @QCEDEV_AES_MODE_CBC:		CBC
- * @QCEDEV_AES_MODE_ECB:		ECB
- * @QCEDEV_AES_MODE_CTR:		CTR
- * @QCEDEV_AES_MODE_XTS:		XTS
- * @QCEDEV_AES_MODE_CCM:		CCM
- * @QCEDEV_DES_MODE_CBC:		CBC
- * @QCEDEV_DES_MODE_ECB:		ECB
- */
-enum qcedev_cipher_mode_enum {
-	QCEDEV_AES_MODE_CBC	= 0,
-	QCEDEV_AES_MODE_ECB	= 1,
-	QCEDEV_AES_MODE_CTR	= 2,
-	QCEDEV_AES_MODE_XTS	= 3,
-	QCEDEV_AES_MODE_CCM	= 4,
-	QCEDEV_DES_MODE_CBC	= 5,
-	QCEDEV_DES_MODE_ECB	= 6,
-	QCEDEV_AES_DES_MODE_LAST
-};
-
-/**
- *enum qcedev_sha_alg_enum : Secure Hashing Algorithm
- * @QCEDEV_ALG_SHA1:		Digest returned: 20 bytes (160 bits)
- * @QCEDEV_ALG_SHA256:		Digest returned: 32 bytes (256 bit)
- * @QCEDEV_ALG_SHA1_HMAC:	HMAC returned 20 bytes (160 bits)
- * @QCEDEV_ALG_SHA256_HMAC:	HMAC returned 32 bytes (256 bit)
- * @QCEDEV_ALG_AES_CMAC:		Configurable MAC size
- */
-enum qcedev_sha_alg_enum {
-	QCEDEV_ALG_SHA1		= 0,
-	QCEDEV_ALG_SHA256	= 1,
-	QCEDEV_ALG_SHA1_HMAC	= 2,
-	QCEDEV_ALG_SHA256_HMAC	= 3,
-	QCEDEV_ALG_AES_CMAC	= 4,
-	QCEDEV_ALG_SHA_ALG_LAST
-};
-
-/**
- * struct buf_info - Buffer information
- * @offset:			Offset from the base address of the buffer
- *				(Used when buffer is allocated using PMEM)
- * @vaddr:			Virtual buffer address pointer
- * @len:				Size of the buffer
- */
-struct	buf_info {
-	union {
-		__u32	offset;
-		__u8		*vaddr;
-	};
-	__u32	len;
-};
-
-/**
- * struct qcedev_vbuf_info - Source and destination Buffer information
- * @src:				Array of buf_info for input/source
- * @dst:				Array of buf_info for output/destination
- */
-struct	qcedev_vbuf_info {
-	struct buf_info	src[QCEDEV_MAX_BUFFERS];
-	struct buf_info	dst[QCEDEV_MAX_BUFFERS];
-};
-
-/**
- * struct qcedev_pmem_info - Stores PMEM buffer information
- * @fd_src:			Handle to /dev/adsp_pmem used to allocate
- *				memory for input/src buffer
- * @src:				Array of buf_info for input/source
- * @fd_dst:			Handle to /dev/adsp_pmem used to allocate
- *				memory for output/dst buffer
- * @dst:				Array of buf_info for output/destination
- * @pmem_src_offset:		The offset from input/src buffer
- *				(allocated by PMEM)
- */
-struct	qcedev_pmem_info {
-	int		fd_src;
-	struct buf_info	src[QCEDEV_MAX_BUFFERS];
-	int		fd_dst;
-	struct buf_info	dst[QCEDEV_MAX_BUFFERS];
-};
-
-/**
- * struct qcedev_cipher_op_req - Holds the ciphering request information
- * @use_pmem (IN):	Flag to indicate if buffer source is PMEM
- *			QCEDEV_USE_PMEM/QCEDEV_NO_PMEM
- * @pmem (IN):		Stores PMEM buffer information.
- *			Refer struct qcedev_pmem_info
- * @vbuf (IN/OUT):	Stores Source and destination Buffer information
- *			Refer to struct qcedev_vbuf_info
- * @data_len (IN):	Total Length of input/src and output/dst in bytes
- * @in_place_op (IN):	Indicates whether the operation is inplace where
- *			source == destination
- *			When using PMEM allocated memory, must set this to 1
- * @enckey (IN):		128 bits of confidentiality key
- *			enckey[0] bit 127-120, enckey[1] bit 119-112,..
- *			enckey[15] bit 7-0
- * @encklen (IN):	Length of the encryption key(set to 128  bits/16
- *			bytes in the driver)
- * @iv (IN/OUT):		Initialisation vector data
- *			This is updated by the driver, incremented by
- *			number of blocks encrypted/decrypted.
- * @ivlen (IN):		Length of the IV
- * @byteoffset (IN):	Offset in the Cipher BLOCK (applicable and to be set
- *			for AES-128 CTR mode only)
- * @alg (IN):		Type of ciphering algorithm: AES/DES/3DES
- * @mode (IN):		Mode use when using AES algorithm: ECB/CBC/CTR
- *			Apllicabel when using AES algorithm only
- * @op (IN):		Type of operation: QCEDEV_OPER_DEC/QCEDEV_OPER_ENC or
- *			QCEDEV_OPER_ENC_NO_KEY/QCEDEV_OPER_DEC_NO_KEY
- *
- *If use_pmem is set to 0, the driver assumes that memory was not allocated
- * via PMEM, and kernel will need to allocate memory and copy data from user
- * space buffer (data_src/dta_dst) and process accordingly and copy data back
- * to the user space buffer
- *
- * If use_pmem is set to 1, the driver assumes that memory was allocated via
- * PMEM.
- * The kernel driver will use the fd_src to determine the kernel virtual address
- * base that maps to the user space virtual address base for the  buffer
- * allocated in user space.
- * The final input/src and output/dst buffer pointer will be determined
- * by adding the offsets to the kernel virtual addr.
- *
- * If use of hardware key is supported in the target, user can configure the
- * key parameters (encklen, enckey) to use the hardware key.
- * In order to use the hardware key, set encklen to 0 and set the enckey
- * data array to 0.
- */
-struct	qcedev_cipher_op_req {
-	__u8				use_pmem;
-	union {
-		struct qcedev_pmem_info	pmem;
-		struct qcedev_vbuf_info	vbuf;
-	};
-	__u32			entries;
-	__u32			data_len;
-	__u8				in_place_op;
-	__u8				enckey[QCEDEV_MAX_KEY_SIZE];
-	__u32			encklen;
-	__u8				iv[QCEDEV_MAX_IV_SIZE];
-	__u32			ivlen;
-	__u32			byteoffset;
-	enum qcedev_cipher_alg_enum	alg;
-	enum qcedev_cipher_mode_enum	mode;
-	enum qcedev_oper_enum		op;
-};
-
-/**
- * struct qcedev_sha_op_req - Holds the hashing request information
- * @data (IN):			Array of pointers to the data to be hashed
- * @entries (IN):		Number of buf_info entries in the data array
- * @data_len (IN):		Length of data to be hashed
- * @digest (IN/OUT):		Returns the hashed data information
- * @diglen (OUT):		Size of the hashed/digest data
- * @authkey (IN):		Pointer to authentication key for HMAC
- * @authklen (IN):		Size of the authentication key
- * @alg (IN):			Secure Hash algorithm
- */
-struct	qcedev_sha_op_req {
-	struct buf_info			data[QCEDEV_MAX_BUFFERS];
-	__u32			entries;
-	__u32			data_len;
-	__u8				digest[QCEDEV_MAX_SHA_DIGEST];
-	__u32			diglen;
-	__u8				*authkey;
-	__u32			authklen;
-	enum qcedev_sha_alg_enum	alg;
-};
-
-/**
- * struct qfips_verify_t - Holds data for FIPS Integrity test
- * @kernel_size  (IN):		Size of kernel Image
- * @kernel       (IN):		pointer to buffer containing the kernel Image
- */
-struct qfips_verify_t {
-	unsigned int kernel_size;
-	void *kernel;
-};
-
-/**
- * struct qcedev_map_buf_req - Holds the mapping request information
- * fd (IN):            Array of fds.
- * num_fds (IN):       Number of fds in fd[].
- * fd_size (IN):       Array of sizes corresponding to each fd in fd[].
- * fd_offset (IN):     Array of offset corresponding to each fd in fd[].
- * vaddr (OUT):        Array of mapped virtual address corresponding to
- *			each fd in fd[].
- */
-struct qcedev_map_buf_req {
-	__s32         fd[QCEDEV_MAX_BUFFERS];
-	__u32        num_fds;
-	__u32        fd_size[QCEDEV_MAX_BUFFERS];
-	__u32        fd_offset[QCEDEV_MAX_BUFFERS];
-	__u64        buf_vaddr[QCEDEV_MAX_BUFFERS];
-};
-
-/**
- * struct qcedev_unmap_buf_req - Holds the hashing request information
- * fd (IN):            Array of fds to unmap
- * num_fds (IN):       Number of fds in fd[].
- */
-struct  qcedev_unmap_buf_req {
-	__s32         fd[QCEDEV_MAX_BUFFERS];
-	__u32        num_fds;
-};
-
-struct file;
-
-#define QCEDEV_IOC_MAGIC	0x87
-
-#define QCEDEV_IOCTL_ENC_REQ		\
-	_IOWR(QCEDEV_IOC_MAGIC, 1, struct qcedev_cipher_op_req)
-#define QCEDEV_IOCTL_DEC_REQ		\
-	_IOWR(QCEDEV_IOC_MAGIC, 2, struct qcedev_cipher_op_req)
-#define QCEDEV_IOCTL_SHA_INIT_REQ	\
-	_IOWR(QCEDEV_IOC_MAGIC, 3, struct qcedev_sha_op_req)
-#define QCEDEV_IOCTL_SHA_UPDATE_REQ	\
-	_IOWR(QCEDEV_IOC_MAGIC, 4, struct qcedev_sha_op_req)
-#define QCEDEV_IOCTL_SHA_FINAL_REQ	\
-	_IOWR(QCEDEV_IOC_MAGIC, 5, struct qcedev_sha_op_req)
-#define QCEDEV_IOCTL_GET_SHA_REQ	\
-	_IOWR(QCEDEV_IOC_MAGIC, 6, struct qcedev_sha_op_req)
-#define QCEDEV_IOCTL_LOCK_CE	\
-	_IO(QCEDEV_IOC_MAGIC, 7)
-#define QCEDEV_IOCTL_UNLOCK_CE	\
-	_IO(QCEDEV_IOC_MAGIC, 8)
-#define QCEDEV_IOCTL_GET_CMAC_REQ	\
-	_IOWR(QCEDEV_IOC_MAGIC, 9, struct qcedev_sha_op_req)
-#define QCEDEV_IOCTL_MAP_BUF_REQ	\
-	_IOWR(QCEDEV_IOC_MAGIC, 10, struct qcedev_map_buf_req)
-#define QCEDEV_IOCTL_UNMAP_BUF_REQ	\
-	_IOWR(QCEDEV_IOC_MAGIC, 11, struct qcedev_unmap_buf_req)
-#endif /* _QCEDEV__H */

+ 0 - 60
crypto-qti/linux/qcrypto.h

@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved.
- */
-
-#ifndef _DRIVERS_CRYPTO_MSM_QCRYPTO_H_
-#define _DRIVERS_CRYPTO_MSM_QCRYPTO_H_
-
-#include <linux/crypto.h>
-#include <crypto/hash.h>
-#include <crypto/skcipher.h>
-#include <crypto/aead.h>
-
-#define QCRYPTO_CTX_KEY_MASK		0x000000ff
-#define QCRYPTO_CTX_USE_HW_KEY		0x00000001
-#define QCRYPTO_CTX_USE_PIPE_KEY	0x00000002
-
-#define QCRYPTO_CTX_XTS_MASK		0x0000ff00
-#define QCRYPTO_CTX_XTS_DU_SIZE_512B	0x00000100
-#define QCRYPTO_CTX_XTS_DU_SIZE_1KB	0x00000200
-
-
-int qcrypto_cipher_set_device(struct skcipher_request *req, unsigned int dev);
-int qcrypto_ahash_set_device(struct ahash_request *req, unsigned int dev);
-int qcrypto_aead_set_device(struct aead_request *req, unsigned int dev);
-
-int qcrypto_cipher_set_flag(struct skcipher_request *req, unsigned int flags);
-int qcrypto_ahash_set_flag(struct ahash_request *req, unsigned int flags);
-int qcrypto_aead_set_flag(struct aead_request *req, unsigned int flags);
-
-int qcrypto_cipher_clear_flag(struct skcipher_request *req,
-							unsigned int flags);
-int qcrypto_ahash_clear_flag(struct ahash_request *req, unsigned int flags);
-int qcrypto_aead_clear_flag(struct aead_request *req, unsigned int flags);
-
-struct crypto_engine_entry {
-	u32 hw_instance;
-	u32 ce_device;
-	int shared;
-};
-
-int qcrypto_get_num_engines(void);
-void qcrypto_get_engine_list(size_t num_engines,
-				struct crypto_engine_entry *arr);
-int qcrypto_cipher_set_device_hw(struct skcipher_request *req,
-				unsigned int fde_pfe,
-				unsigned int hw_inst);
-
-
-struct qcrypto_func_set {
-	int (*cipher_set)(struct skcipher_request *req,
-			unsigned int fde_pfe,
-			unsigned int hw_inst);
-	int (*cipher_flag)(struct skcipher_request *req, unsigned int flags);
-	int (*get_num_engines)(void);
-	void (*get_engine_list)(size_t num_engines,
-				struct crypto_engine_entry *arr);
-};
-
-#endif /* _DRIVERS_CRYPTO_MSM_QCRYPTO_H */

+ 1862 - 0
hdcp/hdcp_qseecom.c

@@ -0,0 +1,1862 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2022, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt)	"[hdcp-qseecom] %s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/kthread.h>
+#include "linux/hdcp_qseecom.h"
+#include "misc/qseecom_kernel.h"
+
+#define HDCP2P2_APP_NAME      "hdcp2p2"
+#define HDCP1_APP_NAME        "hdcp1"
+#define HDCP1OPS_APP_NAME      "ops"
+#define HDCPSRM_APP_NAME      "hdcpsrm"
+#define QSEECOM_SBUFF_SIZE    0x1000
+
+#define MAX_REC_ID_LIST_SIZE    160
+#define MAX_TX_MESSAGE_SIZE	129
+#define MAX_RX_MESSAGE_SIZE	534
+#define MAX_TOPOLOGY_ELEMS	32
+#define HDCP1_NOTIFY_TOPOLOGY   1
+#define HDCP1_AKSV_SIZE         8
+
+#define HDCP1_SET_KEY       202
+#define HDCP1_KEY_VERIFY    204
+#define HDCP1_SET_ENC       205
+
+#define BITS_8_IN_BYTES       1
+#define BITS_16_IN_BYTES      2
+#define BITS_24_IN_BYTES      3
+#define BITS_32_IN_BYTES      4
+#define BITS_40_IN_BYTES      5
+#define BITS_64_IN_BYTES      8
+#define BITS_128_IN_BYTES    16
+#define BITS_160_IN_BYTES    20
+#define BITS_256_IN_BYTES    32
+#define BITS_1024_IN_BYTES  128
+#define BITS_3072_IN_BYTES  384
+#define TXCAPS_SIZE           3
+#define RXCAPS_SIZE           3
+#define RXINFO_SIZE           2
+#define SEQ_NUM_V_SIZE        3
+
+#define RCVR_ID_SIZE BITS_40_IN_BYTES
+#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31
+#define MAX_RCVR_ID_LIST_SIZE \
+		(RCVR_ID_SIZE*MAX_RCVR_IDS_ALLOWED_IN_LIST)
+/*
+ * minimum wait as per standard is 200 ms. keep it 300 ms
+ * to be on safe side.
+ */
+#define SLEEP_SET_HW_KEY_MS 300
+
+/* Wait 200ms after authentication */
+#define SLEEP_FORCE_ENCRYPTION_MS 200
+
+/* hdcp command status */
+#define HDCP_SUCCESS                    0
+
+/* DP device type */
+#define DEVICE_TYPE_DP 0x8002
+
+const char *HdcpErrors[] = {
+	"HDCP_SUCCESS",
+	"HDCP_FAIL",
+	"HDCP_BAD_PARAM",
+	"HDCP_DEVICE_TYPE_UNSUPPORTED",
+	"HDCP_INVALID_COMMAND",
+	"HDCP_INVALID_COMMAND_HANDLE",
+	"HDCP_ERROR_SIZE_IN",
+	"HDCP_ERROR_SIZE_OUT",
+	"HDCP_DATA_SIZE_INSUFFICIENT",
+	"HDCP_UNSUPPORTED_RX_VERSION",
+	"HDCP_WRONG_RX_CAPAB_MASK",
+	"HDCP_WRONG_RX_RSVD",
+	"HDCP_WRONG_RX_HDCP_CAPABLE",
+	"HDCP_RSA_SIGNATURE_VERIFY_FAILED",
+	"HDCP_VERIFY_H_PRIME_FAILED",
+	"HDCP_LC_FAILED",
+	"HDCP_MESSAGE_TIMEOUT",
+	"HDCP_COUNTER_ROLL_OVER",
+	"HDCP_WRONG_RXINFO_RSVD",
+	"HDCP_RXINFO_MAX_DEVS",
+	"HDCP_RXINFO_MAX_CASCADE",
+	"HDCP_WRONG_INITIAL_SEQ_NUM_V",
+	"HDCP_SEQ_NUM_V_ROLL_OVER",
+	"HDCP_WRONG_SEQ_NUM_V",
+	"HDCP_VERIFY_V_FAILED",
+	"HDCP_RPT_METHOD_INVOKED",
+	"HDCP_RPT_STRM_LEN_WRONG",
+	"HDCP_VERIFY_STRM_M_FAILED",
+	"HDCP_TRANSMITTER_NOT_FOUND",
+	"HDCP_SESSION_NOT_FOUND",
+	"HDCP_MAX_SESSION_EXCEEDED",
+	"HDCP_MAX_CONNECTION_EXCEEDED",
+	"HDCP_MAX_STREAMS_EXCEEDED",
+	"HDCP_MAX_DEVICES",
+	"HDCP_ALLOC_FAILED",
+	"HDCP_CONNECTION_NOT_FOUND",
+	"HDCP_HASH_FAILED",
+	"HDCP_BN_FAILED",
+	"HDCP_ENCRYPT_KM_FAILED",
+	"HDCP_DECRYPT_KM_FAILED",
+	"HDCP_HMAC_FAILED",
+	"HDCP_GET_RANDOM_FAILED",
+	"HDCP_INVALID_KEY_HEADER",
+	"HDCP_INVALID_KEY_LC_HASH",
+	"HDCP_INVALID_KEY_HASH",
+	"HDCP_KEY_WRITE_FAILED",
+	"HDCP_KEY_READ_FAILED",
+	"HDCP_KEY_DECRYPT_FAILED",
+	"HDCP_TEST_KEY_ON_SECURE_DEVICE",
+	"HDCP_KEY_VERSION_UNSUPPORTED",
+	"HDCP_RXID_NOT_FOUND",
+	"HDCP_STORAGE_INIT_FAILED",
+	"HDCP_STORAGE_FILE_OPEN_FAILED",
+	"HDCP_STORAGE_FILE_READ_FAILED",
+	"HDCP_STORAGE_FILE_WRITE_FAILED",
+	"HDCP_STORAGE_ID_UNSUPPORTED",
+	"HDCP_MUTUAL_EXCLUSIVE_DEVICE_PRESENT",
+	"HDCP_INVALID_STATE",
+	"HDCP_CONFIG_READ_FAILED",
+	"HDCP_OPEN_TZ_SERVICE_FAILED",
+	"HDCP_HW_CLOCK_OFF",
+	"HDCP_SET_HW_KEY_FAILED",
+	"HDCP_CLEAR_HW_KEY_FAILED",
+	"HDCP_GET_CONTENT_LEVEL_FAILED",
+	"HDCP_STREAMID_INUSE",
+	"HDCP_STREAM_NOT_FOUND",
+	"HDCP_FORCE_ENCRYPTION_FAILED",
+	"HDCP_STREAMNUMBER_INUSE"
+};
+
+/* flags set by tz in response message */
+#define HDCP_TXMTR_SUBSTATE_INIT                              0
+#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST       1
+#define HDCP_TXMTR_SUBSTATE_PROCESSED_RECIEVERID_LIST         2
+#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_STREAM_READY_MESSAGE  3
+#define HDCP_TXMTR_SUBSTATE_REPEATER_AUTH_COMPLETE            4
+
+#define HDCP_DEVICE_ID                         0x0008000
+#define HDCP_CREATE_DEVICE_ID(x)               (HDCP_DEVICE_ID | (x))
+
+#define HDCP_TXMTR_HDMI                        HDCP_CREATE_DEVICE_ID(1)
+
+#define HDCP_TXMTR_SERVICE_ID                 0x0001000
+#define SERVICE_CREATE_CMD(x)                 (HDCP_TXMTR_SERVICE_ID | x)
+
+#define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF)
+#define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF)
+#define HCDP_TXMTR_GET_PATCH_VERSION(v) ((v) & 0xFF)
+
+#define HDCP_CLIENT_MAJOR_VERSION 2
+#define HDCP_CLIENT_MINOR_VERSION 1
+#define HDCP_CLIENT_PATCH_VERSION 0
+#define HDCP_CLIENT_MAKE_VERSION(maj, min, patch) \
+	((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF))
+
+#define hdcp2_app_init_var(x) \
+	struct hdcp_##x##_req *req_buf = NULL; \
+	struct hdcp_##x##_rsp *rsp_buf = NULL; \
+	if (!handle->qseecom_handle) { \
+		pr_err("invalid qseecom_handle while processing %s\n", #x); \
+		rc = -EINVAL; \
+		goto error; \
+	} \
+	req_buf = (struct hdcp_##x##_req *) handle->qseecom_handle->sbuf; \
+	rsp_buf = (struct hdcp_##x##_rsp *) (handle->qseecom_handle->sbuf + \
+		QSEECOM_ALIGN(sizeof(struct hdcp_##x##_req))); \
+	req_buf->commandid = hdcp_cmd_##x
+
+
+#define hdcp2_app_process_cmd(x) \
+({ \
+	int rc = qseecom_send_command(handle->qseecom_handle, \
+		req_buf, QSEECOM_ALIGN(sizeof(struct hdcp_##x##_req)), \
+		rsp_buf, QSEECOM_ALIGN(sizeof(struct hdcp_##x##_rsp))); \
+	if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) { \
+		pr_err("qseecom cmd %s failed with err = %d, status = %d:%s\n" \
+		, #x, rc, rsp_buf->status, \
+		hdcp_cmd_status_to_str(rsp_buf->status)); \
+		rc = -EINVAL; \
+	} \
+	rc; \
+})
+
+enum {
+	hdcp_cmd_tx_init           = SERVICE_CREATE_CMD(1),
+	hdcp_cmd_tx_init_v1        = SERVICE_CREATE_CMD(1),
+	hdcp_cmd_tx_deinit         = SERVICE_CREATE_CMD(2),
+	hdcp_cmd_rcvd_msg          = SERVICE_CREATE_CMD(3),
+	hdcp_cmd_send_timeout      = SERVICE_CREATE_CMD(4),
+	hdcp_cmd_set_hw_key        = SERVICE_CREATE_CMD(5),
+	hdcp_cmd_query_stream_type = SERVICE_CREATE_CMD(6),
+	hdcp_cmd_init_v1           = SERVICE_CREATE_CMD(11),
+	hdcp_cmd_init              = SERVICE_CREATE_CMD(11),
+	hdcp_cmd_deinit            = SERVICE_CREATE_CMD(12),
+	hdcp_cmd_version           = SERVICE_CREATE_CMD(14),
+	hdcp_cmd_verify_key        = SERVICE_CREATE_CMD(15),
+	hdcp_cmd_session_init      = SERVICE_CREATE_CMD(16),
+	hdcp_cmd_session_deinit    = SERVICE_CREATE_CMD(17),
+	hdcp_cmd_start_auth        = SERVICE_CREATE_CMD(18),
+	hdcp_cmd_session_open_stream = SERVICE_CREATE_CMD(20),
+	hdcp_cmd_session_close_stream = SERVICE_CREATE_CMD(21),
+	hdcp_cmd_force_encryption  = SERVICE_CREATE_CMD(22),
+};
+
+enum hdcp_state {
+	HDCP_STATE_INIT = 0x00,
+	HDCP_STATE_APP_LOADED = 0x01,
+	HDCP_STATE_SESSION_INIT = 0x02,
+	HDCP_STATE_TXMTR_INIT = 0x04,
+	HDCP_STATE_AUTHENTICATED = 0x08,
+	HDCP_STATE_ERROR = 0x10
+};
+
+enum hdcp_element {
+	HDCP_TYPE_UNKNOWN,
+	HDCP_TYPE_RECEIVER,
+	HDCP_TYPE_REPEATER,
+};
+
+enum hdcp_version {
+	HDCP_VERSION_UNKNOWN,
+	HDCP_VERSION_2_2,
+	HDCP_VERSION_1_4
+};
+
+struct receiver_info {
+	unsigned char rcvrInfo[RCVR_ID_SIZE];
+	enum hdcp_element elem_type;
+	enum hdcp_version hdcp_version;
+};
+
+struct topology_info {
+	unsigned int nNumRcvrs;
+	struct receiver_info rcvinfo[MAX_TOPOLOGY_ELEMS];
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_set_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_set_rsp {
+	uint32_t commandid;
+	uint32_t ret;
+	uint8_t ksv[HDCP1_AKSV_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_version_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_version_rsp {
+	uint32_t status;
+	uint32_t commandId;
+	uint32_t appversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_verify_key_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_verify_key_rsp {
+	uint32_t status;
+	uint32_t commandId;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_verify_req {
+	uint32_t commandid;
+	uint32_t key_type;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_key_verify_rsp {
+	uint32_t commandId;
+	uint32_t ret;
+};
+
+struct __attribute__ ((__packed__)) hdcp_init_v1_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_init_v1_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_init_req {
+	uint32_t commandid;
+	uint32_t clientversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_init_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t appversion;
+};
+
+struct __attribute__ ((__packed__)) hdcp_deinit_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_deinit_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_session_init_req {
+	uint32_t commandid;
+	uint32_t deviceid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_session_init_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_session_deinit_req {
+	uint32_t commandid;
+	uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_session_deinit_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_v1_req {
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_v1_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_req {
+	uint32_t commandid;
+	uint32_t sessionid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_init_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_deinit_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_tx_deinit_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_rcvd_msg_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t msglen;
+	uint8_t msg[MAX_RX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_rcvd_msg_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t state;
+	uint32_t timeout;
+	uint32_t flag;
+	uint32_t msglen;
+	uint8_t msg[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_hw_key_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_hw_key_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_send_timeout_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_send_timeout_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_query_stream_type_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_query_stream_type_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t msg[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_stream_type_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint8_t streamtype;
+};
+
+struct __attribute__ ((__packed__)) hdcp_set_stream_type_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__ ((__packed__)) hdcp_update_srm_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t srmoffset;
+	uint32_t srmlength;
+};
+
+struct __attribute__ ((__packed__)) hdcp_update_srm_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__ ((__packed__)) hdcp_get_topology_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_get_topology_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	struct topology_info topologyinfo;
+};
+
+struct __attribute__ ((__packed__)) rxvr_info_struct {
+	uint8_t rcvrCert[522];
+	uint8_t rrx[BITS_64_IN_BYTES];
+	uint8_t rxcaps[RXCAPS_SIZE];
+	bool repeater;
+};
+
+struct __attribute__ ((__packed__)) repeater_info_struct {
+	uint8_t RxInfo[RXINFO_SIZE];
+	uint8_t seq_num_V[SEQ_NUM_V_SIZE];
+	bool seq_num_V_Rollover_flag;
+	uint8_t ReceiverIDList[MAX_RCVR_ID_LIST_SIZE];
+	uint32_t ReceiverIDListLen;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_set_enc_req {
+	uint32_t commandid;
+	uint32_t enable;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_set_enc_rsp {
+	uint32_t commandid;
+	uint32_t ret;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_ops_notify_req {
+	uint32_t commandid;
+	uint32_t device_type;
+	uint8_t recv_id_list[MAX_REC_ID_LIST_SIZE];
+	int32_t recv_id_len;
+	struct hdcp1_topology topology;
+	bool is_authenticated;
+};
+
+struct __attribute__ ((__packed__)) hdcp1_ops_notify_rsp {
+	uint32_t commandid;
+	uint32_t ret;
+};
+
+struct __attribute__ ((__packed__)) hdcp_start_auth_req {
+	uint32_t commandid;
+	uint32_t ctxHandle;
+};
+
+struct __attribute__ ((__packed__)) hdcp_start_auth_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t timeout;
+	uint32_t msglen;
+	uint8_t message[MAX_TX_MESSAGE_SIZE];
+};
+
+struct __attribute__((__packed__)) hdcp_session_open_stream_req {
+	uint32_t commandid;
+	uint32_t sessionid;
+	uint32_t vcpayloadid;
+	uint32_t stream_number;
+	uint32_t streamMediaType;
+};
+
+struct __attribute__((__packed__)) hdcp_session_open_stream_rsp {
+	uint32_t status;
+	uint32_t commandid;
+	uint32_t streamid;
+};
+
+struct __attribute__((__packed__)) hdcp_session_close_stream_req {
+	uint32_t commandid;
+	uint32_t sessionid;
+	uint32_t streamid;
+};
+
+struct __attribute__((__packed__)) hdcp_session_close_stream_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct __attribute__((__packed__)) hdcp_force_encryption_req {
+	uint32_t commandid;
+	uint32_t ctxhandle;
+	uint32_t enable;
+};
+
+struct __attribute__ ((__packed__)) hdcp_force_encryption_rsp {
+	uint32_t status;
+	uint32_t commandid;
+};
+
+struct hdcp2_handle {
+	struct hdcp2_app_data app_data;
+	uint32_t tz_ctxhandle;
+	bool feature_supported;
+	enum hdcp_state hdcp_state;
+	struct qseecom_handle *qseecom_handle;
+	struct qseecom_handle *hdcpsrm_qseecom_handle;
+	uint32_t session_id;
+	bool legacy_app;
+	uint32_t device_type;
+	char *app_name;
+
+	int (*app_init)(struct hdcp2_handle *handle);
+	int (*tx_init)(struct hdcp2_handle *handle);
+};
+
+/*
+ * struct hdcp1_handle - handle for HDCP 1.x client
+ * @qseecom_handle - for sending commands to qseecom
+ * @hdcpops_handle - for sending commands to ops TA
+ * @feature_supported - set to true if the platform supports HDCP 1.x
+ * @device_type - the interface type (HDMI or DisplayPort)
+ */
+struct hdcp1_handle {
+	struct qseecom_handle *qseecom_handle;
+	struct qseecom_handle *hdcpops_handle;
+	bool feature_supported;
+	uint32_t device_type;
+	enum hdcp_state hdcp_state;
+	char *app_name;
+};
+
+#define HDCP_CMD_STATUS_TO_STR(x) #x
+static const char *hdcp_cmd_status_to_str(uint32_t err)
+{
+	int len = ARRAY_SIZE(HdcpErrors);
+
+	if (err >= 0 && err < len)
+		return HdcpErrors[err];
+	else
+		return "";
+}
+
+static int hdcp_get_version(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+	uint32_t app_major_version = 0;
+
+	hdcp2_app_init_var(version);
+
+	if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+		pr_err("library already loaded\n");
+		goto error;
+	}
+
+	rc = hdcp2_app_process_cmd(version);
+	if (rc)
+		goto error;
+
+	app_major_version = HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion);
+
+	pr_debug("hdp2p2 app major version %d, app version %d\n",
+		 app_major_version, rsp_buf->appversion);
+
+	if (app_major_version == 1)
+		handle->legacy_app = true;
+error:
+	return rc;
+}
+
+static int hdcp2_app_init_legacy(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(init_v1);
+
+	if (!handle->legacy_app) {
+		pr_err("wrong init function\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+		pr_err("library already loaded\n");
+		goto error;
+	}
+
+	rc = hdcp2_app_process_cmd(init_v1);
+	if (rc)
+		goto error;
+
+	pr_debug("success\n");
+error:
+	return rc;
+}
+
+static int hdcp2_app_init(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+	uint32_t app_minor_version = 0;
+
+	hdcp2_app_init_var(init);
+
+	if (handle->legacy_app) {
+		pr_err("wrong init function\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+		pr_err("library already loaded\n");
+		goto error;
+	}
+
+	req_buf->clientversion =
+	    HDCP_CLIENT_MAKE_VERSION(HDCP_CLIENT_MAJOR_VERSION,
+				     HDCP_CLIENT_MINOR_VERSION,
+				     HDCP_CLIENT_PATCH_VERSION);
+
+	rc = hdcp2_app_process_cmd(init);
+	if (rc)
+		goto error;
+
+	app_minor_version = HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion);
+	if (app_minor_version != HDCP_CLIENT_MINOR_VERSION) {
+		pr_err
+		    ("client-app minor version mismatch app(%d), client(%d)\n",
+		     app_minor_version, HDCP_CLIENT_MINOR_VERSION);
+		rc = -1;
+		goto error;
+	}
+
+	pr_debug("success\n");
+
+	pr_debug("client version major(%d), minor(%d), patch(%d)\n",
+		 HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION,
+		 HDCP_CLIENT_PATCH_VERSION);
+
+	pr_debug("app version major(%d), minor(%d), patch(%d)\n",
+		 HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion),
+		 HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion),
+		 HCDP_TXMTR_GET_PATCH_VERSION(rsp_buf->appversion));
+error:
+	return rc;
+}
+
+static int hdcp2_app_tx_init(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(tx_init);
+
+	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+		pr_err("session not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_TXMTR_INIT) {
+		pr_err("txmtr already initialized\n");
+		goto error;
+	}
+
+	req_buf->sessionid = handle->session_id;
+
+	rc = hdcp2_app_process_cmd(tx_init);
+	if (rc)
+		goto error;
+
+	handle->tz_ctxhandle = rsp_buf->ctxhandle;
+	handle->hdcp_state |= HDCP_STATE_TXMTR_INIT;
+
+	pr_debug("success\n");
+error:
+	return rc;
+}
+
+static int hdcp2_app_tx_init_legacy(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(tx_init_v1);
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("app not loaded\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_TXMTR_INIT) {
+		pr_err("txmtr already initialized\n");
+		goto error;
+	}
+
+	rc = hdcp2_app_process_cmd(tx_init_v1);
+	if (rc)
+		goto error;
+
+	handle->app_data.response.data = rsp_buf->message;
+	handle->app_data.response.length = rsp_buf->msglen;
+	handle->app_data.timeout = rsp_buf->timeout;
+
+	handle->tz_ctxhandle = rsp_buf->ctxhandle;
+	handle->hdcp_state |= HDCP_STATE_TXMTR_INIT;
+
+	pr_debug("success\n");
+error:
+	return rc;
+}
+
+static int hdcp2_app_load(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+		pr_err("%s app already loaded\n", handle->app_name);
+		goto error;
+	}
+
+	rc = qseecom_start_app(&handle->qseecom_handle,
+		 handle->app_name, QSEECOM_SBUFF_SIZE);
+	if (rc) {
+		pr_err("qseecom_start_app failed for HDCP2P2 (%d)\n", rc);
+		goto error;
+	}
+
+	rc = qseecom_start_app(&handle->hdcpsrm_qseecom_handle,
+		 HDCPSRM_APP_NAME, QSEECOM_SBUFF_SIZE);
+	if (rc) {
+		pr_err("qseecom_start_app failed for HDCPSRM (%d)\n", rc);
+		goto hdcpsrm_error;
+	}
+
+	pr_debug("qseecom_start_app success\n");
+
+	rc = hdcp_get_version(handle);
+	if (rc) {
+		pr_err("library get version failed\n");
+		goto get_version_error;
+	}
+
+	if (handle->legacy_app) {
+		handle->app_init = hdcp2_app_init_legacy;
+		handle->tx_init = hdcp2_app_tx_init_legacy;
+	} else {
+		handle->app_init = hdcp2_app_init;
+		handle->tx_init = hdcp2_app_tx_init;
+	}
+
+	rc = handle->app_init(handle);
+	if (rc) {
+		pr_err("app init failed\n");
+		goto get_version_error;
+	}
+
+	handle->hdcp_state |= HDCP_STATE_APP_LOADED;
+
+	return rc;
+get_version_error:
+	qseecom_shutdown_app(&handle->hdcpsrm_qseecom_handle);
+hdcpsrm_error:
+	qseecom_shutdown_app(&handle->qseecom_handle);
+error:
+	return rc;
+}
+
+static int hdcp2_app_unload(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(deinit);
+
+	hdcp2_app_process_cmd(deinit);
+
+	/* deallocate the resources for qseecom HDCPSRM handle */
+	rc = qseecom_shutdown_app(&handle->hdcpsrm_qseecom_handle);
+	if (rc)
+		pr_err("qseecom_shutdown_app failed for HDCPSRM (%d)\n", rc);
+
+	/* deallocate the resources for qseecom HDCP2P2 handle */
+	rc = qseecom_shutdown_app(&handle->qseecom_handle);
+	if (rc) {
+		pr_err("qseecom_shutdown_app failed for HDCP2P2 (%d)\n", rc);
+		return rc;
+	}
+
+	handle->hdcp_state &= ~HDCP_STATE_APP_LOADED;
+	pr_debug("%s app unloaded\n", handle->app_name);
+
+	return rc;
+error:
+	qseecom_shutdown_app(&handle->hdcpsrm_qseecom_handle);
+	return rc;
+}
+
+static int hdcp2_verify_key(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(verify_key);
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("%s app not loaded\n", handle->app_name);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	rc = hdcp2_app_process_cmd(verify_key);
+	pr_debug("verify_key = %d\n", rc);
+
+error:
+	return rc;
+}
+
+bool hdcp2_feature_supported(void *data)
+{
+	int rc = 0;
+	bool supported = false;
+	struct hdcp2_handle *handle = data;
+
+	if (!handle) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (handle->feature_supported) {
+		supported = true;
+		goto error;
+	}
+
+	rc = hdcp2_app_load(handle);
+	if (!rc) {
+		if (!hdcp2_verify_key(handle)) {
+			pr_debug("HDCP 2.2 supported\n");
+			handle->feature_supported = true;
+			supported = true;
+		}
+		hdcp2_app_unload(handle);
+	}
+error:
+	return supported;
+}
+EXPORT_SYMBOL(hdcp2_feature_supported);
+
+static int hdcp2_app_session_init(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(session_init);
+
+	if (!handle->qseecom_handle || !handle->qseecom_handle->sbuf) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("%s app not loaded\n", handle->app_name);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (handle->hdcp_state & HDCP_STATE_SESSION_INIT) {
+		pr_err("session already initialized\n");
+		goto error;
+	}
+
+	req_buf->deviceid = handle->device_type;
+
+	rc = hdcp2_app_process_cmd(session_init);
+	if (rc)
+		goto error;
+
+	pr_debug("session id %d\n", rsp_buf->sessionid);
+
+	handle->session_id = rsp_buf->sessionid;
+	handle->hdcp_state |= HDCP_STATE_SESSION_INIT;
+
+	pr_debug("success\n");
+error:
+	return rc;
+}
+
+static int hdcp2_app_session_deinit(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(session_deinit);
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("%s app not loaded\n", handle->app_name);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+		pr_err("session not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	req_buf->sessionid = handle->session_id;
+
+	rc = hdcp2_app_process_cmd(session_deinit);
+	if (rc)
+		goto error;
+
+	handle->hdcp_state &= ~HDCP_STATE_SESSION_INIT;
+	pr_debug("success\n");
+error:
+	return rc;
+}
+
+static int hdcp2_app_tx_deinit(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(tx_deinit);
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("%s app not loaded\n", handle->app_name);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+		pr_err("txmtr not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+
+	rc = hdcp2_app_process_cmd(tx_deinit);
+	if (rc)
+		goto error;
+
+	handle->hdcp_state &= ~HDCP_STATE_TXMTR_INIT;
+	pr_debug("success\n");
+error:
+	return rc;
+}
+
+static int hdcp2_app_start_auth(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(start_auth);
+
+	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+		pr_err("session not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+		pr_err("txmtr not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	req_buf->ctxHandle = handle->tz_ctxhandle;
+
+	rc = hdcp2_app_process_cmd(start_auth);
+	if (rc)
+		goto error;
+
+	handle->app_data.response.data = rsp_buf->message;
+	handle->app_data.response.length = rsp_buf->msglen;
+	handle->app_data.timeout = rsp_buf->timeout;
+	handle->app_data.repeater_flag = false;
+
+	handle->tz_ctxhandle = rsp_buf->ctxhandle;
+
+	pr_debug("success\n");
+error:
+	return rc;
+}
+
+static int hdcp2_app_start(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	rc = hdcp2_app_load(handle);
+	if (rc)
+		goto error;
+
+	if (!handle->legacy_app) {
+		rc = hdcp2_app_session_init(handle);
+		if (rc)
+			goto error;
+	}
+
+	if (handle->tx_init == NULL) {
+		pr_err("invalid txmtr init function pointer\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	rc = handle->tx_init(handle);
+
+error:
+	return rc;
+}
+
+static int hdcp2_app_stop(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	rc = hdcp2_app_tx_deinit(handle);
+	if (rc)
+		goto end;
+
+	if (!handle->legacy_app) {
+		rc = hdcp2_app_session_deinit(handle);
+		if (rc)
+			goto end;
+	}
+
+	rc = hdcp2_app_unload(handle);
+end:
+	return rc;
+}
+
+static int hdcp2_app_process_msg(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(rcvd_msg);
+
+	if (!handle->app_data.request.data) {
+		pr_err("invalid request buffer\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	req_buf->msglen = handle->app_data.request.length;
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+
+	rc = hdcp2_app_process_cmd(rcvd_msg);
+	if (rc)
+		goto error;
+
+	/* check if it's a repeater */
+	if (rsp_buf->flag == HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST)
+		handle->app_data.repeater_flag = true;
+
+	handle->app_data.response.data = rsp_buf->msg;
+	handle->app_data.response.length = rsp_buf->msglen;
+	handle->app_data.timeout = rsp_buf->timeout;
+error:
+	return rc;
+}
+
+static int hdcp2_app_timeout(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(send_timeout);
+
+	rc = hdcp2_app_process_cmd(send_timeout);
+	if (rc)
+		goto error;
+
+	handle->app_data.response.data = rsp_buf->message;
+	handle->app_data.response.length = rsp_buf->msglen;
+	handle->app_data.timeout = rsp_buf->timeout;
+error:
+	return rc;
+}
+
+static int hdcp2_app_enable_encryption(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(set_hw_key);
+
+	/*
+	 * wait at least 200ms before enabling encryption
+	 * as per hdcp2p2 specifications.
+	 */
+	msleep(SLEEP_SET_HW_KEY_MS);
+
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+
+	rc = hdcp2_app_process_cmd(set_hw_key);
+	if (rc)
+		goto error;
+
+	handle->hdcp_state |= HDCP_STATE_AUTHENTICATED;
+
+	pr_debug("success\n");
+	return rc;
+error:
+	return rc;
+}
+
+static int hdcp2_force_encryption_utility(struct hdcp2_handle *handle,
+					  uint32_t enable)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(force_encryption);
+	if (handle->hdcp_state == HDCP_STATE_AUTHENTICATED)
+		msleep(SLEEP_FORCE_ENCRYPTION_MS);
+
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+	req_buf->enable = enable;
+
+	rc = hdcp2_app_process_cmd(force_encryption);
+	if (rc || (rsp_buf->commandid != hdcp_cmd_force_encryption))
+		goto error;
+
+	return 0;
+error:
+	return rc;
+}
+
+int hdcp2_force_encryption(void *ctx, uint32_t enable)
+{
+	int rc = 0;
+	struct hdcp2_handle *handle = NULL;
+
+	if (!ctx) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	handle = ctx;
+	rc = hdcp2_force_encryption_utility(handle, enable);
+	if (rc)
+		goto error;
+
+	pr_debug("success\n");
+	return 0;
+error:
+	pr_err("failed, rc=%d\n", rc);
+	return rc;
+}
+EXPORT_SYMBOL(hdcp2_force_encryption);
+
+static int hdcp2_app_query_stream(struct hdcp2_handle *handle)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(query_stream_type);
+
+	req_buf->ctxhandle = handle->tz_ctxhandle;
+
+	rc = hdcp2_app_process_cmd(query_stream_type);
+	if (rc)
+		goto error;
+
+	handle->app_data.response.data = rsp_buf->msg;
+	handle->app_data.response.length = rsp_buf->msglen;
+	handle->app_data.timeout = rsp_buf->timeout;
+error:
+	return rc;
+}
+
+static unsigned char *hdcp2_get_recv_buf(struct hdcp2_handle *handle)
+{
+	struct hdcp_rcvd_msg_req *req_buf;
+
+	req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf);
+	return req_buf->msg;
+}
+
+int hdcp2_app_comm(void *ctx, enum hdcp2_app_cmd cmd,
+		struct hdcp2_app_data *app_data)
+{
+	struct hdcp2_handle *handle = NULL;
+	int rc = 0;
+
+	if (!ctx || !app_data) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	handle = ctx;
+	handle->app_data.request.length = app_data->request.length;
+
+	pr_debug("command %s\n", hdcp2_app_cmd_str(cmd));
+
+	switch (cmd) {
+	case HDCP2_CMD_START:
+		rc = hdcp2_app_start(handle);
+		break;
+	case HDCP2_CMD_START_AUTH:
+		rc = hdcp2_app_start_auth(handle);
+		break;
+	case HDCP2_CMD_PROCESS_MSG:
+		rc = hdcp2_app_process_msg(handle);
+		break;
+	case HDCP2_CMD_TIMEOUT:
+		rc = hdcp2_app_timeout(handle);
+		break;
+	case HDCP2_CMD_EN_ENCRYPTION:
+		rc = hdcp2_app_enable_encryption(handle);
+		break;
+	case HDCP2_CMD_QUERY_STREAM:
+		rc = hdcp2_app_query_stream(handle);
+		break;
+	case HDCP2_CMD_STOP:
+		rc = hdcp2_app_stop(handle);
+	default:
+		goto error;
+	}
+
+	if (rc)
+		goto error;
+
+	handle->app_data.request.data = hdcp2_get_recv_buf(handle);
+
+	app_data->request.data = handle->app_data.request.data;
+	app_data->request.length = handle->app_data.request.length;
+	app_data->response.data = handle->app_data.response.data;
+	app_data->response.length = handle->app_data.response.length;
+	app_data->timeout = handle->app_data.timeout;
+	app_data->repeater_flag = handle->app_data.repeater_flag;
+error:
+	return rc;
+}
+EXPORT_SYMBOL(hdcp2_app_comm);
+
+static int hdcp2_open_stream_helper(struct hdcp2_handle *handle,
+		uint8_t vc_payload_id,
+		uint8_t stream_number,
+		uint32_t *stream_id)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(session_open_stream);
+
+	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+		pr_err("session not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+		pr_err("txmtr not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	req_buf->sessionid = handle->session_id;
+	req_buf->vcpayloadid = vc_payload_id;
+	req_buf->stream_number = stream_number;
+	req_buf->streamMediaType = 0;
+
+	rc = hdcp2_app_process_cmd(session_open_stream);
+	if (rc)
+		goto error;
+
+	*stream_id = rsp_buf->streamid;
+
+	pr_debug("success\n");
+
+error:
+	return rc;
+}
+
+int hdcp2_open_stream(void *ctx, uint8_t vc_payload_id, uint8_t stream_number,
+		uint32_t *stream_id)
+{
+	struct hdcp2_handle *handle = NULL;
+
+	if (!ctx) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	handle = ctx;
+
+	return hdcp2_open_stream_helper(handle, vc_payload_id, stream_number,
+		stream_id);
+}
+EXPORT_SYMBOL(hdcp2_open_stream);
+
+static int hdcp2_close_stream_helper(struct hdcp2_handle *handle,
+		uint32_t stream_id)
+{
+	int rc = 0;
+
+	hdcp2_app_init_var(session_close_stream);
+
+	if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) {
+		pr_err("session not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) {
+		pr_err("txmtr not initialized\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	req_buf->sessionid = handle->session_id;
+	req_buf->streamid = stream_id;
+
+	rc = hdcp2_app_process_cmd(session_close_stream);
+
+	if (rc)
+		goto error;
+
+	pr_debug("success\n");
+error:
+	return rc;
+}
+
+int hdcp2_close_stream(void *ctx, uint32_t stream_id)
+{
+	struct hdcp2_handle *handle = NULL;
+
+	if (!ctx) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	handle = ctx;
+
+	return hdcp2_close_stream_helper(handle, stream_id);
+}
+EXPORT_SYMBOL(hdcp2_close_stream);
+
+void *hdcp2_init(u32 device_type)
+{
+	struct hdcp2_handle *handle = NULL;
+
+	handle = kzalloc(sizeof(struct hdcp2_handle), GFP_KERNEL);
+	if (!handle)
+		goto error;
+
+	handle->device_type = device_type;
+	handle->app_name = HDCP2P2_APP_NAME;
+error:
+	return handle;
+}
+EXPORT_SYMBOL(hdcp2_init);
+
+void hdcp2_deinit(void *ctx)
+{
+	kfree_sensitive(ctx);
+}
+EXPORT_SYMBOL(hdcp2_deinit);
+
+void *hdcp1_init(void)
+{
+	struct hdcp1_handle *handle =
+		kzalloc(sizeof(struct hdcp1_handle), GFP_KERNEL);
+
+	if (!handle)
+		goto error;
+
+	handle->app_name = HDCP1_APP_NAME;
+error:
+	return handle;
+}
+EXPORT_SYMBOL(hdcp1_init);
+
+void hdcp1_deinit(void *data)
+{
+	kfree(data);
+}
+EXPORT_SYMBOL(hdcp1_deinit);
+
+static int hdcp1_count_ones(u8 *array, u8 len)
+{
+	int i, j, count = 0;
+
+	for (i = 0; i < len; i++)
+		for (j = 0; j < 8; j++)
+			count += (((array[i] >> j) & 0x1) ? 1 : 0);
+	return count;
+}
+
+static int hdcp1_validate_aksv(u32 aksv_msb, u32 aksv_lsb)
+{
+	int const number_of_ones = 20;
+	u8 aksv[5];
+
+	pr_debug("AKSV=%02x%08x\n", aksv_msb, aksv_lsb);
+
+	aksv[0] =  aksv_lsb        & 0xFF;
+	aksv[1] = (aksv_lsb >> 8)  & 0xFF;
+	aksv[2] = (aksv_lsb >> 16) & 0xFF;
+	aksv[3] = (aksv_lsb >> 24) & 0xFF;
+	aksv[4] =  aksv_msb        & 0xFF;
+
+	/* check there are 20 ones in AKSV */
+	if (hdcp1_count_ones(aksv, 5) != number_of_ones) {
+		pr_err("AKSV bit count failed\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int hdcp1_set_key(struct hdcp1_handle *hdcp1_handle, u32 *aksv_msb,
+		u32 *aksv_lsb)
+{
+	int rc = 0;
+	struct hdcp1_key_set_req *key_set_req;
+	struct hdcp1_key_set_rsp *key_set_rsp;
+	struct qseecom_handle *handle = NULL;
+
+	if (aksv_msb == NULL || aksv_lsb == NULL) {
+		pr_err("invalid aksv\n");
+		return -EINVAL;
+	}
+
+	if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) {
+		pr_err("invalid HDCP 1.x handle\n");
+		return -EINVAL;
+	}
+
+	if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("%s app not loaded\n", hdcp1_handle->app_name);
+		return -EINVAL;
+	}
+
+	handle = hdcp1_handle->qseecom_handle;
+
+	/* set keys and request aksv */
+	key_set_req = (struct hdcp1_key_set_req *)handle->sbuf;
+	key_set_req->commandid = HDCP1_SET_KEY;
+	key_set_rsp = (struct hdcp1_key_set_rsp *)(handle->sbuf +
+			QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req)));
+	rc = qseecom_send_command(handle, key_set_req,
+			QSEECOM_ALIGN(sizeof
+				(struct hdcp1_key_set_req)),
+			key_set_rsp,
+			QSEECOM_ALIGN(sizeof
+				(struct hdcp1_key_set_rsp)));
+
+	if (rc < 0) {
+		pr_err("qseecom cmd failed err=%d\n", rc);
+		return -ENOKEY;
+	}
+
+	rc = key_set_rsp->ret;
+	if (rc) {
+		pr_err("set key cmd failed, rsp=%d\n", key_set_rsp->ret);
+		return -ENOKEY;
+	}
+
+	/* copy bytes into msb and lsb */
+	*aksv_msb = key_set_rsp->ksv[0] << 24 | key_set_rsp->ksv[1] << 16 |
+		key_set_rsp->ksv[2] << 8 | key_set_rsp->ksv[3];
+	*aksv_lsb = key_set_rsp->ksv[4] << 24 | key_set_rsp->ksv[5] << 16 |
+		key_set_rsp->ksv[6] << 8 | key_set_rsp->ksv[7];
+
+	rc = hdcp1_validate_aksv(*aksv_msb, *aksv_lsb);
+	if (rc) {
+		pr_err("aksv validation failed (%d)\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int hdcp1_app_load(struct hdcp1_handle *handle)
+{
+	int rc = 0;
+
+	if (!handle) {
+		pr_err("invalid handle\n");
+		goto error;
+	}
+
+	rc = qseecom_start_app(&handle->qseecom_handle, handle->app_name,
+			QSEECOM_SBUFF_SIZE);
+	if (rc) {
+		pr_err("%s app load failed (%d)\n", handle->app_name, rc);
+		goto error;
+	}
+
+	rc = qseecom_start_app(&handle->hdcpops_handle, HDCP1OPS_APP_NAME,
+			QSEECOM_SBUFF_SIZE);
+	if (rc) {
+		pr_warn("%s app load failed (%d)\n", HDCP1OPS_APP_NAME, rc);
+		handle->hdcpops_handle = NULL;
+	}
+
+	handle->hdcp_state |= HDCP_STATE_APP_LOADED;
+	pr_debug("%s app loaded\n", handle->app_name);
+
+error:
+	return rc;
+}
+
+static void hdcp1_app_unload(struct hdcp1_handle *handle)
+{
+	int rc = 0;
+
+	if (!handle || !handle->qseecom_handle) {
+		pr_err("invalid handle\n");
+		return;
+	}
+
+	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_warn("%s app not loaded\n", handle->app_name);
+		return;
+	}
+
+	if (handle->hdcpops_handle) {
+		/* deallocate the resources for HDCP 1.x ops handle */
+		rc = qseecom_shutdown_app(&handle->hdcpops_handle);
+		if (rc)
+			pr_warn("%s app unload failed (%d)\n", HDCP1OPS_APP_NAME, rc);
+	}
+
+	/* deallocate the resources for qseecom HDCP 1.x handle */
+	rc = qseecom_shutdown_app(&handle->qseecom_handle);
+	if (rc) {
+		pr_err("%s app unload failed (%d)\n", handle->app_name, rc);
+		return;
+	}
+
+	handle->hdcp_state &= ~HDCP_STATE_APP_LOADED;
+	pr_debug("%s app unloaded\n", handle->app_name);
+}
+
+static int hdcp1_verify_key(struct hdcp1_handle *hdcp1_handle)
+{
+	int rc = 0;
+	struct hdcp1_key_verify_req *key_verify_req;
+	struct hdcp1_key_verify_rsp *key_verify_rsp;
+	struct qseecom_handle *handle = NULL;
+
+	if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) {
+		pr_err("invalid HDCP 1.x handle\n");
+		return -EINVAL;
+	}
+
+	if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("%s app not loaded\n", hdcp1_handle->app_name);
+		return -EINVAL;
+	}
+
+	handle = hdcp1_handle->qseecom_handle;
+
+	key_verify_req = (struct hdcp1_key_verify_req *)handle->sbuf;
+	key_verify_req->commandid = HDCP1_KEY_VERIFY;
+	key_verify_rsp = (struct hdcp1_key_verify_rsp *)(handle->sbuf +
+			QSEECOM_ALIGN(sizeof(struct hdcp1_key_verify_req)));
+	rc = qseecom_send_command(handle, key_verify_req,
+			QSEECOM_ALIGN(sizeof
+				(struct hdcp1_key_verify_req)),
+			key_verify_rsp,
+			QSEECOM_ALIGN(sizeof
+				(struct hdcp1_key_set_rsp)));
+
+	if (rc < 0) {
+		pr_err("command HDCP1_KEY_VERIFY failed (%d)\n", rc);
+		return -EINVAL;
+	}
+
+	rc = key_verify_rsp->ret;
+	if (rc) {
+		pr_err("key_verify failed, rsp=%d\n", key_verify_rsp->ret);
+		return -EINVAL;
+	}
+
+	pr_debug("success\n");
+
+	return 0;
+}
+
+bool hdcp1_feature_supported(void *data)
+{
+	bool supported = false;
+	struct hdcp1_handle *handle = data;
+	int rc = 0;
+
+	if (!handle) {
+		pr_err("invalid handle\n");
+		goto error;
+	}
+
+	if (handle->feature_supported) {
+		supported = true;
+		goto error;
+	}
+
+	rc = hdcp1_app_load(handle);
+	if (!rc && (handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		if (!hdcp1_verify_key(handle)) {
+			pr_debug("HDCP 1.x supported\n");
+			handle->feature_supported = true;
+			supported = true;
+		}
+		hdcp1_app_unload(handle);
+	}
+error:
+	return supported;
+}
+EXPORT_SYMBOL(hdcp1_feature_supported);
+
+int hdcp1_set_enc(void *data, bool enable)
+{
+	int rc = 0;
+	struct hdcp1_set_enc_req *set_enc_req;
+	struct hdcp1_set_enc_rsp *set_enc_rsp;
+	struct hdcp1_handle *hdcp1_handle = data;
+	struct qseecom_handle *handle = NULL;
+
+	if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) {
+		pr_err("invalid HDCP 1.x handle\n");
+		return -EINVAL;
+	}
+
+	if (!hdcp1_handle->feature_supported) {
+		pr_err("HDCP 1.x not supported\n");
+		return -EINVAL;
+	}
+
+	if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("%s app not loaded\n", hdcp1_handle->app_name);
+		return -EINVAL;
+	}
+
+	handle = hdcp1_handle->qseecom_handle;
+
+	/* set keys and request aksv */
+	set_enc_req = (struct hdcp1_set_enc_req *)handle->sbuf;
+	set_enc_req->commandid = HDCP1_SET_ENC;
+	set_enc_req->enable = enable;
+	set_enc_rsp = (struct hdcp1_set_enc_rsp *)(handle->sbuf +
+			QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req)));
+	rc = qseecom_send_command(handle, set_enc_req,
+			QSEECOM_ALIGN(sizeof
+				(struct hdcp1_set_enc_req)),
+			set_enc_rsp,
+			QSEECOM_ALIGN(sizeof
+				(struct hdcp1_set_enc_rsp)));
+
+	if (rc < 0) {
+		pr_err("qseecom cmd failed err=%d\n", rc);
+		return -EINVAL;
+	}
+
+	rc = set_enc_rsp->ret;
+	if (rc) {
+		pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret);
+		return -EINVAL;
+	}
+
+	pr_debug("success\n");
+	return 0;
+}
+EXPORT_SYMBOL(hdcp1_set_enc);
+
+int hdcp1_ops_notify(void *data, void *topo, bool is_authenticated)
+{
+	int rc = 0;
+	struct hdcp1_ops_notify_req *ops_notify_req;
+	struct hdcp1_ops_notify_rsp *ops_notify_rsp;
+	struct hdcp1_handle *hdcp1_handle = data;
+	struct qseecom_handle *handle = NULL;
+	struct hdcp1_topology *topology = NULL;
+
+	if (!hdcp1_handle || !hdcp1_handle->hdcpops_handle) {
+		pr_err("invalid HDCP 1.x ops handle\n");
+		return -EINVAL;
+	}
+
+	if (!hdcp1_handle->feature_supported) {
+		pr_err("HDCP 1.x not supported\n");
+		return -EINVAL;
+	}
+
+	if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_err("%s app not loaded\n", HDCP1OPS_APP_NAME);
+		return -EINVAL;
+	}
+
+	handle = hdcp1_handle->hdcpops_handle;
+	topology = (struct hdcp1_topology *)topo;
+
+	/* set keys and request aksv */
+	ops_notify_req = (struct hdcp1_ops_notify_req *)handle->sbuf;
+	ops_notify_req->commandid = HDCP1_NOTIFY_TOPOLOGY;
+	ops_notify_req->device_type = DEVICE_TYPE_DP;
+	ops_notify_req->is_authenticated = is_authenticated;
+	ops_notify_req->topology.depth = topology->depth;
+	ops_notify_req->topology.device_count = topology->device_count;
+	ops_notify_req->topology.max_devices_exceeded = topology->max_devices_exceeded;
+	ops_notify_req->topology.max_cascade_exceeded = topology->max_cascade_exceeded;
+
+	/*
+	 * For hdcp1.4 below two nodes are not applicable but as
+	 * TZ ops ta talks with other drivers with same structure
+	 * and want to maintain same interface across hdcp versions,
+	 * we are setting the values to 0.
+	 */
+	ops_notify_req->topology.hdcp2LegacyDeviceDownstream = 0;
+	ops_notify_req->topology.hdcp1DeviceDownstream = 0;
+
+	memset(ops_notify_req->recv_id_list, 0, sizeof(uint8_t) * MAX_REC_ID_LIST_SIZE);
+
+	ops_notify_rsp = (struct hdcp1_ops_notify_rsp *)(handle->sbuf +
+			QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_req)));
+	rc = qseecom_send_command(handle, ops_notify_req,
+			QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_req)),
+			ops_notify_rsp,
+			QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_rsp)));
+
+	rc = ops_notify_rsp->ret;
+	if (rc < 0) {
+		pr_warn("Ops notify cmd failed, rsp=%d\n", ops_notify_rsp->ret);
+		return -EINVAL;
+	}
+
+	pr_debug("ops notify success\n");
+	return 0;
+}
+EXPORT_SYMBOL(hdcp1_ops_notify);
+
+int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb)
+{
+	int rc = 0;
+	struct hdcp1_handle *hdcp1_handle = data;
+
+	if (!aksv_msb || !aksv_lsb) {
+		pr_err("invalid aksv output buffer\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!hdcp1_handle) {
+		pr_err("invalid handle\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!hdcp1_handle->feature_supported) {
+		pr_err("feature not supported\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED) {
+		pr_debug("%s app already loaded\n", hdcp1_handle->app_name);
+		goto error;
+	}
+
+	rc = hdcp1_app_load(hdcp1_handle);
+	if (rc)
+		goto error;
+
+	rc = hdcp1_set_key(hdcp1_handle, aksv_msb, aksv_lsb);
+	if (rc)
+		goto key_error;
+
+	pr_debug("success\n");
+	return rc;
+
+key_error:
+	hdcp1_app_unload(hdcp1_handle);
+error:
+	return rc;
+}
+EXPORT_SYMBOL(hdcp1_start);
+
+void hdcp1_stop(void *data)
+{
+	struct hdcp1_handle *hdcp1_handle = data;
+
+	if (!hdcp1_handle || !hdcp1_handle->qseecom_handle || !hdcp1_handle->hdcpops_handle) {
+		pr_err("invalid handle\n");
+		return;
+	}
+
+	if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
+		pr_debug("%s app not loaded\n", hdcp1_handle->app_name);
+		return;
+	}
+
+	hdcp1_app_unload(hdcp1_handle);
+}
+EXPORT_SYMBOL(hdcp1_stop);
+
+static int __init hdcp_module_init(void){ return 0; }
+static void __exit hdcp_module_exit(void){ return; }
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("HDCP driver");
+
+module_init(hdcp_module_init);
+module_exit(hdcp_module_exit);

+ 153 - 0
linux/hdcp_qseecom.h

@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2015-2022, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __HDCP_QSEECOM_H
+#define __HDCP_QSEECOM_H
+#include <linux/types.h>
+
+#define HDCP_QSEECOM_ENUM_STR(x)	#x
+
+enum hdcp2_app_cmd {
+	HDCP2_CMD_START,
+	HDCP2_CMD_START_AUTH,
+	HDCP2_CMD_STOP,
+	HDCP2_CMD_PROCESS_MSG,
+	HDCP2_CMD_TIMEOUT,
+	HDCP2_CMD_EN_ENCRYPTION,
+	HDCP2_CMD_QUERY_STREAM,
+};
+
+struct hdcp2_buffer {
+	unsigned char *data;
+	u32 length;
+};
+
+struct hdcp2_app_data {
+	u32 timeout;
+	bool repeater_flag;
+	struct hdcp2_buffer request;	// requests to TA, sent from sink
+	struct hdcp2_buffer response;	// responses from TA, sent to sink
+};
+
+struct hdcp1_topology {
+	uint32_t depth;
+	uint32_t device_count;
+	uint32_t max_devices_exceeded;
+	uint32_t max_cascade_exceeded;
+	uint32_t hdcp2LegacyDeviceDownstream;
+	uint32_t hdcp1DeviceDownstream;
+};
+
+static inline const char *hdcp2_app_cmd_str(enum hdcp2_app_cmd cmd)
+{
+	switch (cmd) {
+	case HDCP2_CMD_START:
+		return HDCP_QSEECOM_ENUM_STR(HDCP2_CMD_START);
+	case HDCP2_CMD_START_AUTH:
+		return HDCP_QSEECOM_ENUM_STR(HDCP2_CMD_START_AUTH);
+	case HDCP2_CMD_STOP:
+		return HDCP_QSEECOM_ENUM_STR(HDCP2_CMD_STOP);
+	case HDCP2_CMD_PROCESS_MSG:
+		return HDCP_QSEECOM_ENUM_STR(HDCP2_CMD_PROCESS_MSG);
+	case HDCP2_CMD_TIMEOUT:
+		return HDCP_QSEECOM_ENUM_STR(HDCP2_CMD_TIMEOUT);
+	case HDCP2_CMD_EN_ENCRYPTION:
+		return HDCP_QSEECOM_ENUM_STR(HDCP2_CMD_EN_ENCRYPTION);
+	case HDCP2_CMD_QUERY_STREAM:
+		return HDCP_QSEECOM_ENUM_STR(HDCP2_CMD_QUERY_STREAM);
+	default:			return "???";
+	}
+}
+
+#if IS_ENABLED(CONFIG_HDCP_QSEECOM)
+void *hdcp1_init(void);
+void hdcp1_deinit(void *data);
+bool hdcp1_feature_supported(void *data);
+int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb);
+int hdcp1_set_enc(void *data, bool enable);
+int hdcp1_ops_notify(void *data, void *topology, bool is_authenticated);
+void hdcp1_stop(void *data);
+
+void *hdcp2_init(u32 device_type);
+void hdcp2_deinit(void *ctx);
+bool hdcp2_feature_supported(void *ctx);
+int hdcp2_app_comm(void *ctx, enum hdcp2_app_cmd cmd,
+		struct hdcp2_app_data *app_data);
+int hdcp2_open_stream(void *ctx, uint8_t vc_payload_id,
+		uint8_t stream_number, uint32_t *stream_id);
+int hdcp2_close_stream(void *ctx, uint32_t stream_id);
+int hdcp2_force_encryption(void *ctx, uint32_t enable);
+#else
+static inline void *hdcp1_init(void)
+{
+	return NULL;
+}
+
+static inline void hdcp1_deinit(void *data)
+{
+}
+
+static inline bool hdcp1_feature_supported(void *data)
+{
+	return false;
+}
+
+static inline int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb)
+{
+	return 0;
+}
+
+static inline int hdcp1_ops_notify(void *data, void *topology, bool is_authenticated)
+{
+	return 0;
+}
+
+static inline int hdcp1_set_enc(void *data, bool enable)
+{
+	return 0;
+}
+
+static inline void hdcp1_stop(void *data)
+{
+}
+
+static inline void *hdcp2_init(u32 device_type)
+{
+	return NULL;
+}
+
+static inline void hdcp2_deinit(void *ctx)
+{
+}
+
+static inline bool hdcp2_feature_supported(void *ctx)
+{
+	return false;
+}
+
+static inline int hdcp2_app_comm(void *ctx, enum hdcp2_app_cmd cmd,
+		struct hdcp2_app_data *app_data)
+{
+	return 0;
+}
+
+static inline int hdcp2_open_stream(void *ctx, uint8_t vc_payload_id,
+		uint8_t stream_number, uint32_t *stream_id)
+{
+	return 0;
+}
+
+static inline int hdcp2_close_stream(void *ctx, uint32_t stream_id)
+{
+	return 0;
+}
+
+static inline int hdcp2_force_encryption(void *ctx, uint32_t enable)
+{
+	return 0;
+}
+#endif /* CONFIG_HDCP_QSEECOM */
+
+#endif /* __HDCP_QSEECOM_H */

+ 0 - 0
smcinvoke/misc/qseecom_kernel.h → linux/misc/qseecom_kernel.h


+ 0 - 0
crypto-qti/linux/qcota.h → linux/qcota.h


+ 2 - 0
securemsm_kernel_product_board.mk

@@ -4,5 +4,7 @@ PRODUCT_PACKAGES += $(KERNEL_MODULES_OUT)/smcinvoke_dlkm.ko \
   $(KERNEL_MODULES_OUT)/qcedev-mod_dlkm.ko \
   $(KERNEL_MODULES_OUT)/qce50_dlkm.ko \
   $(KERNEL_MODULES_OUT)/qcrypto-msm_dlkm.ko \
+  $(KERNEL_MODULES_OUT)/hdcp_qseecom_dlkm.ko \
+
 
 

+ 2 - 0
securemsm_kernel_vendor_board.mk

@@ -3,3 +3,5 @@ BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/smcinvoke_dlkm.ko \
       $(KERNEL_MODULES_OUT)/qcedev-mod_dlkm.ko \
       $(KERNEL_MODULES_OUT)/qcrypto-msm_dlkm.ko \
       $(KERNEL_MODULES_OUT)/qce50_dlkm.ko \
+      $(KERNEL_MODULES_OUT)/hdcp_qseecom_dlkm.ko \
+