diff options
author | Jorge Ramirez-Ortiz <jorge@foundries.io> | 2020-06-15 15:11:31 +0200 |
---|---|---|
committer | Jérôme Forissier <jerome@forissier.org> | 2020-08-11 17:08:51 +0200 |
commit | 30c53a72426366d0a4eb4aa396c37b8fd048a82a (patch) | |
tree | c3420ced402773adaf8ebbedb7d21378236c69f6 /core/arch/arm | |
parent | 6ee9f66689c712fa8783785e9e7f2964bcf136e9 (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.c | 61 | ||||
-rw-r--r-- | core/arch/arm/kernel/sub.mk | 1 |
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 |