// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2019-2020 MediaTek Inc.
 * Author: Elle.Ko <elle.ko@mediatek.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
#include <linux/vmalloc.h>
#include <linux/tee.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
#include <linux/tee_drv.h>
#else
#include "tee_drv_5_15_13.h"
#endif
#else
#include <linux/tee_drv.h>
#endif
#include <linux/uuid.h>
#include <linux/delay.h>
#include "mtk_mad_tee_interface.h"
#define TEE_PARAM_COUNT 4
#define EORIG_2 2
#define MAX_MAD_NUM 4

#define MAD_PARSER_TEE_BASE_PARAM_SIZE    0x80
/**
 * Encode the paramTypes according to the supplied types.
 *
 * @param p0 The first param type.
 * @param p1 The second param type.
 * @param p2 The third param type.
 * @param p3 The fourth param type.
 */
#define TEEC_PARAM_TYPES(p0, p1, p2, p3) \
	((p0) | ((p1) << 4) | ((p2) << 8) | ((p3) << 12))
/**
 * Get the i_th param type from the paramType.
 *
 * @param p The paramType.
 * @param i The i-th parameter to get the type for.
 */
#define TEEC_PARAM_TYPE_GET(p, i) (((p) >> (i * 4)) & 0xF)
enum EN_AUDIO_TEE_CMD {
    E_AUDIO_TEE_SET_DDR_BASE_ADDRESS = 0,
    E_AUDIO_TEE_APPLY_DDR_BASE_ADDRESS,
    E_AUDIO_TEE_LOAD_FIRMWARE,
    E_AUDIO_TEE_LOAD_EXTERNAL_FIRMWARE,
    E_AUDIO_TEE_GET_RESOURCE,
    E_AUDIO_TEE_TEST_PIPE_CONTROL,
    E_AUDIO_TEE_TEST_SECURE_FIRMWARE,
    E_AUDIO_TEE_SET_SECURE_ENABLE,
    E_AUDIO_TEE_ENABLE_SECURE_DEC_R2,
    E_AUDIO_TEE_PARSER_CREATE,
	E_AUDIO_TEE_PARSER_DESTROY,
	E_AUDIO_TEE_PARSER_FRAMING,
};

enum mad_parser_tee_param_type {
	E_AUDIO_PARSER_TEE_PARAM_NONE,
	E_AUDIO_PARSER_TEE_PARAM_VALUE_IN,
	E_AUDIO_PARSER_TEE_PARAM_VALUE_OUT,
	E_AUDIO_PARSER_TEE_PARAM_VALUE_INOUT,
	E_AUDIO_PARSER_TEE_PARAM_MEMREF_IN,
	E_AUDIO_PARSER_TEE_PARAM_MEMREF_OUT,
	E_AUDIO_PARSER_TEE_PARAM_MEMREF_INOUT,
	E_AUDIO_PARSER_TEE_PARAM_PRESET_SHM,
};

struct mad_optee_contex {
	struct tee_context *ctx;
	u32 session_id;
	bool session_initialized;
};
struct TEEC_SharedMemory_2 {
	void *buffer;
	size_t size;
	uint32_t flags;
	size_t alloced_size;
	void *shadow_buffer;
};
struct TempMemoryReference {
	void *buffer;
	size_t size;
};
struct TempValue {
	uint32_t a;
	uint32_t b;
};
struct parameter {
	struct TempValue value;
	struct TempMemoryReference tmpref;
};
struct TEEC_Operation {
	uint32_t paramTypes;
	struct parameter params[TEE_PARAM_COUNT];
};

struct parser_destroy_param {
	uint16_t parser_id;
};
struct parser_framing_param {
	uint32_t parser_id;
	uint32_t sequence_num;
	uint64_t es_start_pa;
	uint64_t es_end_pa;
	uint8_t update_parser;
	uint32_t es_data_offset;
	uint32_t es_data_size;
	uint32_t find_ret;	// out
	uint64_t unit_base;	// out
	uint64_t unit_table;	// out
	uint32_t unit_table_size;
	uint32_t unit_found_num;	// out
	uint8_t find_last_unit;	// out
};
struct header_pre_parse_param {
	uint32_t u32EsId;
	uint32_t u32CodecType;
	uint64_t u64EsDataStart;
	uint64_t u64EsDataEnd;
	uint32_t u32Width;	// out
	uint32_t u32Height;	// out
	uint32_t u32FrameRate;	// out
	uint32_t u32BitDepth;	// out
	uint32_t u32DpbSize;	// out
};

