xref: /optee_os/core/kernel/dt_driver.c (revision 3de8f0de3eb54e05bdbf031d101ff2429348835c)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2021, Linaro Limited
4  * Copyright (c) 2021, Bootlin
5  * Copyright (c) 2021, Linaro Limited
6  * Copyright (c) 2021, STMicroelectronics
7  */
8 
9 #include <assert.h>
10 #include <config.h>
11 #include <initcall.h>
12 #include <kernel/boot.h>
13 #include <kernel/dt.h>
14 #include <kernel/dt_driver.h>
15 #include <libfdt.h>
16 #include <malloc.h>
17 #include <sys/queue.h>
18 #include <tee_api_defines_extensions.h>
19 #include <tee_api_types.h>
20 
21 /*
22  * struct dt_driver_probe - Node instance in secure FDT to probe a driver for
23  *
24  * @link: List hook
25  * @nodeoffset: Node offset of device referenced in the FDT
26  * @type: One of DT_DRIVER_* or DT_DRIVER_NOTYPE.
27  * @deferrals: Driver probe deferrals count
28  * @dt_drv: Matching driver to probe if found or NULL
29  * @dm: Matching reference if applicable or NULL
30  */
31 struct dt_driver_probe {
32 	int nodeoffset;
33 	enum dt_driver_type type;
34 	unsigned int deferrals;
35 	const struct dt_driver *dt_drv;
36 	const struct dt_device_match *dm;
37 	TAILQ_ENTRY(dt_driver_probe) link;
38 };
39 
40 /*
41  * struct dt_driver_provider - DT related info on probed device
42  *
43  * Saves information on the probed device so that device
44  * drivers can get resources from DT phandle and related arguments.
45  *
46  * @nodeoffset: Node offset of device referenced in the FDT
47  * @type: One of DT_DRIVER_* or DT_DRIVER_NOTYPE.
48  * @provider_cells: Cells count in the FDT used by the driver's references
49  * @get_of_device: Function to get driver's device ref from phandle data
50  * @priv_data: Driver private data passed as @get_of_device argument
51  * @link: Reference in DT driver providers list
52  */
53 struct dt_driver_provider {
54 	int nodeoffset;
55 	enum dt_driver_type type;
56 	unsigned int provider_cells;
57 	uint32_t phandle;
58 	get_of_device_func get_of_device;
59 	void *priv_data;
60 	SLIST_ENTRY(dt_driver_provider) link;
61 };
62 
63 /*
64  * Device driver providers are able to provide a driver specific instance
65  * related to device phandle arguments found in the secure embedded FDT.
66  */
67 static SLIST_HEAD(, dt_driver_provider) dt_driver_provider_list =
68 	SLIST_HEAD_INITIALIZER(dt_driver_provider_list);
69 
70 /* FDT nodes for which a matching driver is to be probed */
71 static TAILQ_HEAD(dt_driver_probe_head, dt_driver_probe) dt_driver_probe_list =
72 	TAILQ_HEAD_INITIALIZER(dt_driver_probe_list);
73 
74 /* FDT nodes for which a matching driver has been successfully probed */
75 static TAILQ_HEAD(, dt_driver_probe) dt_driver_ready_list =
76 	TAILQ_HEAD_INITIALIZER(dt_driver_ready_list);
77 
78 /* List of the nodes for which a compatible driver but reported a failure */
79 static TAILQ_HEAD(, dt_driver_probe) dt_driver_failed_list =
80 	TAILQ_HEAD_INITIALIZER(dt_driver_failed_list);
81 
82 /* Flag enabled when a new node (possibly typed) is added in the probe list */
83 static bool added_node;
84 
85 /* Resolve drivers dependencies on core crypto layer */
86 static bool tee_crypt_is_ready;
87 
88 void dt_driver_crypt_init_complete(void)
89 {
90 	assert(!tee_crypt_is_ready);
91 	tee_crypt_is_ready = true;
92 }
93 
94 TEE_Result dt_driver_get_crypto(void)
95 {
96 	if (tee_crypt_is_ready)
97 		return TEE_SUCCESS;
98 	else
99 		return TEE_ERROR_DEFER_DRIVER_INIT;
100 }
101 
102 static void assert_type_is_valid(enum dt_driver_type type)
103 {
104 	switch (type) {
105 	case DT_DRIVER_NOTYPE:
106 	case DT_DRIVER_UART:
107 	case DT_DRIVER_CLK:
108 		return;
109 	default:
110 		assert(0);
111 	}
112 }
113 
114 /*
115  * Driver provider registering API functions
116  */
117 
118 TEE_Result dt_driver_register_provider(const void *fdt, int nodeoffset,
119 				       get_of_device_func get_of_device,
120 				       void *priv, enum dt_driver_type type)
121 {
122 	struct dt_driver_provider *prv = NULL;
123 	int provider_cells = 0;
124 	uint32_t phandle = 0;
125 
126 	assert_type_is_valid(type);
127 
128 	provider_cells = fdt_get_dt_driver_cells(fdt, nodeoffset, type);
129 	if (provider_cells < 0) {
130 		DMSG("Failed to find provider cells: %d", provider_cells);
131 		return TEE_ERROR_GENERIC;
132 	}
133 
134 	phandle = fdt_get_phandle(fdt, nodeoffset);
135 	if (!phandle || phandle == (uint32_t)-1) {
136 		DMSG("Failed to find provide phandle");
137 		return TEE_ERROR_GENERIC;
138 	}
139 
140 	prv = calloc(1, sizeof(*prv));
141 	if (!prv)
142 		return TEE_ERROR_OUT_OF_MEMORY;
143 
144 	prv->nodeoffset = nodeoffset;
145 	prv->type = type;
146 	prv->provider_cells = provider_cells;
147 	prv->phandle = phandle;
148 	prv->get_of_device = get_of_device;
149 	prv->priv_data = priv;
150 
151 	SLIST_INSERT_HEAD(&dt_driver_provider_list, prv, link);
152 
153 	return TEE_SUCCESS;
154 }
155 
156 /*
157  * Helper functions for dt_drivers querying driver provider information
158  */
159 
160 int fdt_get_dt_driver_cells(const void *fdt, int nodeoffset,
161 			    enum dt_driver_type type)
162 {
163 	const char *cells_name = NULL;
164 	const fdt32_t *c = NULL;
165 	int len = 0;
166 
167 	switch (type) {
168 	case DT_DRIVER_CLK:
169 		cells_name = "#clock-cells";
170 		break;
171 	default:
172 		panic();
173 	}
174 
175 	c = fdt_getprop(fdt, nodeoffset, cells_name, &len);
176 	if (!c)
177 		return len;
178 
179 	if (len != sizeof(*c))
180 		return -FDT_ERR_BADNCELLS;
181 
182 	return fdt32_to_cpu(*c);
183 }
184 
185 unsigned int dt_driver_provider_cells(struct dt_driver_provider *prv)
186 {
187 	return prv->provider_cells;
188 }
189 
190 struct dt_driver_provider *
191 dt_driver_get_provider_by_node(int nodeoffset, enum dt_driver_type type)
192 {
193 	struct dt_driver_provider *prv = NULL;
194 
195 	SLIST_FOREACH(prv, &dt_driver_provider_list, link)
196 		if (prv->nodeoffset == nodeoffset && prv->type == type)
197 			return prv;
198 
199 	return NULL;
200 }
201 
202 struct dt_driver_provider *
203 dt_driver_get_provider_by_phandle(uint32_t phandle, enum dt_driver_type type)
204 {
205 	struct dt_driver_provider *prv = NULL;
206 
207 	SLIST_FOREACH(prv, &dt_driver_provider_list, link)
208 		if (prv->phandle == phandle && prv->type == type)
209 			return prv;
210 
211 	return NULL;
212 }
213 
214 static void *device_from_provider_prop(struct dt_driver_provider *prv,
215 					  const uint32_t *prop,
216 					  TEE_Result *res)
217 {
218 	struct dt_driver_phandle_args *pargs = NULL;
219 	unsigned int n = 0;
220 	void *device = NULL;
221 
222 	pargs = calloc(1, prv->provider_cells * sizeof(uint32_t *) +
223 		       sizeof(*pargs));
224 	if (!pargs) {
225 		*res = TEE_ERROR_OUT_OF_MEMORY;
226 		return NULL;
227 	}
228 
229 	pargs->args_count = prv->provider_cells;
230 	for (n = 0; n < prv->provider_cells; n++)
231 		pargs->args[n] = fdt32_to_cpu(prop[n + 1]);
232 
233 	device = prv->get_of_device(pargs, prv->priv_data, res);
234 
235 	free(pargs);
236 
237 	return device;
238 }
239 
240 void *dt_driver_device_from_node_idx_prop(const char *prop_name,
241 					  const void *fdt, int nodeoffset,
242 					  unsigned int prop_idx,
243 					  enum dt_driver_type type,
244 					  TEE_Result *res)
245 {
246 	int len = 0;
247 	int idx = 0;
248 	int idx32 = 0;
249 	int prv_cells = 0;
250 	uint32_t phandle = 0;
251 	const uint32_t *prop = NULL;
252 	struct dt_driver_provider *prv = NULL;
253 
254 	prop = fdt_getprop(fdt, nodeoffset, prop_name, &len);
255 	if (!prop) {
256 		DMSG("Property %s missing in node %s", prop_name,
257 		     fdt_get_name(fdt, nodeoffset, NULL));
258 		*res = TEE_ERROR_GENERIC;
259 		return NULL;
260 	}
261 
262 	while (idx < len) {
263 		idx32 = idx / sizeof(uint32_t);
264 		phandle = fdt32_to_cpu(prop[idx32]);
265 
266 		prv = dt_driver_get_provider_by_phandle(phandle, type);
267 		if (!prv) {
268 			/* No provider registered yet */
269 			*res = TEE_ERROR_DEFER_DRIVER_INIT;
270 			return NULL;
271 		}
272 
273 		prv_cells = dt_driver_provider_cells(prv);
274 		if (prop_idx) {
275 			prop_idx--;
276 			idx += sizeof(phandle) + prv_cells * sizeof(uint32_t);
277 			continue;
278 		}
279 
280 		return device_from_provider_prop(prv, prop + idx32, res);
281 	}
282 
283 	*res = TEE_ERROR_GENERIC;
284 	return NULL;
285 }
286 
287 static unsigned int __maybe_unused probe_list_count(void)
288 {
289 	struct dt_driver_probe *elt = NULL;
290 	unsigned int count = 0;
291 
292 	TAILQ_FOREACH(elt, &dt_driver_probe_list, link)
293 		count++;
294 
295 	return count;
296 }
297 
298 static void __maybe_unused print_probe_list(const void *fdt __maybe_unused)
299 {
300 	struct dt_driver_probe *elt = NULL;
301 
302 	DMSG("Probe list: %u elements", probe_list_count());
303 
304 	TAILQ_FOREACH(elt, &dt_driver_probe_list, link)
305 		DMSG("- Driver %s probes on node %s",
306 		     elt->dt_drv->name,
307 		     fdt_get_name(fdt, elt->nodeoffset, NULL));
308 
309 	DMSG("Probe list end");
310 }
311 
312 /*
313  * Probe element: push to ready list if succeeds, push to probe list if probe
314  * if deferred, panic with an error trace otherwise.
315  */
316 static TEE_Result probe_driver_node(const void *fdt,
317 				    struct dt_driver_probe *elt)
318 {
319 	TEE_Result res = TEE_ERROR_GENERIC;
320 	const char __maybe_unused *drv_name = NULL;
321 	const char __maybe_unused *node_name = NULL;
322 
323 	node_name = fdt_get_name(fdt, elt->nodeoffset, NULL);
324 	drv_name = elt->dt_drv->name;
325 
326 	if (!elt->dt_drv->probe) {
327 		DMSG("No probe operator for driver %s, skipped", drv_name);
328 		return TEE_SUCCESS;
329 	}
330 
331 	FMSG("Probing %s on node %s", drv_name, node_name);
332 
333 	res = elt->dt_drv->probe(fdt, elt->nodeoffset, elt->dm->compat_data);
334 	switch (res) {
335 	case TEE_SUCCESS:
336 		TAILQ_INSERT_HEAD(&dt_driver_ready_list, elt, link);
337 
338 		DMSG("element: %s on node %s initialized", drv_name, node_name);
339 		break;
340 	case TEE_ERROR_DEFER_DRIVER_INIT:
341 		elt->deferrals++;
342 		TAILQ_INSERT_TAIL(&dt_driver_probe_list, elt, link);
343 
344 		DMSG("element: %s on node %s deferred %u time(s)", drv_name,
345 		     node_name, elt->deferrals);
346 		break;
347 	default:
348 		TAILQ_INSERT_HEAD(&dt_driver_failed_list, elt, link);
349 
350 		EMSG("Failed to probe %s on node %s: %#"PRIx32,
351 		     drv_name, node_name, res);
352 		break;
353 	}
354 
355 	return res;
356 }
357 
358 static TEE_Result alloc_elt_and_probe(const void *fdt, int node,
359 				      const struct dt_driver *dt_drv,
360 				      const struct dt_device_match *dm)
361 {
362 	struct dt_driver_probe *elt = NULL;
363 
364 	/* Will be freed when lists are released */
365 	elt = calloc(1, sizeof(*elt));
366 	if (!elt)
367 		return TEE_ERROR_OUT_OF_MEMORY;
368 
369 	elt->nodeoffset = node;
370 	elt->dt_drv = dt_drv;
371 	elt->dm = dm;
372 	elt->type = dt_drv->type;
373 
374 	return probe_driver_node(fdt, elt);
375 }
376 
377 /* Lookup a compatible driver, possibly of a specific @type, for the FDT node */
378 static TEE_Result probe_device_by_compat(const void *fdt, int node,
379 					 const char *compat,
380 					 enum dt_driver_type type)
381 {
382 	const struct dt_driver *drv = NULL;
383 	const struct dt_device_match *dm = NULL;
384 
385 	for_each_dt_driver(drv) {
386 		if (drv->type != type)
387 			continue;
388 
389 		for (dm = drv->match_table; dm && dm->compatible; dm++)
390 			if (strcmp(dm->compatible, compat) == 0)
391 				return alloc_elt_and_probe(fdt, node, drv, dm);
392 	}
393 
394 	return TEE_ERROR_ITEM_NOT_FOUND;
395 }
396 
397 /*
398  * Lookup the best matching compatible driver, possibly of a specific @type,
399  * for the FDT node.
400  */
401 TEE_Result dt_driver_probe_device_by_node(const void *fdt, int nodeoffset,
402 					  enum dt_driver_type type)
403 {
404 	int idx = 0;
405 	int len = 0;
406 	int count = 0;
407 	const char *compat = NULL;
408 	TEE_Result res = TEE_ERROR_GENERIC;
409 
410 	assert_type_is_valid(type);
411 
412 	count = fdt_stringlist_count(fdt, nodeoffset, "compatible");
413 	if (count < 0)
414 		return TEE_ERROR_ITEM_NOT_FOUND;
415 
416 	for (idx = 0; idx < count; idx++) {
417 		compat = fdt_stringlist_get(fdt, nodeoffset, "compatible",
418 					    idx, &len);
419 		if (!compat)
420 			return TEE_ERROR_GENERIC;
421 
422 		res = probe_device_by_compat(fdt, nodeoffset, compat, type);
423 
424 		if (res != TEE_ERROR_ITEM_NOT_FOUND)
425 			return res;
426 	}
427 
428 	return TEE_ERROR_ITEM_NOT_FOUND;
429 }
430 
431 static TEE_Result process_probe_list(const void *fdt)
432 {
433 	struct dt_driver_probe *elt = NULL;
434 	struct dt_driver_probe *prev = NULL;
435 	unsigned int __maybe_unused loop_count = 0;
436 	unsigned int __maybe_unused deferral_loop_count = 0;
437 	bool __maybe_unused one_deferred = false;
438 	bool one_probed_ok = false;
439 
440 	do {
441 		loop_count++;
442 		FMSG("Probe loop %u after %u for deferral(s)", loop_count,
443 		     deferral_loop_count);
444 
445 		/* Hack here for TRACE_DEBUG messages on probe list elements */
446 		if (TRACE_LEVEL >= TRACE_FLOW)
447 			print_probe_list(fdt);
448 
449 		if (TAILQ_EMPTY(&dt_driver_probe_list))
450 			return TEE_SUCCESS;
451 
452 		/*
453 		 * Probe from current end to top. Deferred probed node are
454 		 * pushed back after current tail for the next probe round.
455 		 * Reset probe result flags and see status after probe round.
456 		 */
457 		one_deferred = false;
458 		one_probed_ok = false;
459 		added_node = false;
460 
461 		TAILQ_FOREACH_REVERSE_SAFE(elt, &dt_driver_probe_list,
462 					   dt_driver_probe_head, link, prev) {
463 			TAILQ_REMOVE(&dt_driver_probe_list, elt, link);
464 
465 			switch (probe_driver_node(fdt, elt)) {
466 			case TEE_SUCCESS:
467 				one_probed_ok = true;
468 				break;
469 			case TEE_ERROR_DEFER_DRIVER_INIT:
470 				one_deferred = true;
471 				break;
472 			default:
473 				break;
474 			}
475 		}
476 
477 		if (one_deferred)
478 			deferral_loop_count++;
479 
480 	} while (added_node || one_probed_ok);
481 
482 	EMSG("Panic on unresolved dependencies after %u rounds, %u deferred:",
483 	     loop_count, deferral_loop_count);
484 
485 	TAILQ_FOREACH(elt, &dt_driver_probe_list, link)
486 		EMSG("- Pending: driver %s on node %s", elt->dt_drv->name,
487 		     fdt_get_name(fdt, elt->nodeoffset, NULL));
488 
489 	TAILQ_FOREACH(elt, &dt_driver_failed_list, link)
490 		EMSG("- Failed: driver %s on node %s", elt->dt_drv->name,
491 		     fdt_get_name(fdt, elt->nodeoffset, NULL));
492 
493 	panic();
494 }
495 
496 static int driver_probe_compare(struct dt_driver_probe *candidate,
497 				struct dt_driver_probe *elt)
498 {
499 	if (candidate->nodeoffset != elt->nodeoffset ||
500 	    candidate->type != elt->type)
501 		return 1;
502 
503 	assert(elt->dt_drv == candidate->dt_drv);
504 	return 0;
505 }
506 
507 /*
508  * Return TEE_SUCCESS if compatible found
509  *	  TEE_ERROR_OUT_OF_MEMORY if heap is exhausted
510  */
511 static TEE_Result add_node_to_probe(const void *fdt, int node,
512 				    const struct dt_driver *dt_drv,
513 				    const struct dt_device_match *dm)
514 {
515 	const char __maybe_unused *node_name = fdt_get_name(fdt, node, NULL);
516 	const char __maybe_unused *drv_name = dt_drv->name;
517 	struct dt_driver_probe *elt = NULL;
518 	struct dt_driver_probe elt_new = {
519 		.dm = dm,
520 		.dt_drv = dt_drv,
521 		.nodeoffset = node,
522 		.type = dt_drv->type,
523 	};
524 
525 	/* If node/type found in probe list or ready list, nothing to do */
526 	TAILQ_FOREACH(elt, &dt_driver_probe_list, link)
527 		if (!driver_probe_compare(&elt_new, elt))
528 			return TEE_SUCCESS;
529 
530 	TAILQ_FOREACH(elt, &dt_driver_ready_list, link)
531 		if (!driver_probe_compare(&elt_new, elt))
532 			return TEE_SUCCESS;
533 
534 	elt = malloc(sizeof(*elt));
535 	if (!elt)
536 		return TEE_ERROR_OUT_OF_MEMORY;
537 
538 	DMSG("element: %s on node %s", node_name, drv_name);
539 
540 	memcpy(elt, &elt_new, sizeof(*elt));
541 
542 	added_node = true;
543 
544 	TAILQ_INSERT_TAIL(&dt_driver_probe_list, elt, link);
545 
546 	/* Hack here for TRACE_DEBUG messages on current probe list elements */
547 	if (TRACE_LEVEL >= TRACE_FLOW)
548 		print_probe_list(fdt);
549 
550 	return TEE_SUCCESS;
551 }
552 
553 /*
554  * Add a node to the probe list if a dt_driver matches target compatible.
555  *
556  * If @type is DT_DRIVER_ANY, probe list can hold only 1 driver to probe for
557  * the node. A node may probe several drivers if have a unique driver type.
558  *
559  * Return TEE_SUCCESS if compatible found
560  *	  TEE_ERROR_ITEM_NOT_FOUND if no matching driver
561  *	  TEE_ERROR_OUT_OF_MEMORY if heap is exhausted
562  */
563 static TEE_Result add_probe_node_by_compat(const void *fdt, int node,
564 					   const char *compat)
565 {
566 	TEE_Result res = TEE_ERROR_ITEM_NOT_FOUND;
567 	const struct dt_driver *dt_drv = NULL;
568 	const struct dt_device_match *dm = NULL;
569 	uint32_t found_types = 0;
570 
571 	for_each_dt_driver(dt_drv) {
572 		for (dm = dt_drv->match_table; dm && dm->compatible; dm++) {
573 			if (strcmp(dm->compatible, compat) == 0) {
574 				assert(dt_drv->type < 32);
575 
576 				res = add_node_to_probe(fdt, node, dt_drv, dm);
577 				if (res)
578 					return res;
579 
580 				if (found_types & BIT(dt_drv->type)) {
581 					EMSG("Driver %s multi hit on type %u",
582 					     dt_drv->name, dt_drv->type);
583 					panic();
584 				}
585 				found_types |= BIT(dt_drv->type);
586 
587 				/* Matching found for this driver, try next */
588 				break;
589 			}
590 		}
591 	}
592 
593 	return res;
594 }
595 
596 /*
597  * Add the node to the probe list if matching compatible drivers are found.
598  * Follow node's compatible property list ordering to find matching driver.
599  */
600 TEE_Result dt_driver_maybe_add_probe_node(const void *fdt, int node)
601 {
602 	int idx = 0;
603 	int len = 0;
604 	int count = 0;
605 	const char *compat = NULL;
606 	TEE_Result res = TEE_ERROR_GENERIC;
607 
608 	if (_fdt_get_status(fdt, node) == DT_STATUS_DISABLED)
609 		return TEE_SUCCESS;
610 
611 	count = fdt_stringlist_count(fdt, node, "compatible");
612 	if (count < 0)
613 		return TEE_SUCCESS;
614 
615 	for (idx = 0; idx < count; idx++) {
616 		compat = fdt_stringlist_get(fdt, node, "compatible", idx, &len);
617 		assert(compat && len > 0);
618 
619 		res = add_probe_node_by_compat(fdt, node, compat);
620 
621 		/* Stop lookup if something was found */
622 		if (res != TEE_ERROR_ITEM_NOT_FOUND)
623 			return res;
624 	}
625 
626 	return TEE_SUCCESS;
627 }
628 
629 static void parse_node(const void *fdt, int node)
630 {
631 	TEE_Result __maybe_unused res = TEE_ERROR_GENERIC;
632 	int subnode = 0;
633 
634 	fdt_for_each_subnode(subnode, fdt, node) {
635 		res = dt_driver_maybe_add_probe_node(fdt, subnode);
636 		if (res) {
637 			EMSG("Failed on node %s with %#"PRIx32,
638 			     fdt_get_name(fdt, subnode, NULL), res);
639 			panic();
640 		}
641 
642 		/*
643 		 * Rescursively parse the FDT, skipping disabled nodes.
644 		 * FDT is expected reliable and core shall have sufficient
645 		 * stack depth to possibly parse all DT nodes.
646 		 */
647 		if (IS_ENABLED(CFG_DRIVERS_DT_RECURSIVE_PROBE)) {
648 			if (_fdt_get_status(fdt, subnode) == DT_STATUS_DISABLED)
649 				continue;
650 
651 			parse_node(fdt, subnode);
652 		}
653 	}
654 }
655 
656 /*
657  * Parse FDT for nodes and save in probe list the node for which a dt_driver
658  * matches node's compatible property.
659  */
660 static TEE_Result probe_dt_drivers(void)
661 {
662 	const void *fdt = NULL;
663 
664 	if (!IS_ENABLED(CFG_EMBED_DTB))
665 		return TEE_SUCCESS;
666 
667 	fdt = get_embedded_dt();
668 	assert(fdt);
669 
670 	parse_node(fdt, fdt_path_offset(fdt, "/"));
671 
672 	return process_probe_list(fdt);
673 }
674 
675 driver_init(probe_dt_drivers);
676 
677 static TEE_Result release_probe_lists(void)
678 {
679 	struct dt_driver_probe *elt = NULL;
680 	struct dt_driver_probe *next = NULL;
681 	struct dt_driver_provider *prov = NULL;
682 	struct dt_driver_provider *next_prov = NULL;
683 	const void * __maybe_unused fdt = NULL;
684 
685 	if (!IS_ENABLED(CFG_EMBED_DTB))
686 		return TEE_SUCCESS;
687 
688 	fdt = get_embedded_dt();
689 
690 	assert(fdt && TAILQ_EMPTY(&dt_driver_probe_list));
691 
692 	TAILQ_FOREACH_SAFE(elt, &dt_driver_ready_list, link, next)
693 		free(elt);
694 
695 	TAILQ_FOREACH_SAFE(elt, &dt_driver_failed_list, link, next)
696 	       free(elt);
697 
698 	SLIST_FOREACH_SAFE(prov, &dt_driver_provider_list, link, next_prov)
699 	       free(prov);
700 
701 	return TEE_SUCCESS;
702 }
703 
704 release_init_resource(release_probe_lists);
705 
706 /*
707  * Simple bus support: handy to parse subnodes
708  */
709 static TEE_Result simple_bus_probe(const void *fdt, int node,
710 				   const void *compat_data __unused)
711 {
712 	TEE_Result res = TEE_ERROR_GENERIC;
713 	int subnode = 0;
714 
715 	fdt_for_each_subnode(subnode, fdt, node) {
716 		res = dt_driver_maybe_add_probe_node(fdt, subnode);
717 		if (res) {
718 			EMSG("Failed on node %s with %#"PRIx32,
719 			     fdt_get_name(fdt, subnode, NULL), res);
720 			panic();
721 		}
722 	}
723 
724 	return TEE_SUCCESS;
725 }
726 
727 static const struct dt_device_match simple_bus_match_table[] = {
728 	{ .compatible = "simple-bus" },
729 	{ }
730 };
731 
732 const struct dt_driver simple_bus_dt_driver __dt_driver = {
733 	.name = "simple-bus",
734 	.match_table = simple_bus_match_table,
735 	.probe = simple_bus_probe,
736 };
737