1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2020 Foundries Ltd <jorge@foundries.io>
4 */
5 #include <kernel/rpc_io_i2c.h>
6 #include <kernel/thread.h>
7 #include <mm/mobj.h>
8 #include <string.h>
9
10 /*
11 * @brief: I2C master transfer request to an I2C slave device.
12 * It is the responsibility of the caller to validate the number of bytes
13 * processed by the REE.
14 *
15 * @param req: the secure world I2C master request
16 * @param len: the number of bytes processed by REE
17 * @returns: TEE_SUCCESS on success, TEE_ERROR_XXX on error.
18 */
rpc_io_i2c_transfer(struct rpc_i2c_request * req,size_t * len)19 TEE_Result rpc_io_i2c_transfer(struct rpc_i2c_request *req, size_t *len)
20 {
21 struct thread_param p[4] = { };
22 TEE_Result res = TEE_SUCCESS;
23 struct mobj *mobj = NULL;
24 uint8_t *va = NULL;
25
26 assert(req);
27
28 if (!len)
29 return TEE_ERROR_BAD_PARAMETERS;
30
31 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_I2C,
32 THREAD_SHM_TYPE_KERNEL_PRIVATE,
33 req->buffer_len, &mobj);
34 if (!va)
35 return TEE_ERROR_OUT_OF_MEMORY;
36
37 if (req->mode == RPC_I2C_MODE_WRITE)
38 memcpy(va, req->buffer, req->buffer_len);
39
40 p[0] = THREAD_PARAM_VALUE(IN, req->mode, req->bus, req->chip);
41 p[1] = THREAD_PARAM_VALUE(IN, req->flags, 0, 0);
42 p[2] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, req->buffer_len);
43 p[3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0);
44
45 res = thread_rpc_cmd(OPTEE_RPC_CMD_I2C_TRANSFER, ARRAY_SIZE(p), p);
46 if (res != TEE_SUCCESS)
47 return res;
48
49 /*
50 * Reporting more bytes than supplied or requested from the I2C chip is
51 * an REE error
52 */
53 if (p[3].u.value.a > req->buffer_len)
54 return TEE_ERROR_EXCESS_DATA;
55
56 *len = p[3].u.value.a;
57
58 if (req->mode == RPC_I2C_MODE_READ)
59 memcpy(req->buffer, va, *len);
60
61 return TEE_SUCCESS;
62 }
63