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