xref: /kvm-unit-tests/lib/devicetree.h (revision dd3f102f482b0930a652b601754358c5247f0cb4)
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 
71 /* dt_bus_match_any matches any fdt node, i.e. it always returns true */
72 extern int dt_bus_match_any(const struct dt_device *dev, int fdtnode);
73 
74 /* the processor bus (pbus) address type and register tuple */
75 typedef u64 dt_pbus_addr_t;
76 struct dt_pbus_reg {
77 	dt_pbus_addr_t addr;
78 	dt_pbus_addr_t size;
79 };
80 
dt_pbus_read_cells(u32 nr_cells,u32 * cells)81 static inline dt_pbus_addr_t dt_pbus_read_cells(u32 nr_cells, u32 *cells)
82 {
83 	switch (nr_cells) {
84 	case 1: return cells[0];
85 	case 2: return ((u64)cells[0] << 32) | cells[1];
86 	}
87 	return (~0ULL);
88 }
89 
90 /*
91  * dt_pbus_translate translates device node regs for the
92  * processor bus using the parent node's #address-cells
93  * and #size-cells and dt_pbus_read_cells()
94  * returns
95  *  - zero on success
96  *  - a negative FDT_ERR_* value on failure
97  */
98 extern int dt_pbus_translate(const struct dt_device *dev, int regidx,
99 			     void *reg);
100 
101 /*
102  * dt_pbus_translate_node is the same as dt_pbus_translate but
103  * operates on an fdt node instead of a dt_device
104  */
105 extern int dt_pbus_translate_node(int fdtnode, int regidx,
106 				  struct dt_pbus_reg *reg);
107 
108 /*
109  * dt_pbus_get_base is an alias for
110  *     dt_pbus_translate(dev, 0, base)
111  * returns
112  *  - zero on success
113  *  - a negative FDT_ERR_* value on failure
114  */
dt_pbus_get_base(const struct dt_device * dev,struct dt_pbus_reg * base)115 static inline int dt_pbus_get_base(const struct dt_device *dev,
116 				   struct dt_pbus_reg *base)
117 {
118 	return dt_pbus_translate(dev, 0, base);
119 }
120 
121 /*
122  * dt_bus_init_defaults initializes @bus with
123  *  match		<- dt_bus_match_any
124  *  translate		<- dt_pbus_translate
125  */
126 extern void dt_bus_init_defaults(struct dt_bus *bus);
127 
128 /*
129  * dt_device_init initializes a dt_device with the given parameters
130  */
131 extern void dt_device_init(struct dt_device *dev, const struct dt_bus *bus,
132 			   void *info);
133 
dt_device_bind_node(struct dt_device * dev,int fdtnode)134 static inline void dt_device_bind_node(struct dt_device *dev, int fdtnode)
135 {
136 	dev->fdtnode = fdtnode;
137 }
138 
139 /*
140  * dt_device_find_compatible finds a @compatible node
141  * returns
142  *  - node (>= 0) on success
143  *  - a negative FDT_ERR_* value on failure
144  */
145 extern int dt_device_find_compatible(const struct dt_device *dev,
146 				     const char *compatible);
147 
148 /*
149  * dt_pbus_get_base_compatible simply bundles many functions into one.
150  * It finds the first @compatible fdt node, then translates the 0th reg
151  * tuple (the base) using the processor bus translation, and finally it
152  * stores that result in @base.
153  * returns
154  *  - zero on success
155  *  - a negative FDT_ERR_* value on failure
156  */
157 extern int dt_pbus_get_base_compatible(const char *compatible,
158 				       struct dt_pbus_reg *base);
159 
160 /**********************************************************************
161  * Low-level accessors for required node types and properties
162  **********************************************************************/
163 
164 /*
165  * dt_get_nr_cells sets @nr_address_cells and @nr_size_cells to the
166  * #address-cells and #size-cells properties of @fdtnode
167  * returns
168  *  - zero on success
169  *  - a negative FDT_ERR_* value on failure
170  */
171 extern int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells,
172 					u32 *nr_size_cells);
173 
174 /* dt_reg is a structure for "raw" reg tuples */
175 #define MAX_ADDRESS_CELLS	4
176 #define MAX_SIZE_CELLS		4
177 struct dt_reg {
178 	u32 nr_address_cells, nr_size_cells;
179 	u32 address_cells[MAX_ADDRESS_CELLS];
180 	u32 size_cells[MAX_SIZE_CELLS];
181 };
182 
183 /*
184  * dt_reg_init initialize a dt_reg struct to zero and sets
185  * nr_address_cells and nr_size_cells to @nr_address_cells and
186  * @nr_size_cells respectively.
187  */
188 extern void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells,
189 					    u32 nr_size_cells);
190 
191 /*
192  * dt_get_reg gets the @regidx'th reg tuple of @fdtnode's reg property
193  * and stores it in @reg. @reg must be initialized.
194  * returns
195  *  - zero on success
196  *  - a negative FDT_ERR_* value on failure
197  */
198 extern int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg);
199 
200 /**********************************************************************
201  * High-level accessors for required node types and properties
202  **********************************************************************/
203 
204 /*
205  * dt_get_bootargs gets the string pointer from /chosen/bootargs
206  * returns
207  *  - zero on success
208  *  - a negative FDT_ERR_* value on failure, and @bootargs
209  *    will be set to NULL
210  */
211 extern int dt_get_bootargs(const char **bootargs);
212 
213 /*
214  * dt_get_default_console_node gets the node of the path stored in
215  * /chosen/stdout-path (or the deprecated /chosen/linux,stdout-path)
216  * returns
217  *  - the node (>= 0) on success
218  *  - a negative FDT_ERR_* value on failure
219  */
220 extern int dt_get_default_console_node(void);
221 
222 /*
223  * dt_get_initrd gets the physical address of the initrd and its
224  * size from /chosen
225  * returns
226  *  - zero on success
227  *  - a negative FDT_ERR_* value on failure, and @initrd will be
228  *    set to NULL and @size set to zero
229  */
230 extern int dt_get_initrd(const char **initrd, u32 *size);
231 
232 /*
233  * dt_get_memory_params gets the memory parameters from the /memory node(s)
234  * storing each memory region ("address size" tuple) in consecutive entries
235  * of @regs, up to @nr_regs
236  * returns
237  *  - number of memory regions found on success
238  *  - a negative FDT_ERR_* value on failure
239  */
240 extern int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs);
241 
242 /*
243  * dt_for_each_cpu_node runs @func on each cpu node in the /cpus node
244  * passing it its fdt node, its reg property value, and @info
245  *  - zero on success
246  *  - a negative FDT_ERR_* value on failure
247  */
248 extern int dt_for_each_cpu_node(void (*func)(int fdtnode, u64 regval,
249 				void *info), void *info);
250 
251 #endif /* _DEVICETREE_H_ */
252