blob: 22f489166edec3c762bb5d40a88c4d2334df3c8c [file] [log] [blame]
/* Copyright (c) 2016-2018, The Linux Foundation. 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 version 2 and
* only 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/delay.h>
#include <linux/ktime.h>
#include <linux/mutex.h>
#include <soc/qcom/camera2.h>
#include "qseecom_kernel.h"
#include "msm_camera_tz_util.h"
#define EMPTY_QSEECOM_HANDLE NULL
#define QSEECOM_SBUFF_SIZE SZ_128K
#define MSM_CAMERA_TZ_UTIL_VERBOSE
#define MSM_CAMERA_TZ_BOOT_PROTECTED (false)
/* Update version major number in case the HLOS-TA interface is changed*/
#define TA_IF_VERSION_MAJ 1
#define TA_IF_VERSION_MIN 2
#undef CDBG
#ifdef MSM_CAMERA_TZ_UTIL_VERBOSE
#define CDBG(fmt, args...) \
pr_info(CONFIG_MSM_SEC_CCI_TA_NAME "::%s:%d - " fmt,\
__func__, __LINE__, ##args)
#else /* MSM_CAMERA_TZ_UTIL_VERBOSE */
#define CDBG(fmt, args...) \
pr_debug("%s:%d - " fmt, __func__, __LINE__, ##args)
#endif /* MSM_CAMERA_TZ_UTIL_VERBOSE */
#pragma pack(push, msm_camera_tz_util, 1)
/* MSM_CAMERA_TZ_CMD_GET_IF_VERSION */
#define msm_camera_tz_i2c_get_if_version_req_t msm_camera_tz_generic_req_t
struct msm_camera_tz_i2c_get_if_version_rsp_t {
enum msm_camera_tz_status_t rc;
uint32_t if_version_maj;
uint32_t if_version_min;
};
/* MSM_CAMERA_TZ_CMD_SET_MODE */
struct msm_camera_tz_set_mode_req_t {
enum msm_camera_tz_cmd_id_t cmd_id;
uint32_t mode;
uint32_t hw_block;
};
#define msm_camera_tz_set_mode_rsp_t msm_camera_tz_generic_rsp_t
#pragma pack(pop, msm_camera_tz_util)
/* TA communication control structure */
struct msm_camera_tz_ctrl_t {
uint32_t ta_enabled;
struct qseecom_handle *ta_qseecom_handle;
const char *ta_name;
uint32_t secure_hw_blocks;
};
static struct msm_camera_tz_ctrl_t msm_camera_tz_ctrl = {
0, NULL, CONFIG_MSM_CAMERA_TZ_TA_NAME, 0
};
static DEFINE_MUTEX(msm_camera_tz_util_lock);
struct qseecom_handle *msm_camera_tz_get_ta_handle(void)
{
return msm_camera_tz_ctrl.ta_qseecom_handle;
}
void msm_camera_tz_lock(void)
{
mutex_lock(&msm_camera_tz_util_lock);
}
void msm_camera_tz_unlock(void)
{
mutex_unlock(&msm_camera_tz_util_lock);
}
int32_t get_cmd_rsp_buffers(
struct qseecom_handle *ta_qseecom_handle,
void **cmd, int *cmd_len,
void **rsp, int *rsp_len)
{
if ((ta_qseecom_handle == NULL) ||
(cmd == NULL) || (cmd_len == NULL) ||
(rsp == NULL) || (rsp_len == NULL)) {
pr_err("%s:%d - Bad parameters\n",
__func__, __LINE__);
return -EINVAL;
}
if (*cmd_len & QSEECOM_ALIGN_MASK)
*cmd_len = QSEECOM_ALIGN(*cmd_len);
if (*rsp_len & QSEECOM_ALIGN_MASK)
*rsp_len = QSEECOM_ALIGN(*rsp_len);
if ((*rsp_len + *cmd_len) > QSEECOM_SBUFF_SIZE) {
pr_err("%s:%d - Shared buffer too small to hold cmd=%d and rsp=%d\n",
__func__, __LINE__,
*cmd_len, *rsp_len);
return -ENOMEM;
}
*cmd = ta_qseecom_handle->sbuf;
*rsp = ta_qseecom_handle->sbuf + *cmd_len;
return 0;
}
static int32_t msm_camera_tz_i2c_ta_get_if_version(
struct qseecom_handle *ta_qseecom_handle,
uint32_t *if_version_maj,
uint32_t *if_version_min)
{
int32_t cmd_len, rsp_len;
struct msm_camera_tz_i2c_get_if_version_req_t *cmd;
struct msm_camera_tz_i2c_get_if_version_rsp_t *rsp;
int32_t rc = 0;
CDBG("Enter\n");
if ((ta_qseecom_handle == NULL) ||
(if_version_maj == NULL) || (if_version_min == NULL)) {
pr_err("%s:%d - Bad parameters\n",
__func__, __LINE__);
return -EINVAL;
}
cmd_len = sizeof(struct msm_camera_tz_i2c_get_if_version_req_t);
rsp_len = sizeof(struct msm_camera_tz_i2c_get_if_version_rsp_t);
rc = get_cmd_rsp_buffers(ta_qseecom_handle,
(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
if (!rc) {
cmd->cmd_id = MSM_CAMERA_TZ_CMD_GET_IF_VERSION;
rc = qseecom_send_command(ta_qseecom_handle,
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (rc < 0) {
pr_err("%s:%d - Unable to get if version info, rc=%d\n",
__func__, __LINE__,
rc);
return rc;
}
if (rsp->rc < 0) {
CDBG("TZ App error, rc=%d\n", rsp->rc);
rc = -EFAULT;
} else {
*if_version_maj = rsp->if_version_maj;
*if_version_min = rsp->if_version_min;
CDBG("TZ If version %d.%d\n", *if_version_maj,
*if_version_min);
}
}
return rc;
}
int32_t msm_camera_tz_load_ta(void)
{
int32_t rc = 0;
if (MSM_CAMERA_TZ_BOOT_PROTECTED &&
msm_camera_tz_ctrl.ta_enabled > 0) {
CDBG("TA loaded from boot(TA %s - %d)\n",
msm_camera_tz_ctrl.ta_name,
msm_camera_tz_ctrl.ta_enabled);
return 0;
}
CDBG("Enter (TA name = %s, %d)\n",
msm_camera_tz_ctrl.ta_name,
msm_camera_tz_ctrl.ta_enabled);
msm_camera_tz_lock();
if (msm_camera_tz_ctrl.ta_enabled == 0) {
ktime_t startTime = ktime_get();
/* Start the TA */
if ((msm_camera_tz_ctrl.ta_qseecom_handle == NULL) &&
(msm_camera_tz_ctrl.ta_name != NULL) &&
('\0' != msm_camera_tz_ctrl.ta_name[0])) {
uint32_t if_version_maj = 0;
uint32_t if_version_min = 0;
rc = qseecom_start_app(
&msm_camera_tz_ctrl.ta_qseecom_handle,
(char *)msm_camera_tz_ctrl.ta_name,
QSEECOM_SBUFF_SIZE);
if (!rc)
rc = msm_camera_tz_i2c_ta_get_if_version(
msm_camera_tz_ctrl.ta_qseecom_handle,
&if_version_maj, &if_version_min);
if (!rc) {
if (if_version_maj != TA_IF_VERSION_MAJ) {
CDBG("TA ver mismatch %d.%d != %d.%d\n",
if_version_maj, if_version_min,
TA_IF_VERSION_MAJ,
TA_IF_VERSION_MIN);
rc = qseecom_shutdown_app(
&msm_camera_tz_ctrl.
ta_qseecom_handle);
msm_camera_tz_ctrl.ta_qseecom_handle
= EMPTY_QSEECOM_HANDLE;
rc = -EFAULT;
} else {
msm_camera_tz_ctrl.ta_enabled = 1;
}
}
}
CDBG("Load TA %s - %s(%d) - %lluus\n",
msm_camera_tz_ctrl.ta_name,
(msm_camera_tz_ctrl.ta_enabled)?"Ok" :
"Failed", rc,
ktime_us_delta(ktime_get(), startTime));
} else {
msm_camera_tz_ctrl.ta_enabled++;
CDBG("TA already loaded (TA %s - %d)\n",
msm_camera_tz_ctrl.ta_name,
msm_camera_tz_ctrl.ta_enabled);
}
msm_camera_tz_unlock();
return rc;
}
int32_t msm_camera_tz_unload_ta(void)
{
int32_t rc = -EFAULT;
if (MSM_CAMERA_TZ_BOOT_PROTECTED) {
CDBG("TA loaded from boot(TA %s - %d)\n",
msm_camera_tz_ctrl.ta_name,
msm_camera_tz_ctrl.ta_enabled);
return 0;
}
CDBG("Enter (TA name = %s, %d)\n",
msm_camera_tz_ctrl.ta_name,
msm_camera_tz_ctrl.ta_enabled);
msm_camera_tz_lock();
if (msm_camera_tz_ctrl.ta_enabled == 1) {
ktime_t startTime = ktime_get();
rc = qseecom_shutdown_app(&msm_camera_tz_ctrl.
ta_qseecom_handle);
msm_camera_tz_ctrl.ta_qseecom_handle
= EMPTY_QSEECOM_HANDLE;
msm_camera_tz_ctrl.ta_enabled = 0;
CDBG("Unload TA %s - %s(%d) - %lluus\n",
msm_camera_tz_ctrl.ta_name,
(!rc)?"Ok":"Failed", rc,
ktime_us_delta(ktime_get(), startTime));
} else {
msm_camera_tz_ctrl.ta_enabled--;
CDBG("TA still loaded (TA %s - %d)\n",
msm_camera_tz_ctrl.ta_name,
msm_camera_tz_ctrl.ta_enabled);
}
msm_camera_tz_unlock();
return rc;
}
static int32_t msm_camera_tz_ta_set_mode(uint32_t mode,
uint32_t hw_block)
{
int32_t cmd_len, rsp_len;
struct msm_camera_tz_set_mode_req_t *cmd;
struct msm_camera_tz_set_mode_rsp_t *rsp;
int32_t rc = 0;
struct qseecom_handle *ta_qseecom_handle =
msm_camera_tz_get_ta_handle();
ktime_t startTime = ktime_get();
if (ta_qseecom_handle == NULL) {
pr_err("%s:%d - Bad parameters\n",
__func__, __LINE__);
return -EINVAL;
}
cmd_len = sizeof(struct msm_camera_tz_set_mode_req_t);
rsp_len = sizeof(struct msm_camera_tz_set_mode_rsp_t);
msm_camera_tz_lock();
rc = get_cmd_rsp_buffers(ta_qseecom_handle,
(void **)&cmd, &cmd_len, (void **)&rsp, &rsp_len);
if (!rc) {
cmd->cmd_id = MSM_CAMERA_TZ_CMD_SET_MODE;
cmd->mode = mode;
cmd->hw_block = hw_block;
rc = qseecom_send_command(ta_qseecom_handle,
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (rc < 0) {
pr_err("%s:%d - Failed: rc=%d\n",
__func__, __LINE__,
rc);
msm_camera_tz_unlock();
return rc;
}
rc = rsp->rc;
}
msm_camera_tz_unlock();
CDBG("Done: rc=%d, Mode=0x%08X - %lluus\n",
rc, mode,
ktime_us_delta(ktime_get(), startTime));
return rc;
}
uint32_t msm_camera_tz_set_mode(uint32_t mode,
uint32_t hw_block)
{
uint32_t rc = 0;
switch (mode) {
case MSM_CAMERA_TZ_MODE_SECURE:
rc = msm_camera_tz_load_ta();
if (!rc) {
rc = msm_camera_tz_ta_set_mode(mode, hw_block);
if (rc)
msm_camera_tz_ctrl.secure_hw_blocks |= hw_block;
}
break;
case MSM_CAMERA_TZ_MODE_NON_SECURE:
msm_camera_tz_ta_set_mode(mode, hw_block);
if (rc)
msm_camera_tz_ctrl.secure_hw_blocks &= ~hw_block;
rc = msm_camera_tz_unload_ta();
break;
default:
pr_err("%s:%d - Incorrect mode: %d (hw: 0x%08X)\n",
__func__, __LINE__,
mode, hw_block);
return -EINVAL;
}
CDBG("Set Mode - rc=%d, Mode: 0x%08X\n",
rc, mode);
return rc;
}