struct mad_parser_tee_contex {
	struct mad_optee_contex mad_parser_ctx;
	unsigned char *base_param;
	unsigned char *unit_info;
	// use alloc buffer to get shm
	struct TEEC_SharedMemory_2 base_param_shm;
	struct TEEC_SharedMemory_2 unit_info_shm;
	bool bPresetOK;
};

static struct mad_parser_tee_contex p_mad_tee_ctx[MAX_MAD_NUM];

#define SHM_LEN 8

static int _optee_param_type(enum mad_parser_tee_param_type param_type)
{
	switch (param_type) {
	case E_AUDIO_PARSER_TEE_PARAM_NONE:
		return TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
	case E_AUDIO_PARSER_TEE_PARAM_VALUE_IN:
		return TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
	case E_AUDIO_PARSER_TEE_PARAM_VALUE_OUT:
		return TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
	case E_AUDIO_PARSER_TEE_PARAM_VALUE_INOUT:
		return TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
	case E_AUDIO_PARSER_TEE_PARAM_MEMREF_IN:
		return TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
	case E_AUDIO_PARSER_TEE_PARAM_MEMREF_OUT:
		return TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
	case E_AUDIO_PARSER_TEE_PARAM_MEMREF_INOUT:
		return TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
	case E_AUDIO_PARSER_TEE_PARAM_PRESET_SHM:
		return TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
	default:
		return TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
	}
}


