// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2025 Amlogic, Inc. All rights reserved. */ #include #include #include #include #include #include #include #define DRIVER_NAME "tee_info" #define DRIVER_DESC "Amlogic tee driver" #define TEE_MSG_UID_0 0x384fb3e0 #define TEE_MSG_UID_1 0xe7f811e3 #define TEE_MSG_UID_2 0xaf630002 #define TEE_MSG_UID_3 0xa5d5c51b static int disable_flag; #define TEE_SMC_FUNCID_CALLS_REVISION 0xFF03 #define TEE_SMC_CALLS_REVISION \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_TRUSTED_OS_END, \ TEE_SMC_FUNCID_CALLS_REVISION) #define TEE_SMC_FUNCID_CALLS_UID 0xFF01 #define TEE_SMC_CALLS_UID \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_TRUSTED_OS_END, \ TEE_SMC_FUNCID_CALLS_UID) #define TEE_SMC_FAST_CALL_VAL(func_num) \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ ARM_SMCCC_OWNER_TRUSTED_OS, (func_num)) #define TEE_SMC_FUNCID_GET_OS_REVISION 0x0001 #define TEE_SMC_CALL_GET_OS_REVISION \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_GET_OS_REVISION) #define TEE_SMC_FUNCID_CONFIG_DEVICE_SECURE 14 #define TEE_SMC_CONFIG_DEVICE_SECURE \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_CONFIG_DEVICE_SECURE) #define TEE_SMC_FUNCID_LOAD_VIDEO_FW 15 #define TEE_SMC_LOAD_VIDEO_FW \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_LOAD_VIDEO_FW) #define TEE_SMC_FUNCID_ENABLE_LOGGER 0xE001 #define TEE_SMC_ENABLE_LOGGER \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_ENABLE_LOGGER) #define TEE_SMC_FUNCID_UPDATE_TRACE_LEVEL 0xE002 #define TEE_SMC_UPDATE_TRACE_LEVEL \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_UPDATE_TRACE_LEVEL) #define TEE_SMC_FUNCID_PROTECT_TVP_MEM 0xE020 #define TEE_SMC_PROTECT_TVP_MEM \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_PROTECT_TVP_MEM) #define TEE_SMC_FUNCID_UNPROTECT_TVP_MEM 0xE021 #define TEE_SMC_UNPROTECT_TVP_MEM \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_UNPROTECT_TVP_MEM) #define TEE_SMC_FUNCID_PROTECT_MEM_BY_TYPE 0xE023 #define TEE_SMC_PROTECT_MEM_BY_TYPE \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_PROTECT_MEM_BY_TYPE) #define TEE_SMC_FUNCID_UNPROTECT_MEM 0xE024 #define TEE_SMC_UNPROTECT_MEM \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_UNPROTECT_MEM) #define TEE_SMC_FUNCID_CHECK_IN_MEM 0xE025 #define TEE_SMC_CHECK_IN_MEM \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_CHECK_IN_MEM) #define TEE_SMC_FUNCID_CHECK_OUT_MEM 0xE026 #define TEE_SMC_CHECK_OUT_MEM \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_CHECK_OUT_MEM) #define TEE_SMC_FUNCID_DEMUX_CONFIG_PIPELINE 0xE050 #define TEE_SMC_DEMUX_CONFIG_PIPELINE \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_DEMUX_CONFIG_PIPELINE) #define TEE_SMC_FUNCID_DEMUX_CONFIG_PAD 0xE051 #define TEE_SMC_DEMUX_CONFIG_PAD \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_DEMUX_CONFIG_PAD) #define TEE_SMC_FUNCID_READ_REG 0xE052 #define TEE_SMC_READ_REG \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_READ_REG) #define TEE_SMC_FUNCID_WRITE_REG 0xE053 #define TEE_SMC_WRITE_REG \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_WRITE_REG) #define TEE_SMC_FUNCID_SYS_BOOT_COMPLETE 0xE060 #define TEE_SMC_SYS_BOOT_COMPLETE \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_SYS_BOOT_COMPLETE) #define TEE_SMC_FUNCID_SYS_GET_BOOT_COMPLETE 0xE061 #define TEE_SMC_SYS_GET_BOOT_COMPLETE \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_SYS_GET_BOOT_COMPLETE) #define TEE_SMC_FUNCID_VP9_PROB_PROCESS 0xE070 #define TEE_SMC_VP9_PROB_PROCESS \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_VP9_PROB_PROCESS) #define TEE_SMC_FUNCID_VP9_PROB_MALLOC 0xE071 #define TEE_SMC_VP9_PROB_MALLOC \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_VP9_PROB_MALLOC) #define TEE_SMC_FUNCID_VP9_PROB_FREE 0xE072 #define TEE_SMC_VP9_PROB_FREE \ TEE_SMC_FAST_CALL_VAL(TEE_SMC_FUNCID_VP9_PROB_FREE) /* tee param number */ #define TEE_PARAM_NUM 4 /* tvp memory command */ #define TVP_CMD_PROTECT_MEM 0 #define TVP_CMD_UNPROTECT_MEM 1 #define TVP_CMD_CHECK_IN_MEM 2 #define TVP_CMD_CHECK_OUT_MEM 3 #define TVP_CMD_REGISTER_MEM 4 #define TVP_CMD_SECTBL_MEM_MAP 5 #define TVP_CMD_SECTBL_GET_INFO 6 #define TVP_CMD_SECTBL_SECMEM_SET 7 #define PTA_TVP_UUID UUID_INIT(0x1a658fe8, 0x894e, 0x4403, \ 0xae, 0xa6, 0x5a, 0xe6, 0x91, 0xe8, 0xa3, 0x5f) /* stest pta related */ struct tee_sys_info { char module[64]; char status[128]; }; #define STEST_CMD_GET_SYS_INFO 5 #define STEST_GET_SYS_INFO_CNT 32 #define PTA_STEST_UUID UUID_INIT(0x7a7050be, 0xb5f8, 0x4c06, \ 0x81, 0xca, 0x52, 0x3a, 0xb2, 0x02, 0xa3, 0x8a) /* debug pta related */ #define DEBUG_CMD_GET_TRACE_EXT_LEVEL 17 #define DEBUG_CMD_SET_TRACE_EXT_LEVEL 18 #define PTA_DEBUG_UUID UUID_INIT(0xd96a5b40, 0xe2c7, 0xb1af, \ 0x87, 0x94, 0x10, 0x02, 0xa5, 0xd5, 0xc6, 0x1c) static struct class *tee_sys_class; static DEFINE_MUTEX(tee_config_mutex); /* TEE Sub-modules ID */ enum module_id_e { MODULE_ID_KEYTABLE = 0, MODULE_ID_KEYLADDER = 1, MODULE_ID_CRYPTO = 2, MODULE_ID_TVP = 3, MODULE_ID_DMC = 4, MODULE_ID_HDCP = 5, MODULE_ID_EFUSE = 6, MODULE_ID_PROVISION = 7, MODULE_ID_PERMISSION = 8, MODULE_ID_RNG = 9, MODULE_ID_RPMB = 10, MODULE_ID_SECTIMER = 11, MODULE_ID_VIDEOFW = 12, MODULE_ID_WATERMARK = 13, MODULE_ID_MAX, }; /* TEE Sub-modules Name */ static const char *tee_module_name[MODULE_ID_MAX] = { "keytable", /* MODULE_ID_KEYTABLE */ "keyladder", /* MODULE_ID_KEYLADDER */ "crypto", /* MODULE_ID_CRYPTO */ "tvp", /* MODULE_ID_TVP */ "dmc", /* MODULE_ID_DMC */ "hdcp", /* MODULE_ID_HDCP */ "efuse", /* MODULE_ID_EFUSE */ "provision", /* MODULE_ID_PROVISION */ "permission",/* MODULE_ID_PERMISSION */ "rng", /* MODULE_ID_RNG */ "rpmb", /* MODULE_ID_RPMB */ "sectimer", /* MODULE_ID_SECTIMER */ "videofw", /* MODULE_ID_VIDEOFW */ "watermark", /* MODULE_ID_WATERMARK */ }; struct tee_smc_calls_revision_result { unsigned long major; unsigned long minor; unsigned long reserved0; unsigned long reserved1; }; static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) { return (ver->impl_id == TEE_IMPL_ID_OPTEE); } /* Invoke pta cmd with tee context, the tee context have been allocated*/ static int tee_pta_invoke_cmd(struct tee_context *ctx, uuid_t uuid, u32 cmd, struct tee_param *param) { int ret = 0; struct tee_ioctl_open_session_arg sess_arg = { 0 }; struct tee_ioctl_invoke_arg inv_arg = { 0 }; /* Check tee ctx */ if (IS_ERR(ctx)) { pr_err("%s is null, cmd = %u\n", __func__, cmd); return -ENODEV; } /* Open session */ memcpy(sess_arg.uuid, uuid.b, TEE_IOCTL_UUID_LEN); sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; sess_arg.num_params = 0; ret = tee_client_open_session(ctx, &sess_arg, NULL); if (ret < 0 || sess_arg.ret != TEEC_SUCCESS) { pr_err("%s open session failed, cmd = %u, ret = %d, res = 0x%x, origin = 0x%x\n", __func__, cmd, ret, sess_arg.ret, sess_arg.ret_origin); ret = sess_arg.ret; goto out; } /* Invoke function */ inv_arg.func = cmd; inv_arg.session = sess_arg.session; inv_arg.num_params = TEE_PARAM_NUM; ret = tee_client_invoke_func(ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != TEEC_SUCCESS) { pr_err("%s invoke func failed, cmd = %u, ret= %d, res = 0x%x, origin = 0x%x\n", __func__, cmd, ret, inv_arg.ret, inv_arg.ret_origin); ret = inv_arg.ret; } tee_client_close_session(ctx, sess_arg.session); out: return ret; } static int tee_msg_os_revision(u32 *major, u32 *minor) { union { struct arm_smccc_res smccc; struct tee_smc_calls_revision_result result; } res; arm_smccc_smc(TEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc); *major = res.result.major; *minor = res.result.minor; return 0; } static int tee_get_sys_info(char *buf) { int ret = 0; struct tee_context *ctx = NULL; struct tee_shm *shm_pool = NULL; uuid_t uuid = PTA_STEST_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; char *shm_data = NULL; struct tee_sys_info *sys_info = NULL; int i = 0; int buf_offs = 0; /* Open context with TEE driver */ ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } shm_pool = tee_shm_alloc_kernel_buf(ctx, STEST_GET_SYS_INFO_CNT * sizeof(struct tee_sys_info)); if (IS_ERR(shm_pool)) { pr_err("%s tee_shm_alloc failed\n", __func__); ret = -ENOMEM; goto out; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; param[0].u.memref.shm = shm_pool; param[0].u.memref.size = STEST_GET_SYS_INFO_CNT * sizeof(struct tee_sys_info); param[0].u.memref.shm_offs = 0; ret = tee_pta_invoke_cmd(ctx, uuid, STEST_CMD_GET_SYS_INFO, param); if (!ret) { shm_data = tee_shm_get_va(shm_pool, 0); if (IS_ERR(shm_data)) { pr_err("%s tee_shm_get_va failed\n", __func__); ret = -EBUSY; goto out_shm; } for (i = 0; i < param[0].u.memref.size / sizeof(struct tee_sys_info); i++) { sys_info = (struct tee_sys_info *)shm_data; sprintf(buf + buf_offs, "%-55s | %s\n", sys_info->module, sys_info->status); buf_offs = strlen(buf); shm_data += sizeof(struct tee_sys_info); } } out_shm: tee_shm_free(shm_pool); out: tee_client_close_context(ctx); return ret; } static int tee_set_trace_ext_level(int module_id, int trace_level) { int ret = 0; struct tee_context *ctx = NULL; uuid_t uuid = PTA_DEBUG_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; /* Open context with TEE driver */ ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = module_id; param[0].u.value.b = trace_level; ret = tee_pta_invoke_cmd(ctx, uuid, DEBUG_CMD_SET_TRACE_EXT_LEVEL, param); if (ret) pr_err("%s invoke set trace level command failed\n", __func__); tee_client_close_context(ctx); return ret; } static int tee_get_trace_ext_level(int module_id, int *trace_level) { int ret = 0; struct tee_context *ctx = NULL; uuid_t uuid = PTA_DEBUG_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; /* Open context with TEE driver */ ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT; param[0].u.value.a = module_id; ret = tee_pta_invoke_cmd(ctx, uuid, DEBUG_CMD_GET_TRACE_EXT_LEVEL, param); if (ret) { pr_err("%s invoke get trace level command failed\n", __func__); *trace_level = -1; goto out; } *trace_level = param[0].u.value.b; out: tee_client_close_context(ctx); return ret; } static int tee_msg_api_revision(u32 *major, u32 *minor) { union { struct arm_smccc_res smccc; struct tee_smc_calls_revision_result result; } res; arm_smccc_smc(TEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc); *major = res.result.major; *minor = res.result.minor; return 0; } static int tee_set_sys_boot_complete(void) { struct arm_smccc_res res; static int inited; res.a0 = 0; if (!inited) { arm_smccc_smc(TEE_SMC_SYS_BOOT_COMPLETE, 0, 0, 0, 0, 0, 0, 0, &res); if (!res.a0) inited = 1; } return res.a0; } static int tee_get_sys_boot_complete(void) { struct arm_smccc_res res; res.a0 = 0; arm_smccc_smc(TEE_SMC_SYS_GET_BOOT_COMPLETE, 0, 0, 0, 0, 0, 0, 0, &res); return res.a0; } static ssize_t os_version_show(const struct class *class, const struct class_attribute *attr, char *buf) { int ret; u32 major, minor; ret = tee_msg_os_revision(&major, &minor); if (ret) return 0; ret = sprintf(buf, "os version: V%d.%d\n", major, minor); return ret; } static ssize_t sys_info_show(const struct class *class, const struct class_attribute *attr, char *buf) { int ret; ret = tee_get_sys_info(buf); if (ret) return 0; ret = strlen(buf); return ret; } static ssize_t api_version_show(const struct class *class, const struct class_attribute *attr, char *buf) { int ret; u32 major, minor; ret = tee_msg_api_revision(&major, &minor); if (ret) return 0; ret = sprintf(buf, "api version: V%d.%d\n", major, minor); return ret; } static ssize_t log_mode_show(const struct class *class, const struct class_attribute *attr, char *buf) { int ret = 0; ret = sprintf(buf, " 0:uart\n 1:kmsg\n"); return ret; } static ssize_t log_level_show(const struct class *class, const struct class_attribute *attr, char *buf) { int ret = 0; ret = sprintf(buf, " 0:NO LOG\n 1:ERROR\n 2:INFO\n 3:DEBUG\n 4:FLOW\n"); return ret; } static ssize_t sys_boot_complete_show(const struct class *class, const struct class_attribute *attr, char *buf) { int ret = 0; /* return 1 means it doesn't need to update efuse for anti-rollback. * return 0xFFFFFFFF means BL32 is not supported tee_get_sys_boot_complete */ ret = tee_get_sys_boot_complete(); if (ret == 1) ret = sprintf(buf, "1\n"); else ret = sprintf(buf, "0\n"); return ret; } static ssize_t modules_log_level_show(const struct class *class, const struct class_attribute *attr, char *buf) { int ret = 0; int trace_level = 0; int i = 0; for (i = 0; i < MODULE_ID_MAX; i++) { tee_get_trace_ext_level(i, &trace_level); sprintf(buf + strlen(buf), "%-55s | %d\n", tee_module_name[i], trace_level); } ret = strlen(buf); return ret; } static ssize_t sys_boot_complete_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { bool val; int ret = 0; if (kstrtobool(buf, &val)) return -EINVAL; if (val) ret = tee_set_sys_boot_complete(); if (ret) return -EINVAL; return count; } static ssize_t log_mode_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { struct arm_smccc_res res; int val = 0; if (memcmp(buf, "1", 1) == 0) val = 1; else if (memcmp(buf, "0", 1) == 0) val = 0; else return count; arm_smccc_smc(TEE_SMC_ENABLE_LOGGER, val, 0, 0, 0, 0, 0, 0, &res); if (res.a0 == 0) { if (val == 0) pr_err("Set log mode:0\n"); else pr_err("Set log mode:1\n"); } return count; } static ssize_t log_level_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { struct arm_smccc_res res; int val = 0; res.a0 = 0; if (kstrtoint(buf, 0, &val)) return -EINVAL; arm_smccc_smc(TEE_SMC_UPDATE_TRACE_LEVEL, val, 0, 0, 0, 0, 0, 0, &res); val = res.a0; pr_err("Set log level:%d\n", val); return count; } static ssize_t modules_log_level_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { int val = 0; int trace_level = 0; int i = 0; if (kstrtoint(buf, 0, &val)) return -EINVAL; trace_level = val & 0x7; for (i = 0; i < MODULE_ID_MAX; i++) { if ((val & (0x1 << (3 + i))) != 0) tee_set_trace_ext_level(i, trace_level); } return count; } static CLASS_ATTR_RO(os_version); static CLASS_ATTR_RO(api_version); static CLASS_ATTR_RO(sys_info); static CLASS_ATTR_RW(sys_boot_complete); static CLASS_ATTR_RW(log_mode); static CLASS_ATTR_RW(log_level); static CLASS_ATTR_RW(modules_log_level); /* * index: firmware index * vdec: vdec type(0: compatible, 1: legency vdec, 2: HEVC vdec) */ static int tee_load_firmware(u32 index, u32 vdec, bool is_swap) { struct arm_smccc_res res; arm_smccc_smc(TEE_SMC_LOAD_VIDEO_FW, index, vdec, is_swap, 0, 0, 0, 0, &res); return res.a0; } int tee_load_video_fw(u32 index, u32 vdec) { return tee_load_firmware(index, vdec, false); } EXPORT_SYMBOL(tee_load_video_fw); int tee_load_video_fw_swap(u32 index, u32 vdec, bool is_swap) { return tee_load_firmware(index, vdec, is_swap); } EXPORT_SYMBOL(tee_load_video_fw_swap); bool tee_enabled(void) { struct arm_smccc_res res; if (disable_flag == 1) return false; /*return false;*/ /*disable tee load temporary*/ arm_smccc_smc(TEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res); if (res.a0 == TEE_MSG_UID_0 && res.a1 == TEE_MSG_UID_1 && res.a2 == TEE_MSG_UID_2 && res.a3 == TEE_MSG_UID_3) return true; return false; } EXPORT_SYMBOL(tee_enabled); /* This function will be deprecated */ u32 tee_protect_tvp_mem(phys_addr_t start, size_t size, u32 *handle) { int ret = 0; mutex_lock(&tee_config_mutex); ret = tee_protect_mem(TEE_MEM_TYPE_STREAM_OUTPUT, 0, start, size, handle); mutex_unlock(&tee_config_mutex); return ret; } EXPORT_SYMBOL(tee_protect_tvp_mem); /* This function will be deprecated */ void tee_unprotect_tvp_mem(u32 handle) { tee_unprotect_mem(handle); } EXPORT_SYMBOL(tee_unprotect_tvp_mem); /* This function will be deprecated */ u32 tee_protect_mem_by_type(u32 type, phys_addr_t start, size_t size, u32 *handle) { return tee_protect_mem(type, 0, start, size, handle); } EXPORT_SYMBOL(tee_protect_mem_by_type); u32 tee_protect_mem(u32 type, u32 level, phys_addr_t start, size_t size, u32 *handle) { int ret = 0; uuid_t uuid = PTA_TVP_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; struct tee_context *ctx = NULL; if (!handle) return -EINVAL; if (!size || !start) return -EINVAL; ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = (u64)type; param[0].u.value.b = (u64)level; param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[1].u.value.a = start & 0xffffffff; param[1].u.value.b = (sizeof(phys_addr_t) == sizeof(u32)) ? 0 : start >> 32; param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[2].u.value.a = size & 0xffffffff; param[2].u.value.b = (sizeof(size_t) == sizeof(u32)) ? 0 : size >> 32; param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; ret = tee_pta_invoke_cmd(ctx, uuid, TVP_CMD_PROTECT_MEM, param); if (!ret) *handle = (u32)param[3].u.value.a; tee_client_close_context(ctx); return ret; } EXPORT_SYMBOL(tee_protect_mem); void tee_unprotect_mem(u32 handle) { uuid_t uuid = PTA_TVP_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; struct tee_context *ctx = NULL; ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = (u64)handle; tee_pta_invoke_cmd(ctx, uuid, TVP_CMD_UNPROTECT_MEM, param); tee_client_close_context(ctx); } EXPORT_SYMBOL(tee_unprotect_mem); int tee_check_in_mem(phys_addr_t pa, size_t size) { int ret = 0; uuid_t uuid = PTA_TVP_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; struct tee_context *ctx = NULL; ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = pa & 0xffffffff; param[0].u.value.b = (sizeof(phys_addr_t) == sizeof(u32)) ? 0 : pa >> 32; param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[1].u.value.a = size & 0xffffffff; param[1].u.value.b = (sizeof(size_t) == sizeof(u32)) ? 0 : size >> 32; ret = tee_pta_invoke_cmd(ctx, uuid, TVP_CMD_CHECK_IN_MEM, param); tee_client_close_context(ctx); return ret; } EXPORT_SYMBOL(tee_check_in_mem); int tee_check_out_mem(phys_addr_t pa, size_t size) { int ret = 0; uuid_t uuid = PTA_TVP_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; struct tee_context *ctx = NULL; ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = pa & 0xffffffff; param[0].u.value.b = (sizeof(phys_addr_t) == sizeof(u32)) ? 0 : pa >> 32; param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[1].u.value.a = size & 0xffffffff; param[1].u.value.b = (sizeof(size_t) == sizeof(u32)) ? 0 : size >> 32; ret = tee_pta_invoke_cmd(ctx, uuid, TVP_CMD_CHECK_OUT_MEM, param); tee_client_close_context(ctx); return ret; } EXPORT_SYMBOL(tee_check_out_mem); u32 tee_register_mem(u32 type, phys_addr_t pa, size_t size) { int ret = 0; uuid_t uuid = PTA_TVP_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; struct tee_context *ctx = NULL; if (!pa || !size) return -EINVAL; ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = (u64)type; param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[1].u.value.a = pa & 0xffffffff; param[1].u.value.b = (sizeof(phys_addr_t) == sizeof(u32)) ? 0 : pa >> 32; param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[2].u.value.a = size & 0xffffffff; param[2].u.value.b = (sizeof(size_t) == sizeof(u32)) ? 0 : size >> 32; ret = tee_pta_invoke_cmd(ctx, uuid, TVP_CMD_REGISTER_MEM, param); tee_client_close_context(ctx); return ret; } EXPORT_SYMBOL(tee_register_mem); int tee_config_device_state(int dev_id, int secure) { struct arm_smccc_res res; arm_smccc_smc(TEE_SMC_CONFIG_DEVICE_SECURE, dev_id, secure, 0, 0, 0, 0, 0, &res); return res.a0; } EXPORT_SYMBOL(tee_config_device_state); int tee_config_device_state_lock(int dev_id, int secure) { struct arm_smccc_res res; mutex_lock(&tee_config_mutex); arm_smccc_smc(TEE_SMC_CONFIG_DEVICE_SECURE, dev_id, secure, 0, 0, 0, 0, 0, &res); mutex_unlock(&tee_config_mutex); return res.a0; } EXPORT_SYMBOL(tee_config_device_state_lock); void tee_demux_config_pipeline(int tsn_in, int tsn_out) { struct arm_smccc_res res; arm_smccc_smc(TEE_SMC_DEMUX_CONFIG_PIPELINE, tsn_in, tsn_out, 0, 0, 0, 0, 0, &res); } EXPORT_SYMBOL(tee_demux_config_pipeline); int tee_demux_config_pad(int reg, int val) { struct arm_smccc_res res; arm_smccc_smc(TEE_SMC_DEMUX_CONFIG_PAD, reg, val, 0, 0, 0, 0, 0, &res); return res.a0; } EXPORT_SYMBOL(tee_demux_config_pad); int tee_read_reg_bits(u32 reg, u32 *val, u32 offset, u32 length) { struct arm_smccc_res res; arm_smccc_smc(TEE_SMC_READ_REG, reg, 0, offset, length, 0, 0, 0, &res); *val = res.a2; return res.a0; } EXPORT_SYMBOL(tee_read_reg_bits); int tee_write_reg_bits(u32 reg, u32 val, u32 offset, u32 length) { struct arm_smccc_res res; arm_smccc_smc(TEE_SMC_WRITE_REG, reg, val, offset, length, 0, 0, 0, &res); return res.a0; } EXPORT_SYMBOL(tee_write_reg_bits); int tee_vp9_prob_process(u32 cur_frame_type, u32 prev_frame_type, u32 prob_status, u32 prob_addr) { struct arm_smccc_res res; arm_smccc_smc(TEE_SMC_VP9_PROB_PROCESS, cur_frame_type, prev_frame_type, prob_status, prob_addr, 0, 0, 0, &res); return res.a0; } EXPORT_SYMBOL(tee_vp9_prob_process); int tee_vp9_prob_malloc(u32 *prob_addr) { struct arm_smccc_res res; if (!prob_addr) return 0xFFFF0006; arm_smccc_smc(TEE_SMC_VP9_PROB_MALLOC, 0, 0, 0, 0, 0, 0, 0, &res); *prob_addr = res.a1; return res.a0; } EXPORT_SYMBOL(tee_vp9_prob_malloc); int tee_vp9_prob_free(u32 prob_addr) { struct arm_smccc_res res; arm_smccc_smc(TEE_SMC_VP9_PROB_FREE, prob_addr, 0, 0, 0, 0, 0, 0, &res); return res.a0; } EXPORT_SYMBOL(tee_vp9_prob_free); u32 tee_sectbl_mem_map(phys_addr_t tbl0_sta, size_t tbl0_size, u32 tbl0_blk_size, phys_addr_t tbl1_sta, size_t tbl1_size, u32 tbl1_blk_size) { int ret = 0; struct tee_context *ctx = NULL; struct tee_shm *shm_pool = NULL; uuid_t uuid = PTA_TVP_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; struct tee_sectbl_info *sectbl_info = NULL; ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } shm_pool = tee_shm_alloc_kernel_buf(ctx, sizeof(struct tee_sectbl_info)); if (IS_ERR(shm_pool)) { pr_err("%s tee_shm_alloc failed\n", __func__); ret = -ENOMEM; goto out; } sectbl_info = tee_shm_get_va(shm_pool, 0); if (IS_ERR(sectbl_info)) { pr_err("%s tee_shm_get_va failed\n", __func__); ret = -EBUSY; goto out; } sectbl_info->tbl0_sta = tbl0_sta; sectbl_info->tbl0_size = tbl0_size; sectbl_info->tbl0_blk_size = tbl0_blk_size; sectbl_info->tbl1_sta = tbl1_sta; sectbl_info->tbl1_size = tbl1_size; sectbl_info->tbl1_blk_size = tbl1_blk_size; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; param[0].u.memref.shm = shm_pool; param[0].u.memref.size = sizeof(struct tee_sectbl_info); param[0].u.memref.shm_offs = 0; ret = tee_pta_invoke_cmd(ctx, uuid, TVP_CMD_SECTBL_MEM_MAP, param); if (ret) pr_err("%s invoke sectbl mem map command failed\n", __func__); out: if (shm_pool) tee_shm_free(shm_pool); tee_client_close_context(ctx); return ret; } EXPORT_SYMBOL(tee_sectbl_mem_map); u32 tee_sectbl_get_info(struct tee_sectbl_info *sectbl_info) { int ret = 0; struct tee_context *ctx = NULL; struct tee_shm *shm_pool = NULL; uuid_t uuid = PTA_TVP_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; struct tee_sectbl_info *tbl_info = NULL; if (!sectbl_info) { pr_err("%s sectbl_info NULL\n", __func__); return -EINVAL; } ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } shm_pool = tee_shm_alloc_kernel_buf(ctx, sizeof(struct tee_sectbl_info)); if (IS_ERR(shm_pool)) { pr_err("%s tee_shm_alloc failed\n", __func__); ret = -ENOMEM; goto out; } tbl_info = tee_shm_get_va(shm_pool, 0); if (IS_ERR(tbl_info)) { pr_err("%s tee_shm_get_va failed\n", __func__); ret = -EBUSY; goto out; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; param[0].u.memref.shm = shm_pool; param[0].u.memref.size = sizeof(struct tee_sectbl_info); param[0].u.memref.shm_offs = 0; ret = tee_pta_invoke_cmd(ctx, uuid, TVP_CMD_SECTBL_GET_INFO, param); if (ret) { pr_err("%s invoke sectbl get info command failed\n", __func__); goto out; } memcpy(sectbl_info, tbl_info, sizeof(struct tee_sectbl_info)); out: if (shm_pool) tee_shm_free(shm_pool); tee_client_close_context(ctx); return ret; } EXPORT_SYMBOL(tee_sectbl_get_info); u32 tee_sectbl_secmem_set(phys_addr_t start, size_t size, u32 secure) { int ret = 0; uuid_t uuid = PTA_TVP_UUID; struct tee_param param[TEE_PARAM_NUM] = { 0 }; struct tee_context *ctx = NULL; ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); if (IS_ERR(ctx)) { pr_err("%s open context failed\n", __func__); return -ENODEV; } param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = start & 0xffffffff; param[0].u.value.b = (sizeof(phys_addr_t) == sizeof(u32)) ? 0 : start >> 32; param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[1].u.value.a = size & 0xffffffff; param[1].u.value.b = (sizeof(size_t) == sizeof(u32)) ? 0 : size >> 32; param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[2].u.value.a = (u64)secure; ret = tee_pta_invoke_cmd(ctx, uuid, TVP_CMD_SECTBL_SECMEM_SET, param); if (ret) pr_err("%s invoke sectbl set command failed\n", __func__); tee_client_close_context(ctx); return ret; } EXPORT_SYMBOL(tee_sectbl_secmem_set); int tee_create_sysfs(void) { int ret; tee_sys_class = class_create(DRIVER_NAME); ret = class_create_file(tee_sys_class, &class_attr_os_version); if (ret != 0) { pr_err("create class file os_version fail\n"); return ret; } ret = class_create_file(tee_sys_class, &class_attr_api_version); if (ret != 0) { pr_err("create class file api_version fail\n"); return ret; } ret = class_create_file(tee_sys_class, &class_attr_sys_info); if (ret != 0) { pr_err("create class file sys_info fail\n"); return ret; } ret = class_create_file(tee_sys_class, &class_attr_sys_boot_complete); if (ret != 0) { pr_err("create class file sys_boot_complete fail\n"); return ret; } ret = class_create_file(tee_sys_class, &class_attr_log_mode); if (ret != 0) { pr_err("create class file log_mode fail\n"); return ret; } ret = class_create_file(tee_sys_class, &class_attr_log_level); if (ret != 0) { pr_err("create class file log_level fail\n"); return ret; } ret = class_create_file(tee_sys_class, &class_attr_modules_log_level); if (ret != 0) { pr_err("create class file modules_log_level fail\n"); return ret; } return ret; } static int __init aml_tee_modinit(void) { return tee_create_sysfs(); } arch_initcall(aml_tee_modinit); static void __exit aml_tee_modexit(void) { class_destroy(tee_sys_class); } __module_param(disable_flag, uint, 0664); MODULE_PARM_DESC(disable_flag, "\n tee firmload disable_flag flag\n"); module_exit(aml_tee_modexit); MODULE_AUTHOR("pengguang.zhu"); MODULE_DESCRIPTION("AMLOGIC tee driver"); MODULE_LICENSE("GPL");