xref: /openbmc/u-boot/drivers/tee/optee/core.c (revision 232cfd6d)
1d4bd3d25SJens Wiklander // SPDX-License-Identifier: GPL-2.0+
2d4bd3d25SJens Wiklander /*
3d4bd3d25SJens Wiklander  * Copyright (c) 2018 Linaro Limited
4d4bd3d25SJens Wiklander  */
5d4bd3d25SJens Wiklander 
6d4bd3d25SJens Wiklander #include <common.h>
7d4bd3d25SJens Wiklander #include <dm.h>
8d4bd3d25SJens Wiklander #include <log.h>
9d4bd3d25SJens Wiklander #include <tee.h>
10d4bd3d25SJens Wiklander #include <linux/arm-smccc.h>
11d4bd3d25SJens Wiklander #include <linux/io.h>
12d4bd3d25SJens Wiklander 
13d4bd3d25SJens Wiklander #include "optee_smc.h"
14d4bd3d25SJens Wiklander #include "optee_msg.h"
15d4bd3d25SJens Wiklander #include "optee_private.h"
16d4bd3d25SJens Wiklander 
17d4bd3d25SJens Wiklander #define PAGELIST_ENTRIES_PER_PAGE \
18d4bd3d25SJens Wiklander 	((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
19d4bd3d25SJens Wiklander 
20d4bd3d25SJens Wiklander typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long,
21d4bd3d25SJens Wiklander 			       unsigned long, unsigned long, unsigned long,
22d4bd3d25SJens Wiklander 			       unsigned long, unsigned long,
23d4bd3d25SJens Wiklander 			       struct arm_smccc_res *);
24d4bd3d25SJens Wiklander 
25d4bd3d25SJens Wiklander struct optee_pdata {
26d4bd3d25SJens Wiklander 	optee_invoke_fn *invoke_fn;
27d4bd3d25SJens Wiklander };
28d4bd3d25SJens Wiklander 
29d4bd3d25SJens Wiklander struct rpc_param {
30d4bd3d25SJens Wiklander 	u32	a0;
31d4bd3d25SJens Wiklander 	u32	a1;
32d4bd3d25SJens Wiklander 	u32	a2;
33d4bd3d25SJens Wiklander 	u32	a3;
34d4bd3d25SJens Wiklander 	u32	a4;
35d4bd3d25SJens Wiklander 	u32	a5;
36d4bd3d25SJens Wiklander 	u32	a6;
37d4bd3d25SJens Wiklander 	u32	a7;
38d4bd3d25SJens Wiklander };
39d4bd3d25SJens Wiklander 
40d4bd3d25SJens Wiklander /**
41d4bd3d25SJens Wiklander  * reg_pair_to_ptr() - Make a pointer of 2 32-bit values
42d4bd3d25SJens Wiklander  * @reg0:	High bits of the pointer
43d4bd3d25SJens Wiklander  * @reg1:	Low bits of the pointer
44d4bd3d25SJens Wiklander  *
45d4bd3d25SJens Wiklander  * Returns the combined result, note that if a pointer is 32-bit wide @reg0
46d4bd3d25SJens Wiklander  * will be discarded.
47d4bd3d25SJens Wiklander  */
reg_pair_to_ptr(u32 reg0,u32 reg1)48d4bd3d25SJens Wiklander static void *reg_pair_to_ptr(u32 reg0, u32 reg1)
49d4bd3d25SJens Wiklander {
50d4bd3d25SJens Wiklander 	return (void *)(ulong)(((u64)reg0 << 32) | reg1);
51d4bd3d25SJens Wiklander }
52d4bd3d25SJens Wiklander 
53d4bd3d25SJens Wiklander /**
54d4bd3d25SJens Wiklander  * reg_pair_from_64() - Split a 64-bit value into two 32-bit values
55d4bd3d25SJens Wiklander  * @reg0:	High bits of @val
56d4bd3d25SJens Wiklander  * @reg1:	Low bits of @val
57d4bd3d25SJens Wiklander  * @val:	The value to split
58d4bd3d25SJens Wiklander  */
reg_pair_from_64(u32 * reg0,u32 * reg1,u64 val)59d4bd3d25SJens Wiklander static void reg_pair_from_64(u32 *reg0, u32 *reg1, u64 val)
60d4bd3d25SJens Wiklander {
61d4bd3d25SJens Wiklander 	*reg0 = val >> 32;
62d4bd3d25SJens Wiklander 	*reg1 = val;
63d4bd3d25SJens Wiklander }
64d4bd3d25SJens Wiklander 
65d4bd3d25SJens Wiklander /**
66d4bd3d25SJens Wiklander  * optee_alloc_and_init_page_list() - Provide page list of memory buffer
67d4bd3d25SJens Wiklander  * @buf:		Start of buffer
68d4bd3d25SJens Wiklander  * @len:		Length of buffer
69d4bd3d25SJens Wiklander  * @phys_buf_ptr	Physical pointer with coded offset to page list
70d4bd3d25SJens Wiklander  *
71d4bd3d25SJens Wiklander  * Secure world doesn't share mapping with Normal world (U-Boot in this case)
72d4bd3d25SJens Wiklander  * so physical pointers are needed when sharing pointers.
73d4bd3d25SJens Wiklander  *
74d4bd3d25SJens Wiklander  * Returns a pointer page list on success or NULL on failure
75d4bd3d25SJens Wiklander  */
optee_alloc_and_init_page_list(void * buf,ulong len,u64 * phys_buf_ptr)76d4bd3d25SJens Wiklander void *optee_alloc_and_init_page_list(void *buf, ulong len, u64 *phys_buf_ptr)
77d4bd3d25SJens Wiklander {
78d4bd3d25SJens Wiklander 	const unsigned int page_size = OPTEE_MSG_NONCONTIG_PAGE_SIZE;
79d4bd3d25SJens Wiklander 	const phys_addr_t page_mask = page_size - 1;
80d4bd3d25SJens Wiklander 	u8 *buf_base;
81d4bd3d25SJens Wiklander 	unsigned int page_offset;
82d4bd3d25SJens Wiklander 	unsigned int num_pages;
83d4bd3d25SJens Wiklander 	unsigned int list_size;
84d4bd3d25SJens Wiklander 	unsigned int n;
85d4bd3d25SJens Wiklander 	void *page_list;
86d4bd3d25SJens Wiklander 	struct {
87d4bd3d25SJens Wiklander 		u64 pages_list[PAGELIST_ENTRIES_PER_PAGE];
88d4bd3d25SJens Wiklander 		u64 next_page_data;
89d4bd3d25SJens Wiklander 	} *pages_data;
90d4bd3d25SJens Wiklander 
91d4bd3d25SJens Wiklander 	/*
92d4bd3d25SJens Wiklander 	 * A Memory buffer is described in chunks of 4k. The list of
93d4bd3d25SJens Wiklander 	 * physical addresses has to be represented by a physical pointer
94d4bd3d25SJens Wiklander 	 * too and a single list has to start at a 4k page and fit into
95d4bd3d25SJens Wiklander 	 * that page. In order to be able to describe large memory buffers
96d4bd3d25SJens Wiklander 	 * these 4k pages carrying physical addresses are linked together
97d4bd3d25SJens Wiklander 	 * in a list. See OPTEE_MSG_ATTR_NONCONTIG in
98d4bd3d25SJens Wiklander 	 * drivers/tee/optee/optee_msg.h for more information.
99d4bd3d25SJens Wiklander 	 */
100d4bd3d25SJens Wiklander 
101d4bd3d25SJens Wiklander 	page_offset = (ulong)buf & page_mask;
102d4bd3d25SJens Wiklander 	num_pages = roundup(page_offset + len, page_size) / page_size;
103d4bd3d25SJens Wiklander 	list_size = DIV_ROUND_UP(num_pages, PAGELIST_ENTRIES_PER_PAGE) *
104d4bd3d25SJens Wiklander 		    page_size;
105d4bd3d25SJens Wiklander 	page_list = memalign(page_size, list_size);
106d4bd3d25SJens Wiklander 	if (!page_list)
107d4bd3d25SJens Wiklander 		return NULL;
108d4bd3d25SJens Wiklander 
109d4bd3d25SJens Wiklander 	pages_data = page_list;
110d4bd3d25SJens Wiklander 	buf_base = (u8 *)rounddown((ulong)buf, page_size);
111d4bd3d25SJens Wiklander 	n = 0;
112d4bd3d25SJens Wiklander 	while (num_pages) {
113d4bd3d25SJens Wiklander 		pages_data->pages_list[n] = virt_to_phys(buf_base);
114d4bd3d25SJens Wiklander 		n++;
115d4bd3d25SJens Wiklander 		buf_base += page_size;
116d4bd3d25SJens Wiklander 		num_pages--;
117d4bd3d25SJens Wiklander 
118d4bd3d25SJens Wiklander 		if (n == PAGELIST_ENTRIES_PER_PAGE) {
119d4bd3d25SJens Wiklander 			pages_data->next_page_data =
120d4bd3d25SJens Wiklander 				virt_to_phys(pages_data + 1);
121d4bd3d25SJens Wiklander 			pages_data++;
122d4bd3d25SJens Wiklander 			n = 0;
123d4bd3d25SJens Wiklander 		}
124d4bd3d25SJens Wiklander 	}
125d4bd3d25SJens Wiklander 
126d4bd3d25SJens Wiklander 	*phys_buf_ptr = virt_to_phys(page_list) | page_offset;
127d4bd3d25SJens Wiklander 	return page_list;
128d4bd3d25SJens Wiklander }
129d4bd3d25SJens Wiklander 
optee_get_version(struct udevice * dev,struct tee_version_data * vers)130d4bd3d25SJens Wiklander static void optee_get_version(struct udevice *dev,
131d4bd3d25SJens Wiklander 			      struct tee_version_data *vers)
132d4bd3d25SJens Wiklander {
133d4bd3d25SJens Wiklander 	struct tee_version_data v = {
134d4bd3d25SJens Wiklander 		.gen_caps = TEE_GEN_CAP_GP | TEE_GEN_CAP_REG_MEM,
135d4bd3d25SJens Wiklander 	};
136d4bd3d25SJens Wiklander 
137d4bd3d25SJens Wiklander 	*vers = v;
138d4bd3d25SJens Wiklander }
139d4bd3d25SJens Wiklander 
get_msg_arg(struct udevice * dev,uint num_params,struct tee_shm ** shmp,struct optee_msg_arg ** msg_arg)140d4bd3d25SJens Wiklander static int get_msg_arg(struct udevice *dev, uint num_params,
141d4bd3d25SJens Wiklander 		       struct tee_shm **shmp, struct optee_msg_arg **msg_arg)
142d4bd3d25SJens Wiklander {
143d4bd3d25SJens Wiklander 	int rc;
144d4bd3d25SJens Wiklander 	struct optee_msg_arg *ma;
145d4bd3d25SJens Wiklander 
146d4bd3d25SJens Wiklander 	rc = __tee_shm_add(dev, OPTEE_MSG_NONCONTIG_PAGE_SIZE, NULL,
147d4bd3d25SJens Wiklander 			   OPTEE_MSG_GET_ARG_SIZE(num_params), TEE_SHM_ALLOC,
148d4bd3d25SJens Wiklander 			   shmp);
149d4bd3d25SJens Wiklander 	if (rc)
150d4bd3d25SJens Wiklander 		return rc;
151d4bd3d25SJens Wiklander 
152d4bd3d25SJens Wiklander 	ma = (*shmp)->addr;
153d4bd3d25SJens Wiklander 	memset(ma, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
154d4bd3d25SJens Wiklander 	ma->num_params = num_params;
155d4bd3d25SJens Wiklander 	*msg_arg = ma;
156d4bd3d25SJens Wiklander 
157d4bd3d25SJens Wiklander 	return 0;
158d4bd3d25SJens Wiklander }
159d4bd3d25SJens Wiklander 
to_msg_param(struct optee_msg_param * msg_params,uint num_params,const struct tee_param * params)160d4bd3d25SJens Wiklander static int to_msg_param(struct optee_msg_param *msg_params, uint num_params,
161d4bd3d25SJens Wiklander 			const struct tee_param *params)
162d4bd3d25SJens Wiklander {
163d4bd3d25SJens Wiklander 	uint n;
164d4bd3d25SJens Wiklander 
165d4bd3d25SJens Wiklander 	for (n = 0; n < num_params; n++) {
166d4bd3d25SJens Wiklander 		const struct tee_param *p = params + n;
167d4bd3d25SJens Wiklander 		struct optee_msg_param *mp = msg_params + n;
168d4bd3d25SJens Wiklander 
169d4bd3d25SJens Wiklander 		switch (p->attr) {
170d4bd3d25SJens Wiklander 		case TEE_PARAM_ATTR_TYPE_NONE:
171d4bd3d25SJens Wiklander 			mp->attr = OPTEE_MSG_ATTR_TYPE_NONE;
172d4bd3d25SJens Wiklander 			memset(&mp->u, 0, sizeof(mp->u));
173d4bd3d25SJens Wiklander 			break;
174d4bd3d25SJens Wiklander 		case TEE_PARAM_ATTR_TYPE_VALUE_INPUT:
175d4bd3d25SJens Wiklander 		case TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT:
176d4bd3d25SJens Wiklander 		case TEE_PARAM_ATTR_TYPE_VALUE_INOUT:
177d4bd3d25SJens Wiklander 			mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr -
178d4bd3d25SJens Wiklander 				   TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
179d4bd3d25SJens Wiklander 			mp->u.value.a = p->u.value.a;
180d4bd3d25SJens Wiklander 			mp->u.value.b = p->u.value.b;
181d4bd3d25SJens Wiklander 			mp->u.value.c = p->u.value.c;
182d4bd3d25SJens Wiklander 			break;
183d4bd3d25SJens Wiklander 		case TEE_PARAM_ATTR_TYPE_MEMREF_INPUT:
184d4bd3d25SJens Wiklander 		case TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
185d4bd3d25SJens Wiklander 		case TEE_PARAM_ATTR_TYPE_MEMREF_INOUT:
186d4bd3d25SJens Wiklander 			mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr -
187d4bd3d25SJens Wiklander 				   TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
188d4bd3d25SJens Wiklander 			mp->u.rmem.shm_ref = (ulong)p->u.memref.shm;
189d4bd3d25SJens Wiklander 			mp->u.rmem.size = p->u.memref.size;
190d4bd3d25SJens Wiklander 			mp->u.rmem.offs = p->u.memref.shm_offs;
191d4bd3d25SJens Wiklander 			break;
192d4bd3d25SJens Wiklander 		default:
193d4bd3d25SJens Wiklander 			return -EINVAL;
194d4bd3d25SJens Wiklander 		}
195d4bd3d25SJens Wiklander 	}
196d4bd3d25SJens Wiklander 	return 0;
197d4bd3d25SJens Wiklander }
198d4bd3d25SJens Wiklander 
from_msg_param(struct tee_param * params,uint num_params,const struct optee_msg_param * msg_params)199d4bd3d25SJens Wiklander static int from_msg_param(struct tee_param *params, uint num_params,
200d4bd3d25SJens Wiklander 			  const struct optee_msg_param *msg_params)
201d4bd3d25SJens Wiklander {
202d4bd3d25SJens Wiklander 	uint n;
203d4bd3d25SJens Wiklander 	struct tee_shm *shm;
204d4bd3d25SJens Wiklander 
205d4bd3d25SJens Wiklander 	for (n = 0; n < num_params; n++) {
206d4bd3d25SJens Wiklander 		struct tee_param *p = params + n;
207d4bd3d25SJens Wiklander 		const struct optee_msg_param *mp = msg_params + n;
208d4bd3d25SJens Wiklander 		u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK;
209d4bd3d25SJens Wiklander 
210d4bd3d25SJens Wiklander 		switch (attr) {
211d4bd3d25SJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_NONE:
212d4bd3d25SJens Wiklander 			p->attr = TEE_PARAM_ATTR_TYPE_NONE;
213d4bd3d25SJens Wiklander 			memset(&p->u, 0, sizeof(p->u));
214d4bd3d25SJens Wiklander 			break;
215d4bd3d25SJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
216d4bd3d25SJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
217d4bd3d25SJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
218d4bd3d25SJens Wiklander 			p->attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT + attr -
219d4bd3d25SJens Wiklander 				  OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
220d4bd3d25SJens Wiklander 			p->u.value.a = mp->u.value.a;
221d4bd3d25SJens Wiklander 			p->u.value.b = mp->u.value.b;
222d4bd3d25SJens Wiklander 			p->u.value.c = mp->u.value.c;
223d4bd3d25SJens Wiklander 			break;
224d4bd3d25SJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
225d4bd3d25SJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
226d4bd3d25SJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
227d4bd3d25SJens Wiklander 			p->attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT + attr -
228d4bd3d25SJens Wiklander 				  OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
229d4bd3d25SJens Wiklander 			p->u.memref.size = mp->u.rmem.size;
230d4bd3d25SJens Wiklander 			shm = (struct tee_shm *)(ulong)mp->u.rmem.shm_ref;
231d4bd3d25SJens Wiklander 
232d4bd3d25SJens Wiklander 			if (!shm) {
233d4bd3d25SJens Wiklander 				p->u.memref.shm_offs = 0;
234d4bd3d25SJens Wiklander 				p->u.memref.shm = NULL;
235d4bd3d25SJens Wiklander 				break;
236d4bd3d25SJens Wiklander 			}
237d4bd3d25SJens Wiklander 			p->u.memref.shm_offs = mp->u.rmem.offs;
238d4bd3d25SJens Wiklander 			p->u.memref.shm = shm;
239d4bd3d25SJens Wiklander 			break;
240d4bd3d25SJens Wiklander 		default:
241d4bd3d25SJens Wiklander 			return -EINVAL;
242d4bd3d25SJens Wiklander 		}
243d4bd3d25SJens Wiklander 	}
244d4bd3d25SJens Wiklander 	return 0;
245d4bd3d25SJens Wiklander }
246d4bd3d25SJens Wiklander 
handle_rpc(struct udevice * dev,struct rpc_param * param,void * page_list)247d4bd3d25SJens Wiklander static void handle_rpc(struct udevice *dev, struct rpc_param *param,
248d4bd3d25SJens Wiklander 		       void *page_list)
249d4bd3d25SJens Wiklander {
250d4bd3d25SJens Wiklander 	struct tee_shm *shm;
251d4bd3d25SJens Wiklander 
252d4bd3d25SJens Wiklander 	switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
253d4bd3d25SJens Wiklander 	case OPTEE_SMC_RPC_FUNC_ALLOC:
254d4bd3d25SJens Wiklander 		if (!__tee_shm_add(dev, OPTEE_MSG_NONCONTIG_PAGE_SIZE, NULL,
255d4bd3d25SJens Wiklander 				   param->a1, TEE_SHM_ALLOC | TEE_SHM_REGISTER,
256d4bd3d25SJens Wiklander 				   &shm)) {
257d4bd3d25SJens Wiklander 			reg_pair_from_64(&param->a1, &param->a2,
258d4bd3d25SJens Wiklander 					 virt_to_phys(shm->addr));
259d4bd3d25SJens Wiklander 			/* "cookie" */
260d4bd3d25SJens Wiklander 			reg_pair_from_64(&param->a4, &param->a5, (ulong)shm);
261d4bd3d25SJens Wiklander 		} else {
262d4bd3d25SJens Wiklander 			param->a1 = 0;
263d4bd3d25SJens Wiklander 			param->a2 = 0;
264d4bd3d25SJens Wiklander 			param->a4 = 0;
265d4bd3d25SJens Wiklander 			param->a5 = 0;
266d4bd3d25SJens Wiklander 		}
267d4bd3d25SJens Wiklander 		break;
268d4bd3d25SJens Wiklander 	case OPTEE_SMC_RPC_FUNC_FREE:
269d4bd3d25SJens Wiklander 		shm = reg_pair_to_ptr(param->a1, param->a2);
270d4bd3d25SJens Wiklander 		tee_shm_free(shm);
271d4bd3d25SJens Wiklander 		break;
272d4bd3d25SJens Wiklander 	case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
273d4bd3d25SJens Wiklander 		break;
274d4bd3d25SJens Wiklander 	case OPTEE_SMC_RPC_FUNC_CMD:
275d4bd3d25SJens Wiklander 		shm = reg_pair_to_ptr(param->a1, param->a2);
276d4bd3d25SJens Wiklander 		optee_suppl_cmd(dev, shm, page_list);
277d4bd3d25SJens Wiklander 		break;
278d4bd3d25SJens Wiklander 	default:
279d4bd3d25SJens Wiklander 		break;
280d4bd3d25SJens Wiklander 	}
281d4bd3d25SJens Wiklander 
282d4bd3d25SJens Wiklander 	param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
283d4bd3d25SJens Wiklander }
284d4bd3d25SJens Wiklander 
call_err_to_res(u32 call_err)285d4bd3d25SJens Wiklander static u32 call_err_to_res(u32 call_err)
286d4bd3d25SJens Wiklander {
287d4bd3d25SJens Wiklander 	switch (call_err) {
288d4bd3d25SJens Wiklander 	case OPTEE_SMC_RETURN_OK:
289d4bd3d25SJens Wiklander 		return TEE_SUCCESS;
290d4bd3d25SJens Wiklander 	default:
291d4bd3d25SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
292d4bd3d25SJens Wiklander 	}
293d4bd3d25SJens Wiklander }
294d4bd3d25SJens Wiklander 
do_call_with_arg(struct udevice * dev,struct optee_msg_arg * arg)295d4bd3d25SJens Wiklander static u32 do_call_with_arg(struct udevice *dev, struct optee_msg_arg *arg)
296d4bd3d25SJens Wiklander {
297d4bd3d25SJens Wiklander 	struct optee_pdata *pdata = dev_get_platdata(dev);
298d4bd3d25SJens Wiklander 	struct rpc_param param = { .a0 = OPTEE_SMC_CALL_WITH_ARG };
299d4bd3d25SJens Wiklander 	void *page_list = NULL;
300d4bd3d25SJens Wiklander 
301d4bd3d25SJens Wiklander 	reg_pair_from_64(&param.a1, &param.a2, virt_to_phys(arg));
302d4bd3d25SJens Wiklander 	while (true) {
303d4bd3d25SJens Wiklander 		struct arm_smccc_res res;
304d4bd3d25SJens Wiklander 
305d4bd3d25SJens Wiklander 		pdata->invoke_fn(param.a0, param.a1, param.a2, param.a3,
306d4bd3d25SJens Wiklander 				 param.a4, param.a5, param.a6, param.a7, &res);
307d4bd3d25SJens Wiklander 
308d4bd3d25SJens Wiklander 		free(page_list);
309d4bd3d25SJens Wiklander 		page_list = NULL;
310d4bd3d25SJens Wiklander 
311d4bd3d25SJens Wiklander 		if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
312d4bd3d25SJens Wiklander 			param.a0 = res.a0;
313d4bd3d25SJens Wiklander 			param.a1 = res.a1;
314d4bd3d25SJens Wiklander 			param.a2 = res.a2;
315d4bd3d25SJens Wiklander 			param.a3 = res.a3;
316d4bd3d25SJens Wiklander 			handle_rpc(dev, &param, &page_list);
317d4bd3d25SJens Wiklander 		} else {
318*232cfd6dSJens Wiklander 			/*
319*232cfd6dSJens Wiklander 			 * In case we've accessed RPMB to serve an RPC
320*232cfd6dSJens Wiklander 			 * request we need to restore the previously
321*232cfd6dSJens Wiklander 			 * selected partition as the caller may expect it
322*232cfd6dSJens Wiklander 			 * to remain unchanged.
323*232cfd6dSJens Wiklander 			 */
324*232cfd6dSJens Wiklander 			optee_suppl_rpmb_release(dev);
325d4bd3d25SJens Wiklander 			return call_err_to_res(res.a0);
326d4bd3d25SJens Wiklander 		}
327d4bd3d25SJens Wiklander 	}
328d4bd3d25SJens Wiklander }
329d4bd3d25SJens Wiklander 
optee_close_session(struct udevice * dev,u32 session)330d4bd3d25SJens Wiklander static int optee_close_session(struct udevice *dev, u32 session)
331d4bd3d25SJens Wiklander {
332d4bd3d25SJens Wiklander 	int rc;
333d4bd3d25SJens Wiklander 	struct tee_shm *shm;
334d4bd3d25SJens Wiklander 	struct optee_msg_arg *msg_arg;
335d4bd3d25SJens Wiklander 
336d4bd3d25SJens Wiklander 	rc = get_msg_arg(dev, 0, &shm, &msg_arg);
337d4bd3d25SJens Wiklander 	if (rc)
338d4bd3d25SJens Wiklander 		return rc;
339d4bd3d25SJens Wiklander 
340d4bd3d25SJens Wiklander 	msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
341d4bd3d25SJens Wiklander 	msg_arg->session = session;
342d4bd3d25SJens Wiklander 	do_call_with_arg(dev, msg_arg);
343d4bd3d25SJens Wiklander 
344d4bd3d25SJens Wiklander 	tee_shm_free(shm);
345d4bd3d25SJens Wiklander 
346d4bd3d25SJens Wiklander 	return 0;
347d4bd3d25SJens Wiklander }
348d4bd3d25SJens Wiklander 
optee_open_session(struct udevice * dev,struct tee_open_session_arg * arg,uint num_params,struct tee_param * params)349d4bd3d25SJens Wiklander static int optee_open_session(struct udevice *dev,
350d4bd3d25SJens Wiklander 			      struct tee_open_session_arg *arg,
351d4bd3d25SJens Wiklander 			      uint num_params, struct tee_param *params)
352d4bd3d25SJens Wiklander {
353d4bd3d25SJens Wiklander 	int rc;
354d4bd3d25SJens Wiklander 	struct tee_shm *shm;
355d4bd3d25SJens Wiklander 	struct optee_msg_arg *msg_arg;
356d4bd3d25SJens Wiklander 
357d4bd3d25SJens Wiklander 	rc = get_msg_arg(dev, num_params + 2, &shm, &msg_arg);
358d4bd3d25SJens Wiklander 	if (rc)
359d4bd3d25SJens Wiklander 		return rc;
360d4bd3d25SJens Wiklander 
361d4bd3d25SJens Wiklander 	msg_arg->cmd = OPTEE_MSG_CMD_OPEN_SESSION;
362d4bd3d25SJens Wiklander 	/*
363d4bd3d25SJens Wiklander 	 * Initialize and add the meta parameters needed when opening a
364d4bd3d25SJens Wiklander 	 * session.
365d4bd3d25SJens Wiklander 	 */
366d4bd3d25SJens Wiklander 	msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
367d4bd3d25SJens Wiklander 				  OPTEE_MSG_ATTR_META;
368d4bd3d25SJens Wiklander 	msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
369d4bd3d25SJens Wiklander 				  OPTEE_MSG_ATTR_META;
370d4bd3d25SJens Wiklander 	memcpy(&msg_arg->params[0].u.value, arg->uuid, sizeof(arg->uuid));
371d4bd3d25SJens Wiklander 	memcpy(&msg_arg->params[1].u.value, arg->uuid, sizeof(arg->clnt_uuid));
372d4bd3d25SJens Wiklander 	msg_arg->params[1].u.value.c = arg->clnt_login;
373d4bd3d25SJens Wiklander 
374d4bd3d25SJens Wiklander 	rc = to_msg_param(msg_arg->params + 2, num_params, params);
375d4bd3d25SJens Wiklander 	if (rc)
376d4bd3d25SJens Wiklander 		goto out;
377d4bd3d25SJens Wiklander 
378d4bd3d25SJens Wiklander 	arg->ret = do_call_with_arg(dev, msg_arg);
379d4bd3d25SJens Wiklander 	if (arg->ret) {
380d4bd3d25SJens Wiklander 		arg->ret_origin = TEE_ORIGIN_COMMS;
381d4bd3d25SJens Wiklander 		goto out;
382d4bd3d25SJens Wiklander 	}
383d4bd3d25SJens Wiklander 
384d4bd3d25SJens Wiklander 	if (from_msg_param(params, num_params, msg_arg->params + 2)) {
385d4bd3d25SJens Wiklander 		arg->ret = TEE_ERROR_COMMUNICATION;
386d4bd3d25SJens Wiklander 		arg->ret_origin = TEE_ORIGIN_COMMS;
387d4bd3d25SJens Wiklander 		/* Close session again to avoid leakage */
388d4bd3d25SJens Wiklander 		optee_close_session(dev, msg_arg->session);
389d4bd3d25SJens Wiklander 		goto out;
390d4bd3d25SJens Wiklander 	}
391d4bd3d25SJens Wiklander 
392d4bd3d25SJens Wiklander 	arg->session = msg_arg->session;
393d4bd3d25SJens Wiklander 	arg->ret = msg_arg->ret;
394d4bd3d25SJens Wiklander 	arg->ret_origin = msg_arg->ret_origin;
395d4bd3d25SJens Wiklander out:
396d4bd3d25SJens Wiklander 	tee_shm_free(shm);
397d4bd3d25SJens Wiklander 
398d4bd3d25SJens Wiklander 	return rc;
399d4bd3d25SJens Wiklander }
400d4bd3d25SJens Wiklander 
optee_invoke_func(struct udevice * dev,struct tee_invoke_arg * arg,uint num_params,struct tee_param * params)401d4bd3d25SJens Wiklander static int optee_invoke_func(struct udevice *dev, struct tee_invoke_arg *arg,
402d4bd3d25SJens Wiklander 			     uint num_params, struct tee_param *params)
403d4bd3d25SJens Wiklander {
404d4bd3d25SJens Wiklander 	struct tee_shm *shm;
405d4bd3d25SJens Wiklander 	struct optee_msg_arg *msg_arg;
406d4bd3d25SJens Wiklander 	int rc;
407d4bd3d25SJens Wiklander 
408d4bd3d25SJens Wiklander 	rc = get_msg_arg(dev, num_params, &shm, &msg_arg);
409d4bd3d25SJens Wiklander 	if (rc)
410d4bd3d25SJens Wiklander 		return rc;
411d4bd3d25SJens Wiklander 	msg_arg->cmd = OPTEE_MSG_CMD_INVOKE_COMMAND;
412d4bd3d25SJens Wiklander 	msg_arg->func = arg->func;
413d4bd3d25SJens Wiklander 	msg_arg->session = arg->session;
414d4bd3d25SJens Wiklander 
415d4bd3d25SJens Wiklander 	rc = to_msg_param(msg_arg->params, num_params, params);
416d4bd3d25SJens Wiklander 	if (rc)
417d4bd3d25SJens Wiklander 		goto out;
418d4bd3d25SJens Wiklander 
419d4bd3d25SJens Wiklander 	arg->ret = do_call_with_arg(dev, msg_arg);
420d4bd3d25SJens Wiklander 	if (arg->ret) {
421d4bd3d25SJens Wiklander 		arg->ret_origin = TEE_ORIGIN_COMMS;
422d4bd3d25SJens Wiklander 		goto out;
423d4bd3d25SJens Wiklander 	}
424d4bd3d25SJens Wiklander 
425d4bd3d25SJens Wiklander 	if (from_msg_param(params, num_params, msg_arg->params)) {
426d4bd3d25SJens Wiklander 		arg->ret = TEE_ERROR_COMMUNICATION;
427d4bd3d25SJens Wiklander 		arg->ret_origin = TEE_ORIGIN_COMMS;
428d4bd3d25SJens Wiklander 		goto out;
429d4bd3d25SJens Wiklander 	}
430d4bd3d25SJens Wiklander 
431d4bd3d25SJens Wiklander 	arg->ret = msg_arg->ret;
432d4bd3d25SJens Wiklander 	arg->ret_origin = msg_arg->ret_origin;
433d4bd3d25SJens Wiklander out:
434d4bd3d25SJens Wiklander 	tee_shm_free(shm);
435d4bd3d25SJens Wiklander 	return rc;
436d4bd3d25SJens Wiklander }
437d4bd3d25SJens Wiklander 
optee_shm_register(struct udevice * dev,struct tee_shm * shm)438d4bd3d25SJens Wiklander static int optee_shm_register(struct udevice *dev, struct tee_shm *shm)
439d4bd3d25SJens Wiklander {
440d4bd3d25SJens Wiklander 	struct tee_shm *shm_arg;
441d4bd3d25SJens Wiklander 	struct optee_msg_arg *msg_arg;
442d4bd3d25SJens Wiklander 	void *pl;
443d4bd3d25SJens Wiklander 	u64 ph_ptr;
444d4bd3d25SJens Wiklander 	int rc;
445d4bd3d25SJens Wiklander 
446d4bd3d25SJens Wiklander 	rc = get_msg_arg(dev, 1, &shm_arg, &msg_arg);
447d4bd3d25SJens Wiklander 	if (rc)
448d4bd3d25SJens Wiklander 		return rc;
449d4bd3d25SJens Wiklander 
450d4bd3d25SJens Wiklander 	pl = optee_alloc_and_init_page_list(shm->addr, shm->size, &ph_ptr);
451d4bd3d25SJens Wiklander 	if (!pl) {
452d4bd3d25SJens Wiklander 		rc = -ENOMEM;
453d4bd3d25SJens Wiklander 		goto out;
454d4bd3d25SJens Wiklander 	}
455d4bd3d25SJens Wiklander 
456d4bd3d25SJens Wiklander 	msg_arg->cmd = OPTEE_MSG_CMD_REGISTER_SHM;
457d4bd3d25SJens Wiklander 	msg_arg->params->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
458d4bd3d25SJens Wiklander 				OPTEE_MSG_ATTR_NONCONTIG;
459d4bd3d25SJens Wiklander 	msg_arg->params->u.tmem.buf_ptr = ph_ptr;
460d4bd3d25SJens Wiklander 	msg_arg->params->u.tmem.shm_ref = (ulong)shm;
461d4bd3d25SJens Wiklander 	msg_arg->params->u.tmem.size = shm->size;
462d4bd3d25SJens Wiklander 
463d4bd3d25SJens Wiklander 	if (do_call_with_arg(dev, msg_arg) || msg_arg->ret)
464d4bd3d25SJens Wiklander 		rc = -EINVAL;
465d4bd3d25SJens Wiklander 
466d4bd3d25SJens Wiklander 	free(pl);
467d4bd3d25SJens Wiklander out:
468d4bd3d25SJens Wiklander 	tee_shm_free(shm_arg);
469d4bd3d25SJens Wiklander 
470d4bd3d25SJens Wiklander 	return rc;
471d4bd3d25SJens Wiklander }
472d4bd3d25SJens Wiklander 
optee_shm_unregister(struct udevice * dev,struct tee_shm * shm)473d4bd3d25SJens Wiklander static int optee_shm_unregister(struct udevice *dev, struct tee_shm *shm)
474d4bd3d25SJens Wiklander {
475d4bd3d25SJens Wiklander 	struct tee_shm *shm_arg;
476d4bd3d25SJens Wiklander 	struct optee_msg_arg *msg_arg;
477d4bd3d25SJens Wiklander 	int rc;
478d4bd3d25SJens Wiklander 
479d4bd3d25SJens Wiklander 	rc = get_msg_arg(dev, 1, &shm_arg, &msg_arg);
480d4bd3d25SJens Wiklander 	if (rc)
481d4bd3d25SJens Wiklander 		return rc;
482d4bd3d25SJens Wiklander 
483d4bd3d25SJens Wiklander 	msg_arg->cmd = OPTEE_MSG_CMD_UNREGISTER_SHM;
484d4bd3d25SJens Wiklander 	msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
485d4bd3d25SJens Wiklander 	msg_arg->params[0].u.rmem.shm_ref = (ulong)shm;
486d4bd3d25SJens Wiklander 
487d4bd3d25SJens Wiklander 	if (do_call_with_arg(dev, msg_arg) || msg_arg->ret)
488d4bd3d25SJens Wiklander 		rc = -EINVAL;
489d4bd3d25SJens Wiklander 	tee_shm_free(shm_arg);
490d4bd3d25SJens Wiklander 
491d4bd3d25SJens Wiklander 	return rc;
492d4bd3d25SJens Wiklander }
493d4bd3d25SJens Wiklander 
494d4bd3d25SJens Wiklander static const struct tee_driver_ops optee_ops = {
495d4bd3d25SJens Wiklander 	.get_version = optee_get_version,
496d4bd3d25SJens Wiklander 	.open_session = optee_open_session,
497d4bd3d25SJens Wiklander 	.close_session = optee_close_session,
498d4bd3d25SJens Wiklander 	.invoke_func = optee_invoke_func,
499d4bd3d25SJens Wiklander 	.shm_register = optee_shm_register,
500d4bd3d25SJens Wiklander 	.shm_unregister = optee_shm_unregister,
501d4bd3d25SJens Wiklander };
502d4bd3d25SJens Wiklander 
is_optee_api(optee_invoke_fn * invoke_fn)503d4bd3d25SJens Wiklander static bool is_optee_api(optee_invoke_fn *invoke_fn)
504d4bd3d25SJens Wiklander {
505d4bd3d25SJens Wiklander 	struct arm_smccc_res res;
506d4bd3d25SJens Wiklander 
507d4bd3d25SJens Wiklander 	invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
508d4bd3d25SJens Wiklander 
509d4bd3d25SJens Wiklander 	return res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 &&
510d4bd3d25SJens Wiklander 	       res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3;
511d4bd3d25SJens Wiklander }
512d4bd3d25SJens Wiklander 
print_os_revision(optee_invoke_fn * invoke_fn)513d4bd3d25SJens Wiklander static void print_os_revision(optee_invoke_fn *invoke_fn)
514d4bd3d25SJens Wiklander {
515d4bd3d25SJens Wiklander 	union {
516d4bd3d25SJens Wiklander 		struct arm_smccc_res smccc;
517d4bd3d25SJens Wiklander 		struct optee_smc_call_get_os_revision_result result;
518d4bd3d25SJens Wiklander 	} res = {
519d4bd3d25SJens Wiklander 		.result = {
520d4bd3d25SJens Wiklander 		.build_id = 0
521d4bd3d25SJens Wiklander 		}
522d4bd3d25SJens Wiklander 	};
523d4bd3d25SJens Wiklander 
524d4bd3d25SJens Wiklander 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
525d4bd3d25SJens Wiklander 		  &res.smccc);
526d4bd3d25SJens Wiklander 
527d4bd3d25SJens Wiklander 	if (res.result.build_id)
528d4bd3d25SJens Wiklander 		debug("OP-TEE revision %lu.%lu (%08lx)\n", res.result.major,
529d4bd3d25SJens Wiklander 		      res.result.minor, res.result.build_id);
530d4bd3d25SJens Wiklander 	else
531d4bd3d25SJens Wiklander 		debug("OP-TEE revision %lu.%lu\n", res.result.major,
532d4bd3d25SJens Wiklander 		      res.result.minor);
533d4bd3d25SJens Wiklander }
534d4bd3d25SJens Wiklander 
api_revision_is_compatible(optee_invoke_fn * invoke_fn)535d4bd3d25SJens Wiklander static bool api_revision_is_compatible(optee_invoke_fn *invoke_fn)
536d4bd3d25SJens Wiklander {
537d4bd3d25SJens Wiklander 	union {
538d4bd3d25SJens Wiklander 		struct arm_smccc_res smccc;
539d4bd3d25SJens Wiklander 		struct optee_smc_calls_revision_result result;
540d4bd3d25SJens Wiklander 	} res;
541d4bd3d25SJens Wiklander 
542d4bd3d25SJens Wiklander 	invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
543d4bd3d25SJens Wiklander 
544d4bd3d25SJens Wiklander 	return res.result.major == OPTEE_MSG_REVISION_MAJOR &&
545d4bd3d25SJens Wiklander 	       (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR;
546d4bd3d25SJens Wiklander }
547d4bd3d25SJens Wiklander 
exchange_capabilities(optee_invoke_fn * invoke_fn,u32 * sec_caps)548d4bd3d25SJens Wiklander static bool exchange_capabilities(optee_invoke_fn *invoke_fn, u32 *sec_caps)
549d4bd3d25SJens Wiklander {
550d4bd3d25SJens Wiklander 	union {
551d4bd3d25SJens Wiklander 		struct arm_smccc_res smccc;
552d4bd3d25SJens Wiklander 		struct optee_smc_exchange_capabilities_result result;
553d4bd3d25SJens Wiklander 	} res;
554d4bd3d25SJens Wiklander 
555d4bd3d25SJens Wiklander 	invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES,
556d4bd3d25SJens Wiklander 		  OPTEE_SMC_NSEC_CAP_UNIPROCESSOR, 0, 0, 0, 0, 0, 0,
557d4bd3d25SJens Wiklander 		  &res.smccc);
558d4bd3d25SJens Wiklander 
559d4bd3d25SJens Wiklander 	if (res.result.status != OPTEE_SMC_RETURN_OK)
560d4bd3d25SJens Wiklander 		return false;
561d4bd3d25SJens Wiklander 
562d4bd3d25SJens Wiklander 	*sec_caps = res.result.capabilities;
563d4bd3d25SJens Wiklander 
564d4bd3d25SJens Wiklander 	return true;
565d4bd3d25SJens Wiklander }
566d4bd3d25SJens Wiklander 
567d4bd3d25SJens Wiklander /* Simple wrapper functions to be able to use a function pointer */
optee_smccc_smc(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long a4,unsigned long a5,unsigned long a6,unsigned long a7,struct arm_smccc_res * res)568d4bd3d25SJens Wiklander static void optee_smccc_smc(unsigned long a0, unsigned long a1,
569d4bd3d25SJens Wiklander 			    unsigned long a2, unsigned long a3,
570d4bd3d25SJens Wiklander 			    unsigned long a4, unsigned long a5,
571d4bd3d25SJens Wiklander 			    unsigned long a6, unsigned long a7,
572d4bd3d25SJens Wiklander 			    struct arm_smccc_res *res)
573d4bd3d25SJens Wiklander {
574d4bd3d25SJens Wiklander 	arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
575d4bd3d25SJens Wiklander }
576d4bd3d25SJens Wiklander 
optee_smccc_hvc(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long a4,unsigned long a5,unsigned long a6,unsigned long a7,struct arm_smccc_res * res)577d4bd3d25SJens Wiklander static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
578d4bd3d25SJens Wiklander 			    unsigned long a2, unsigned long a3,
579d4bd3d25SJens Wiklander 			    unsigned long a4, unsigned long a5,
580d4bd3d25SJens Wiklander 			    unsigned long a6, unsigned long a7,
581d4bd3d25SJens Wiklander 			    struct arm_smccc_res *res)
582d4bd3d25SJens Wiklander {
583d4bd3d25SJens Wiklander 	arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
584d4bd3d25SJens Wiklander }
585d4bd3d25SJens Wiklander 
get_invoke_func(struct udevice * dev)586d4bd3d25SJens Wiklander static optee_invoke_fn *get_invoke_func(struct udevice *dev)
587d4bd3d25SJens Wiklander {
588d4bd3d25SJens Wiklander 	const char *method;
589d4bd3d25SJens Wiklander 
590d4bd3d25SJens Wiklander 	debug("optee: looking for conduit method in DT.\n");
591d4bd3d25SJens Wiklander 	method = ofnode_get_property(dev->node, "method", NULL);
592d4bd3d25SJens Wiklander 	if (!method) {
593d4bd3d25SJens Wiklander 		debug("optee: missing \"method\" property\n");
594d4bd3d25SJens Wiklander 		return ERR_PTR(-ENXIO);
595d4bd3d25SJens Wiklander 	}
596d4bd3d25SJens Wiklander 
597d4bd3d25SJens Wiklander 	if (!strcmp("hvc", method))
598d4bd3d25SJens Wiklander 		return optee_smccc_hvc;
599d4bd3d25SJens Wiklander 	else if (!strcmp("smc", method))
600d4bd3d25SJens Wiklander 		return optee_smccc_smc;
601d4bd3d25SJens Wiklander 
602d4bd3d25SJens Wiklander 	debug("optee: invalid \"method\" property: %s\n", method);
603d4bd3d25SJens Wiklander 	return ERR_PTR(-EINVAL);
604d4bd3d25SJens Wiklander }
605d4bd3d25SJens Wiklander 
optee_ofdata_to_platdata(struct udevice * dev)606d4bd3d25SJens Wiklander static int optee_ofdata_to_platdata(struct udevice *dev)
607d4bd3d25SJens Wiklander {
608d4bd3d25SJens Wiklander 	struct optee_pdata *pdata = dev_get_platdata(dev);
609d4bd3d25SJens Wiklander 
610d4bd3d25SJens Wiklander 	pdata->invoke_fn = get_invoke_func(dev);
611d4bd3d25SJens Wiklander 	if (IS_ERR(pdata->invoke_fn))
612d4bd3d25SJens Wiklander 		return PTR_ERR(pdata->invoke_fn);
613d4bd3d25SJens Wiklander 
614d4bd3d25SJens Wiklander 	return 0;
615d4bd3d25SJens Wiklander }
616d4bd3d25SJens Wiklander 
optee_probe(struct udevice * dev)617d4bd3d25SJens Wiklander static int optee_probe(struct udevice *dev)
618d4bd3d25SJens Wiklander {
619d4bd3d25SJens Wiklander 	struct optee_pdata *pdata = dev_get_platdata(dev);
620d4bd3d25SJens Wiklander 	u32 sec_caps;
621d4bd3d25SJens Wiklander 
622d4bd3d25SJens Wiklander 	if (!is_optee_api(pdata->invoke_fn)) {
623d4bd3d25SJens Wiklander 		debug("%s: OP-TEE api uid mismatch\n", __func__);
624d4bd3d25SJens Wiklander 		return -ENOENT;
625d4bd3d25SJens Wiklander 	}
626d4bd3d25SJens Wiklander 
627d4bd3d25SJens Wiklander 	print_os_revision(pdata->invoke_fn);
628d4bd3d25SJens Wiklander 
629d4bd3d25SJens Wiklander 	if (!api_revision_is_compatible(pdata->invoke_fn)) {
630d4bd3d25SJens Wiklander 		debug("%s: OP-TEE api revision mismatch\n", __func__);
631d4bd3d25SJens Wiklander 		return -ENOENT;
632d4bd3d25SJens Wiklander 	}
633d4bd3d25SJens Wiklander 
634d4bd3d25SJens Wiklander 	/*
635d4bd3d25SJens Wiklander 	 * OP-TEE can use both shared memory via predefined pool or as
636d4bd3d25SJens Wiklander 	 * dynamic shared memory provided by normal world. To keep things
637d4bd3d25SJens Wiklander 	 * simple we're only using dynamic shared memory in this driver.
638d4bd3d25SJens Wiklander 	 */
639d4bd3d25SJens Wiklander 	if (!exchange_capabilities(pdata->invoke_fn, &sec_caps) ||
640d4bd3d25SJens Wiklander 	    !(sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)) {
641d4bd3d25SJens Wiklander 		debug("%s: OP-TEE capabilities mismatch\n", __func__);
642d4bd3d25SJens Wiklander 		return -ENOENT;
643d4bd3d25SJens Wiklander 	}
644d4bd3d25SJens Wiklander 
645d4bd3d25SJens Wiklander 	return 0;
646d4bd3d25SJens Wiklander }
647d4bd3d25SJens Wiklander 
648d4bd3d25SJens Wiklander static const struct udevice_id optee_match[] = {
649d4bd3d25SJens Wiklander 	{ .compatible = "linaro,optee-tz" },
650d4bd3d25SJens Wiklander 	{},
651d4bd3d25SJens Wiklander };
652d4bd3d25SJens Wiklander 
653d4bd3d25SJens Wiklander U_BOOT_DRIVER(optee) = {
654d4bd3d25SJens Wiklander 	.name = "optee",
655d4bd3d25SJens Wiklander 	.id = UCLASS_TEE,
656d4bd3d25SJens Wiklander 	.of_match = optee_match,
657d4bd3d25SJens Wiklander 	.ofdata_to_platdata = optee_ofdata_to_platdata,
658d4bd3d25SJens Wiklander 	.probe = optee_probe,
659d4bd3d25SJens Wiklander 	.ops = &optee_ops,
660d4bd3d25SJens Wiklander 	.platdata_auto_alloc_size = sizeof(struct optee_pdata),
661*232cfd6dSJens Wiklander 	.priv_auto_alloc_size = sizeof(struct optee_private),
662d4bd3d25SJens Wiklander };
663