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_res_mem_dt_node() - Create "reserved-memory" parent and child nodes.
310 * @dt: Pointer to a device tree descriptor which has DTB.
311 * @name: Name of the child node.
312 * @pa: Physical address of specific reserved memory region.
313 * @size: Size of specific reserved memory region.
314 *
315 * Returns 0 if succeeds, otherwise a negative libfdt error number.
316 */
317 int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name,
318 paddr_t pa, size_t size);
319
320 /*
321 * init_manifest_dt() - Initialize the manifest DTB to given address.
322 * @fdt: Physical address where the manifest DTB located.
323 * @max_size: Maximum size of the DTB
324 *
325 * Initialize the manifest DTB to physical address
326 */
327 void init_manifest_dt(void *fdt, size_t max_size);
328
329 /*
330 * reinit_manifest_dt() - Reinitialize the manifest DTB
331 *
332 * Reserve used physical memory, add MMU mapping of the manifest DTB, and
333 * initialize device tree overlay
334 */
335 void reinit_manifest_dt(void);
336
337 /* Returns TOS_FW_CONFIG DTB or SP manifest DTB if present, otherwise NULL */
338 void *get_manifest_dt(void);
339
340 #else /* !CFG_DT */
341
dt_find_compatible_driver(const void * fdt __unused,int offs __unused)342 static inline const struct dt_driver *dt_find_compatible_driver(
343 const void *fdt __unused,
344 int offs __unused)
345 {
346 return NULL;
347 }
348
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)349 static inline int dt_map_dev(const void *fdt __unused, int offs __unused,
350 vaddr_t *vbase __unused, size_t *size __unused,
351 enum dt_map_dev_directive mapping __unused)
352 {
353 return -1;
354 }
355
fdt_reg_base_address(const void * fdt __unused,int offs __unused)356 static inline paddr_t fdt_reg_base_address(const void *fdt __unused,
357 int offs __unused)
358 {
359 return (paddr_t)-1;
360 }
361
fdt_reg_size(const void * fdt __unused,int offs __unused)362 static inline size_t fdt_reg_size(const void *fdt __unused,
363 int offs __unused)
364 {
365 return (size_t)-1;
366 }
367
fdt_reg_info(const void * fdt __unused,int offs __unused,paddr_t * base __unused,size_t * size __unused)368 static inline int fdt_reg_info(const void *fdt __unused, int offs __unused,
369 paddr_t *base __unused, size_t *size __unused)
370 {
371 return -1;
372 }
373
fdt_get_status(const void * fdt __unused,int offs __unused)374 static inline int fdt_get_status(const void *fdt __unused, int offs __unused)
375 {
376 return -1;
377 }
378
379 __noreturn
fdt_fill_device_info(const void * fdt __unused,struct dt_node_info * info __unused,int node __unused)380 static inline void fdt_fill_device_info(const void *fdt __unused,
381 struct dt_node_info *info __unused,
382 int node __unused)
383 {
384 panic();
385 }
386
fdt_read_uint32_array(const void * fdt __unused,int node __unused,const char * prop_name __unused,uint32_t * array __unused,size_t count __unused)387 static inline int fdt_read_uint32_array(const void *fdt __unused,
388 int node __unused,
389 const char *prop_name __unused,
390 uint32_t *array __unused,
391 size_t count __unused)
392 {
393 return -1;
394 }
395
fdt_read_uint32(const void * fdt __unused,int node __unused,const char * prop_name __unused,uint32_t * value __unused)396 static inline int fdt_read_uint32(const void *fdt __unused,
397 int node __unused,
398 const char *prop_name __unused,
399 uint32_t *value __unused)
400 {
401 return -1;
402 }
403
fdt_read_uint32_default(const void * fdt __unused,int node __unused,const char * prop_name __unused,uint32_t dflt_value __unused)404 static inline uint32_t fdt_read_uint32_default(const void *fdt __unused,
405 int node __unused,
406 const char *prop_name __unused,
407 uint32_t dflt_value __unused)
408 {
409 return dflt_value;
410 }
411
fdt_read_uint32_index(const void * fdt __unused,int node __unused,const char * prop_name __unused,int index __unused,uint32_t * value __unused)412 static inline int fdt_read_uint32_index(const void *fdt __unused,
413 int node __unused,
414 const char *prop_name __unused,
415 int index __unused,
416 uint32_t *value __unused)
417 {
418 return -1;
419 }
420
fdt_get_reg_props_by_index(const void * fdt __unused,int node __unused,int index __unused,paddr_t * base __unused,size_t * size __unused)421 static inline int fdt_get_reg_props_by_index(const void *fdt __unused,
422 int node __unused,
423 int index __unused,
424 paddr_t *base __unused,
425 size_t *size __unused)
426 {
427 return -1;
428 }
429
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)430 static inline int fdt_get_reg_props_by_name(const void *fdt __unused,
431 int node __unused,
432 const char *name __unused,
433 paddr_t *base __unused,
434 size_t *size __unused)
435 {
436 return -1;
437 }
438
dt_getprop_as_number(const void * fdt __unused,int nodeoffset __unused,const char * name __unused,uint64_t * num __unused)439 static inline int dt_getprop_as_number(const void *fdt __unused,
440 int nodeoffset __unused,
441 const char *name __unused,
442 uint64_t *num __unused)
443 {
444 return -1;
445 }
446
get_dt(void)447 static inline void *get_dt(void)
448 {
449 return NULL;
450 }
451
get_secure_dt(void)452 static inline void *get_secure_dt(void)
453 {
454 return NULL;
455 }
456
get_embedded_dt(void)457 static inline void *get_embedded_dt(void)
458 {
459 return NULL;
460 }
461
is_embedded_dt(void * fdt __unused)462 static inline bool is_embedded_dt(void *fdt __unused)
463 {
464 return false;
465 }
466
get_external_dt_desc(void)467 static inline struct dt_descriptor *get_external_dt_desc(void)
468 {
469 return NULL;
470 }
471
init_external_dt(unsigned long phys_dt __unused,size_t dt_sz __unused)472 static inline void init_external_dt(unsigned long phys_dt __unused,
473 size_t dt_sz __unused)
474 {
475 }
476
get_external_dt(void)477 static inline void *get_external_dt(void)
478 {
479 return NULL;
480 }
481
add_dt_path_subnode(struct dt_descriptor * dt __unused,const char * path __unused,const char * subnode __unused)482 static inline int add_dt_path_subnode(struct dt_descriptor *dt __unused,
483 const char *path __unused,
484 const char *subnode __unused)
485 {
486 return -1;
487 }
488
add_res_mem_dt_node(struct dt_descriptor * dt __unused,const char * name __unused,paddr_t pa __unused,size_t size __unused)489 static inline int add_res_mem_dt_node(struct dt_descriptor *dt __unused,
490 const char *name __unused,
491 paddr_t pa __unused,
492 size_t size __unused)
493 {
494 return -1;
495 }
496
init_manifest_dt(void * fdt __unused,size_t max_size __unused)497 static inline void init_manifest_dt(void *fdt __unused,
498 size_t max_size __unused)
499 {
500 }
501
reinit_manifest_dt(void)502 static inline void reinit_manifest_dt(void)
503 {
504 }
505
get_manifest_dt(void)506 static inline void *get_manifest_dt(void)
507 {
508 return NULL;
509 }
510
511 #endif /* !CFG_DT */
512
513 #ifdef CFG_DT_CACHED_NODE_INFO
514 /*
515 * Find the offset of a parent node in the parent node cache
516 * @fdt: FDT to work on
517 * @node_offset: Offset of the node we look for its parent
518 * @parent_offset: Output parent node offset upon success
519 * @return 0 on success and -1 on failure
520 */
521 int fdt_find_cached_parent_node(const void *fdt, int node_offset,
522 int *parent_offset);
523
524 /*
525 * Find the address/size cells value of a parent node in the parent node cache
526 * @fdt: FDT to work on
527 * @node_offset: Offset of the node we look for its parent
528 * @address_cells: Pointer to output #address-cells value upon success or NULL
529 * @size_cells: Pointer to output #size-cells value upon success or NULL
530 * @return 0 on success and -FDT_ERR_NOTFOUND on failure
531 */
532 int fdt_find_cached_parent_reg_cells(const void *fdt, int node_offset,
533 int *address_cells, int *size_cells);
534 /*
535 * Find the node offset from its phandle in the phandle cache
536 * @fdt: FDT to work on
537 * @phandle: Node phandle
538 * @node_offset: Pointer to output node offset upon success
539 * @return 0 on success and -FDT_ERR_NOTFOUND on failure
540 */
541 int fdt_find_cached_node_phandle(const void *fdt, uint32_t phandle,
542 int *node_offset);
543 #else
fdt_find_cached_parent_node(const void * fdt __unused,int node_offset __unused,int * parent_offset __unused)544 static inline int fdt_find_cached_parent_node(const void *fdt __unused,
545 int node_offset __unused,
546 int *parent_offset __unused)
547 {
548 return -1;
549 }
550
fdt_find_cached_parent_reg_cells(const void * fdt __unused,int node_offset __unused,int * address_cells __unused,int * size_cells __unused)551 static inline int fdt_find_cached_parent_reg_cells(const void *fdt __unused,
552 int node_offset __unused,
553 int *address_cells __unused,
554 int *size_cells __unused)
555 {
556 return -1;
557 }
558
fdt_find_cached_node_phandle(const void * fdt __unused,uint32_t phandle __unused,int * node_offset __unused)559 static inline int fdt_find_cached_node_phandle(const void *fdt __unused,
560 uint32_t phandle __unused,
561 int *node_offset __unused)
562 {
563 return -1;
564 }
565 #endif /* CFG_DT_CACHED_NODE_INFO */
566 #endif /* __KERNEL_DT_H */
567