static int teec_allocatesharedmemory(struct tee_context *ctx,
		struct TEEC_SharedMemory_2 *shm)
{
	struct tee_shm *_shm = NULL;
	void *shm_va = NULL;
	size_t len;
	struct tee_context *context = ctx;
	shm->shadow_buffer = shm->buffer = NULL;
	len = shm->size;
	if (!len)
		len = SHM_LEN;
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
	_shm = tee_shm_alloc(context, len,
			TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
#else
	_shm = tee_shm_alloc_kernel_buf(context, len);
#endif
	if (IS_ERR(_shm)) {
		pr_err("%s %d: tee_shm_alloc Fail\n",
			__func__, __LINE__);
		return -ENOMEM;
	}
	shm_va = tee_shm_get_va(_shm, 0);
	if (IS_ERR(shm_va)) {
		pr_err("%s %d: tee_shm_get_va Fail\n",
			__func__, __LINE__);
		return -ENOMEM;
	}
	shm->buffer = shm_va;
	shm->shadow_buffer = (void *)_shm;
	shm->alloced_size = len;
	return 0;
}
static void teec_releasesharedmemory(struct TEEC_SharedMemory_2 *shm)
{
	if (shm->shadow_buffer)
		tee_shm_free((struct tee_shm *)shm->shadow_buffer);
	shm->shadow_buffer = NULL;
	shm->buffer = NULL;
}
static int teec_pre_process_tmpref(struct tee_context *ctx,
		uint32_t param_type, struct TempMemoryReference *tmpref,
		struct tee_param *param, struct TEEC_SharedMemory_2 *shm)
{
	int res;
	param->attr = param_type;
	shm->size = tmpref->size;
	res = teec_allocatesharedmemory(ctx, shm);
	if (res != 0)
		return res;
	memcpy(shm->buffer, tmpref->buffer, tmpref->size);
	param->u.memref.size = tmpref->size;
	//Workaround, shm->shadow_buffer is shm object.
	param->u.memref.shm = (struct tee_shm *)shm->shadow_buffer;
	return 0;
}
static int teec_pre_process_operation(struct tee_context *ctx,
		struct TEEC_Operation *operation,
		struct tee_param *params, struct TEEC_SharedMemory_2 *shms)
{
	int res;
	size_t n;
	uint32_t param_type;
	memset(shms, 0, sizeof(*shms) * TEE_PARAM_COUNT);
	if (!operation) {
		memset(params, 0, sizeof(*params) * TEE_PARAM_COUNT);
		return 0;
	}
	for (n = 0; n < TEE_PARAM_COUNT; n++) {
		param_type = TEEC_PARAM_TYPE_GET(operation->paramTypes, n);
		switch (param_type) {
		case E_AUDIO_PARSER_TEE_PARAM_NONE:
			params[n].attr = _optee_param_type(param_type);
			break;
		case E_AUDIO_PARSER_TEE_PARAM_VALUE_IN:
		case E_AUDIO_PARSER_TEE_PARAM_VALUE_OUT:
		case E_AUDIO_PARSER_TEE_PARAM_VALUE_INOUT:
			params[n].attr = _optee_param_type(param_type);
			params[n].u.value.a = operation->params[n].value.a;
			params[n].u.value.b = operation->params[n].value.b;
			break;
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_IN:
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_OUT:
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_INOUT:
			res = teec_pre_process_tmpref(ctx,
						_optee_param_type(param_type),
						&operation->params[n].tmpref,
						params + n, shms + n);
			if (res != 0)
				return res;
			break;
		case E_AUDIO_PARSER_TEE_PARAM_PRESET_SHM:
			params[n].attr = _optee_param_type(param_type);
			params[n].u.memref.shm =
				(struct tee_shm *)operation->params[n].tmpref.buffer;
			params[n].u.memref.size =
				operation->params[n].tmpref.size;
			params[n].u.memref.shm_offs = 0;
			break;
		default:
			pr_err("[%s] param_type not support!",
				__func__);
			return -1;
		}
	}
	return 0;
}
static void teec_post_process_tmpref(uint32_t param_type,
		struct TempMemoryReference *tmpref,
		struct tee_param *param, struct TEEC_SharedMemory_2 *shm)
{
	if (param_type != E_AUDIO_PARSER_TEE_PARAM_MEMREF_IN) {
		if (param->u.memref.size <= tmpref->size && tmpref->buffer)
			memcpy(tmpref->buffer, shm->buffer,
				param->u.memref.size);
		tmpref->size = param->u.memref.size;
	}
}
static void teec_post_process_operation(struct TEEC_Operation *operation,
		struct tee_param *params, struct TEEC_SharedMemory_2 *shms)
{
	size_t n;
	if (!operation)
		return;
	for (n = 0; n < TEE_PARAM_COUNT; n++) {
		uint32_t param_type;
		param_type = TEEC_PARAM_TYPE_GET(operation->paramTypes, n);
		switch (param_type) {
		case E_AUDIO_PARSER_TEE_PARAM_VALUE_IN:
			break;
		case E_AUDIO_PARSER_TEE_PARAM_VALUE_OUT:
		case E_AUDIO_PARSER_TEE_PARAM_VALUE_INOUT:
			operation->params[n].value.a = params[n].u.value.a;
			operation->params[n].value.b = params[n].u.value.b;
			break;
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_IN:
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_OUT:
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_INOUT:
			teec_post_process_tmpref(param_type,
						 &operation->params[n].tmpref,
						 params + n, shms + n);
			break;
		case E_AUDIO_PARSER_TEE_PARAM_PRESET_SHM:
			// do nothing
			break;
		default:
			break;
		}
	}
}
static void teec_free_temp_refs(struct TEEC_Operation *operation,
		struct TEEC_SharedMemory_2 *shms)
{
	size_t n;
	if (!operation)
		return;
	for (n = 0; n < TEE_PARAM_COUNT; n++) {
		switch (TEEC_PARAM_TYPE_GET(operation->paramTypes, n)) {
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_IN:
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_OUT:
		case E_AUDIO_PARSER_TEE_PARAM_MEMREF_INOUT:
			teec_releasesharedmemory(shms + n);
			break;
		default:
			break;
		}
	}
}
static int _optee_match(struct tee_ioctl_version_data *data, const void *vers)
{
	return 1;
}
static int mad_tee_init_session(struct mad_optee_contex *mad_ctx)
{
	struct tee_context *tee_ctx;
	struct tee_ioctl_version_data vers = {
		.impl_id = TEE_OPTEE_CAP_TZ,
		.impl_caps = TEE_IMPL_ID_OPTEE,
		.gen_caps = TEE_GEN_CAP_GP,
	};
	if (mad_ctx->session_initialized)
		return 0;
	tee_ctx = tee_client_open_context(NULL,
			_optee_match, NULL, &vers);
	if (IS_ERR(tee_ctx)) {
		pr_err("[%s] context is NULL\n", __func__);
		return -EINVAL;
	}
	mad_ctx->ctx = tee_ctx;
	mad_ctx->session_initialized = true;
	return 0;
}
static void mad_tee_destroy_session(struct mad_optee_contex *mad_ctx)
{
	if (!mad_ctx->session_initialized)
		return;
	tee_client_close_context(mad_ctx->ctx);
	mad_ctx->ctx = NULL;
	mad_ctx->session_initialized = false;
}

#define UUID_0 0x778ee68e
#define UUID_1 0x6ee0
#define UUID_2 0x11e8
#define UUID_3 0xad
#define UUID_4 0xc0
#define UUID_5 0xfa
#define UUID_6 0x7a
#define UUID_7 0xe0
#define UUID_8 0x1b
#define UUID_9 0xbe
#define UUID_10 0xbc

static int mad_tee_open_session(struct mad_optee_contex *mad_ctx)
{
	struct tee_ioctl_open_session_arg arg;
	struct tee_param param;
	int rc;
	int res;
	uuid_t uuid = UUID_INIT(UUID_0, UUID_1, UUID_2,
		UUID_3, UUID_4, UUID_5, UUID_6, UUID_7, UUID_8, UUID_9, UUID_10);

	res = mad_tee_init_session(mad_ctx);
	if (res != 0) {
		pr_err("[%s] adec_tee_init_session fail\n", __func__);
		return -EINVAL;
	}
	memset(&arg, 0, sizeof(arg));
	memset(&param, 0, sizeof(param));
	memcpy(arg.uuid, &uuid, TEE_IOCTL_UUID_LEN);
	arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
	rc = tee_client_open_session(mad_ctx->ctx,
			&arg, (struct tee_param *)&param);
	if (rc == 0) {
		mad_ctx->session_id = arg.session;
	} else {
		pr_err("[%s] tee_client_open_session fail,rc=0x%x\n",
				__func__, rc);
		return -EINVAL;
	}
	return 0;
}
static int mad_tee_close_session(struct mad_optee_contex *mad_ctx)
{
	tee_client_close_session(mad_ctx->ctx, mad_ctx->session_id);
	mad_tee_destroy_session(mad_ctx);
	return 0;
}
static int mad_tee_invoke(uint32_t commandID, struct TEEC_Operation *operation,
		uint32_t *return_origin, u16 parser_id)
{
	//struct mad_optee_contex mad_ctx;
	struct tee_ioctl_invoke_arg arg;
	struct tee_param params[TEE_PARAM_COUNT];
	int res;
	uint32_t eorig = 0;
	struct TEEC_SharedMemory_2 shm[TEE_PARAM_COUNT];
	int rc;
	struct mad_optee_contex *p_mad_parser_ctx = NULL;
	struct mad_parser_tee_contex *pCtx = NULL;

	if (parser_id >= MAX_MAD_NUM)
		return -EINVAL;
	pCtx = &p_mad_tee_ctx[parser_id];
	p_mad_parser_ctx = &pCtx->mad_parser_ctx;

	if (!p_mad_parser_ctx->ctx) {
		pr_err("[%s] Err: Not init Ves Parser TEE context\n", __func__);
		return -EINVAL;
	}

	if (!operation) {
		eorig = 1;
		res = -1;
		return res;
	}

	memset(&arg, 0x0, sizeof(arg));
	memset(params, 0x0, sizeof(params));
	memset(shm, 0x0, sizeof(shm));

	arg.num_params = TEE_PARAM_COUNT;
	arg.session = p_mad_parser_ctx->session_id;
	arg.func = commandID;
	res = teec_pre_process_operation(p_mad_parser_ctx->ctx,
			operation, params, shm);

	if (res != 0) {
		eorig = 1;
		goto out_free_temp_refs;
	}
	rc = tee_client_invoke_func(p_mad_parser_ctx->ctx, &arg, params);

	if (rc) {
		eorig = EORIG_2;
		res = rc;
		goto out_free_temp_refs;
	}
	res = arg.ret;
	eorig = arg.ret_origin;
	teec_post_process_operation(operation, params, shm);

out_free_temp_refs:
	teec_free_temp_refs(operation, shm);
	if (return_origin)
		*return_origin = eorig;
	return res;
}

static void *_mad_parser_register_shm(struct mad_parser_tee_contex *pCtx,
					void *buffer, uint32_t size, int *err)
{
	struct tee_shm *_shm;
	struct mad_optee_contex *p_mad_parser_ctx = &pCtx->mad_parser_ctx;

	if (!p_mad_parser_ctx->ctx) {
		pr_err("[%s] Err: Not init Ves Parser TEE context\n", __func__);
		*err = -EINVAL;
		return (void *) 0;
	}
	if (buffer == NULL || size == 0) {
		pr_err("[%s] Err: buffer: %p size: %d\n",
			__func__, buffer, size);
		*err = -EINVAL;
		return (void *) 0;
	}
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
	_shm = tee_shm_register(p_mad_parser_ctx->ctx,
		(unsigned long)buffer,
		size,
		TEE_SHM_DMA_BUF | TEE_SHM_KERNEL_MAPPED);
#else
	_shm = tee_shm_register_kernel_buf(p_mad_parser_ctx->ctx,
			(void *)buffer, size);
#endif

	if (IS_ERR(_shm)) {
		pr_err("%s %d: tee_shm_register fail. buffer %p size %u\n",
		       __func__, __LINE__, buffer, size);
		*err = -ENOMEM;
		return (void *) 0;
	}

	return _shm;
}

static int _mad_parser_unregister_shm(struct mad_parser_tee_contex *pCtx,
	struct TEEC_SharedMemory_2 *shm)
{
	struct mad_optee_contex *p_mad_parser_ctx = &pCtx->mad_parser_ctx;

