aboutsummaryrefslogtreecommitdiff
path: root/core/arch/arm
diff options
context:
space:
mode:
authorJorge Ramirez-Ortiz <jorge@foundries.io>2020-06-15 15:11:31 +0200
committerJérôme Forissier <jerome@forissier.org>2020-08-11 17:08:51 +0200
commit30c53a72426366d0a4eb4aa396c37b8fd048a82a (patch)
treec3420ced402773adaf8ebbedb7d21378236c69f6 /core/arch/arm
parent6ee9f66689c712fa8783785e9e7f2964bcf136e9 (diff)
core: arm: rpc i2c trampoline driver
Gives OP-TEE access to the i2c buses initialized and controlled by the REE kernel. This is done by memory mapping a buffer from the thread's cache where the input or output data is transferred. Using this mechanism, OP-TEE clients do not have to worry about REE RUNTIME_PM features switching off clocks from the controllers or collisions with other bus masters. This driver assumes that the I2C chip is on a REE statically assigned bus which value is known to OP-TEE (it will not query/probe the REE). The slave address can be either seven or ten bits. When using a ten bit address, the corresponding flag needs to be set in the command and the REE adapter must support the requested addressing mode. Signed-off-by: Jorge Ramirez-Ortiz <jorge@foundries.io> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org> Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
Diffstat (limited to 'core/arch/arm')
-rw-r--r--core/arch/arm/kernel/rpc_io_i2c.c61
-rw-r--r--core/arch/arm/kernel/sub.mk1
2 files changed, 62 insertions, 0 deletions
diff --git a/core/arch/arm/kernel/rpc_io_i2c.c b/core/arch/arm/kernel/rpc_io_i2c.c
new file mode 100644
index 00000000..b48320ad
--- /dev/null
+++ b/core/arch/arm/kernel/rpc_io_i2c.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2020 Foundries Ltd <jorge@foundries.io>
+ */
+#include <kernel/rpc_io_i2c.h>
+#include <kernel/thread.h>
+#include <mm/mobj.h>
+#include <string.h>
+
+/*
+ * @brief: I2C master transfer request to an I2C slave device.
+ * It is the responsibility of the caller to validate the number of bytes
+ * processed by the REE.
+ *
+ * @param req: the secure world I2C master request
+ * @param len: the number of bytes processed by REE
+ * @returns: TEE_SUCCESS on success, TEE_ERROR_XXX on error.
+ */
+TEE_Result rpc_io_i2c_transfer(struct rpc_i2c_request *req, size_t *len)
+{
+ struct thread_param p[4] = { };
+ TEE_Result res = TEE_SUCCESS;
+ struct mobj *mobj = NULL;
+ uint8_t *va = NULL;
+
+ assert(req);
+
+ if (!len)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ va = thread_rpc_shm_cache_alloc(THREAD_SHM_TYPE_KERNEL_PRIVATE,
+ req->buffer_len, &mobj);
+ if (!va)
+ return TEE_ERROR_OUT_OF_MEMORY;
+
+ if (req->mode == RPC_I2C_MODE_WRITE)
+ memcpy(va, req->buffer, req->buffer_len);
+
+ p[0] = THREAD_PARAM_VALUE(IN, req->mode, req->bus, req->chip);
+ p[1] = THREAD_PARAM_VALUE(IN, req->flags, 0, 0);
+ p[2] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, req->buffer_len);
+ p[3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0);
+
+ res = thread_rpc_cmd(OPTEE_RPC_CMD_I2C_TRANSFER, ARRAY_SIZE(p), p);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ /*
+ * Reporting more bytes than supplied or requested from the I2C chip is
+ * an REE error
+ */
+ if (p[2].u.value.a > req->buffer_len)
+ return TEE_ERROR_EXCESS_DATA;
+
+ *len = p[2].u.value.a;
+
+ if (req->mode == RPC_I2C_MODE_READ)
+ memcpy(req->buffer, va, *len);
+
+ return TEE_SUCCESS;
+}
diff --git a/core/arch/arm/kernel/sub.mk b/core/arch/arm/kernel/sub.mk
index 4190a0c5..71a89553 100644
--- a/core/arch/arm/kernel/sub.mk
+++ b/core/arch/arm/kernel/sub.mk
@@ -6,6 +6,7 @@ srcs-$(CFG_SECSTOR_TA) += secstor_ta.c
endif
srcs-y += pseudo_ta.c
srcs-y += tee_time.c
+srcs-y += rpc_io_i2c.c
srcs-y += otp_stubs.c
srcs-y += delay.c