xref: /optee_os/core/kernel/dt_driver.c (revision 5f7f88c6b9d618d1e068166bbf2b07757350791d)
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_CLK:
107 	case DT_DRIVER_RSTCTRL:
108 	case DT_DRIVER_UART:
109 	case DT_DRIVER_GPIO:
110 	case DT_DRIVER_I2C:
111 	case DT_DRIVER_PINCTRL:
112 	case DT_DRIVER_INTERRUPT:
113 	case DT_DRIVER_REGULATOR:
114 	case DT_DRIVER_NVMEM:
115 		return;
116 	default:
117 		assert(0);
118 	}
119 }
120 
121 /*
122  * Driver provider registering API functions
123  */
124 
125 TEE_Result dt_driver_register_provider(const void *fdt, int nodeoffset,
126 				       get_of_device_func get_of_device,
127 				       void *priv, enum dt_driver_type type)
128 {
129 	struct dt_driver_provider *prv = NULL;
130 	int provider_cells = 0;
131 	uint32_t phandle = 0;
132 
133 	assert_type_is_valid(type);
134 
135 	provider_cells = fdt_get_dt_driver_cells(fdt, nodeoffset, type);
136 	if (provider_cells < 0) {
137 		DMSG("Failed to find provider cells: %d", provider_cells);
138 		return TEE_ERROR_GENERIC;
139 	}
140 
141 	phandle = fdt_get_phandle(fdt, nodeoffset);
142 	if (phandle == (uint32_t)-1) {
143 		DMSG("Failed to find provide phandle");
144 		return TEE_ERROR_GENERIC;
145 	}
146 
147 	prv = calloc(1, sizeof(*prv));
148 	if (!prv)
149 		return TEE_ERROR_OUT_OF_MEMORY;
150 
151 	prv->nodeoffset = nodeoffset;
152 	prv->type = type;
153 	prv->provider_cells = provider_cells;
154 	prv->phandle = phandle;
155 	prv->get_of_device = get_of_device;
156 	prv->priv_data = priv;
157 
158 	SLIST_INSERT_HEAD(&dt_driver_provider_list, prv, link);
159 
160 	return TEE_SUCCESS;
161 }
162 
163 static bool dt_driver_use_parent_controller(enum dt_driver_type type)
164 {
165 	switch (type) {
166 	case DT_DRIVER_PINCTRL:
167 	case DT_DRIVER_NVMEM:
168 		return true;
169 	default:
170 		return false;
171 	}
172 }
173 
174 /*
175  * Helper functions for dt_drivers querying driver provider information
176  */
177 
178 int fdt_get_dt_driver_cells(const void *fdt, int nodeoffset,
179 			    enum dt_driver_type type)
180 {
181 	const char *cells_name = NULL;
182 	const fdt32_t *c = NULL;
183 	int len = 0;
184 
185 	if (dt_driver_use_parent_controller(type))
186 		return 0;
187 
188 	switch (type) {
189 	case DT_DRIVER_CLK:
190 		cells_name = "#clock-cells";
191 		break;
192 	case DT_DRIVER_INTERRUPT:
193 		cells_name = "#interrupt-cells";
194 		break;
195 	case DT_DRIVER_RSTCTRL:
196 		cells_name = "#reset-cells";
197 		break;
198 	case DT_DRIVER_GPIO:
199 		cells_name = "#gpio-cells";
200 		break;
201 	case DT_DRIVER_I2C:
202 	case DT_DRIVER_REGULATOR:
203 		return 0;
204 	default:
205 		panic();
206 	}
207 
208 	c = fdt_getprop(fdt, nodeoffset, cells_name, &len);
209 	if (!c)
210 		return len;
211 
212 	if (len != sizeof(*c))
213 		return -FDT_ERR_BADNCELLS;
214 
215 	return fdt32_to_cpu(*c);
216 }
217 
218 unsigned int dt_driver_provider_cells(struct dt_driver_provider *prv)
219 {
220 	return prv->provider_cells;
221 }
222 
223 void *dt_driver_provider_priv_data(struct dt_driver_provider *prv)
224 {
225 	return prv->priv_data;
226 }
227 
228 struct dt_driver_provider *
229 dt_driver_get_provider_by_node(int nodeoffset, enum dt_driver_type type)
230 {
231 	struct dt_driver_provider *prv = NULL;
232 
233 	SLIST_FOREACH(prv, &dt_driver_provider_list, link)
234 		if (prv->nodeoffset == nodeoffset && prv->type == type)
235 			return prv;
236 
237 	return NULL;
238 }
239 
240 struct dt_driver_provider *
241 dt_driver_get_provider_by_phandle(uint32_t phandle, enum dt_driver_type type)
242 {
243 	struct dt_driver_provider *prv = NULL;
244 
245 	SLIST_FOREACH(prv, &dt_driver_provider_list, link)
246 		if (prv->phandle == phandle && prv->type == type)
247 			return prv;
248 
249 	return NULL;
250 }
251 
252 static TEE_Result device_from_provider_prop(struct dt_driver_provider *prv,
253 					    const void *fdt, int phandle_node,
254 					    const uint32_t *prop,
255 					    void *device_ref)
256 {
257 	TEE_Result res = TEE_ERROR_GENERIC;
258 	struct dt_pargs *pargs = NULL;
259 	unsigned int n = 0;
260 
261 	pargs = calloc(1, prv->provider_cells * sizeof(uint32_t *) +
262 		       sizeof(*pargs));
263 	if (!pargs)
264 		return TEE_ERROR_OUT_OF_MEMORY;
265 
266 	pargs->fdt = fdt;
267 	pargs->phandle_node = phandle_node;
268 	pargs->args_count = prv->provider_cells;
269 	for (n = 0; n < prv->provider_cells; n++)
270 		pargs->args[n] = fdt32_to_cpu(prop[n]);
271 
272 	res = prv->get_of_device(pargs, prv->priv_data, device_ref);
273 
274 	free(pargs);
275 
276 	return res;
277 }
278 
279 TEE_Result dt_driver_device_from_parent(const void *fdt, int nodeoffset,
280 					enum dt_driver_type type,
281 					void *device_ref)
282 {
283 	int parent = -1;
284 	struct dt_driver_provider *prv = NULL;
285 
286 	assert(fdt == get_secure_dt());
287 
288 	parent = fdt_parent_offset(fdt, nodeoffset);
289 	if (parent < 0)
290 		return TEE_ERROR_GENERIC;
291 
292 	prv = dt_driver_get_provider_by_node(parent, type);
293 	if (!prv) {
294 		/* No provider registered yet */
295 		return TEE_ERROR_DEFER_DRIVER_INIT;
296 	}
297 
298 	return device_from_provider_prop(prv, fdt, nodeoffset, NULL,
299 					 device_ref);
300 }
301 
302 TEE_Result dt_driver_device_from_node_idx_prop_phandle(const char *prop_name,
303 						       const void *fdt,
304 						       int nodeoffs,
305 						       unsigned int prop_index,
306 						       enum dt_driver_type type,
307 						       uint32_t phandle,
308 						       void *device_ref)
309 {
310 	int len = 0;
311 	const uint32_t *prop = NULL;
312 	int phandle_node_unused = -1;
313 	struct dt_driver_provider *prv = NULL;
314 
315 	prop = fdt_getprop(fdt, nodeoffs, prop_name, &len);
316 	if (!prop) {
317 		if (len != -FDT_ERR_NOTFOUND) {
318 			DMSG("Corrupted node %s", prop_name);
319 			return TEE_ERROR_GENERIC;
320 		} else {
321 			DMSG("Property %s missing in node %s", prop_name,
322 			     fdt_get_name(fdt, nodeoffs, NULL));
323 			return TEE_ERROR_ITEM_NOT_FOUND;
324 		}
325 	}
326 
327 	prv = dt_driver_get_provider_by_phandle(phandle, type);
328 	if (!prv)
329 		return TEE_ERROR_DEFER_DRIVER_INIT;
330 
331 	prop_index *= dt_driver_provider_cells(prv);
332 	if ((prop_index + 1) * sizeof(*prop) > (size_t)len)
333 		return TEE_ERROR_ITEM_NOT_FOUND;
334 
335 	return device_from_provider_prop(prv, fdt, phandle_node_unused,
336 					 prop + prop_index, device_ref);
337 }
338 
339 TEE_Result dt_driver_device_from_node_idx_prop(const char *prop_name,
340 					       const void *fdt, int nodeoffset,
341 					       unsigned int prop_idx,
342 					       enum dt_driver_type type,
343 					       void *device_ref)
344 {
345 	int len = 0;
346 	int idx = 0;
347 	int idx32 = 0;
348 	int prv_cells = 0;
349 	int phandle_node = -1;
350 	uint32_t phandle = 0;
351 	const uint32_t *prop = NULL;
352 	struct dt_driver_provider *prv = NULL;
353 
354 	prop = fdt_getprop(fdt, nodeoffset, prop_name, &len);
355 	if (!prop) {
356 		DMSG("Property %s missing in node %s", prop_name,
357 		     fdt_get_name(fdt, nodeoffset, NULL));
358 		return TEE_ERROR_ITEM_NOT_FOUND;
359 	}
360 
361 	while (idx < len) {
362 		idx32 = idx / sizeof(uint32_t);
363 		phandle = fdt32_to_cpu(prop[idx32]);
364 		if (!phandle) {
365 			if (!prop_idx)
366 				break;
367 			idx += sizeof(phandle);
368 			prop_idx--;
369 			continue;
370 		}
371 
372 		/*
373 		 * In some cases, pinctrl, i2c, nvmem, etc, the consumer phandle
374 		 * points directly to a subnode of the parent. In such cases,
375 		 * the provider does not have any "-cells" property and
376 		 * potentially no "phandle" property.
377 		 */
378 		if (dt_driver_use_parent_controller(type)) {
379 			phandle_node = fdt_node_offset_by_phandle(fdt, phandle);
380 			if (phandle_node < 0)
381 				return TEE_ERROR_GENERIC;
382 
383 			nodeoffset = fdt_parent_offset(fdt, phandle_node);
384 			if (nodeoffset < 0)
385 				return TEE_ERROR_GENERIC;
386 
387 			prv = dt_driver_get_provider_by_node(nodeoffset, type);
388 		} else {
389 			prv = dt_driver_get_provider_by_phandle(phandle, type);
390 		}
391 
392 		if (prv) {
393 			prv_cells = dt_driver_provider_cells(prv);
394 		} else if (prop_idx) {
395 			/*
396 			 * When we need to skip another provider phandle
397 			 * arguments cells (aka when prop_idx != 0), we don't
398 			 * really need the skipped provider to be already
399 			 * registered, we can look straight in its DT node.
400 			 */
401 			phandle_node = fdt_node_offset_by_phandle(fdt, phandle);
402 			if (phandle_node < 0) {
403 				DMSG("Can't find node for phandle %"PRIu32,
404 				     phandle);
405 				return TEE_ERROR_GENERIC;
406 			}
407 
408 			prv_cells = fdt_get_dt_driver_cells(fdt, phandle_node,
409 							    type);
410 			if (prv_cells < 0) {
411 				DMSG("Can't find cells count on node %s: %d",
412 				     fdt_get_name(fdt, phandle_node, NULL),
413 				     prv_cells);
414 				return TEE_ERROR_GENERIC;
415 			}
416 		}
417 
418 		if (prop_idx) {
419 			prop_idx--;
420 			idx += sizeof(phandle) + prv_cells * sizeof(uint32_t);
421 			continue;
422 		}
423 
424 		if (!prv)
425 			return TEE_ERROR_DEFER_DRIVER_INIT;
426 
427 		/* Skip property cell with the phandle, already handled */
428 		idx32++;
429 
430 		return device_from_provider_prop(prv, fdt, phandle_node,
431 						 prop + idx32, device_ref);
432 	}
433 
434 	return TEE_ERROR_ITEM_NOT_FOUND;
435 }
436 
437 static void __maybe_unused print_probe_list(const void *fdt __maybe_unused)
438 {
439 	struct dt_driver_probe *elt = NULL;
440 	unsigned int count = 0;
441 
442 	TAILQ_FOREACH(elt, &dt_driver_probe_list, link)
443 		count++;
444 
445 	DMSG("Probe list: %u elements", count);
446 	TAILQ_FOREACH(elt, &dt_driver_probe_list, link)
447 		DMSG("|- Driver %s probes on node %s",
448 		     elt->dt_drv->name,
449 		     fdt_get_name(fdt, elt->nodeoffset, NULL));
450 
451 	DMSG("`- Probe list end");
452 
453 	count = 0;
454 	TAILQ_FOREACH(elt, &dt_driver_failed_list, link)
455 		count++;
456 
457 	DMSG("Failed list: %u elements", count);
458 	TAILQ_FOREACH(elt, &dt_driver_failed_list, link)
459 		EMSG("|- Driver %s on node %s failed", elt->dt_drv->name,
460 		     fdt_get_name(fdt, elt->nodeoffset, NULL));
461 
462 	DMSG("`- Failed list end");
463 }
464 
465 /*
466  * Probe element: push to ready list if succeeds, push to probe list if probe
467  * if deferred, panic with an error trace otherwise.
468  */
469 static TEE_Result probe_driver_node(const void *fdt,
470 				    struct dt_driver_probe *elt)
471 {
472 	TEE_Result res = TEE_ERROR_GENERIC;
473 	const char __maybe_unused *drv_name = NULL;
474 	const char __maybe_unused *node_name = NULL;
475 
476 	node_name = fdt_get_name(fdt, elt->nodeoffset, NULL);
477 	drv_name = elt->dt_drv->name;
478 
479 	if (!elt->dt_drv->probe) {
480 		DMSG("No probe operator for driver %s, skipped", drv_name);
481 		return TEE_SUCCESS;
482 	}
483 
484 	FMSG("Probing %s on node %s", drv_name, node_name);
485 
486 	res = elt->dt_drv->probe(fdt, elt->nodeoffset, elt->dm->compat_data);
487 	switch (res) {
488 	case TEE_SUCCESS:
489 		TAILQ_INSERT_HEAD(&dt_driver_ready_list, elt, link);
490 
491 		DMSG("element: %s on node %s initialized", drv_name, node_name);
492 		break;
493 	case TEE_ERROR_DEFER_DRIVER_INIT:
494 		elt->deferrals++;
495 		TAILQ_INSERT_TAIL(&dt_driver_probe_list, elt, link);
496 
497 		DMSG("element: %s on node %s deferred %u time(s)", drv_name,
498 		     node_name, elt->deferrals);
499 		break;
500 	case TEE_ERROR_NODE_DISABLED:
501 		DMSG("element: %s on node %s is disabled", drv_name, node_name);
502 		break;
503 	default:
504 		TAILQ_INSERT_HEAD(&dt_driver_failed_list, elt, link);
505 
506 		EMSG("Failed to probe %s on node %s: %#"PRIx32,
507 		     drv_name, node_name, res);
508 		break;
509 	}
510 
511 	return res;
512 }
513 
514 static TEE_Result alloc_elt_and_probe(const void *fdt, int node,
515 				      const struct dt_driver *dt_drv,
516 				      const struct dt_device_match *dm)
517 {
518 	struct dt_driver_probe *elt = NULL;
519 
520 	/* Will be freed when lists are released */
521 	elt = calloc(1, sizeof(*elt));
522 	if (!elt)
523 		return TEE_ERROR_OUT_OF_MEMORY;
524 
525 	elt->nodeoffset = node;
526 	elt->dt_drv = dt_drv;
527 	elt->dm = dm;
528 	elt->type = dt_drv->type;
529 
530 	return probe_driver_node(fdt, elt);
531 }
532 
533 /* Lookup a compatible driver, possibly of a specific @type, for the FDT node */
534 static TEE_Result probe_device_by_compat(const void *fdt, int node,
535 					 const char *compat,
536 					 enum dt_driver_type type)
537 {
538 	const struct dt_driver *drv = NULL;
539 	const struct dt_device_match *dm = NULL;
540 
541 	for_each_dt_driver(drv) {
542 		if (drv->type != type)
543 			continue;
544 
545 		for (dm = drv->match_table; dm && dm->compatible; dm++)
546 			if (strcmp(dm->compatible, compat) == 0)
547 				return alloc_elt_and_probe(fdt, node, drv, dm);
548 	}
549 
550 	return TEE_ERROR_ITEM_NOT_FOUND;
551 }
552 
553 /*
554  * Lookup the best matching compatible driver, possibly of a specific @type,
555  * for the FDT node.
556  */
557 TEE_Result dt_driver_probe_device_by_node(const void *fdt, int nodeoffset,
558 					  enum dt_driver_type type)
559 {
560 	int idx = 0;
561 	int len = 0;
562 	int count = 0;
563 	const char *compat = NULL;
564 	TEE_Result res = TEE_ERROR_GENERIC;
565 
566 	assert_type_is_valid(type);
567 
568 	count = fdt_stringlist_count(fdt, nodeoffset, "compatible");
569 	if (count < 0)
570 		return TEE_ERROR_ITEM_NOT_FOUND;
571 
572 	for (idx = 0; idx < count; idx++) {
573 		compat = fdt_stringlist_get(fdt, nodeoffset, "compatible",
574 					    idx, &len);
575 		if (!compat)
576 			return TEE_ERROR_GENERIC;
577 
578 		res = probe_device_by_compat(fdt, nodeoffset, compat, type);
579 
580 		if (res != TEE_ERROR_ITEM_NOT_FOUND)
581 			return res;
582 	}
583 
584 	return TEE_ERROR_ITEM_NOT_FOUND;
585 }
586 
587 static TEE_Result process_probe_list(const void *fdt)
588 {
589 	struct dt_driver_probe *elt = NULL;
590 	struct dt_driver_probe *prev = NULL;
591 	static unsigned int __maybe_unused loop_count;
592 	static unsigned int __maybe_unused deferral_loop_count;
593 	bool __maybe_unused one_deferred = false;
594 	bool one_probed_ok = false;
595 
596 	do {
597 		loop_count++;
598 		FMSG("Probe loop %u after %u for deferral(s)", loop_count,
599 		     deferral_loop_count);
600 
601 		/* Hack here for TRACE_DEBUG messages on probe list elements */
602 		if (TRACE_LEVEL >= TRACE_FLOW)
603 			print_probe_list(fdt);
604 
605 		if (TAILQ_EMPTY(&dt_driver_probe_list))
606 			return TEE_SUCCESS;
607 
608 		/*
609 		 * Probe from current end to top. Deferred probed node are
610 		 * pushed back after current tail for the next probe round.
611 		 * Reset probe result flags and see status after probe round.
612 		 */
613 		one_deferred = false;
614 		one_probed_ok = false;
615 		added_node = false;
616 
617 		TAILQ_FOREACH_REVERSE_SAFE(elt, &dt_driver_probe_list,
618 					   dt_driver_probe_head, link, prev) {
619 			TAILQ_REMOVE(&dt_driver_probe_list, elt, link);
620 
621 			switch (probe_driver_node(fdt, elt)) {
622 			case TEE_SUCCESS:
623 				one_probed_ok = true;
624 				break;
625 			case TEE_ERROR_DEFER_DRIVER_INIT:
626 				one_deferred = true;
627 				break;
628 			default:
629 				break;
630 			}
631 		}
632 
633 		if (one_deferred)
634 			deferral_loop_count++;
635 
636 	} while (added_node || one_probed_ok);
637 
638 	DMSG("Unresolved dependencies after %u rounds, %u deferred",
639 	     loop_count, deferral_loop_count);
640 
641 	if (one_deferred)
642 		return TEE_ERROR_DEFER_DRIVER_INIT;
643 	else
644 		return TEE_ERROR_GENERIC;
645 }
646 
647 static int driver_probe_compare(struct dt_driver_probe *candidate,
648 				struct dt_driver_probe *elt)
649 {
650 	if (candidate->nodeoffset != elt->nodeoffset ||
651 	    candidate->type != elt->type)
652 		return 1;
653 
654 	assert(elt->dt_drv == candidate->dt_drv);
655 	return 0;
656 }
657 
658 /*
659  * Return TEE_SUCCESS if compatible found
660  *	  TEE_ERROR_OUT_OF_MEMORY if heap is exhausted
661  */
662 static TEE_Result add_node_to_probe(const void *fdt, int node,
663 				    const struct dt_driver *dt_drv,
664 				    const struct dt_device_match *dm)
665 {
666 	const char __maybe_unused *node_name = fdt_get_name(fdt, node, NULL);
667 	const char __maybe_unused *drv_name = dt_drv->name;
668 	struct dt_driver_probe *elt = NULL;
669 	struct dt_driver_probe elt_new = {
670 		.dm = dm,
671 		.dt_drv = dt_drv,
672 		.nodeoffset = node,
673 		.type = dt_drv->type,
674 	};
675 
676 	/* If node/type found in probe list or ready list, nothing to do */
677 	TAILQ_FOREACH(elt, &dt_driver_probe_list, link)
678 		if (!driver_probe_compare(&elt_new, elt))
679 			return TEE_SUCCESS;
680 
681 	TAILQ_FOREACH(elt, &dt_driver_ready_list, link)
682 		if (!driver_probe_compare(&elt_new, elt))
683 			return TEE_SUCCESS;
684 
685 	elt = malloc(sizeof(*elt));
686 	if (!elt)
687 		return TEE_ERROR_OUT_OF_MEMORY;
688 
689 	DMSG("element: %s on node %s", drv_name, node_name);
690 
691 	memcpy(elt, &elt_new, sizeof(*elt));
692 
693 	added_node = true;
694 
695 	TAILQ_INSERT_TAIL(&dt_driver_probe_list, elt, link);
696 
697 	/* Hack here for TRACE_DEBUG messages on current probe list elements */
698 	if (TRACE_LEVEL >= TRACE_FLOW)
699 		print_probe_list(fdt);
700 
701 	return TEE_SUCCESS;
702 }
703 
704 /*
705  * Add a node to the probe list if a dt_driver matches target compatible.
706  *
707  * If @type is DT_DRIVER_ANY, probe list can hold only 1 driver to probe for
708  * the node. A node may probe several drivers if have a unique driver type.
709  *
710  * Return TEE_SUCCESS if compatible found
711  *	  TEE_ERROR_ITEM_NOT_FOUND if no matching driver
712  *	  TEE_ERROR_OUT_OF_MEMORY if heap is exhausted
713  */
714 static TEE_Result add_probe_node_by_compat(const void *fdt, int node,
715 					   const char *compat)
716 {
717 	TEE_Result res = TEE_ERROR_ITEM_NOT_FOUND;
718 	const struct dt_driver *dt_drv = NULL;
719 	const struct dt_device_match *dm = NULL;
720 	uint32_t found_types = 0;
721 
722 	for_each_dt_driver(dt_drv) {
723 		for (dm = dt_drv->match_table; dm && dm->compatible; dm++) {
724 			if (strcmp(dm->compatible, compat) == 0) {
725 				assert(dt_drv->type < 32);
726 
727 				res = add_node_to_probe(fdt, node, dt_drv, dm);
728 				if (res)
729 					return res;
730 
731 				if (found_types & BIT(dt_drv->type)) {
732 					EMSG("Driver %s multi hit on type %u",
733 					     dt_drv->name, dt_drv->type);
734 					panic();
735 				}
736 				found_types |= BIT(dt_drv->type);
737 
738 				/* Matching found for this driver, try next */
739 				break;
740 			}
741 		}
742 	}
743 
744 	return res;
745 }
746 
747 /*
748  * Add the node to the probe list if matching compatible drivers are found.
749  * Follow node's compatible property list ordering to find matching driver.
750  */
751 TEE_Result dt_driver_maybe_add_probe_node(const void *fdt, int node)
752 {
753 	int idx = 0;
754 	int len = 0;
755 	int count = 0;
756 	const char *compat = NULL;
757 	TEE_Result res = TEE_ERROR_GENERIC;
758 
759 	if (fdt_get_status(fdt, node) == DT_STATUS_DISABLED)
760 		return TEE_SUCCESS;
761 
762 	count = fdt_stringlist_count(fdt, node, "compatible");
763 	if (count < 0)
764 		return TEE_SUCCESS;
765 
766 	for (idx = 0; idx < count; idx++) {
767 		compat = fdt_stringlist_get(fdt, node, "compatible", idx, &len);
768 		assert(compat && len > 0);
769 
770 		res = add_probe_node_by_compat(fdt, node, compat);
771 
772 		/* Stop lookup if something was found */
773 		if (res != TEE_ERROR_ITEM_NOT_FOUND)
774 			return res;
775 	}
776 
777 	return TEE_SUCCESS;
778 }
779 
780 static void parse_node(const void *fdt, int node)
781 {
782 	TEE_Result __maybe_unused res = TEE_ERROR_GENERIC;
783 	int subnode = 0;
784 
785 	fdt_for_each_subnode(subnode, fdt, node) {
786 		res = dt_driver_maybe_add_probe_node(fdt, subnode);
787 		if (res) {
788 			EMSG("Failed on node %s with %#"PRIx32,
789 			     fdt_get_name(fdt, subnode, NULL), res);
790 			panic();
791 		}
792 
793 		/*
794 		 * Rescursively parse the FDT, skipping disabled nodes.
795 		 * FDT is expected reliable and core shall have sufficient
796 		 * stack depth to possibly parse all DT nodes.
797 		 */
798 		if (IS_ENABLED(CFG_DRIVERS_DT_RECURSIVE_PROBE)) {
799 			if (fdt_get_status(fdt, subnode) == DT_STATUS_DISABLED)
800 				continue;
801 
802 			parse_node(fdt, subnode);
803 		}
804 	}
805 }
806 
807 /*
808  * Parse FDT for nodes and save in probe list the node for which a dt_driver
809  * matches node's compatible property.
810  */
811 static TEE_Result probe_dt_drivers_early(void)
812 {
813 	TEE_Result res = TEE_ERROR_GENERIC;
814 	const void *fdt = NULL;
815 
816 	fdt = get_secure_dt();
817 	if (!fdt)
818 		return TEE_SUCCESS;
819 
820 	parse_node(fdt, fdt_path_offset(fdt, "/"));
821 
822 	res = process_probe_list(fdt);
823 	if (res == TEE_ERROR_DEFER_DRIVER_INIT) {
824 		DMSG("Deferred drivers probing");
825 		print_probe_list(fdt);
826 		res = TEE_SUCCESS;
827 	}
828 
829 	return res;
830 }
831 
832 static TEE_Result probe_dt_drivers(void)
833 {
834 	TEE_Result res = TEE_ERROR_GENERIC;
835 	const void *fdt = NULL;
836 
837 	fdt = get_secure_dt();
838 	if (!fdt)
839 		return TEE_SUCCESS;
840 
841 	res = process_probe_list(fdt);
842 	if (res || !TAILQ_EMPTY(&dt_driver_failed_list)) {
843 		EMSG("Probe sequence result: %#"PRIx32, res);
844 		print_probe_list(fdt);
845 		panic();
846 	}
847 
848 	return TEE_SUCCESS;
849 }
850 
851 early_init_late(probe_dt_drivers_early);
852 driver_init(probe_dt_drivers);
853 
854 static TEE_Result release_probe_lists(void)
855 {
856 	struct dt_driver_probe *elt = NULL;
857 	struct dt_driver_probe *next = NULL;
858 	struct dt_driver_provider *prov = NULL;
859 	struct dt_driver_provider *next_prov = NULL;
860 	const void *fdt = NULL;
861 
862 	fdt = get_secure_dt();
863 	if (!fdt)
864 		return TEE_SUCCESS;
865 
866 	assert(fdt && TAILQ_EMPTY(&dt_driver_probe_list));
867 
868 	TAILQ_FOREACH_SAFE(elt, &dt_driver_ready_list, link, next)
869 		free(elt);
870 
871 	TAILQ_FOREACH_SAFE(elt, &dt_driver_failed_list, link, next)
872 	       free(elt);
873 
874 	SLIST_FOREACH_SAFE(prov, &dt_driver_provider_list, link, next_prov)
875 	       free(prov);
876 
877 	return TEE_SUCCESS;
878 }
879 
880 release_init_resource(release_probe_lists);
881 
882 /*
883  * Simple bus support: handy to parse subnodes
884  */
885 static TEE_Result simple_bus_probe(const void *fdt, int node,
886 				   const void *compat_data __unused)
887 {
888 	TEE_Result res = TEE_ERROR_GENERIC;
889 	int subnode = 0;
890 
891 	fdt_for_each_subnode(subnode, fdt, node) {
892 		res = dt_driver_maybe_add_probe_node(fdt, subnode);
893 		if (res) {
894 			EMSG("Failed on node %s with %#"PRIx32,
895 			     fdt_get_name(fdt, subnode, NULL), res);
896 			panic();
897 		}
898 	}
899 
900 	return TEE_SUCCESS;
901 }
902 
903 static const struct dt_device_match simple_bus_match_table[] = {
904 	{ .compatible = "simple-bus" },
905 	{ }
906 };
907 
908 DEFINE_DT_DRIVER(simple_bus_dt_driver) = {
909 	.name = "simple-bus",
910 	.match_table = simple_bus_match_table,
911 	.probe = simple_bus_probe,
912 };
913