	if (!p_mad_parser_ctx->ctx) {
		pr_err("[%s] Err: Not init Ves Parser TEE context\n", __func__);
		return -EINVAL;
	}

	if (!pCtx->bPresetOK) {
		pr_err("[%s] Err: Not Peset param shm\n", __func__);
		return -EINVAL;
	}

	if (!shm->shadow_buffer) {
		pr_err("[%s] Err: NULL TEE shm\n", __func__);
	} else {
		tee_shm_free(shm->shadow_buffer);
		shm->shadow_buffer = NULL;
	}

	if (!shm->buffer)
		pr_err("[%s] Err: NULL TEE buffer\n", __func__);
	else {
		vfree(shm->buffer);
		shm->buffer = NULL;
	}

	return 0;
}

static int mad_parser_preset_param(struct mad_parser_tee_contex *pCtx)
{
	void *ret_addr = 0;
	int err = 0;

	memset(&pCtx->base_param_shm, 0, sizeof(pCtx->base_param_shm));
	memset(&pCtx->unit_info_shm, 0, sizeof(pCtx->unit_info_shm));

	// alloc base param
	pCtx->base_param = vzalloc(MAD_PARSER_TEE_BASE_PARAM_SIZE);
	if (!pCtx->base_param)
		return -ENOMEM;

	// register base  param
	ret_addr = _mad_parser_register_shm(pCtx,
		pCtx->base_param,
		MAD_PARSER_TEE_BASE_PARAM_SIZE, &err);
	if (ret_addr > 0) {
		pCtx->base_param_shm.shadow_buffer = ret_addr;
		pCtx->base_param_shm.buffer = pCtx->base_param;
		pCtx->base_param_shm.alloced_size = MAD_PARSER_TEE_BASE_PARAM_SIZE;
		pr_err("\033[1;33m[%s] %d register base param suc\033[m\n", __func__, __LINE__);
	} else {
		vfree(pCtx->base_param);
		pCtx->base_param = NULL;
		pr_err("\033[1;33m[%s] %d register base param fail err: %d\033[m\n",
			__func__, __LINE__, err);
		return -ENOMEM;
	}

	pr_err("\033[1;33m[%s] %d register suc\033[m\n", __func__, __LINE__);
	return 0;
}
static void mad_parser_unset_param(struct mad_parser_tee_contex *pCtx)
{
	if (_mad_parser_unregister_shm(pCtx, &pCtx->base_param_shm))
		pr_err("[%s] _ves_parser_unregister_shm base_param_shm fail\n",
			__func__);
	pCtx->base_param = NULL;
}

int mad_parser_tee_create(u16 parser_id,
	struct parser_create_param *param)
{
	struct TEEC_Operation op;
	int res;
	uint32_t err_origin = 0;
	struct parser_create_param *create_param;
	struct mad_parser_tee_contex *pCtx = NULL;

