blob: f8e05b63952ee86c5a543bf95b1e4b028dfe225c [file] [log] [blame] [edit]
// 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");