xref: /optee_os/core/include/kernel/dt.h (revision ba2a6adb764f1310ad3c3091d89de84274f86b02)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2016-2021, Linaro Limited
4  */
5 
6 #ifndef KERNEL_DT_H
7 #define KERNEL_DT_H
8 
9 #include <compiler.h>
10 #include <kernel/interrupt.h>
11 #include <kernel/panic.h>
12 #include <scattered_array.h>
13 #include <stdint.h>
14 #include <tee_api_types.h>
15 #include <types_ext.h>
16 #include <util.h>
17 
18 /*
19  * Bitfield to reflect status and secure-status values ("okay", "disabled"
20  * or not present)
21  */
22 #define DT_STATUS_DISABLED		U(0)
23 #define DT_STATUS_OK_NSEC		BIT(0)
24 #define DT_STATUS_OK_SEC		BIT(1)
25 
26 #define DT_INFO_INVALID_REG		((paddr_t)-1)
27 #define DT_INFO_INVALID_REG_SIZE	((size_t)-1)
28 #define DT_INFO_INVALID_CLOCK		-1
29 #define DT_INFO_INVALID_RESET		-1
30 #define DT_INFO_INVALID_INTERRUPT	-1
31 
32 /*
33  * @status: Bit mask for DT_STATUS_*
34  * @reg: Device register physical base address or DT_INFO_INVALID_REG
35  * @reg_size: Device register size or DT_INFO_INVALID_REG_SIZE
36  * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK
37  * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK
38  * @interrupt: Device interrupt identifier (positive value) or
39  * DT_INFO_INVALID_INTERRUPT
40  * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if
41  * not present
42  * @prio: interrupt priority parsed from interrupts properties or 0 if not
43  * present
44  */
45 struct dt_node_info {
46 	unsigned int status;
47 	paddr_t reg;
48 	size_t reg_size;
49 	int clock;
50 	int reset;
51 	int interrupt;
52 	uint32_t type;
53 	uint32_t prio;
54 };
55 
56 /*
57  * DT-aware drivers
58  */
59 
60 struct dt_device_match {
61 	const char *compatible;
62 	const void *compat_data;
63 };
64 
65 /*
66  * DT_MAP_AUTO: Uses status properties from device tree to determine mapping.
67  * DT_MAP_SECURE: Force mapping for device to be secure.
68  * DT_MAP_NON_SECURE: Force mapping for device to be non-secure.
69  */
70 enum dt_map_dev_directive {
71 	DT_MAP_AUTO,
72 	DT_MAP_SECURE,
73 	DT_MAP_NON_SECURE
74 };
75 
76 /*
77  * dt_getprop_as_number() - get a DT property a unsigned number
78  * @fdt: DT base address
79  * @nodeoffset: node offset
80  * @name: property string name
81  * @num: output number read
82  * Return 0 on success and a negative FDT error value on error
83  *
84  * The size of the property determines if it is read as an unsigned 32-bit
85  * or 64-bit integer.
86  */
87 int dt_getprop_as_number(const void *fdt, int nodeoffset, const char *name,
88 			 uint64_t *num);
89 
90 #ifdef CFG_DT
91 /*
92  * Find a driver that is suitable for the given DT node, that is, with
93  * a matching "compatible" property.
94  *
95  * @fdt: pointer to the device tree
96  * @offs: node offset
97  */
98 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs);
99 
100 /*
101  * Map a device into secure or non-secure memory and return the base VA and
102  * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or
103  * MEM_AREA_IO_NSEC, depending on the device status.
104  * If the mapping already exists, the function simply returns the @vbase and
105  * @size information.
106  *
107  * @offs is the offset of the node that describes the device in @fdt.
108  * @base receives the base virtual address corresponding to the base physical
109  * address of the "reg" property
110  * @size receives the size of the mapping
111  * @mapping what kind of mapping is done for memory.
112  *
113  * Returns 0 on success or -1 in case of error.
114  */
115 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size,
116 	       enum dt_map_dev_directive mapping);
117 
118 /*
119  * Check whether the node at @offs contains the property with propname or not.
120  *
121  * @offs is the offset of the node that describes the device in @fdt.
122  * @propname is the property that need to check
123  *
124  * Returns true on success or false if no propname.
125  */
126 bool dt_have_prop(const void *fdt, int offs, const char *propname);
127 
128 /*
129  * Modify or add "status" property to "disabled"
130  *
131  * @fdt reference to the Device Tree
132  * @node is the node offset to modify
133  *
134  * Returns 0 on success or -1 on failure
135  */
136 int dt_disable_status(void *fdt, int node);
137 
138 /*
139  * Force secure-status = "okay" and status="disabled" for the target node.
140  *
141  * @fdt reference to the Device Tree
142  * @node is the node offset to modify
143  *
144  * Returns 0 on success or -1 on failure
145  */
146 int dt_enable_secure_status(void *fdt, int node);
147 
148 /*
149  * FDT manipulation functions, not provided by <libfdt.h>
150  */
151 
152 /*
153  * Return the base address for the "reg" property of the specified node or
154  * (paddr_t)-1 in case of error
155  */
156 paddr_t fdt_reg_base_address(const void *fdt, int offs);
157 
158 /*
159  * Return the reg size for the reg property of the specified node or -1 in case
160  * of error
161  */
162 size_t fdt_reg_size(const void *fdt, int offs);
163 
164 /*
165  * Read the status and secure-status properties into a bitfield.
166  * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled,
167  * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC.
168  */
169 int fdt_get_status(const void *fdt, int offs);
170 
171 /*
172  * fdt_fill_device_info - Get generic device info from a node
173  *
174  * This function fills the generic information from a given node.
175  * Currently supports a single base register, a single clock,
176  * a single reset ID line and a single interrupt ID.
177  * Default DT_INFO_* macros are used when the relate property is not found.
178  */
179 void fdt_fill_device_info(const void *fdt, struct dt_node_info *info,
180 			  int node);
181 /*
182  * Read cells from a given property of the given node. Any number of 32-bit
183  * cells of the property can be read. Returns 0 on success, or a negative
184  * FDT error value otherwise.
185  */
186 int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name,
187 			  uint32_t *array, size_t count);
188 
189 /*
190  * Read one cell from a given multi-value property of the given node.
191  * Returns 0 on success, or a negative FDT error value otherwise.
192  */
193 int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name,
194 			  int index, uint32_t *value);
195 
196 /*
197  * Read one cell from a given property of the given node.
198  * Returns 0 on success, or a negative FDT error value otherwise.
199  */
200 int fdt_read_uint32(const void *fdt, int node, const char *prop_name,
201 		    uint32_t *value);
202 
203 /*
204  * Read one cell from a property of a cell or default to a given value
205  * Returns the 32bit cell value or @dflt_value on failure.
206  */
207 uint32_t fdt_read_uint32_default(const void *fdt, int node,
208 				 const char *prop_name, uint32_t dflt_value);
209 
210 /*
211  * This function fills reg node info (base & size) with an index.
212  *
213  * Returns 0 on success and a negative FDT error code on failure.
214  */
215 int fdt_get_reg_props_by_index(const void *fdt, int node, int index,
216 			       paddr_t *base, size_t *size);
217 
218 /*
219  * This function fills reg node info (base & size) with an index found by
220  * checking the reg-names node.
221  *
222  * Returns 0 on success and a negative FDT error code on failure.
223  */
224 int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name,
225 			      paddr_t *base, size_t *size);
226 
227 #else /* !CFG_DT */
228 
229 static inline const struct dt_driver *dt_find_compatible_driver(
230 					const void *fdt __unused,
231 					int offs __unused)
232 {
233 	return NULL;
234 }
235 
236 static inline int dt_map_dev(const void *fdt __unused, int offs __unused,
237 			     vaddr_t *vbase __unused, size_t *size __unused,
238 			     enum dt_map_dev_directive mapping __unused)
239 {
240 	return -1;
241 }
242 
243 static inline paddr_t fdt_reg_base_address(const void *fdt __unused,
244 					   int offs __unused)
245 {
246 	return (paddr_t)-1;
247 }
248 
249 static inline size_t fdt_reg_size(const void *fdt __unused,
250 				  int offs __unused)
251 {
252 	return (size_t)-1;
253 }
254 
255 static inline int fdt_get_status(const void *fdt __unused, int offs __unused)
256 {
257 	return -1;
258 }
259 
260 __noreturn
261 static inline void fdt_fill_device_info(const void *fdt __unused,
262 					struct dt_node_info *info __unused,
263 					int node __unused)
264 {
265 	panic();
266 }
267 
268 static inline int fdt_read_uint32_array(const void *fdt __unused,
269 					int node __unused,
270 					const char *prop_name __unused,
271 					uint32_t *array __unused,
272 					size_t count __unused)
273 {
274 	return -1;
275 }
276 
277 static inline int fdt_read_uint32(const void *fdt __unused,
278 				  int node __unused,
279 				  const char *prop_name __unused,
280 				  uint32_t *value __unused)
281 {
282 	return -1;
283 }
284 
285 static inline uint32_t fdt_read_uint32_default(const void *fdt __unused,
286 					       int node __unused,
287 					       const char *prop_name __unused,
288 					       uint32_t dflt_value __unused)
289 {
290 	return dflt_value;
291 }
292 
293 static inline int fdt_read_uint32_index(const void *fdt __unused,
294 					int node __unused,
295 					const char *prop_name __unused,
296 					int index __unused,
297 					uint32_t *value __unused)
298 {
299 	return -1;
300 }
301 
302 static inline int fdt_get_reg_props_by_index(const void *fdt __unused,
303 					     int node __unused,
304 					     int index __unused,
305 					     paddr_t *base __unused,
306 					     size_t *size __unused)
307 {
308 	return -1;
309 }
310 
311 static inline int fdt_get_reg_props_by_name(const void *fdt __unused,
312 					    int node __unused,
313 					    const char *name __unused,
314 					    paddr_t *base __unused,
315 					    size_t *size __unused)
316 {
317 	return -1;
318 }
319 
320 #endif /* !CFG_DT */
321 #endif /* KERNEL_DT_H */
322