	if (parser_id >= MAX_MAD_NUM)
		return -EINVAL;
	pCtx = &p_mad_tee_ctx[parser_id];

	if (pCtx->bPresetOK == 0) {
		// open session to create tee ctx
		res = mad_tee_open_session(&pCtx->mad_parser_ctx);

		if (res) {
			pr_err("\033[1;33m[%s] %d open_session fail\033[m\n", __func__, __LINE__);
			return -EINVAL;
		}
		pCtx->bPresetOK = !mad_parser_preset_param(pCtx);
	}
	if (!pCtx->bPresetOK)
		return -ENOMEM;
	memset(&op, 0, sizeof(struct TEEC_Operation));
	op.paramTypes = TEEC_PARAM_TYPES(E_AUDIO_PARSER_TEE_PARAM_PRESET_SHM,
						E_AUDIO_PARSER_TEE_PARAM_NONE,
						E_AUDIO_PARSER_TEE_PARAM_NONE,
						E_AUDIO_PARSER_TEE_PARAM_NONE);
	op.params[0].tmpref.buffer =
		(void *) pCtx->base_param_shm.shadow_buffer;
	op.params[0].tmpref.size = sizeof(struct parser_create_param);

	memset(pCtx->base_param_shm.buffer, 0, MAD_PARSER_TEE_BASE_PARAM_SIZE);

