File size: 7,589 Bytes
8df6da4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#ifndef _DEVICETREE_H_
#define _DEVICETREE_H_
/*
 * devicetree builds on libfdt to implement abstractions and accessors
 * for Linux required device tree content. The accessors provided are
 * common across architectures. See section III of the kernel doc
 * Documentation/devicetree/booting-without-of.txt
 *
 * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.
 */
#include "libcflat.h"
#include "libfdt/libfdt.h"

/**********************************************************************
 * devicetree init and libfdt helpers
 **********************************************************************/

/* dt_init initializes devicetree with a pointer to an fdt, @fdt_ptr */
extern int dt_init(const void *fdt_ptr);

/* get the fdt pointer that devicetree is using */
extern const void *dt_fdt(void);

/* check for an initialized, valid devicetree */
extern bool dt_available(void);

/* traverse child nodes */
#define dt_for_each_subnode(n, s)					\
	for (s = fdt_first_subnode(dt_fdt(), n);			\
	     s != -FDT_ERR_NOTFOUND;					\
	     s = fdt_next_subnode(dt_fdt(), s))

/**********************************************************************
 * Abstractions for required node types and properties
 **********************************************************************/

struct dt_device {
	int fdtnode;
	const struct dt_bus *bus;

	/*
	 * info is a pointer to device specific data, which may be
	 * used by the bus match() and translate() functions
	 */
	void *info;
};

struct dt_bus {
	/*
	 * match a device @dev to an fdt node @fdtnode
	 * returns
	 *  - a positive value on match
	 *  - zero on no match
	 *  - a negative FDT_ERR_* value on failure
	 */
	int (*match)(const struct dt_device *dev, int fdtnode);

	/*
	 * translate the @regidx'th "address size" tuple of
	 * @dev's fdt node's "reg" property, and store the result
	 * in @reg, a bus specific structure
	 * returns
	 *  - zero on success
	 *  - a negative FDT_ERR_* value on failure
	 */
	int (*translate)(const struct dt_device *dev, int regidx, void *reg);
};

/* dt_bus_match_any matches any fdt node, i.e. it always returns true */
extern int dt_bus_match_any(const struct dt_device *dev, int fdtnode);

/* the processor bus (pbus) address type and register tuple */
typedef u64 dt_pbus_addr_t;
struct dt_pbus_reg {
	dt_pbus_addr_t addr;
	dt_pbus_addr_t size;
};

static inline dt_pbus_addr_t dt_pbus_read_cells(u32 nr_cells, u32 *cells)
{
	switch (nr_cells) {
	case 1: return cells[0];
	case 2: return ((u64)cells[0] << 32) | cells[1];
	}
	return (~0ULL);
}

/*
 * dt_pbus_translate translates device node regs for the
 * processor bus using the parent node's #address-cells
 * and #size-cells and dt_pbus_read_cells()
 * returns
 *  - zero on success
 *  - a negative FDT_ERR_* value on failure
 */
extern int dt_pbus_translate(const struct dt_device *dev, int regidx,
			     void *reg);

/*
 * dt_pbus_translate_node is the same as dt_pbus_translate but
 * operates on an fdt node instead of a dt_device
 */
extern int dt_pbus_translate_node(int fdtnode, int regidx,
				  struct dt_pbus_reg *reg);

/*
 * dt_pbus_get_base is an alias for
 *     dt_pbus_translate(dev, 0, base)
 * returns
 *  - zero on success
 *  - a negative FDT_ERR_* value on failure
 */
static inline int dt_pbus_get_base(const struct dt_device *dev,
				   struct dt_pbus_reg *base)
{
	return dt_pbus_translate(dev, 0, base);
}

/*
 * dt_bus_init_defaults initializes @bus with
 *  match		<- dt_bus_match_any
 *  translate		<- dt_pbus_translate
 */
extern void dt_bus_init_defaults(struct dt_bus *bus);

