xref: /optee_os/core/include/kernel/dt.h (revision bce2f88ab347b28f4149dacef2ad48ac67a500b6)
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  * struct dt_descriptor - Descriptor of the device tree
78  * @blob: Pointer to the device tree binary
79  * @frag_id: Used ID of fragments for device tree overlay
80  */
81 struct dt_descriptor {
82 	void *blob;
83 #ifdef _CFG_USE_DTB_OVERLAY
84 	int frag_id;
85 #endif
86 };
87 
88 extern uint8_t embedded_secure_dtb[];
89 
90 /*
91  * dt_getprop_as_number() - get a DT property a unsigned number
92  * @fdt: DT base address
93  * @nodeoffset: node offset
94  * @name: property string name
95  * @num: output number read
96  * Return 0 on success and a negative FDT error value on error
97  *
98  * The size of the property determines if it is read as an unsigned 32-bit
99  * or 64-bit integer.
100  */
101 int dt_getprop_as_number(const void *fdt, int nodeoffset, const char *name,
102 			 uint64_t *num);
103 
104 #ifdef CFG_DT
105 /*
106  * Find a driver that is suitable for the given DT node, that is, with
107  * a matching "compatible" property.
108  *
109  * @fdt: pointer to the device tree
110  * @offs: node offset
111  */
112 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs);
113 
114 /*
115  * Map a device into secure or non-secure memory and return the base VA and
116  * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or
117  * MEM_AREA_IO_NSEC, depending on the device status.
118  * If the mapping already exists, the function simply returns the @vbase and
119  * @size information.
120  *
121  * @offs is the offset of the node that describes the device in @fdt.
122  * @base receives the base virtual address corresponding to the base physical
123  * address of the "reg" property
124  * @size receives the size of the mapping
125  * @mapping what kind of mapping is done for memory.
126  *
127  * Returns 0 on success or -1 in case of error.
128  */
129 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size,
130 	       enum dt_map_dev_directive mapping);
131 
132 /*
133  * Check whether the node at @offs contains the property with propname or not.
134  *
135  * @offs is the offset of the node that describes the device in @fdt.
136  * @propname is the property that need to check
137  *
138  * Returns true on success or false if no propname.
139  */
140 bool dt_have_prop(const void *fdt, int offs, const char *propname);
141 
142 /*
143  * Modify or add "status" property to "disabled"
144  *
145  * @fdt reference to the Device Tree
146  * @node is the node offset to modify
147  *
148  * Returns 0 on success or -1 on failure
149  */
150 int dt_disable_status(void *fdt, int node);
151 
152 /*
153  * Force secure-status = "okay" and status="disabled" for the target node.
154  *
155  * @fdt reference to the Device Tree
156  * @node is the node offset to modify
157  *
158  * Returns 0 on success or -1 on failure
159  */
160 int dt_enable_secure_status(void *fdt, int node);
161 
162 /*
163  * FDT manipulation functions, not provided by <libfdt.h>
164  */
165 
166 /*
167  * Return the base address for the "reg" property of the specified node or
168  * (paddr_t)-1 in case of error
169  */
170 paddr_t fdt_reg_base_address(const void *fdt, int offs);
171 
172 /*
173  * Return the reg size for the reg property of the specified node or -1 in case
174  * of error
175  */
176 size_t fdt_reg_size(const void *fdt, int offs);
177 
178 /*
179  * Read the status and secure-status properties into a bitfield.
180  * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled,
181  * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC.
182  */
183 int fdt_get_status(const void *fdt, int offs);
184 
185 /*
186  * fdt_fill_device_info - Get generic device info from a node
187  *
188  * This function fills the generic information from a given node.
189  * Currently supports a single base register, a single clock,
190  * a single reset ID line and a single interrupt ID.
191  * Default DT_INFO_* macros are used when the relate property is not found.
192  */
193 void fdt_fill_device_info(const void *fdt, struct dt_node_info *info,
194 			  int node);
195 /*
196  * Read cells from a given property of the given node. Any number of 32-bit
197  * cells of the property can be read. Returns 0 on success, or a negative
198  * FDT error value otherwise.
199  */
200 int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name,
201 			  uint32_t *array, size_t count);
202 
203 /*
204  * Read one cell from a given multi-value property of the given node.
205  * Returns 0 on success, or a negative FDT error value otherwise.
206  */
207 int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name,
208 			  int index, uint32_t *value);
209 
210 /*
211  * Read one cell from a given property of the given node.
212  * Returns 0 on success, or a negative FDT error value otherwise.
213  */
214 int fdt_read_uint32(const void *fdt, int node, const char *prop_name,
215 		    uint32_t *value);
216 
217 /*
218  * Read one cell from a property of a cell or default to a given value
219  * Returns the 32bit cell value or @dflt_value on failure.
220  */
221 uint32_t fdt_read_uint32_default(const void *fdt, int node,
222 				 const char *prop_name, uint32_t dflt_value);
223 
224 /*
225  * This function fills reg node info (base & size) with an index.
226  *
227  * Returns 0 on success and a negative FDT error code on failure.
228  */
229 int fdt_get_reg_props_by_index(const void *fdt, int node, int index,
230 			       paddr_t *base, size_t *size);
231 
232 /*
233  * This function fills reg node info (base & size) with an index found by
234  * checking the reg-names node.
235  *
236  * Returns 0 on success and a negative FDT error code on failure.
237  */
238 int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name,
239 			      paddr_t *base, size_t *size);
240 
241 /* Returns embedded DTB if present, then external DTB if found, then NULL */
242 void *get_dt(void);
243 
244 /*
245  * get_secure_dt() - returns secure DTB for drivers
246  *
247  * Returns device tree that is considered secure for drivers to use.
248  *
249  * 1. Returns embedded DTB if available,
250  * 2. Secure external DTB if available,
251  * 3. If neither then NULL
252  */
253 void *get_secure_dt(void);
254 
255 /* Returns embedded DTB location if present, otherwise NULL */
256 void *get_embedded_dt(void);
257 
258 /* Returns true if passed DTB is same as Embedded DTB, otherwise false */
259 static inline bool is_embedded_dt(void *fdt)
260 {
261 	return fdt && fdt == get_embedded_dt();
262 }
263 
264 /* Returns DTB descriptor of the external DTB if present, otherwise NULL */
265 struct dt_descriptor *get_external_dt_desc(void);
266 
267 /*
268  * init_external_dt() - Initialize the external DTB located at given address.
269  * @phys_dt:	Physical address where the external DTB located.
270  * @dt_sz:	Maximum size of the external DTB.
271  *
272  * Initialize the external DTB.
273  *
274  * 1. Add MMU mapping of the external DTB,
275  * 2. Initialize device tree overlay
276  */
277 void init_external_dt(unsigned long phys_dt, size_t dt_sz);
278 
279 /* Returns external DTB if present, otherwise NULL */
280 void *get_external_dt(void);
281 
282 /*
283  * add_dt_path_subnode() - Add new child node into a parent node.
284  * @dt:		Pointer to a device tree descriptor which has DTB.
285  * @path:	Path to the parent node.
286  * @subnode:	Name of the child node.
287  *
288  * Returns the offset of the child node in DTB on success or a negative libfdt
289  * error number.
290  */
291 int add_dt_path_subnode(struct dt_descriptor *dt, const char *path,
292 			const char *subnode);
293 
294 /*
295  * add_res_mem_dt_node() - Create "reserved-memory" parent and child nodes.
296  * @dt:		Pointer to a device tree descriptor which has DTB.
297  * @name:	Name of the child node.
298  * @pa:		Physical address of specific reserved memory region.
299  * @size:	Size of specific reserved memory region.
300  *
301  * Returns 0 if succeeds, otherwise a negative libfdt error number.
302  */
303 int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name,
304 			paddr_t pa, size_t size);
305 
306 #else /* !CFG_DT */
307 
308 static inline const struct dt_driver *dt_find_compatible_driver(
309 					const void *fdt __unused,
310 					int offs __unused)
311 {
312 	return NULL;
313 }
314 
315 static inline int dt_map_dev(const void *fdt __unused, int offs __unused,
316 			     vaddr_t *vbase __unused, size_t *size __unused,
317 			     enum dt_map_dev_directive mapping __unused)
318 {
319 	return -1;
320 }
321 
322 static inline paddr_t fdt_reg_base_address(const void *fdt __unused,
323 					   int offs __unused)
324 {
325 	return (paddr_t)-1;
326 }
327 
328 static inline size_t fdt_reg_size(const void *fdt __unused,
329 				  int offs __unused)
330 {
331 	return (size_t)-1;
332 }
333 
334 static inline int fdt_get_status(const void *fdt __unused, int offs __unused)
335 {
336 	return -1;
337 }
338 
339 __noreturn
340 static inline void fdt_fill_device_info(const void *fdt __unused,
341 					struct dt_node_info *info __unused,
342 					int node __unused)
343 {
344 	panic();
345 }
346 
347 static inline int fdt_read_uint32_array(const void *fdt __unused,
348 					int node __unused,
349 					const char *prop_name __unused,
350 					uint32_t *array __unused,
351 					size_t count __unused)
352 {
353 	return -1;
354 }
355 
356 static inline int fdt_read_uint32(const void *fdt __unused,
357 				  int node __unused,
358 				  const char *prop_name __unused,
359 				  uint32_t *value __unused)
360 {
361 	return -1;
362 }
363 
364 static inline uint32_t fdt_read_uint32_default(const void *fdt __unused,
365 					       int node __unused,
366 					       const char *prop_name __unused,
367 					       uint32_t dflt_value __unused)
368 {
369 	return dflt_value;
370 }
371 
372 static inline int fdt_read_uint32_index(const void *fdt __unused,
373 					int node __unused,
374 					const char *prop_name __unused,
375 					int index __unused,
376 					uint32_t *value __unused)
377 {
378 	return -1;
379 }
380 
381 static inline int fdt_get_reg_props_by_index(const void *fdt __unused,
382 					     int node __unused,
383 					     int index __unused,
384 					     paddr_t *base __unused,
385 					     size_t *size __unused)
386 {
387 	return -1;
388 }
389 
390 static inline int fdt_get_reg_props_by_name(const void *fdt __unused,
391 					    int node __unused,
392 					    const char *name __unused,
393 					    paddr_t *base __unused,
394 					    size_t *size __unused)
395 {
396 	return -1;
397 }
398 
399 static inline void *get_dt(void)
400 {
401 	return NULL;
402 }
403 
404 static inline void *get_secure_dt(void)
405 {
406 	return NULL;
407 }
408 
409 static inline void *get_embedded_dt(void)
410 {
411 	return NULL;
412 }
413 
414 static inline bool is_embedded_dt(void *fdt __unused)
415 {
416 	return false;
417 }
418 
419 static inline struct dt_descriptor *get_external_dt_desc(void)
420 {
421 	return NULL;
422 }
423 
424 static inline void init_external_dt(unsigned long phys_dt __unused,
425 				    size_t dt_sz __unused)
426 {
427 }
428 
429 static inline void *get_external_dt(void)
430 {
431 	return NULL;
432 }
433 
434 static inline int add_dt_path_subnode(struct dt_descriptor *dt __unused,
435 				      const char *path __unused,
436 				      const char *subnode __unused)
437 {
438 	return -1;
439 }
440 
441 static inline int add_res_mem_dt_node(struct dt_descriptor *dt __unused,
442 				      const char *name __unused,
443 				      paddr_t pa __unused,
444 				      size_t size __unused)
445 {
446 	return -1;
447 }
448 
449 #endif /* !CFG_DT */
450 #endif /* __KERNEL_DT_H */
451