	create_param = (struct parser_create_param *) pCtx->base_param_shm.buffer;
	create_param->u64SecureEsStartAddr = param->u64SecureEsStartAddr;
	create_param->u64SecureEsEndAddr = param->u64SecureEsEndAddr;
	create_param->u64NonSecureEsStartAddr = param->u64NonSecureEsStartAddr;
	create_param->u64NonSecureEsEndAddr = param->u64NonSecureEsEndAddr;
	create_param->u8IncompleteBs = param->u8IncompleteBs;
	create_param->u16ParserId = param->u16ParserId;

	res = mad_tee_invoke(E_AUDIO_TEE_PARSER_CREATE,
		&op, &err_origin, parser_id);

	if (res != 0) {
		pr_err("[%s] Parser create fail - res:0x%x err: 0x%x\n",
			__func__, res, err_origin);
		return res;
	}

	return 0;
}
int mad_parser_tee_destroy(u16 parser_id)
{
	struct TEEC_Operation op;
	int res;
	uint32_t err_origin = 0;
	struct parser_destroy_param *destroy_param;
	struct mad_parser_tee_contex *pCtx = NULL;

	if (parser_id >= MAX_MAD_NUM)
		return -EINVAL;
	pCtx = &p_mad_tee_ctx[parser_id];

	if (!pCtx->bPresetOK)
		return -ENOMEM;

	memset(&op, 0, sizeof(struct TEEC_Operation));
	op.paramTypes = TEEC_PARAM_TYPES(E_AUDIO_PARSER_TEE_PARAM_PRESET_SHM,
						E_AUDIO_PARSER_TEE_PARAM_NONE,
						E_AUDIO_PARSER_TEE_PARAM_NONE,
						E_AUDIO_PARSER_TEE_PARAM_NONE);
	op.params[0].tmpref.buffer = (void *) pCtx->base_param_shm.shadow_buffer;
	op.params[0].tmpref.size = sizeof(struct parser_destroy_param);

	memset(pCtx->base_param_shm.buffer, 0, MAD_PARSER_TEE_BASE_PARAM_SIZE);
	destroy_param = (struct parser_destroy_param *) pCtx->base_param_shm.buffer;
	destroy_param->parser_id = parser_id;

	res = mad_tee_invoke(E_AUDIO_TEE_PARSER_DESTROY,
		&op, &err_origin, parser_id);

	mad_parser_unset_param(pCtx);
	if (pCtx->mad_parser_ctx.ctx)
		mad_tee_close_session(&pCtx->mad_parser_ctx);

	pCtx->bPresetOK = 0;

	if (res != 0) {
		pr_err("[%s] Parser destroy fail - res:0x%x err: 0x%x\n",
			__func__, res, err_origin);
		return res;
	}
	return 0;
}
int mad_parser_tee_framing(u16 parser_id,
	struct ST_AUDIO_PARSER_FRAMING_PARAM *param)
{
	struct TEEC_Operation op;
	int res;
	uint32_t err_origin = 0;
	struct ST_AUDIO_PARSER_FRAMING_PARAM *framing_param;
	struct mad_parser_tee_contex *pCtx = NULL;

	if (parser_id >= MAX_MAD_NUM)
		return -EINVAL;
	pCtx = &p_mad_tee_ctx[parser_id];

	if (!pCtx->bPresetOK)
		return -ENOMEM;

	if (!param)
		return -EFAULT;