/*
 * dt_device_init initializes a dt_device with the given parameters
 */
extern void dt_device_init(struct dt_device *dev, const struct dt_bus *bus,
			   void *info);

static inline void dt_device_bind_node(struct dt_device *dev, int fdtnode)
{
	dev->fdtnode = fdtnode;
}

/*
 * dt_device_find_compatible finds a @compatible node
 * returns
 *  - node (>= 0) on success
 *  - a negative FDT_ERR_* value on failure
 */
extern int dt_device_find_compatible(const struct dt_device *dev,
				     const char *compatible);

/*
 * dt_pbus_get_base_compatible simply bundles many functions into one.
 * It finds the first @compatible fdt node, then translates the 0th reg
 * tuple (the base) using the processor bus translation, and finally it
 * stores that result in @base.
 * returns
 *  - zero on success
 *  - a negative FDT_ERR_* value on failure
 */
extern int dt_pbus_get_base_compatible(const char *compatible,
				       struct dt_pbus_reg *base);

/**********************************************************************
 * Low-level accessors for required node types and properties
 **********************************************************************/

/*
 * dt_get_nr_cells sets @nr_address_cells and @nr_size_cells to the
 * #address-cells and #size-cells properties of @fdtnode
 * returns
 *  - zero on success
 *  - a negative FDT_ERR_* value on failure
 */
extern int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells,
					u32 *nr_size_cells);

/* dt_reg is a structure for "raw" reg tuples */
#define MAX_ADDRESS_CELLS	4
#define MAX_SIZE_CELLS		4
struct dt_reg {
	u32 nr_address_cells, nr_size_cells;
	u32 address_cells[MAX_ADDRESS_CELLS];
	u32 size_cells[MAX_SIZE_CELLS];
};

/*
 * dt_reg_init initialize a dt_reg struct to zero and sets
 * nr_address_cells and nr_size_cells to @nr_address_cells and
 * @nr_size_cells respectively.
 */
extern void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells,
					    u32 nr_size_cells);

/*
 * dt_get_reg gets the @regidx'th reg tuple of @fdtnode's reg property
 * and stores it in @reg. @reg must be initialized.
 * returns
 *  - zero on success
 *  - a negative FDT_ERR_* value on failure
 */
extern int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg);

/**********************************************************************
 * High-level accessors for required node types and properties
 **********************************************************************/

/*
 * dt_get_bootargs gets the string pointer from /chosen/bootargs
 * returns
 *  - zero on success
 *  - a negative FDT_ERR_* value on failure, and @bootargs
 *    will be set to NULL
 */
extern int dt_get_bootargs(const char **bootargs);

/*
 * dt_get_default_console_node gets the node of the path stored in
 * /chosen/stdout-path (or the deprecated /chosen/linux,stdout-path)
 * returns
 *  - the node (>= 0) on success
 *  - a negative FDT_ERR_* value on failure
 */
extern int dt_get_default_console_node(void);

/*
 * dt_get_initrd gets the physical address of the initrd and its
 * size from /chosen
 * returns
 *  - zero on success
 *  - a negative FDT_ERR_* value on failure, and @initrd will be
 *    set to NULL and @size set to zero
 */
extern int dt_get_initrd(const char **initrd, u32 *size);

/*
 * dt_get_memory_params gets the memory parameters from the /memory node(s)
 * storing each memory region ("address size" tuple) in consecutive entries
 * of @regs, up to @nr_regs
 * returns
 *  - number of memory regions found on success
 *  - a negative FDT_ERR_* value on failure
 */
extern int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs);

/*
 * dt_for_each_cpu_node runs @func on each cpu node in the /cpus node
 * passing it its fdt node, its reg property value, and @info
 *  - zero on success
 *  - a negative FDT_ERR_* value on failure
 */
extern int dt_for_each_cpu_node(void (*func)(int fdtnode, u64 regval,
				void *info), void *info);

#endif /* _DEVICETREE_H_ */