xref: /kvm-unit-tests/lib/devicetree.h (revision d3aacb4f57d05f74f2030dbe12e7dfd6aa1b273d)
1 #ifndef _DEVICETREE_H_
2 #define _DEVICETREE_H_
3 /*
4  * devicetree builds on libfdt to implement abstractions and accessors
5  * for Linux required device tree content. The accessors provided are
6  * common across architectures. See section III of the kernel doc
7  * Documentation/devicetree/booting-without-of.txt
8  *
9  * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
10  *
11  * This work is licensed under the terms of the GNU LGPL, version 2.
12  */
13 #include "libcflat.h"
14 #include "libfdt/libfdt.h"
15 
16 /**********************************************************************
17  * devicetree init and libfdt helpers
18  **********************************************************************/
19 
20 /* dt_init initializes devicetree with a pointer to an fdt, @fdt_ptr */
21 extern int dt_init(const void *fdt_ptr);
22 
23 /* get the fdt pointer that devicetree is using */
24 extern const void *dt_fdt(void);
25 
26 /* check for an initialized, valid devicetree */
27 extern bool dt_available(void);
28 
29 /* traverse child nodes */
30 #define dt_for_each_subnode(n, s)					\
31 	for (s = fdt_first_subnode(dt_fdt(), n);			\
32 	     s != -FDT_ERR_NOTFOUND;					\
33 	     s = fdt_next_subnode(dt_fdt(), s))
34 
35 /**********************************************************************
36  * Abstractions for required node types and properties
37  **********************************************************************/
38 
39 struct dt_device {
40 	int fdtnode;
41 	const struct dt_bus *bus;
42 
43 	/*
44 	 * info is a pointer to device specific data, which may be
45 	 * used by the bus match() and translate() functions
46 	 */
47 	void *info;
48 };
49 
50 struct dt_bus {
51 	/*
52 	 * match a device @dev to an fdt node @fdtnode
53 	 * returns
54 	 *  - a positive value on match
55 	 *  - zero on no match
56 	 *  - a negative FDT_ERR_* value on failure
57 	 */
58 	int (*match)(const struct dt_device *dev, int fdtnode);
59 
60 	/*
61 	 * translate the @regidx'th "address size" tuple of
62 	 * @dev's fdt node's "reg" property, and store the result
63 	 * in @reg, a bus specific structure
64 	 * returns
65 	 *  - zero on success
66 	 *  - a negative FDT_ERR_* value on failure
67 	 */
68 	int (*translate)(const struct dt_device *dev, int regidx, void *reg);
69 
70 	/* the bus #address-cells and #size-cells properties */
71 	u32 nr_address_cells, nr_size_cells;
72 };
73 
74 /* dt_bus_match_any matches any fdt node, i.e. it always returns true */
75 extern int dt_bus_match_any(const struct dt_device *dev, int fdtnode);
76 
77 /* the processor bus (pbus) address type and register tuple */
78 typedef u64 dt_pbus_addr_t;
79 struct dt_pbus_reg {
80 	dt_pbus_addr_t addr;
81 	dt_pbus_addr_t size;
82 };
83 
84 static inline dt_pbus_addr_t dt_pbus_read_cells(u32 nr_cells, u32 *cells)
85 {
86 	switch (nr_cells) {
87 	case 1: return cells[0];
88 	case 2: return ((u64)cells[0] << 32) | cells[1];
89 	}
90 	return (~0ULL);
91 }
92 
93 /*
94  * dt_pbus_translate translates device node regs for the
95  * processor bus using the root node's #address-cells and
96  * #size-cells and dt_pbus_read_cells()
97  * returns
98  *  - zero on success
99  *  - a negative FDT_ERR_* value on failure
100  */
101 extern int dt_pbus_translate(const struct dt_device *dev, int regidx,
102 			     void *reg);
103 
104 /*
105  * dt_pbus_translate_node is the same as dt_pbus_translate but
106  * operates on an fdt node instead of a dt_device
107  */
108 extern int dt_pbus_translate_node(int fdtnode, int regidx,
109 				  struct dt_pbus_reg *reg);
110 
111 /*
112  * dt_pbus_get_base is an alias for
113  *     dt_pbus_translate(dev, 0, base)
114  * returns
115  *  - zero on success
116  *  - a negative FDT_ERR_* value on failure
117  */
118 static inline int dt_pbus_get_base(const struct dt_device *dev,
119 				   struct dt_pbus_reg *base)
120 {
121 	return dt_pbus_translate(dev, 0, base);
122 }
123 
124 /*
125  * dt_bus_init_defaults initializes @bus with
126  *  match		<- dt_bus_match_any
127  *  translate		<- dt_pbus_translate
128  *  nr_address_cells	<- #address-cells of the root node
129  *  nr_size_cells	<- #size-cells of the root node
130  */
131 extern void dt_bus_init_defaults(struct dt_bus *bus);
132 
133 /*
134  * dt_device_init initializes a dt_device with the given parameters
135  */
136 extern void dt_device_init(struct dt_device *dev, const struct dt_bus *bus,
137 			   void *info);
138 
139 static inline void dt_device_bind_node(struct dt_device *dev, int fdtnode)
140 {
141 	dev->fdtnode = fdtnode;
142 }
143 
144 /*
145  * dt_device_find_compatible finds a @compatible node
146  * returns
147  *  - node (>= 0) on success
148  *  - a negative FDT_ERR_* value on failure
149  */
150 extern int dt_device_find_compatible(const struct dt_device *dev,
151 				     const char *compatible);
152 
153 /*
154  * dt_pbus_get_base_compatible simply bundles many functions into one.
155  * It finds the first @compatible fdt node, then translates the 0th reg
156  * tuple (the base) using the processor bus translation, and finally it
157  * stores that result in @base.
158  * returns
159  *  - zero on success
160  *  - a negative FDT_ERR_* value on failure
161  */
162 extern int dt_pbus_get_base_compatible(const char *compatible,
163 				       struct dt_pbus_reg *base);
164 
165 /**********************************************************************
166  * Low-level accessors for required node types and properties
167  **********************************************************************/
168 
169 /*
170  * dt_get_nr_cells sets @nr_address_cells and @nr_size_cells to the
171  * #address-cells and #size-cells properties of @fdtnode
172  * returns
173  *  - zero on success
174  *  - a negative FDT_ERR_* value on failure
175  */
176 extern int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells,
177 					u32 *nr_size_cells);
178 
179 /* dt_reg is a structure for "raw" reg tuples */
180 #define MAX_ADDRESS_CELLS	4
181 #define MAX_SIZE_CELLS		4
182 struct dt_reg {
183 	u32 nr_address_cells, nr_size_cells;
184 	u32 address_cells[MAX_ADDRESS_CELLS];
185 	u32 size_cells[MAX_SIZE_CELLS];
186 };
187 
188 /*
189  * dt_reg_init initialize a dt_reg struct to zero and sets
190  * nr_address_cells and nr_size_cells to @nr_address_cells and
191  * @nr_size_cells respectively.
192  */
193 extern void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells,
194 					    u32 nr_size_cells);
195 
196 /*
197  * dt_get_reg gets the @regidx'th reg tuple of @fdtnode's reg property
198  * and stores it in @reg. @reg must be initialized.
199  * returns
200  *  - zero on success
201  *  - a negative FDT_ERR_* value on failure
202  */
203 extern int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg);
204 
205 /**********************************************************************
206  * High-level accessors for required node types and properties
207  **********************************************************************/
208 
209 /*
210  * dt_get_bootargs gets a pointer to /chosen/bootargs
211  * returns
212  *  - zero on success
213  *  - a negative FDT_ERR_* value on failure
214  */
215 extern int dt_get_bootargs(const char **bootargs);
216 
217 /*
218  * dt_get_memory_params gets the memory parameters from the /memory node(s)
219  * storing each memory region ("address size" tuple) in consecutive entries
220  * of @regs, up to @nr_regs
221  * returns
222  *  - number of memory regions found on success
223  *  - a negative FDT_ERR_* value on failure
224  */
225 extern int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs);
226 
227 /*
228  * dt_for_each_cpu_node runs @func on each cpu node in the /cpus node
229  * passing it its fdt node, its reg property value, and @info
230  *  - zero on success
231  *  - a negative FDT_ERR_* value on failure
232  */
233 extern int dt_for_each_cpu_node(void (*func)(int fdtnode, u32 regval,
234 				void *info), void *info);
235 
236 #endif /* _DEVICETREE_H_ */
237