xref: /optee_os/core/kernel/dt_driver.c (revision f498c4042931108699ecc3d692cd2250700f8756)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2021, Linaro Limited
4  * Copyright (c) 2021, Bootlin
5  */
6 
7 #include <initcall.h>
8 #include <kernel/dt.h>
9 #include <kernel/dt_driver.h>
10 #include <libfdt.h>
11 #include <malloc.h>
12 #include <sys/queue.h>
13 #include <tee_api_types.h>
14 
15 struct dt_driver_prov_list dt_driver_provider_list =
16 	SLIST_HEAD_INITIALIZER(dt_driver_provider_list);
17 
18 /*
19  * Driver provider registering API functions
20  */
21 
22 TEE_Result dt_driver_register_provider(const void *fdt, int nodeoffset,
23 				       get_of_device_func get_of_device,
24 				       void *priv, enum dt_driver_type type)
25 {
26 	struct dt_driver_provider *prv = NULL;
27 	int provider_cells = 0;
28 	uint32_t phandle = 0;
29 
30 	provider_cells = fdt_get_dt_driver_cells(fdt, nodeoffset, type);
31 	if (provider_cells < 0) {
32 		DMSG("Failed to find provider cells: %d", provider_cells);
33 		return TEE_ERROR_GENERIC;
34 	}
35 
36 	phandle = fdt_get_phandle(fdt, nodeoffset);
37 	if (!phandle || phandle == (uint32_t)-1) {
38 		DMSG("Failed to find provide phandle");
39 		return TEE_ERROR_GENERIC;
40 	}
41 
42 	prv = calloc(1, sizeof(*prv));
43 	if (!prv)
44 		return TEE_ERROR_OUT_OF_MEMORY;
45 
46 	prv->nodeoffset = nodeoffset;
47 	prv->type = type;
48 	prv->provider_cells = provider_cells;
49 	prv->phandle = phandle;
50 	prv->get_of_device = get_of_device;
51 	prv->priv_data = priv;
52 
53 	SLIST_INSERT_HEAD(&dt_driver_provider_list, prv, link);
54 
55 	return TEE_SUCCESS;
56 }
57 
58 /* Release driver provider references once all dt_drivers are initialized */
59 static TEE_Result dt_driver_release_provider(void)
60 {
61 	struct dt_driver_provider *prv = NULL;
62 
63 	while (!SLIST_EMPTY(&dt_driver_provider_list)) {
64 		prv = SLIST_FIRST(&dt_driver_provider_list);
65 		SLIST_REMOVE_HEAD(&dt_driver_provider_list, link);
66 		free(prv);
67 	}
68 
69 	return TEE_SUCCESS;
70 }
71 
72 driver_init_late(dt_driver_release_provider);
73 
74 /*
75  * Helper functions for dt_drivers querying driver provider information
76  */
77 
78 int fdt_get_dt_driver_cells(const void *fdt, int nodeoffset,
79 			    enum dt_driver_type type)
80 {
81 	const char *cells_name = NULL;
82 	const fdt32_t *c = NULL;
83 	int len = 0;
84 
85 	switch (type) {
86 	case DT_DRIVER_CLK:
87 		cells_name = "#clock-cells";
88 		break;
89 	default:
90 		panic();
91 	}
92 
93 	c = fdt_getprop(fdt, nodeoffset, cells_name, &len);
94 	if (!c)
95 		return len;
96 
97 	if (len != sizeof(*c))
98 		return -FDT_ERR_BADNCELLS;
99 
100 	return fdt32_to_cpu(*c);
101 }
102 
103 unsigned int dt_driver_provider_cells(struct dt_driver_provider *prv)
104 {
105 	return prv->provider_cells;
106 }
107 
108 struct dt_driver_provider *dt_driver_get_provider_by_node(int nodeoffset)
109 {
110 	struct dt_driver_provider *prv = NULL;
111 
112 	SLIST_FOREACH(prv, &dt_driver_provider_list, link)
113 		if (prv->nodeoffset == nodeoffset)
114 			return prv;
115 
116 	return NULL;
117 }
118 
119 struct dt_driver_provider *dt_driver_get_provider_by_phandle(uint32_t phandle)
120 {
121 	struct dt_driver_provider *prv = NULL;
122 
123 	SLIST_FOREACH(prv, &dt_driver_provider_list, link)
124 		if (prv->phandle == phandle)
125 			return prv;
126 
127 	return NULL;
128 }
129