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