xref: /optee_os/core/include/kernel/dt.h (revision 3c778dee8bd290f7adacd7734d53b2442520693e)
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/panic.h>
11 #include <scattered_array.h>
12 #include <stdint.h>
13 #include <tee_api_types.h>
14 #include <types_ext.h>
15 #include <util.h>
16 
17 /*
18  * Bitfield to reflect status and secure-status values ("okay", "disabled"
19  * or not present)
20  */
21 #define DT_STATUS_DISABLED		U(0)
22 #define DT_STATUS_OK_NSEC		BIT(0)
23 #define DT_STATUS_OK_SEC		BIT(1)
24 
25 #define DT_INFO_INVALID_REG		((paddr_t)-1)
26 #define DT_INFO_INVALID_REG_SIZE	((size_t)-1)
27 #define DT_INFO_INVALID_CLOCK		-1
28 #define DT_INFO_INVALID_RESET		-1
29 #define DT_INFO_INVALID_INTERRUPT	-1
30 
31 /*
32  * @status: Bit mask for DT_STATUS_*
33  * @reg: Device register physical base address or DT_INFO_INVALID_REG
34  * @reg_size: Device register size or DT_INFO_INVALID_REG_SIZE
35  * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK
36  * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK
37  * @interrupt: Device interrupt identifier (positive value) or
38  * DT_INFO_INVALID_INTERRUPT
39  * @type: IRQ_TYPE_* value parsed from interrupts properties or IRQ_TYPE_NONE if
40  * not present
41  * @prio: interrupt priority parsed from interrupts properties or 0 if not
42  * present
43  */
44 struct dt_node_info {
45 	unsigned int status;
46 	paddr_t reg;
47 	size_t reg_size;
48 	int clock;
49 	int reset;
50 	int interrupt;
51 	uint32_t type;
52 	uint32_t prio;
53 };
54 
55 /*
56  * DT-aware drivers
57  */
58 
59 struct dt_device_match {
60 	const char *compatible;
61 	const void *compat_data;
62 };
63 
64 /*
65  * DT_MAP_AUTO: Uses status properties from device tree to determine mapping.
66  * DT_MAP_SECURE: Force mapping for device to be secure.
67  * DT_MAP_NON_SECURE: Force mapping for device to be non-secure.
68  */
69 enum dt_map_dev_directive {
70 	DT_MAP_AUTO,
71 	DT_MAP_SECURE,
72 	DT_MAP_NON_SECURE
73 };
74 
75 /*
76  * struct dt_descriptor - Descriptor of the device tree
77  * @blob: Pointer to the device tree binary
78  * @frag_id: Used ID of fragments for device tree overlay
79  */
80 struct dt_descriptor {
81 	void *blob;
82 #ifdef _CFG_USE_DTB_OVERLAY
83 	int frag_id;
84 #endif
85 };
86 
87 extern uint8_t embedded_secure_dtb[];
88 
89 #ifdef CFG_DT
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 /*
105  * Find a driver that is suitable for the given DT node, that is, with
106  * a matching "compatible" property.
107  *
108  * @fdt: pointer to the device tree
109  * @offs: node offset
110  */
111 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs);
112 
113 /*
114  * Map a device into secure or non-secure memory and return the base VA and
115  * the mapping size. The mapping is done with type MEM_AREA_IO_SEC or
116  * MEM_AREA_IO_NSEC, depending on the device status.
117  * If the mapping already exists, the function simply returns the @vbase and
118  * @size information.
119  *
120  * @offs is the offset of the node that describes the device in @fdt.
121  * @base receives the base virtual address corresponding to the base physical
122  * address of the "reg" property
123  * @size receives the size of the mapping
124  * @mapping what kind of mapping is done for memory.
125  *
126  * Returns 0 on success or -1 in case of error.
127  */
128 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size,
129 	       enum dt_map_dev_directive mapping);
130 
131 /*
132  * Check whether the node at @offs contains the property with propname or not.
133  *
134  * @offs is the offset of the node that describes the device in @fdt.
135  * @propname is the property that need to check
136  *
137  * Returns true on success or false if no propname.
138  */
139 bool dt_have_prop(const void *fdt, int offs, const char *propname);
140 
141 /*
142  * Modify or add "status" property to "disabled"
143  *
144  * @fdt reference to the Device Tree
145  * @node is the node offset to modify
146  *
147  * Returns 0 on success or -1 on failure
148  */
149 int dt_disable_status(void *fdt, int node);
150 
151 /*
152  * Force secure-status = "okay" and status="disabled" for the target node.
153  *
154  * @fdt reference to the Device Tree
155  * @node is the node offset to modify
156  *
157  * Returns 0 on success or -1 on failure
158  */
159 int dt_enable_secure_status(void *fdt, int node);
160 
161 /*
162  * FDT manipulation functions, not provided by <libfdt.h>
163  */
164 
165 /*
166  * Return the base address for the "reg" property of the specified node or
167  * (paddr_t)-1 in case of error
168  */
169 paddr_t fdt_reg_base_address(const void *fdt, int offs);
170 
171 /*
172  * Return the reg size for the reg property of the specified node or -1 in case
173  * of error
174  */
175 size_t fdt_reg_size(const void *fdt, int offs);
176 
177 /*
178  * Read the base address and/or reg size for the "reg" property of the
179  * specified node.
180  * @fdt: Reference to the Device Tree
181  * @offs: Offset to the node to read "reg" property from
182  * @base: Pointer to the output base address value, or NULL
183  * @size: Pointer to the output size value, or NULL
184  * Returns 0 on success and a negative FDT error value in case of failure
185  */
186 int fdt_reg_info(const void *fdt, int offs, paddr_t *base, size_t *size);
187 
188 /*
189  * Read the status and secure-status properties into a bitfield.
190  * Return -1 on failure, DT_STATUS_DISABLED if the node is disabled,
191  * otherwise return a combination of DT_STATUS_OK_NSEC and DT_STATUS_OK_SEC.
192  */
193 int fdt_get_status(const void *fdt, int offs);
194 
195 /*
196  * fdt_fill_device_info - Get generic device info from a node
197  *
198  * This function fills the generic information from a given node.
199  * Currently supports a single base register, a single clock,
200  * a single reset ID line and a single interrupt ID.
201  * Default DT_INFO_* macros are used when the relate property is not found.
202  */
203 void fdt_fill_device_info(const void *fdt, struct dt_node_info *info,
204 			  int node);
205 /*
206  * Read cells from a given property of the given node. Any number of 32-bit
207  * cells of the property can be read. Returns 0 on success, or a negative
208  * FDT error value otherwise.
209  */
210 int fdt_read_uint32_array(const void *fdt, int node, const char *prop_name,
211 			  uint32_t *array, size_t count);
212 
213 /*
214  * Read one cell from a given multi-value property of the given node.
215  * Returns 0 on success, or a negative FDT error value otherwise.
216  */
217 int fdt_read_uint32_index(const void *fdt, int node, const char *prop_name,
218 			  int index, uint32_t *value);
219 
220 /*
221  * Read one cell from a given property of the given node.
222  * Returns 0 on success, or a negative FDT error value otherwise.
223  */
224 int fdt_read_uint32(const void *fdt, int node, const char *prop_name,
225 		    uint32_t *value);
226 
227 /*
228  * Read one cell from a property of a cell or default to a given value
229  * Returns the 32bit cell value or @dflt_value on failure.
230  */
231 uint32_t fdt_read_uint32_default(const void *fdt, int node,
232 				 const char *prop_name, uint32_t dflt_value);
233 
234 /*
235  * This function fills reg node info (base & size) with an index.
236  *
237  * Returns 0 on success and a negative FDT error code on failure.
238  */
239 int fdt_get_reg_props_by_index(const void *fdt, int node, int index,
240 			       paddr_t *base, size_t *size);
241 
242 /*
243  * This function fills reg node info (base & size) with an index found by
244  * checking the reg-names node.
245  *
246  * Returns 0 on success and a negative FDT error code on failure.
247  */
248 int fdt_get_reg_props_by_name(const void *fdt, int node, const char *name,
249 			      paddr_t *base, size_t *size);
250 
251 /*
252  * Returns embedded DTB if present, then external DTB if found,
253  * then manifest DTB if found, then NULL.
254  */
255 void *get_dt(void);
256 
257 /*
258  * get_secure_dt() - returns secure DTB for drivers
259  *
260  * Returns device tree that is considered secure for drivers to use.
261  *
262  * 1. Returns embedded DTB if available,
263  * 2. Secure external DTB if available,
264  * 3. Manifest DTB if available,
265  * 4. If neither then NULL
266  */
267 void *get_secure_dt(void);
268 
269 /* Returns embedded DTB location if present, otherwise NULL */
270 void *get_embedded_dt(void);
271 
272 /* Returns true if passed DTB is same as Embedded DTB, otherwise false */
is_embedded_dt(void * fdt)273 static inline bool is_embedded_dt(void *fdt)
274 {
275 	return fdt && fdt == get_embedded_dt();
276 }
277 
278 /* Returns DTB descriptor of the external DTB if present, otherwise NULL */
279 struct dt_descriptor *get_external_dt_desc(void);
280 
281 /*
282  * init_external_dt() - Initialize the external DTB located at given address.
283  * @phys_dt:	Physical address where the external DTB located.
284  * @dt_sz:	Maximum size of the external DTB.
285  *
286  * Initialize the external DTB.
287  *
288  * 1. Add MMU mapping of the external DTB,
289  * 2. Initialize device tree overlay
290  */
291 void init_external_dt(unsigned long phys_dt, size_t dt_sz);
292 
293 /* Returns external DTB if present, otherwise NULL */
294 void *get_external_dt(void);
295 
296 /*
297  * add_dt_path_subnode() - Add new child node into a parent node.
298  * @dt:		Pointer to a device tree descriptor which has DTB.
299  * @path:	Path to the parent node.
300  * @subnode:	Name of the child node.
301  *
302  * Returns the offset of the child node in DTB on success or a negative libfdt
303  * error number.
304  */
305 int add_dt_path_subnode(struct dt_descriptor *dt, const char *path,
306 			const char *subnode);
307 
308 /*
309  * add_dt_node_overlay_fragment() - Add an overlay node fragment for a node.
310  * @node:	Offset of the node where to add an overlay fragment
311  *
312  * Returns the offset into the __overlay__ child node which can be used
313  * by the caller to add properties on success or a negative libfdt
314  * error number.
315  */
316 int add_dt_node_overlay_fragment(int node);
317 
318 /*
319  * add_res_mem_dt_node() - Create "reserved-memory" parent and child nodes.
320  * @dt:		Pointer to a device tree descriptor which has DTB.
321  * @name:	Name of the child node.
322  * @pa:		Physical address of specific reserved memory region.
323  * @size:	Size of specific reserved memory region.
324  *
325  * Returns 0 if succeeds, otherwise a negative libfdt error number.
326  */
327 int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name,
328 			paddr_t pa, size_t size);
329 
330 /*
331  * init_manifest_dt() - Initialize the manifest DTB to given address.
332  * @fdt:	Physical address where the manifest DTB located.
333  * @max_size:	Maximum size of the DTB
334  *
335  * Initialize the manifest DTB to physical address
336  */
337 void init_manifest_dt(void *fdt, size_t max_size);
338 
339 /*
340  * reinit_manifest_dt() - Reinitialize the manifest DTB
341  *
342  * Reserve used physical memory, add MMU mapping of the manifest DTB, and
343  * initialize device tree overlay
344  */
345 void reinit_manifest_dt(void);
346 
347 /* Returns TOS_FW_CONFIG DTB or SP manifest DTB if present, otherwise NULL */
348 void *get_manifest_dt(void);
349 
350 #else /* !CFG_DT */
351 
dt_find_compatible_driver(const void * fdt __unused,int offs __unused)352 static inline const struct dt_driver *dt_find_compatible_driver(
353 					const void *fdt __unused,
354 					int offs __unused)
355 {
356 	return NULL;
357 }
358 
dt_map_dev(const void * fdt __unused,int offs __unused,vaddr_t * vbase __unused,size_t * size __unused,enum dt_map_dev_directive mapping __unused)359 static inline int dt_map_dev(const void *fdt __unused, int offs __unused,
360 			     vaddr_t *vbase __unused, size_t *size __unused,
361 			     enum dt_map_dev_directive mapping __unused)
362 {
363 	return -1;
364 }
365 
fdt_reg_base_address(const void * fdt __unused,int offs __unused)366 static inline paddr_t fdt_reg_base_address(const void *fdt __unused,
367 					   int offs __unused)
368 {
369 	return (paddr_t)-1;
370 }
371 
fdt_reg_size(const void * fdt __unused,int offs __unused)372 static inline size_t fdt_reg_size(const void *fdt __unused,
373 				  int offs __unused)
374 {
375 	return (size_t)-1;
376 }
377 
fdt_reg_info(const void * fdt __unused,int offs __unused,paddr_t * base __unused,size_t * size __unused)378 static inline int fdt_reg_info(const void *fdt __unused, int offs __unused,
379 			       paddr_t *base __unused, size_t *size __unused)
380 {
381 	return -1;
382 }
383 
fdt_get_status(const void * fdt __unused,int offs __unused)384 static inline int fdt_get_status(const void *fdt __unused, int offs __unused)
385 {
386 	return -1;
387 }
388 
389 __noreturn
fdt_fill_device_info(const void * fdt __unused,struct dt_node_info * info __unused,int node __unused)390 static inline void fdt_fill_device_info(const void *fdt __unused,
391 					struct dt_node_info *info __unused,
392 					int node __unused)
393 {
394 	panic();
395 }
396 
fdt_read_uint32_array(const void * fdt __unused,int node __unused,const char * prop_name __unused,uint32_t * array __unused,size_t count __unused)397 static inline int fdt_read_uint32_array(const void *fdt __unused,
398 					int node __unused,
399 					const char *prop_name __unused,
400 					uint32_t *array __unused,
401 					size_t count __unused)
402 {
403 	return -1;
404 }
405 
fdt_read_uint32(const void * fdt __unused,int node __unused,const char * prop_name __unused,uint32_t * value __unused)406 static inline int fdt_read_uint32(const void *fdt __unused,
407 				  int node __unused,
408 				  const char *prop_name __unused,
409 				  uint32_t *value __unused)
410 {
411 	return -1;
412 }
413 
fdt_read_uint32_default(const void * fdt __unused,int node __unused,const char * prop_name __unused,uint32_t dflt_value __unused)414 static inline uint32_t fdt_read_uint32_default(const void *fdt __unused,
415 					       int node __unused,
416 					       const char *prop_name __unused,
417 					       uint32_t dflt_value __unused)
418 {
419 	return dflt_value;
420 }
421 
fdt_read_uint32_index(const void * fdt __unused,int node __unused,const char * prop_name __unused,int index __unused,uint32_t * value __unused)422 static inline int fdt_read_uint32_index(const void *fdt __unused,
423 					int node __unused,
424 					const char *prop_name __unused,
425 					int index __unused,
426 					uint32_t *value __unused)
427 {
428 	return -1;
429 }
430 
fdt_get_reg_props_by_index(const void * fdt __unused,int node __unused,int index __unused,paddr_t * base __unused,size_t * size __unused)431 static inline int fdt_get_reg_props_by_index(const void *fdt __unused,
432 					     int node __unused,
433 					     int index __unused,
434 					     paddr_t *base __unused,
435 					     size_t *size __unused)
436 {
437 	return -1;
438 }
439 
fdt_get_reg_props_by_name(const void * fdt __unused,int node __unused,const char * name __unused,paddr_t * base __unused,size_t * size __unused)440 static inline int fdt_get_reg_props_by_name(const void *fdt __unused,
441 					    int node __unused,
442 					    const char *name __unused,
443 					    paddr_t *base __unused,
444 					    size_t *size __unused)
445 {
446 	return -1;
447 }
448 
dt_getprop_as_number(const void * fdt __unused,int nodeoffset __unused,const char * name __unused,uint64_t * num __unused)449 static inline int dt_getprop_as_number(const void *fdt __unused,
450 				       int nodeoffset __unused,
451 				       const char *name __unused,
452 				       uint64_t *num __unused)
453 {
454 	return -1;
455 }
456 
get_dt(void)457 static inline void *get_dt(void)
458 {
459 	return NULL;
460 }
461 
get_secure_dt(void)462 static inline void *get_secure_dt(void)
463 {
464 	return NULL;
465 }
466 
get_embedded_dt(void)467 static inline void *get_embedded_dt(void)
468 {
469 	return NULL;
470 }
471 
is_embedded_dt(void * fdt __unused)472 static inline bool is_embedded_dt(void *fdt __unused)
473 {
474 	return false;
475 }
476 
get_external_dt_desc(void)477 static inline struct dt_descriptor *get_external_dt_desc(void)
478 {
479 	return NULL;
480 }
481 
init_external_dt(unsigned long phys_dt __unused,size_t dt_sz __unused)482 static inline void init_external_dt(unsigned long phys_dt __unused,
483 				    size_t dt_sz __unused)
484 {
485 }
486 
get_external_dt(void)487 static inline void *get_external_dt(void)
488 {
489 	return NULL;
490 }
491 
add_dt_path_subnode(struct dt_descriptor * dt __unused,const char * path __unused,const char * subnode __unused)492 static inline int add_dt_path_subnode(struct dt_descriptor *dt __unused,
493 				      const char *path __unused,
494 				      const char *subnode __unused)
495 {
496 	return -1;
497 }
498 
add_dt_node_overlay_fragment(int node __unused)499 static inline int add_dt_node_overlay_fragment(int node __unused)
500 {
501 	return -1;
502 }
503 
add_res_mem_dt_node(struct dt_descriptor * dt __unused,const char * name __unused,paddr_t pa __unused,size_t size __unused)504 static inline int add_res_mem_dt_node(struct dt_descriptor *dt __unused,
505 				      const char *name __unused,
506 				      paddr_t pa __unused,
507 				      size_t size __unused)
508 {
509 	return -1;
510 }
511 
init_manifest_dt(void * fdt __unused,size_t max_size __unused)512 static inline void init_manifest_dt(void *fdt __unused,
513 				    size_t max_size __unused)
514 {
515 }
516 
reinit_manifest_dt(void)517 static inline void reinit_manifest_dt(void)
518 {
519 }
520 
get_manifest_dt(void)521 static inline void *get_manifest_dt(void)
522 {
523 	return NULL;
524 }
525 
526 #endif /* !CFG_DT */
527 
528 #ifdef CFG_DT_CACHED_NODE_INFO
529 /*
530  * Find the offset of a parent node in the parent node cache
531  * @fdt: FDT to work on
532  * @node_offset: Offset of the node we look for its parent
533  * @parent_offset: Output parent node offset upon success
534  * @return 0 on success and -1 on failure
535  */
536 int fdt_find_cached_parent_node(const void *fdt, int node_offset,
537 				int *parent_offset);
538 
539 /*
540  * Find the address/size cells value of a parent node in the parent node cache
541  * @fdt: FDT to work on
542  * @node_offset: Offset of the node we look for its parent
543  * @address_cells: Pointer to output #address-cells value upon success or NULL
544  * @size_cells: Pointer to output #size-cells value upon success or NULL
545  * @return 0 on success and -FDT_ERR_NOTFOUND on failure
546  */
547 int fdt_find_cached_parent_reg_cells(const void *fdt, int node_offset,
548 				     int *address_cells, int *size_cells);
549 /*
550  * Find the node offset from its phandle in the phandle cache
551  * @fdt: FDT to work on
552  * @phandle: Node phandle
553  * @node_offset: Pointer to output node offset upon success
554  * @return 0 on success and -FDT_ERR_NOTFOUND on failure
555  */
556 int fdt_find_cached_node_phandle(const void *fdt, uint32_t phandle,
557 				 int *node_offset);
558 #else
fdt_find_cached_parent_node(const void * fdt __unused,int node_offset __unused,int * parent_offset __unused)559 static inline int fdt_find_cached_parent_node(const void *fdt __unused,
560 					      int node_offset __unused,
561 					      int *parent_offset __unused)
562 {
563 	return -1;
564 }
565 
fdt_find_cached_parent_reg_cells(const void * fdt __unused,int node_offset __unused,int * address_cells __unused,int * size_cells __unused)566 static inline int fdt_find_cached_parent_reg_cells(const void *fdt __unused,
567 						   int node_offset __unused,
568 						   int *address_cells __unused,
569 						   int *size_cells __unused)
570 {
571 	return -1;
572 }
573 
fdt_find_cached_node_phandle(const void * fdt __unused,uint32_t phandle __unused,int * node_offset __unused)574 static inline int fdt_find_cached_node_phandle(const void *fdt __unused,
575 					       uint32_t phandle __unused,
576 					       int *node_offset __unused)
577 {
578 	return -1;
579 }
580 #endif /* CFG_DT_CACHED_NODE_INFO */
581 #endif /* __KERNEL_DT_H */
582