	memset(&op, 0, sizeof(struct TEEC_Operation));
	op.paramTypes = TEEC_PARAM_TYPES(
		E_AUDIO_PARSER_TEE_PARAM_PRESET_SHM,
		E_AUDIO_PARSER_TEE_PARAM_NONE,
		E_AUDIO_PARSER_TEE_PARAM_NONE,
		E_AUDIO_PARSER_TEE_PARAM_NONE);
	op.params[0].tmpref.buffer = (void *) pCtx->base_param_shm.shadow_buffer;
	op.params[0].tmpref.size = sizeof(struct ST_AUDIO_PARSER_FRAMING_PARAM);

	memset(pCtx->base_param_shm.buffer, 0, MAD_PARSER_TEE_BASE_PARAM_SIZE);
	framing_param = (struct ST_AUDIO_PARSER_FRAMING_PARAM *) pCtx->base_param_shm.buffer;
	framing_param->u16ParserId = parser_id;
	framing_param->u32SequenceNum = param->u32SequenceNum;
	framing_param->u32SequenceLng = param->u32SequenceLng;
	framing_param->u32InSecureEsDataOffset = param->u32InSecureEsDataOffset;
	framing_param->u32InSecureEsDataSize = param->u32InSecureEsDataSize;
	framing_param->u32InNonSecureEsDataOffset = param->u32InNonSecureEsDataOffset;
	framing_param->u32InNonSecureEsDataSize = param->u32InNonSecureEsDataSize;

	res = mad_tee_invoke(E_AUDIO_TEE_PARSER_FRAMING,
		&op, &err_origin, parser_id);

	if (res != 0) {
		return res;
	}
	param->u32OutSecureEsDataOffset = framing_param->u32OutSecureEsDataOffset;
	param->u32OutSecureEsDataSize = framing_param->u32OutSecureEsDataSize;
	param->u32OutNonSecureEsDataOffset = framing_param->u32OutNonSecureEsDataOffset;
	param->u32OutNonSecureEsDataSize = framing_param->u32OutNonSecureEsDataSize;

	return 0;
}
int mad_parser_tee_setmode(u16 parser_id,
	struct _ST_AUDIO_SECURE_INFO *param)
{
	struct TEEC_Operation op;
	int res;
	uint32_t err_origin = 0;
	struct _ST_AUDIO_SECURE_INFO *secure_info;
	struct mad_parser_tee_contex *pCtx = NULL;

	if (parser_id >= MAX_MAD_NUM)
		return -EINVAL;
	pCtx = &p_mad_tee_ctx[parser_id];

	if (pCtx->bPresetOK == 0) {
		// open session to create tee ctx
		res = mad_tee_open_session(&pCtx->mad_parser_ctx);

		if (res) {
			pr_err("\033[1;33m[%s] %d open_session fail\033[m\n", __func__, __LINE__);
			return -EINVAL;
		}

		pCtx->bPresetOK = !mad_parser_preset_param(pCtx);
	}
	if (!pCtx->bPresetOK)
		return -ENOMEM;

	if (!param)
		return -EFAULT;

	memset(&op, 0, sizeof(struct TEEC_Operation));
	op.paramTypes = TEEC_PARAM_TYPES(
		E_AUDIO_PARSER_TEE_PARAM_PRESET_SHM,
		E_AUDIO_PARSER_TEE_PARAM_NONE,
		E_AUDIO_PARSER_TEE_PARAM_NONE,
		E_AUDIO_PARSER_TEE_PARAM_NONE);
	op.params[0].tmpref.buffer = (void *) pCtx->base_param_shm.shadow_buffer;
	op.params[0].tmpref.size = sizeof(struct _ST_AUDIO_SECURE_INFO);

	memset(pCtx->base_param_shm.buffer, 0, MAD_PARSER_TEE_BASE_PARAM_SIZE);
	secure_info = (struct _ST_AUDIO_SECURE_INFO *) pCtx->base_param_shm.buffer;
	secure_info->u8SvpEnableFlag = param->u8SvpEnableFlag;
	secure_info->u16ParserId = parser_id;
	secure_info->u32pipelineID = param->u32pipelineID;
	secure_info->u8Version = param->u8Version;

	res = mad_tee_invoke(E_AUDIO_TEE_SET_SECURE_ENABLE,
		&op, &err_origin, parser_id);

	if (res != 0)
		return res;

	return 0;
}
