summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/tee/optee/Makefile1
-rw-r--r--drivers/tee/optee/i2c.c90
-rw-r--r--drivers/tee/optee/optee_msg.h21
-rw-r--r--drivers/tee/optee/optee_msg_supplicant.h5
-rw-r--r--drivers/tee/optee/optee_private.h17
-rw-r--r--drivers/tee/optee/supplicant.c3
6 files changed, 137 insertions, 0 deletions
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
index 928d3f80027..068c6e7aa1b 100644
--- a/drivers/tee/optee/Makefile
+++ b/drivers/tee/optee/Makefile
@@ -2,4 +2,5 @@
obj-y += core.o
obj-y += supplicant.o
+obj-$(CONFIG_DM_I2C) += i2c.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
diff --git a/drivers/tee/optee/i2c.c b/drivers/tee/optee/i2c.c
new file mode 100644
index 00000000000..ef4e10f9912
--- /dev/null
+++ b/drivers/tee/optee/i2c.c
@@ -0,0 +1,90 @@
+// 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;
+}
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
index 24c60960fc4..8d40ce60c2b 100644
--- a/drivers/tee/optee/optee_msg.h
+++ b/drivers/tee/optee/optee_msg.h
@@ -422,4 +422,25 @@ struct optee_msg_arg {
*/
#define OPTEE_MSG_RPC_CMD_SHM_FREE 7
+/*
+ * Access a device on an i2c bus
+ *
+ * [in] param[0].u.value.a mode: RD(0), WR(1)
+ * [in] param[0].u.value.b i2c adapter
+ * [in] param[0].u.value.c i2c chip
+ *
+ * [in] param[1].u.value.a i2c control flags
+ *
+ * [in/out] memref[2] buffer to exchange the transfer data
+ * with the secure world
+ *
+ * [out] param[3].u.value.a bytes transferred by the driver
+ */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21
+/* I2C master transfer modes */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD 0
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR 1
+/* I2C master control flags */
+#define OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT BIT(0)
+
#endif /* _OPTEE_MSG_H */
diff --git a/drivers/tee/optee/optee_msg_supplicant.h b/drivers/tee/optee/optee_msg_supplicant.h
index a0fb8063c81..963cfd47824 100644
--- a/drivers/tee/optee/optee_msg_supplicant.h
+++ b/drivers/tee/optee/optee_msg_supplicant.h
@@ -148,6 +148,11 @@
#define OPTEE_MSG_RPC_CMD_SHM_FREE 7
/*
+ * I2C bus access
+ */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21
+
+/*
* Was OPTEE_MSG_RPC_CMD_SQL_FS, which isn't supported any longer
*/
#define OPTEE_MSG_RPC_CMD_SQL_FS_RESERVED 8
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index 9442d1c176b..1f07a27ee4b 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -60,6 +60,23 @@ static inline void optee_suppl_rpmb_release(struct udevice *dev)
}
#endif
+#ifdef CONFIG_DM_I2C
+/**
+ * optee_suppl_cmd_i2c_transfer() - route I2C requests to an I2C chip
+ * @arg: OP-TEE message (layout specified in optee_msg.h) defining the
+ * transfer mode (read/write), adapter, chip and control flags.
+ *
+ * Handles OP-TEE requests to transfer data to the I2C chip on the I2C adapter.
+ */
+void optee_suppl_cmd_i2c_transfer(struct optee_msg_arg *arg);
+#else
+static inline void optee_suppl_cmd_i2c_transfer(struct optee_msg_arg *arg)
+{
+ debug("OPTEE_MSG_RPC_CMD_I2C_TRANSFER not implemented\n");
+ arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
+}
+#endif
+
void *optee_alloc_and_init_page_list(void *buf, ulong len, u64 *phys_buf_ptr);
#endif /* __OPTEE_PRIVATE_H */
diff --git a/drivers/tee/optee/supplicant.c b/drivers/tee/optee/supplicant.c
index ae042b9a204..f9dd874b594 100644
--- a/drivers/tee/optee/supplicant.c
+++ b/drivers/tee/optee/supplicant.c
@@ -89,6 +89,9 @@ void optee_suppl_cmd(struct udevice *dev, struct tee_shm *shm_arg,
case OPTEE_MSG_RPC_CMD_RPMB:
optee_suppl_cmd_rpmb(dev, arg);
break;
+ case OPTEE_MSG_RPC_CMD_I2C_TRANSFER:
+ optee_suppl_cmd_i2c_transfer(arg);
+ break;
default:
arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
}