| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * drivers/amlogic/tee/tee.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * 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/kernel.h> |
| #include <linux/module.h> |
| #include <linux/arm-smccc.h> |
| #include <linux/platform_device.h> |
| |
| #include <linux/amlogic/tee.h> |
| #include <asm/cputype.h> |
| #include <linux/tee_drv.h> |
| |
| #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 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; |
| |
| /* 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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(struct class *class, |
| 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) |
| { |
| return tee_protect_mem(TEE_MEM_TYPE_STREAM_OUTPUT, 0, start, size, handle); |
| } |
| 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; |
| |
| 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; |
| |
| 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); |
| |
| 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); |
| |
| int tee_create_sysfs(void) |
| { |
| int ret; |
| |
| tee_sys_class = class_create(THIS_MODULE, 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<pengguang.zhu@amlogic.com>"); |
| MODULE_DESCRIPTION("AMLOGIC tee driver"); |
| MODULE_LICENSE("GPL"); |