xref: /optee_os/core/pta/tests/dt_driver_test.c (revision 39d1e320ec639a05e1c04b4fe1729904a0399f2b)
1a564092cSEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause
2a564092cSEtienne Carriere /*
3a564092cSEtienne Carriere  * Copyright (c) 2022, Linaro Limited
4a564092cSEtienne Carriere  *
5a564092cSEtienne Carriere  * Tests introduce dummy test drivers and assiciated devices defined in
6a564092cSEtienne Carriere  * dt_driver_test.dtsi file with device resource dependencies.
7a564092cSEtienne Carriere  */
8a564092cSEtienne Carriere 
9a564092cSEtienne Carriere #include <assert.h>
10a564092cSEtienne Carriere #include <config.h>
11a564092cSEtienne Carriere #include <crypto/crypto.h>
12a564092cSEtienne Carriere #include <drivers/clk.h>
13a564092cSEtienne Carriere #include <drivers/clk_dt.h>
14a564092cSEtienne Carriere #include <drivers/gpio.h>
15a564092cSEtienne Carriere #include <drivers/rstctrl.h>
16a564092cSEtienne Carriere #include <initcall.h>
17a564092cSEtienne Carriere #include <kernel/dt_driver.h>
18a564092cSEtienne Carriere #include <malloc.h>
19a564092cSEtienne Carriere #include <sys/queue.h>
20a564092cSEtienne Carriere #include <tee_api_defines_extensions.h>
21a564092cSEtienne Carriere #include <tee_api_types.h>
22a564092cSEtienne Carriere 
23a564092cSEtienne Carriere #define DT_TEST_MSG(...)	FMSG("(dt-driver-test) " __VA_ARGS__)
24a564092cSEtienne Carriere 
25a564092cSEtienne Carriere /* Test state IDs */
26a564092cSEtienne Carriere enum dt_test_sid { DEFAULT = 0, IN_PROGRESS, SUCCESS, FAILED };
27a564092cSEtienne Carriere 
28a564092cSEtienne Carriere /*
29a564092cSEtienne Carriere  * DT tests state to be reported from PTA_INVOKE_TESTS_CMD_DT_TEST_STATUS
30a564092cSEtienne Carriere  * possibly printed to console. A test can be skipped (DEFAULT) or be
31a564092cSEtienne Carriere  * successful (SUCCESS) orthewise it has failed (IN_PROGRESS, FAILED).
32a564092cSEtienne Carriere  */
33a564092cSEtienne Carriere struct dt_test_state {
34a564092cSEtienne Carriere 	enum dt_test_sid probe_deferral;
35a564092cSEtienne Carriere 	enum dt_test_sid probe_clocks;
36a564092cSEtienne Carriere 	enum dt_test_sid probe_gpios;
37a564092cSEtienne Carriere 	enum dt_test_sid probe_resets;
38a564092cSEtienne Carriere 	enum dt_test_sid crypto_dependencies;
39a564092cSEtienne Carriere };
40a564092cSEtienne Carriere 
41a564092cSEtienne Carriere /*
42a564092cSEtienne Carriere  * References allocated from heap to be free once test completed
43a564092cSEtienne Carriere  * dt_test_alloc(), dt_test_free(), dt_test_free_all()
44a564092cSEtienne Carriere  */
45a564092cSEtienne Carriere struct dt_test_free_ref {
46a564092cSEtienne Carriere 	void *p;
47a564092cSEtienne Carriere 	SLIST_ENTRY(dt_test_free_ref) link;
48a564092cSEtienne Carriere };
49a564092cSEtienne Carriere 
50a564092cSEtienne Carriere static struct dt_test_state dt_test_state;
51a564092cSEtienne Carriere 
52a564092cSEtienne Carriere static const char __maybe_unused * const dt_test_str_sid[] = {
53a564092cSEtienne Carriere 	[DEFAULT] = "not run",
54a564092cSEtienne Carriere 	[IN_PROGRESS] = "in-progress",
55a564092cSEtienne Carriere 	[SUCCESS] = "successful",
56a564092cSEtienne Carriere 	[FAILED] = "failed",
57a564092cSEtienne Carriere };
58a564092cSEtienne Carriere 
59a564092cSEtienne Carriere /* Reference allocations during test for release_init_resource initcall level */
60a564092cSEtienne Carriere static SLIST_HEAD(dt_test_free_refs, dt_test_free_ref) dt_test_free_list =
61a564092cSEtienne Carriere 	SLIST_HEAD_INITIALIZER(dt_test_free_list);
62a564092cSEtienne Carriere 
dt_test_alloc(size_t size)63a564092cSEtienne Carriere static void __maybe_unused *dt_test_alloc(size_t size)
64a564092cSEtienne Carriere {
65a564092cSEtienne Carriere 	struct dt_test_free_ref *ref = NULL;
66a564092cSEtienne Carriere 
67a564092cSEtienne Carriere 	ref = calloc(1, sizeof(*ref) + size);
68a564092cSEtienne Carriere 	if (!ref)
69a564092cSEtienne Carriere 		return NULL;
70a564092cSEtienne Carriere 
71a564092cSEtienne Carriere 	ref->p = ref + 1;
72a564092cSEtienne Carriere 	SLIST_INSERT_HEAD(&dt_test_free_list, ref, link);
73a564092cSEtienne Carriere 
74a564092cSEtienne Carriere 	return ref->p;
75a564092cSEtienne Carriere }
76a564092cSEtienne Carriere 
dt_test_free(void * p)77a564092cSEtienne Carriere static void __maybe_unused dt_test_free(void *p)
78a564092cSEtienne Carriere {
79a564092cSEtienne Carriere 	struct dt_test_free_ref *ref = NULL;
80a564092cSEtienne Carriere 	struct dt_test_free_ref *t_ref = NULL;
81a564092cSEtienne Carriere 
82a564092cSEtienne Carriere 	if (!p)
83a564092cSEtienne Carriere 		return;
84a564092cSEtienne Carriere 
85a564092cSEtienne Carriere 	SLIST_FOREACH_SAFE(ref, &dt_test_free_list, link, t_ref) {
86a564092cSEtienne Carriere 		if (ref->p == p) {
87a564092cSEtienne Carriere 			SLIST_REMOVE(&dt_test_free_list, ref,
88a564092cSEtienne Carriere 				     dt_test_free_ref, link);
89a564092cSEtienne Carriere 			free(ref);
90a564092cSEtienne Carriere 			return;
91a564092cSEtienne Carriere 		}
92a564092cSEtienne Carriere 	}
93a564092cSEtienne Carriere 
94a564092cSEtienne Carriere 	panic();
95a564092cSEtienne Carriere }
96a564092cSEtienne Carriere 
dt_test_free_all(void)97a564092cSEtienne Carriere static void dt_test_free_all(void)
98a564092cSEtienne Carriere {
99a564092cSEtienne Carriere 	while (!SLIST_EMPTY(&dt_test_free_list)) {
100a564092cSEtienne Carriere 		struct dt_test_free_ref *ref = SLIST_FIRST(&dt_test_free_list);
101a564092cSEtienne Carriere 
102a564092cSEtienne Carriere 		SLIST_REMOVE(&dt_test_free_list, ref, dt_test_free_ref, link);
103a564092cSEtienne Carriere 		free(ref);
104a564092cSEtienne Carriere 	}
105a564092cSEtienne Carriere }
106a564092cSEtienne Carriere 
dt_test_release(void)107a564092cSEtienne Carriere static TEE_Result dt_test_release(void)
108a564092cSEtienne Carriere {
109a564092cSEtienne Carriere 	dt_test_free_all();
110a564092cSEtienne Carriere 
111a564092cSEtienne Carriere 	DT_TEST_MSG("Probe deferral: %s",
112a564092cSEtienne Carriere 		    dt_test_str_sid[dt_test_state.probe_deferral]);
113a564092cSEtienne Carriere 	DT_TEST_MSG("Clocks probe: %s",
114a564092cSEtienne Carriere 		    dt_test_str_sid[dt_test_state.probe_clocks]);
115a564092cSEtienne Carriere 	DT_TEST_MSG("GPIO ctrl probe: %s",
116a564092cSEtienne Carriere 		    dt_test_str_sid[dt_test_state.probe_gpios]);
117a564092cSEtienne Carriere 	DT_TEST_MSG("Reset ctrl probe: %s",
118a564092cSEtienne Carriere 		    dt_test_str_sid[dt_test_state.probe_resets]);
119a564092cSEtienne Carriere 	DT_TEST_MSG("Crypto deps.: %s",
120a564092cSEtienne Carriere 		    dt_test_str_sid[dt_test_state.crypto_dependencies]);
121a564092cSEtienne Carriere 
122a564092cSEtienne Carriere 	return dt_driver_test_status();
123a564092cSEtienne Carriere }
124a564092cSEtienne Carriere 
125a564092cSEtienne Carriere release_init_resource(dt_test_release);
126a564092cSEtienne Carriere 
dt_driver_test_status(void)127a564092cSEtienne Carriere TEE_Result dt_driver_test_status(void)
128a564092cSEtienne Carriere {
129a564092cSEtienne Carriere 	TEE_Result res = TEE_SUCCESS;
130a564092cSEtienne Carriere 
131a564092cSEtienne Carriere 	if (dt_test_state.probe_deferral != SUCCESS) {
132a564092cSEtienne Carriere 		EMSG("Probe deferral test failed");
133a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
134a564092cSEtienne Carriere 	}
135a564092cSEtienne Carriere 	if (IS_ENABLED(CFG_DRIVERS_CLK) &&
136a564092cSEtienne Carriere 	    dt_test_state.probe_clocks != SUCCESS) {
137a564092cSEtienne Carriere 		EMSG("Clocks probing test failed");
138a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
139a564092cSEtienne Carriere 	}
140a564092cSEtienne Carriere 	if (IS_ENABLED(CFG_DRIVERS_GPIOS) &&
141a564092cSEtienne Carriere 	    dt_test_state.probe_gpios != SUCCESS) {
142a564092cSEtienne Carriere 		EMSG("GPIO controllers probing test failed");
143a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
144a564092cSEtienne Carriere 	}
145a564092cSEtienne Carriere 	if (IS_ENABLED(CFG_DRIVERS_RSTCTRL) &&
146a564092cSEtienne Carriere 	    dt_test_state.probe_resets != SUCCESS) {
147a564092cSEtienne Carriere 		EMSG("Reset controllers probing test failed");
148a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
149a564092cSEtienne Carriere 	}
150a564092cSEtienne Carriere 	if (dt_test_state.crypto_dependencies != SUCCESS) {
151a564092cSEtienne Carriere 		EMSG("Probe deferral on crypto dependencies test failed");
152a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
153a564092cSEtienne Carriere 	}
154a564092cSEtienne Carriere 
155a564092cSEtienne Carriere 	return res;
156a564092cSEtienne Carriere }
157a564092cSEtienne Carriere 
probe_test_clocks(const void * fdt,int node)158a564092cSEtienne Carriere static TEE_Result probe_test_clocks(const void *fdt, int node)
159a564092cSEtienne Carriere {
160a564092cSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
161a564092cSEtienne Carriere 	struct clk *clk0 = NULL;
162a564092cSEtienne Carriere 	struct clk *clk1 = NULL;
163a564092cSEtienne Carriere 	struct clk *clk = NULL;
164a564092cSEtienne Carriere 
165a564092cSEtienne Carriere 	DT_TEST_MSG("Probe clocks");
166a564092cSEtienne Carriere 	dt_test_state.probe_clocks = IN_PROGRESS;
167a564092cSEtienne Carriere 
168a564092cSEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 0, &clk0);
169a564092cSEtienne Carriere 	if (res)
170a564092cSEtienne Carriere 		goto err;
171a564092cSEtienne Carriere 
172a564092cSEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 1, &clk1);
173a564092cSEtienne Carriere 	if (res)
174a564092cSEtienne Carriere 		goto err;
175a564092cSEtienne Carriere 
176a564092cSEtienne Carriere 	DT_TEST_MSG("Check valid clock references");
177a564092cSEtienne Carriere 
178a564092cSEtienne Carriere 	if (clk_enable(clk0)) {
179a564092cSEtienne Carriere 		DT_TEST_MSG("Can't enable %s", clk_get_name(clk0));
180a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
181a564092cSEtienne Carriere 		goto err;
182a564092cSEtienne Carriere 	}
183a564092cSEtienne Carriere 	clk_disable(clk0);
184a564092cSEtienne Carriere 
185a564092cSEtienne Carriere 	res = clk_dt_get_by_name(fdt, node, "clk0", &clk);
186a564092cSEtienne Carriere 	if (res || clk != clk0) {
187a564092cSEtienne Carriere 		DT_TEST_MSG("Unexpected clock reference");
188a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
189a564092cSEtienne Carriere 		goto err;
190a564092cSEtienne Carriere 	}
191a564092cSEtienne Carriere 
192a564092cSEtienne Carriere 	res = clk_dt_get_by_name(fdt, node, "clk1", &clk);
193a564092cSEtienne Carriere 	if (res || clk != clk1) {
194a564092cSEtienne Carriere 		DT_TEST_MSG("Unexpected clock reference");
195a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
196a564092cSEtienne Carriere 		goto err;
197a564092cSEtienne Carriere 	}
198a564092cSEtienne Carriere 
199a564092cSEtienne Carriere 	DT_TEST_MSG("Bad clock reference");
200a564092cSEtienne Carriere 
201a564092cSEtienne Carriere 	res = clk_dt_get_by_index(fdt, node, 3, &clk);
202a564092cSEtienne Carriere 	if (!res) {
203a564092cSEtienne Carriere 		DT_TEST_MSG("Unexpected clock found on invalid index");
204a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
205a564092cSEtienne Carriere 		goto err;
206a564092cSEtienne Carriere 	}
207a564092cSEtienne Carriere 
208a564092cSEtienne Carriere 	res = clk_dt_get_by_name(fdt, node, "clk2", &clk);
209a564092cSEtienne Carriere 	if (!res) {
210a564092cSEtienne Carriere 		DT_TEST_MSG("Unexpected clock found on invalid name");
211a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
212a564092cSEtienne Carriere 		goto err;
213a564092cSEtienne Carriere 	}
214a564092cSEtienne Carriere 
215a564092cSEtienne Carriere 	dt_test_state.probe_clocks = SUCCESS;
216a564092cSEtienne Carriere 	return TEE_SUCCESS;
217a564092cSEtienne Carriere 
218a564092cSEtienne Carriere err:
219a564092cSEtienne Carriere 	if (res != TEE_ERROR_DEFER_DRIVER_INIT)
220a564092cSEtienne Carriere 		dt_test_state.probe_clocks = FAILED;
221a564092cSEtienne Carriere 
222a564092cSEtienne Carriere 	return res;
223a564092cSEtienne Carriere }
224a564092cSEtienne Carriere 
probe_test_resets(const void * fdt,int node)225a564092cSEtienne Carriere static TEE_Result probe_test_resets(const void *fdt, int node)
226a564092cSEtienne Carriere {
227a564092cSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
228a564092cSEtienne Carriere 	struct rstctrl *rstctrl0 = NULL;
229a564092cSEtienne Carriere 	struct rstctrl *rstctrl1 = NULL;
230a564092cSEtienne Carriere 	struct rstctrl *rstctrl = NULL;
231a564092cSEtienne Carriere 
232a564092cSEtienne Carriere 	DT_TEST_MSG("Probe reset controllers");
233a564092cSEtienne Carriere 	dt_test_state.probe_resets = IN_PROGRESS;
234a564092cSEtienne Carriere 
235a564092cSEtienne Carriere 	res = rstctrl_dt_get_by_index(fdt, node, 0, &rstctrl0);
236a564092cSEtienne Carriere 	if (res)
237a564092cSEtienne Carriere 		goto err;
238a564092cSEtienne Carriere 
239a564092cSEtienne Carriere 	DT_TEST_MSG("Check valid reset controller");
240a564092cSEtienne Carriere 
241a564092cSEtienne Carriere 	if (rstctrl_assert(rstctrl0)) {
242a564092cSEtienne Carriere 		EMSG("Can't assert rstctrl %s", rstctrl_name(rstctrl0));
243a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
244a564092cSEtienne Carriere 		goto err;
245a564092cSEtienne Carriere 	}
246a564092cSEtienne Carriere 
247a564092cSEtienne Carriere 	res = rstctrl_dt_get_by_name(fdt, node, "rst0", &rstctrl);
248a564092cSEtienne Carriere 	if (res)
249a564092cSEtienne Carriere 		goto err;
250a564092cSEtienne Carriere 
251a564092cSEtienne Carriere 	if (rstctrl != rstctrl0) {
252a564092cSEtienne Carriere 		EMSG("Unexpected reset controller reference");
253a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
254a564092cSEtienne Carriere 		goto err;
255a564092cSEtienne Carriere 	}
256a564092cSEtienne Carriere 
257a564092cSEtienne Carriere 	res = rstctrl_dt_get_by_name(fdt, node, "rst1", &rstctrl1);
258a564092cSEtienne Carriere 	if (res)
259a564092cSEtienne Carriere 		goto err;
260a564092cSEtienne Carriere 
261a564092cSEtienne Carriere 	if (!rstctrl1 || rstctrl1 == rstctrl0) {
262a564092cSEtienne Carriere 		EMSG("Unexpected reset controller reference");
263a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
264a564092cSEtienne Carriere 		goto err;
265a564092cSEtienne Carriere 	}
266a564092cSEtienne Carriere 
267a564092cSEtienne Carriere 	dt_test_state.probe_resets = SUCCESS;
268a564092cSEtienne Carriere 	return TEE_SUCCESS;
269a564092cSEtienne Carriere 
270a564092cSEtienne Carriere err:
271a564092cSEtienne Carriere 	if (res != TEE_ERROR_DEFER_DRIVER_INIT)
272a564092cSEtienne Carriere 		dt_test_state.probe_resets = FAILED;
273a564092cSEtienne Carriere 
274a564092cSEtienne Carriere 	return res;
275a564092cSEtienne Carriere }
276a564092cSEtienne Carriere 
probe_test_gpios(const void * fdt,int node)277a564092cSEtienne Carriere static TEE_Result probe_test_gpios(const void *fdt, int node)
278a564092cSEtienne Carriere {
279a564092cSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
280a564092cSEtienne Carriere 	struct gpio *gpio = NULL;
281a564092cSEtienne Carriere 
282a564092cSEtienne Carriere 	DT_TEST_MSG("Probe GPIO controllers");
283a564092cSEtienne Carriere 	dt_test_state.probe_gpios = IN_PROGRESS;
284a564092cSEtienne Carriere 
285*39d1e320SPatrick Delaunay 	res = gpio_dt_cfg_by_index(fdt, node, 0, "test", GPIO_IN, &gpio);
286a564092cSEtienne Carriere 	if (res)
287a564092cSEtienne Carriere 		goto err;
288a564092cSEtienne Carriere 
289a564092cSEtienne Carriere 	if (gpio_get_direction(gpio) != GPIO_DIR_IN) {
290a564092cSEtienne Carriere 		EMSG("Unexpected gpio_get_direction() return value");
291a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
292a564092cSEtienne Carriere 		goto err;
293a564092cSEtienne Carriere 	}
294a564092cSEtienne Carriere 
295a564092cSEtienne Carriere 	/* GPIO is declared as ACTIVE_LOW in device-tree */
296a564092cSEtienne Carriere 	if (gpio_get_value(gpio) != GPIO_LEVEL_LOW) {
297a564092cSEtienne Carriere 		EMSG("Unexpected gpio_get_value() return value");
298a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
299a564092cSEtienne Carriere 		goto err;
300a564092cSEtienne Carriere 	}
301a564092cSEtienne Carriere 
302*39d1e320SPatrick Delaunay 	res = gpio_dt_cfg_by_index(fdt, node, 1, "test", GPIO_IN, &gpio);
303a564092cSEtienne Carriere 	if (res)
304a564092cSEtienne Carriere 		goto err;
305a564092cSEtienne Carriere 
306a564092cSEtienne Carriere 	if (gpio_get_direction(gpio) != GPIO_DIR_IN) {
307a564092cSEtienne Carriere 		EMSG("Unexpected gpio_get_direction() return value");
308a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
309a564092cSEtienne Carriere 		goto err;
310a564092cSEtienne Carriere 	}
311a564092cSEtienne Carriere 
312a564092cSEtienne Carriere 	if (gpio_get_value(gpio) != GPIO_LEVEL_HIGH) {
313a564092cSEtienne Carriere 		EMSG("Unexpected gpio_get_value() return value");
314a564092cSEtienne Carriere 		res = TEE_ERROR_GENERIC;
315a564092cSEtienne Carriere 		goto err;
316a564092cSEtienne Carriere 	}
317a564092cSEtienne Carriere 
318a564092cSEtienne Carriere 	dt_test_state.probe_gpios = SUCCESS;
319a564092cSEtienne Carriere 	return TEE_SUCCESS;
320a564092cSEtienne Carriere 
321a564092cSEtienne Carriere err:
322a564092cSEtienne Carriere 	if (res != TEE_ERROR_DEFER_DRIVER_INIT)
323a564092cSEtienne Carriere 		dt_test_state.probe_gpios = FAILED;
324a564092cSEtienne Carriere 
325a564092cSEtienne Carriere 	return res;
326a564092cSEtienne Carriere }
327a564092cSEtienne Carriere 
328a564092cSEtienne Carriere /*
329a564092cSEtienne Carriere  * Consumer test driver: instance probed from the compatible
330a564092cSEtienne Carriere  * node parsed in the DT. It consumes emulated resource obtained
331a564092cSEtienne Carriere  * from DT references. Probe shall succeed only once all resources
332a564092cSEtienne Carriere  * are found.
333a564092cSEtienne Carriere  */
dt_test_consumer_probe(const void * fdt,int node,const void * compat_data __unused)334a564092cSEtienne Carriere static TEE_Result dt_test_consumer_probe(const void *fdt, int node,
335a564092cSEtienne Carriere 					 const void *compat_data __unused)
336a564092cSEtienne Carriere {
337a564092cSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
338a564092cSEtienne Carriere 
339a564092cSEtienne Carriere 	if (IS_ENABLED(CFG_DRIVERS_CLK)) {
340a564092cSEtienne Carriere 		res = probe_test_clocks(fdt, node);
341a564092cSEtienne Carriere 		if (res)
342a564092cSEtienne Carriere 			goto err_probe;
343a564092cSEtienne Carriere 	}
344a564092cSEtienne Carriere 
345a564092cSEtienne Carriere 	if (IS_ENABLED(CFG_DRIVERS_RSTCTRL)) {
346a564092cSEtienne Carriere 		res = probe_test_resets(fdt, node);
347a564092cSEtienne Carriere 		if (res)
348a564092cSEtienne Carriere 			goto err_probe;
349a564092cSEtienne Carriere 	}
350a564092cSEtienne Carriere 
351a564092cSEtienne Carriere 	if (IS_ENABLED(CFG_DRIVERS_GPIO)) {
352a564092cSEtienne Carriere 		res = probe_test_gpios(fdt, node);
353a564092cSEtienne Carriere 		if (res)
354a564092cSEtienne Carriere 			goto err_probe;
355a564092cSEtienne Carriere 	}
356a564092cSEtienne Carriere 
357a564092cSEtienne Carriere 	if (dt_test_state.probe_deferral != IN_PROGRESS) {
358a564092cSEtienne Carriere 		dt_test_state.probe_deferral = FAILED;
359a564092cSEtienne Carriere 		return TEE_ERROR_GENERIC;
360a564092cSEtienne Carriere 	}
361a564092cSEtienne Carriere 
362a564092cSEtienne Carriere 	dt_test_state.probe_deferral = SUCCESS;
363a564092cSEtienne Carriere 
364a564092cSEtienne Carriere 	return TEE_SUCCESS;
365a564092cSEtienne Carriere 
366a564092cSEtienne Carriere err_probe:
367a564092cSEtienne Carriere 	assert(res);
368a564092cSEtienne Carriere 
369a564092cSEtienne Carriere 	if (res == TEE_ERROR_DEFER_DRIVER_INIT &&
370a564092cSEtienne Carriere 	    dt_test_state.probe_deferral == DEFAULT) {
371a564092cSEtienne Carriere 		/* We expect at least a probe deferral */
372a564092cSEtienne Carriere 		dt_test_state.probe_deferral = IN_PROGRESS;
373a564092cSEtienne Carriere 	}
374a564092cSEtienne Carriere 
375a564092cSEtienne Carriere 	return res;
376a564092cSEtienne Carriere }
377a564092cSEtienne Carriere 
378a564092cSEtienne Carriere static const struct dt_device_match dt_test_consumer_match_table[] = {
379a564092cSEtienne Carriere 	{ .compatible = "linaro,dt-test-consumer", },
380a564092cSEtienne Carriere 	{ }
381a564092cSEtienne Carriere };
382a564092cSEtienne Carriere 
383a564092cSEtienne Carriere DEFINE_DT_DRIVER(dt_test_consumer_driver) = {
384a564092cSEtienne Carriere 	.name = "dt-test-consumer",
385a564092cSEtienne Carriere 	.match_table = dt_test_consumer_match_table,
386a564092cSEtienne Carriere 	.probe = dt_test_consumer_probe,
387a564092cSEtienne Carriere };
388a564092cSEtienne Carriere 
dt_test_crypt_consumer_probe(const void * fdt __unused,int node __unused,const void * compat_data __unused)389a564092cSEtienne Carriere static TEE_Result dt_test_crypt_consumer_probe(const void *fdt __unused,
390a564092cSEtienne Carriere 					       int node __unused,
391a564092cSEtienne Carriere 					       const void *compat_data __unused)
392a564092cSEtienne Carriere {
393a564092cSEtienne Carriere 	TEE_Result res = dt_driver_get_crypto();
394a564092cSEtienne Carriere 	uint8_t __maybe_unused byte = 0;
395a564092cSEtienne Carriere 
396a564092cSEtienne Carriere 	if (res == TEE_ERROR_DEFER_DRIVER_INIT &&
397a564092cSEtienne Carriere 	    dt_test_state.crypto_dependencies == DEFAULT) {
398a564092cSEtienne Carriere 		/* We expect to be deferred */
399a564092cSEtienne Carriere 		dt_test_state.crypto_dependencies = IN_PROGRESS;
400a564092cSEtienne Carriere 	}
401a564092cSEtienne Carriere 
402a564092cSEtienne Carriere 	if (res)
403a564092cSEtienne Carriere 		return res;
404a564092cSEtienne Carriere 
405a564092cSEtienne Carriere 	if (dt_test_state.crypto_dependencies == DEFAULT) {
406a564092cSEtienne Carriere 		EMSG("Test expects at least a driver probe deferral");
407a564092cSEtienne Carriere 		dt_test_state.crypto_dependencies = FAILED;
408a564092cSEtienne Carriere 		return TEE_ERROR_GENERIC;
409a564092cSEtienne Carriere 	}
410a564092cSEtienne Carriere 
411a564092cSEtienne Carriere 	if (crypto_rng_read(&byte, sizeof(byte))) {
412a564092cSEtienne Carriere 		dt_test_state.crypto_dependencies = FAILED;
413a564092cSEtienne Carriere 		return TEE_ERROR_GENERIC;
414a564092cSEtienne Carriere 	}
415a564092cSEtienne Carriere 
416a564092cSEtienne Carriere 	dt_test_state.crypto_dependencies = SUCCESS;
417a564092cSEtienne Carriere 	return TEE_SUCCESS;
418a564092cSEtienne Carriere }
419a564092cSEtienne Carriere 
420a564092cSEtienne Carriere static const struct dt_device_match dt_test_crypt_consumer_match_table[] = {
421a564092cSEtienne Carriere 	{ .compatible = "linaro,dt-test-crypt-consumer", },
422a564092cSEtienne Carriere 	{ }
423a564092cSEtienne Carriere };
424a564092cSEtienne Carriere 
425a564092cSEtienne Carriere DEFINE_DT_DRIVER(dt_test_consumer_driver) = {
426a564092cSEtienne Carriere 	.name = "dt-test-crypt-consumer",
427a564092cSEtienne Carriere 	.match_table = dt_test_crypt_consumer_match_table,
428a564092cSEtienne Carriere 	.probe = dt_test_crypt_consumer_probe,
429a564092cSEtienne Carriere };
430a564092cSEtienne Carriere 
431a564092cSEtienne Carriere #ifdef CFG_DRIVERS_CLK
432a564092cSEtienne Carriere #define DT_TEST_CLK_COUNT		2
433a564092cSEtienne Carriere 
434a564092cSEtienne Carriere #define DT_TEST_CLK0_BINDING_ID		3
435a564092cSEtienne Carriere #define DT_TEST_CLK1_BINDING_ID		7
436a564092cSEtienne Carriere 
437a564092cSEtienne Carriere static const char *dt_test_clk_name[DT_TEST_CLK_COUNT] = {
438a564092cSEtienne Carriere 	"dt_test-clk3",
439a564092cSEtienne Carriere 	"dt_test-clk7",
440a564092cSEtienne Carriere };
441a564092cSEtienne Carriere 
442a564092cSEtienne Carriere /* Emulating a clock does not require operators */
443a564092cSEtienne Carriere static const struct clk_ops dt_test_clock_provider_ops;
444a564092cSEtienne Carriere 
dt_test_get_clk(struct dt_pargs * args,void * data,struct clk ** out_device)445b357d34fSEtienne Carriere static TEE_Result dt_test_get_clk(struct dt_pargs *args, void *data,
446b357d34fSEtienne Carriere 				  struct clk **out_device)
447a564092cSEtienne Carriere {
448a564092cSEtienne Carriere 	struct clk *clk_ref = data;
449a564092cSEtienne Carriere 	struct clk *clk = NULL;
450a564092cSEtienne Carriere 
451b357d34fSEtienne Carriere 	if (args->args_count != 1)
452b357d34fSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
453a564092cSEtienne Carriere 
454a564092cSEtienne Carriere 	switch (args->args[0]) {
455a564092cSEtienne Carriere 	case DT_TEST_CLK0_BINDING_ID:
456a564092cSEtienne Carriere 		clk = clk_ref;
457a564092cSEtienne Carriere 		break;
458a564092cSEtienne Carriere 	case DT_TEST_CLK1_BINDING_ID:
459a564092cSEtienne Carriere 		clk = clk_ref + 1;
460a564092cSEtienne Carriere 		break;
461a564092cSEtienne Carriere 	default:
462a564092cSEtienne Carriere 		EMSG("Unexpected binding ID %"PRIu32, args->args[0]);
463b357d34fSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
464a564092cSEtienne Carriere 	}
465a564092cSEtienne Carriere 
466a564092cSEtienne Carriere 	DT_TEST_MSG("Providing clock %s", clk_get_name(clk));
467a564092cSEtienne Carriere 
468b357d34fSEtienne Carriere 	*out_device = clk;
469b357d34fSEtienne Carriere 	return TEE_SUCCESS;
470a564092cSEtienne Carriere }
471a564092cSEtienne Carriere 
dt_test_clock_provider_probe(const void * fdt,int node,const void * compat_data __unused)472a564092cSEtienne Carriere static TEE_Result dt_test_clock_provider_probe(const void *fdt, int node,
473a564092cSEtienne Carriere 					       const void *compat_data __unused)
474a564092cSEtienne Carriere {
475a564092cSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
476a564092cSEtienne Carriere 	struct clk *clk = NULL;
477a564092cSEtienne Carriere 	size_t n = 0;
478a564092cSEtienne Carriere 
479a564092cSEtienne Carriere 	DT_TEST_MSG("Register clocks");
480a564092cSEtienne Carriere 
481a564092cSEtienne Carriere 	clk = dt_test_alloc(DT_TEST_CLK_COUNT * sizeof(*clk));
482a564092cSEtienne Carriere 	if (!clk)
483a564092cSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
484a564092cSEtienne Carriere 
485a564092cSEtienne Carriere 	for (n = 0; n < DT_TEST_CLK_COUNT; n++) {
486a564092cSEtienne Carriere 		clk[n].ops = &dt_test_clock_provider_ops;
487a564092cSEtienne Carriere 		clk[n].name = dt_test_clk_name[n];
488a564092cSEtienne Carriere 
489a564092cSEtienne Carriere 		res = clk_register(clk + n);
490a564092cSEtienne Carriere 		if (res)
491a564092cSEtienne Carriere 			goto err;
492a564092cSEtienne Carriere 	}
493a564092cSEtienne Carriere 
494a564092cSEtienne Carriere 	res = clk_dt_register_clk_provider(fdt, node, dt_test_get_clk, clk);
495a564092cSEtienne Carriere 	if (res)
496a564092cSEtienne Carriere 		goto err;
497a564092cSEtienne Carriere 
498a564092cSEtienne Carriere 	return TEE_SUCCESS;
499a564092cSEtienne Carriere 
500a564092cSEtienne Carriere err:
501a564092cSEtienne Carriere 	dt_test_free(clk);
502a564092cSEtienne Carriere 	return res;
503a564092cSEtienne Carriere }
504a564092cSEtienne Carriere 
505a564092cSEtienne Carriere CLK_DT_DECLARE(dt_test_clock_provider, "linaro,dt-test-provider",
506a564092cSEtienne Carriere 	       dt_test_clock_provider_probe);
507a564092cSEtienne Carriere #endif /* CFG_DRIVERS_CLK */
508a564092cSEtienne Carriere 
509a564092cSEtienne Carriere #ifdef CFG_DRIVERS_RSTCTRL
510a564092cSEtienne Carriere #define DT_TEST_RSTCTRL_COUNT		2
511a564092cSEtienne Carriere 
512a564092cSEtienne Carriere #define DT_TEST_RSTCTRL0_BINDING_ID	5
513a564092cSEtienne Carriere #define DT_TEST_RSTCTRL1_BINDING_ID	35
514a564092cSEtienne Carriere 
515a564092cSEtienne Carriere struct dt_test_rstctrl {
516a564092cSEtienne Carriere 	unsigned int dt_binding;
517a564092cSEtienne Carriere 	struct rstctrl rstctrl;
518a564092cSEtienne Carriere };
519a564092cSEtienne Carriere 
to_test_rstctrl(struct rstctrl * rstctrl)520a564092cSEtienne Carriere static struct dt_test_rstctrl *to_test_rstctrl(struct rstctrl *rstctrl)
521a564092cSEtienne Carriere {
522a564092cSEtienne Carriere 	return container_of(rstctrl, struct dt_test_rstctrl, rstctrl);
523a564092cSEtienne Carriere }
524a564092cSEtienne Carriere 
dt_test_rstctrl_stub(struct rstctrl * rstctrl __maybe_unused,unsigned int to_us __unused)525a564092cSEtienne Carriere static TEE_Result dt_test_rstctrl_stub(struct rstctrl *rstctrl __maybe_unused,
526a564092cSEtienne Carriere 				       unsigned int to_us __unused)
527a564092cSEtienne Carriere {
528a564092cSEtienne Carriere 	struct dt_test_rstctrl *dev = to_test_rstctrl(rstctrl);
529a564092cSEtienne Carriere 
530a564092cSEtienne Carriere 	switch (dev->dt_binding) {
531a564092cSEtienne Carriere 	case DT_TEST_RSTCTRL0_BINDING_ID:
532a564092cSEtienne Carriere 	case DT_TEST_RSTCTRL1_BINDING_ID:
533a564092cSEtienne Carriere 		return TEE_SUCCESS;
534a564092cSEtienne Carriere 	default:
535a564092cSEtienne Carriere 		EMSG("Unexpected rstctrl reference");
536a564092cSEtienne Carriere 		return TEE_ERROR_GENERIC;
537a564092cSEtienne Carriere 	}
538a564092cSEtienne Carriere }
539a564092cSEtienne Carriere 
dt_test_rstctrl_name(struct rstctrl * rstctrl __maybe_unused)540a564092cSEtienne Carriere static const char *dt_test_rstctrl_name(struct rstctrl *rstctrl __maybe_unused)
541a564092cSEtienne Carriere {
542a564092cSEtienne Carriere 	static const char *rstctrl_name[DT_TEST_RSTCTRL_COUNT] = {
543a564092cSEtienne Carriere 		"dt_test-rstctrl5",
544a564092cSEtienne Carriere 		"dt_test-rstctrl35",
545a564092cSEtienne Carriere 	};
546a564092cSEtienne Carriere 	struct dt_test_rstctrl *dev = to_test_rstctrl(rstctrl);
547a564092cSEtienne Carriere 
548a564092cSEtienne Carriere 	switch (dev->dt_binding) {
549a564092cSEtienne Carriere 	case DT_TEST_RSTCTRL0_BINDING_ID:
550a564092cSEtienne Carriere 		return rstctrl_name[0];
551a564092cSEtienne Carriere 	case DT_TEST_RSTCTRL1_BINDING_ID:
552a564092cSEtienne Carriere 		return rstctrl_name[1];
553a564092cSEtienne Carriere 	default:
554a564092cSEtienne Carriere 		EMSG("Unexpected rstctrl reference");
555a564092cSEtienne Carriere 		return NULL;
556a564092cSEtienne Carriere 	}
557a564092cSEtienne Carriere }
558a564092cSEtienne Carriere 
559a564092cSEtienne Carriere const struct rstctrl_ops dt_test_rstctrl_ops = {
560a564092cSEtienne Carriere 	.assert_level = dt_test_rstctrl_stub,
561a564092cSEtienne Carriere 	.deassert_level = dt_test_rstctrl_stub,
562a564092cSEtienne Carriere 	.get_name = dt_test_rstctrl_name,
563a564092cSEtienne Carriere };
564a564092cSEtienne Carriere 
dt_test_get_rstctrl(struct dt_pargs * args,void * data,struct rstctrl ** out_device)565b357d34fSEtienne Carriere static TEE_Result dt_test_get_rstctrl(struct dt_pargs *args, void *data,
566b357d34fSEtienne Carriere 				      struct rstctrl **out_device)
567a564092cSEtienne Carriere {
568a564092cSEtienne Carriere 	struct dt_test_rstctrl *ref = data;
569a564092cSEtienne Carriere 	struct rstctrl *rstctrl = NULL;
570a564092cSEtienne Carriere 
571b357d34fSEtienne Carriere 	if (args->args_count != 1)
572b357d34fSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
573a564092cSEtienne Carriere 
574a564092cSEtienne Carriere 	switch (args->args[0]) {
575a564092cSEtienne Carriere 	case DT_TEST_RSTCTRL0_BINDING_ID:
576a564092cSEtienne Carriere 		rstctrl = &ref[0].rstctrl;
577a564092cSEtienne Carriere 		break;
578a564092cSEtienne Carriere 	case DT_TEST_RSTCTRL1_BINDING_ID:
579a564092cSEtienne Carriere 		rstctrl = &ref[1].rstctrl;
580a564092cSEtienne Carriere 		break;
581a564092cSEtienne Carriere 	default:
582a564092cSEtienne Carriere 		EMSG("Unexpected binding ID %"PRIu32, args->args[0]);
583b357d34fSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
584a564092cSEtienne Carriere 	}
585a564092cSEtienne Carriere 
586a564092cSEtienne Carriere 	DT_TEST_MSG("Providing reset controller %s", rstctrl_name(rstctrl));
587a564092cSEtienne Carriere 
588b357d34fSEtienne Carriere 	*out_device = rstctrl;
589b357d34fSEtienne Carriere 
590b357d34fSEtienne Carriere 	return TEE_SUCCESS;
591a564092cSEtienne Carriere }
592a564092cSEtienne Carriere 
dt_test_rstctrl_provider_probe(const void * fdt,int offs,const void * data __unused)593a564092cSEtienne Carriere static TEE_Result dt_test_rstctrl_provider_probe(const void *fdt, int offs,
594a564092cSEtienne Carriere 						 const void *data __unused)
595a564092cSEtienne Carriere {
596a564092cSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
597a564092cSEtienne Carriere 	struct dt_test_rstctrl *devices = NULL;
598a564092cSEtienne Carriere 
599a564092cSEtienne Carriere 	DT_TEST_MSG("Register reset controllers");
600a564092cSEtienne Carriere 
601a564092cSEtienne Carriere 	assert(rstctrl_ops_is_valid(&dt_test_rstctrl_ops));
602a564092cSEtienne Carriere 
603a564092cSEtienne Carriere 	devices = dt_test_alloc(DT_TEST_RSTCTRL_COUNT * sizeof(*devices));
604a564092cSEtienne Carriere 	if (!devices)
605a564092cSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
606a564092cSEtienne Carriere 
607a564092cSEtienne Carriere 	devices[0].rstctrl.ops = &dt_test_rstctrl_ops;
608a564092cSEtienne Carriere 	devices[0].dt_binding = DT_TEST_RSTCTRL0_BINDING_ID;
609a564092cSEtienne Carriere 
610a564092cSEtienne Carriere 	devices[1].rstctrl.ops = &dt_test_rstctrl_ops;
611a564092cSEtienne Carriere 	devices[1].dt_binding = DT_TEST_RSTCTRL1_BINDING_ID;
612a564092cSEtienne Carriere 
613a564092cSEtienne Carriere 	res = rstctrl_register_provider(fdt, offs, dt_test_get_rstctrl,
614a564092cSEtienne Carriere 					devices);
615a564092cSEtienne Carriere 	if (res) {
616a564092cSEtienne Carriere 		dt_test_free(devices);
617a564092cSEtienne Carriere 		return res;
618a564092cSEtienne Carriere 	}
619a564092cSEtienne Carriere 
620a564092cSEtienne Carriere 	return TEE_SUCCESS;
621a564092cSEtienne Carriere }
622a564092cSEtienne Carriere 
623a564092cSEtienne Carriere RSTCTRL_DT_DECLARE(dt_test_rstctrl_provider, "linaro,dt-test-provider",
624a564092cSEtienne Carriere 		   dt_test_rstctrl_provider_probe);
625a564092cSEtienne Carriere #endif /* CFG_DRIVERS_RSTCTRL */
626a564092cSEtienne Carriere 
627a564092cSEtienne Carriere #ifdef CFG_DRIVERS_GPIO
628a564092cSEtienne Carriere #define DT_TEST_GPIO_COUNT	2
629a564092cSEtienne Carriere 
630a564092cSEtienne Carriere #define DT_TEST_GPIO0_PIN	1
631a564092cSEtienne Carriere #define DT_TEST_GPIO0_FLAGS	GPIO_ACTIVE_LOW
632a564092cSEtienne Carriere #define DT_TEST_GPIO1_PIN	2
633a564092cSEtienne Carriere #define DT_TEST_GPIO1_FLAGS	GPIO_PULL_UP
634a564092cSEtienne Carriere 
635a564092cSEtienne Carriere struct dt_test_gpio {
636a564092cSEtienne Carriere 	unsigned int pin;
637a564092cSEtienne Carriere 	unsigned int flags;
638a564092cSEtienne Carriere 	struct gpio_chip gpio_chip;
639a564092cSEtienne Carriere };
640a564092cSEtienne Carriere 
to_test_gpio(struct gpio_chip * chip)641a564092cSEtienne Carriere static struct dt_test_gpio *to_test_gpio(struct gpio_chip *chip)
642a564092cSEtienne Carriere {
643a564092cSEtienne Carriere 	return container_of(chip, struct dt_test_gpio, gpio_chip);
644a564092cSEtienne Carriere }
645a564092cSEtienne Carriere 
dt_test_gpio_get_direction(struct gpio_chip * chip,unsigned int gpio_pin)646a564092cSEtienne Carriere static enum gpio_dir dt_test_gpio_get_direction(struct gpio_chip *chip,
647a564092cSEtienne Carriere 						unsigned int gpio_pin)
648a564092cSEtienne Carriere {
649a564092cSEtienne Carriere 	struct dt_test_gpio *dtg = to_test_gpio(chip);
650a564092cSEtienne Carriere 
651a564092cSEtienne Carriere 	if (dtg->pin != gpio_pin)
652a564092cSEtienne Carriere 		panic("Invalid GPIO number");
653a564092cSEtienne Carriere 
654a564092cSEtienne Carriere 	return GPIO_DIR_IN;
655a564092cSEtienne Carriere }
656a564092cSEtienne Carriere 
dt_test_gpio_set_direction(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_dir direction __unused)657a564092cSEtienne Carriere static void dt_test_gpio_set_direction(struct gpio_chip *chip,
658a564092cSEtienne Carriere 				       unsigned int gpio_pin,
659a564092cSEtienne Carriere 				       enum gpio_dir direction __unused)
660a564092cSEtienne Carriere {
661a564092cSEtienne Carriere 	struct dt_test_gpio *dtg = to_test_gpio(chip);
662a564092cSEtienne Carriere 
663a564092cSEtienne Carriere 	if (dtg->pin != gpio_pin)
664a564092cSEtienne Carriere 		panic("Invalid GPIO number");
665a564092cSEtienne Carriere }
666a564092cSEtienne Carriere 
dt_test_gpio_get_value(struct gpio_chip * chip,unsigned int gpio_pin)667a564092cSEtienne Carriere static enum gpio_level dt_test_gpio_get_value(struct gpio_chip *chip,
668a564092cSEtienne Carriere 					      unsigned int gpio_pin)
669a564092cSEtienne Carriere {
670a564092cSEtienne Carriere 	struct dt_test_gpio *dtg = to_test_gpio(chip);
671a564092cSEtienne Carriere 
672a564092cSEtienne Carriere 	if (dtg->pin != gpio_pin)
673a564092cSEtienne Carriere 		panic("Invalid GPIO number");
674a564092cSEtienne Carriere 
675a564092cSEtienne Carriere 	return GPIO_LEVEL_HIGH;
676a564092cSEtienne Carriere }
677a564092cSEtienne Carriere 
dt_test_gpio_set_value(struct gpio_chip * chip,unsigned int gpio_pin,enum gpio_level value __unused)678a564092cSEtienne Carriere static void dt_test_gpio_set_value(struct gpio_chip *chip,
679a564092cSEtienne Carriere 				   unsigned int gpio_pin,
680a564092cSEtienne Carriere 				   enum gpio_level value __unused)
681a564092cSEtienne Carriere {
682a564092cSEtienne Carriere 	struct dt_test_gpio *dtg = to_test_gpio(chip);
683a564092cSEtienne Carriere 
684a564092cSEtienne Carriere 	if (dtg->pin != gpio_pin)
685a564092cSEtienne Carriere 		panic("Invalid GPIO number");
686a564092cSEtienne Carriere }
687a564092cSEtienne Carriere 
688a564092cSEtienne Carriere static const struct gpio_ops dt_test_gpio_ops = {
689a564092cSEtienne Carriere 	.get_direction = dt_test_gpio_get_direction,
690a564092cSEtienne Carriere 	.set_direction = dt_test_gpio_set_direction,
691a564092cSEtienne Carriere 	.get_value = dt_test_gpio_get_value,
692a564092cSEtienne Carriere 	.set_value = dt_test_gpio_set_value,
693a564092cSEtienne Carriere };
694a564092cSEtienne Carriere 
dt_test_gpio_get_dt(struct dt_pargs * args,void * data,struct gpio ** out_device)695b357d34fSEtienne Carriere static TEE_Result dt_test_gpio_get_dt(struct dt_pargs *args, void *data,
696b357d34fSEtienne Carriere 				      struct gpio **out_device)
697a564092cSEtienne Carriere {
698b357d34fSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
699a564092cSEtienne Carriere 	struct gpio *gpio = NULL;
700a564092cSEtienne Carriere 	struct dt_test_gpio *gpios = (struct dt_test_gpio *)data;
701a564092cSEtienne Carriere 
702b357d34fSEtienne Carriere 	res = gpio_dt_alloc_pin(args, &gpio);
703b357d34fSEtienne Carriere 	if (res)
704b357d34fSEtienne Carriere 		return res;
705a564092cSEtienne Carriere 
706a564092cSEtienne Carriere 	switch (gpio->pin) {
707a564092cSEtienne Carriere 	case DT_TEST_GPIO0_PIN:
708a564092cSEtienne Carriere 		gpio->chip = &gpios[0].gpio_chip;
709a564092cSEtienne Carriere 		if (gpio->dt_flags != gpios[0].flags) {
710a564092cSEtienne Carriere 			EMSG("Unexpected dt_flags %#"PRIx32, gpio->dt_flags);
711a564092cSEtienne Carriere 			free(gpio);
712b357d34fSEtienne Carriere 			return TEE_ERROR_GENERIC;
713a564092cSEtienne Carriere 		}
714a564092cSEtienne Carriere 		break;
715a564092cSEtienne Carriere 	case DT_TEST_GPIO1_PIN:
716a564092cSEtienne Carriere 		gpio->chip = &gpios[1].gpio_chip;
717a564092cSEtienne Carriere 		if (gpio->dt_flags != gpios[1].flags) {
718a564092cSEtienne Carriere 			EMSG("Unexpected dt_flags %#"PRIx32, gpio->dt_flags);
719a564092cSEtienne Carriere 			free(gpio);
720b357d34fSEtienne Carriere 			return TEE_ERROR_GENERIC;
721a564092cSEtienne Carriere 		}
722a564092cSEtienne Carriere 		break;
723a564092cSEtienne Carriere 	default:
724a564092cSEtienne Carriere 		EMSG("Unexpected pin ID %u", gpio->pin);
725a564092cSEtienne Carriere 		free(gpio);
726b357d34fSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
727a564092cSEtienne Carriere 	};
728a564092cSEtienne Carriere 
729b357d34fSEtienne Carriere 	*out_device = gpio;
730b357d34fSEtienne Carriere 
731b357d34fSEtienne Carriere 	return TEE_SUCCESS;
732a564092cSEtienne Carriere }
733a564092cSEtienne Carriere 
dt_test_gpio_provider_probe(const void * fdt,int offs,const void * data __unused)734a564092cSEtienne Carriere static TEE_Result dt_test_gpio_provider_probe(const void *fdt, int offs,
735a564092cSEtienne Carriere 					      const void *data __unused)
736a564092cSEtienne Carriere {
737a564092cSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
738a564092cSEtienne Carriere 	struct dt_test_gpio *gpios = NULL;
739a564092cSEtienne Carriere 
740a564092cSEtienne Carriere 	DT_TEST_MSG("Register GPIO controllers");
741a564092cSEtienne Carriere 
742a564092cSEtienne Carriere 	assert(gpio_ops_is_valid(&dt_test_gpio_ops));
743a564092cSEtienne Carriere 
744a564092cSEtienne Carriere 	gpios = dt_test_alloc(DT_TEST_GPIO_COUNT * sizeof(*gpios));
745a564092cSEtienne Carriere 	if (!gpios)
746a564092cSEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
747a564092cSEtienne Carriere 
748a564092cSEtienne Carriere 	gpios[0].gpio_chip.ops = &dt_test_gpio_ops;
749a564092cSEtienne Carriere 	gpios[0].pin = DT_TEST_GPIO0_PIN;
750a564092cSEtienne Carriere 	gpios[0].flags = DT_TEST_GPIO0_FLAGS;
751a564092cSEtienne Carriere 
752a564092cSEtienne Carriere 	gpios[1].gpio_chip.ops = &dt_test_gpio_ops;
753a564092cSEtienne Carriere 	gpios[1].pin = DT_TEST_GPIO1_PIN;
754a564092cSEtienne Carriere 	gpios[1].flags = DT_TEST_GPIO1_FLAGS;
755a564092cSEtienne Carriere 
756a564092cSEtienne Carriere 	res = gpio_register_provider(fdt, offs, dt_test_gpio_get_dt, gpios);
757a564092cSEtienne Carriere 	if (res) {
758a564092cSEtienne Carriere 		dt_test_free(gpios);
759a564092cSEtienne Carriere 		return res;
760a564092cSEtienne Carriere 	}
761a564092cSEtienne Carriere 
762a564092cSEtienne Carriere 	return TEE_SUCCESS;
763a564092cSEtienne Carriere }
764a564092cSEtienne Carriere 
765a564092cSEtienne Carriere GPIO_DT_DECLARE(dt_test_gpio_provider, "linaro,dt-test-provider",
766a564092cSEtienne Carriere 		dt_test_gpio_provider_probe);
767a564092cSEtienne Carriere #endif /* CFG_DRIVERS_GPIO */
768