xref: /optee_os/core/include/kernel/dt.h (revision 6cfa381e534b362afbd103f526b132048e54ba47)
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  *
271  * Initialize the external DTB.
272  *
273  * 1. Add MMU mapping of the external DTB,
274  * 2. Initialize device tree overlay
275  */
276 void init_external_dt(unsigned long phys_dt);
277 
278 /* Returns external DTB if present, otherwise NULL */
279 void *get_external_dt(void);
280 
281 /*
282  * add_dt_path_subnode() - Add new child node into a parent node.
283  * @dt:		Pointer to a device tree descriptor which has DTB.
284  * @path:	Path to the parent node.
285  * @subnode:	Name of the child node.
286  *
287  * Returns the offset of the child node in DTB on success or a negative libfdt
288  * error number.
289  */
290 int add_dt_path_subnode(struct dt_descriptor *dt, const char *path,
291 			const char *subnode);
292 
293 /*
294  * add_res_mem_dt_node() - Create "reserved-memory" parent and child nodes.
295  * @dt:		Pointer to a device tree descriptor which has DTB.
296  * @name:	Name of the child node.
297  * @pa:		Physical address of specific reserved memory region.
298  * @size:	Size of specific reserved memory region.
299  *
300  * Returns 0 if succeeds, otherwise a negative libfdt error number.
301  */
302 int add_res_mem_dt_node(struct dt_descriptor *dt, const char *name,
303 			paddr_t pa, size_t size);
304 
305 #else /* !CFG_DT */
306 
307 static inline const struct dt_driver *dt_find_compatible_driver(
308 					const void *fdt __unused,
309 					int offs __unused)
310 {
311 	return NULL;
312 }
313 
314 static inline int dt_map_dev(const void *fdt __unused, int offs __unused,
315 			     vaddr_t *vbase __unused, size_t *size __unused,
316 			     enum dt_map_dev_directive mapping __unused)
317 {
318 	return -1;
319 }
320 
321 static inline paddr_t fdt_reg_base_address(const void *fdt __unused,
322 					   int offs __unused)
323 {
324 	return (paddr_t)-1;
325 }
326 
327 static inline size_t fdt_reg_size(const void *fdt __unused,
328 				  int offs __unused)
329 {
330 	return (size_t)-1;
331 }
332 
333 static inline int fdt_get_status(const void *fdt __unused, int offs __unused)
334 {
335 	return -1;
336 }
337 
338 __noreturn
339 static inline void fdt_fill_device_info(const void *fdt __unused,
340 					struct dt_node_info *info __unused,
341 					int node __unused)
342 {
343 	panic();
344 }
345 
346 static inline int fdt_read_uint32_array(const void *fdt __unused,
347 					int node __unused,
348 					const char *prop_name __unused,
349 					uint32_t *array __unused,
350 					size_t count __unused)
351 {
352 	return -1;
353 }
354 
355 static inline int fdt_read_uint32(const void *fdt __unused,
356 				  int node __unused,
357 				  const char *prop_name __unused,
358 				  uint32_t *value __unused)
359 {
360 	return -1;
361 }
362 
363 static inline uint32_t fdt_read_uint32_default(const void *fdt __unused,
364 					       int node __unused,
365 					       const char *prop_name __unused,
366 					       uint32_t dflt_value __unused)
367 {
368 	return dflt_value;
369 }
370 
371 static inline int fdt_read_uint32_index(const void *fdt __unused,
372 					int node __unused,
373 					const char *prop_name __unused,
374 					int index __unused,
375 					uint32_t *value __unused)
376 {
377 	return -1;
378 }
379 
380 static inline int fdt_get_reg_props_by_index(const void *fdt __unused,
381 					     int node __unused,
382 					     int index __unused,
383 					     paddr_t *base __unused,
384 					     size_t *size __unused)
385 {
386 	return -1;
387 }
388 
389 static inline int fdt_get_reg_props_by_name(const void *fdt __unused,
390 					    int node __unused,
391 					    const char *name __unused,
392 					    paddr_t *base __unused,
393 					    size_t *size __unused)
394 {
395 	return -1;
396 }
397 
398 static inline void *get_dt(void)
399 {
400 	return NULL;
401 }
402 
403 static inline void *get_secure_dt(void)
404 {
405 	return NULL;
406 }
407 
408 static inline void *get_embedded_dt(void)
409 {
410 	return NULL;
411 }
412 
413 static inline bool is_embedded_dt(void *fdt __unused)
414 {
415 	return false;
416 }
417 
418 static inline struct dt_descriptor *get_external_dt_desc(void)
419 {
420 	return NULL;
421 }
422 
423 static inline void init_external_dt(unsigned long phys_dt __unused)
424 {
425 }
426 
427 static inline void *get_external_dt(void)
428 {
429 	return NULL;
430 }
431 
432 static inline int add_dt_path_subnode(struct dt_descriptor *dt __unused,
433 				      const char *path __unused,
434 				      const char *subnode __unused)
435 {
436 	return -1;
437 }
438 
439 static inline int add_res_mem_dt_node(struct dt_descriptor *dt __unused,
440 				      const char *name __unused,
441 				      paddr_t pa __unused,
442 				      size_t size __unused)
443 {
444 	return -1;
445 }
446 
447 #endif /* !CFG_DT */
448 #endif /* KERNEL_DT_H */
449