u-boot/drivers/tee/optee/i2c.c
Jorge Ramirez-Ortiz 4e96356185 drivers: tee: i2c trampoline driver
This commit gives the secure world access to the I2C bus so it can
communicate with I2C slaves (typically those would be secure elements
like the NXP SE050).

A similar service implementation has been merged in linux:
c05210ab ("drivers: optee: allow op-tee to access devices on the i2c
bus")

Signed-off-by: Jorge Ramirez-Ortiz <jorge@foundries.io>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
2021-02-16 11:48:20 -05:00

90 lines
1.9 KiB
C

// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2020 Foundries.io Ltd
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <tee.h>
#include "optee_msg.h"
#include "optee_private.h"
static int check_xfer_flags(struct udevice *chip, uint tee_flags)
{
uint flags;
int ret;
ret = i2c_get_chip_flags(chip, &flags);
if (ret)
return ret;
if (tee_flags & OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT) {
if (!(flags & DM_I2C_CHIP_10BIT))
return -EINVAL;
} else {
if (flags & DM_I2C_CHIP_10BIT)
return -EINVAL;
}
return 0;
}
void optee_suppl_cmd_i2c_transfer(struct optee_msg_arg *arg)
{
const u8 attr[] = {
OPTEE_MSG_ATTR_TYPE_VALUE_INPUT,
OPTEE_MSG_ATTR_TYPE_VALUE_INPUT,
OPTEE_MSG_ATTR_TYPE_RMEM_INOUT,
OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT,
};
struct udevice *chip_dev;
struct tee_shm *shm;
u8 *buf;
int ret;
if (arg->num_params != ARRAY_SIZE(attr) ||
arg->params[0].attr != attr[0] ||
arg->params[1].attr != attr[1] ||
arg->params[2].attr != attr[2] ||
arg->params[3].attr != attr[3]) {
goto bad;
}
shm = (struct tee_shm *)(unsigned long)arg->params[2].u.rmem.shm_ref;
buf = shm->addr;
if (!buf)
goto bad;
if (i2c_get_chip_for_busnum((int)arg->params[0].u.value.b,
(int)arg->params[0].u.value.c,
0, &chip_dev))
goto bad;
if (check_xfer_flags(chip_dev, arg->params[1].u.value.a))
goto bad;
switch (arg->params[0].u.value.a) {
case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD:
ret = dm_i2c_read(chip_dev, 0, buf,
(size_t)arg->params[2].u.rmem.size);
break;
case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR:
ret = dm_i2c_write(chip_dev, 0, buf,
(size_t)arg->params[2].u.rmem.size);
break;
default:
goto bad;
}
if (ret) {
arg->ret = TEE_ERROR_COMMUNICATION;
} else {
arg->params[3].u.value.a = arg->params[2].u.rmem.size;
arg->ret = TEE_SUCCESS;
}
return;
bad:
arg->ret = TEE_ERROR_BAD_PARAMETERS;
}