aboutsummaryrefslogtreecommitdiff
path: root/include/device.h
blob: 28dbd5d764868064341cd271b80cb4237f1f1603 (plain)
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
/* Copyright 2013-2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __DEVICE_H
#define __DEVICE_H
#include <ccan/list/list.h>
#include <ccan/short_types/short_types.h>
#include <compiler.h>

/* Any property or node with this prefix will not be passed to the kernel. */
#define DT_PRIVATE	"skiboot,"

/*
 * An in-memory representation of a node in the device tree.
 *
 * This is trivially flattened into an fdt.
 *
 * Note that the add_* routines will make a copy of the name if it's not
 * a read-only string (ie. usually a string literal).
 */
struct dt_property {
	struct list_node list;
	const char *name;
	size_t len;
	char prop[/* len */];
};

struct dt_node {
	const char *name;
	struct list_node list;
	struct list_head properties;
	struct list_head children;
	struct dt_node *parent;
	u32 phandle;
};

/* This is shared with device_tree.c .. make it static when
 * the latter is gone (hopefully soon)
 */
extern u32 last_phandle;

extern struct dt_node *dt_root;
extern struct dt_node *dt_chosen;

/* Create a root node: ie. a parentless one. */
struct dt_node *dt_new_root(const char *name);

/* Graft a root node into this tree. */
bool dt_attach_root(struct dt_node *parent, struct dt_node *root);

/* Add a child node. */
struct dt_node *dt_new(struct dt_node *parent, const char *name);
struct dt_node *dt_new_addr(struct dt_node *parent, const char *name,
			    uint64_t unit_addr);
struct dt_node *dt_new_2addr(struct dt_node *parent, const char *name,
			     uint64_t unit_addr0, uint64_t unit_addr1);

/* Copy node to new parent, including properties and subnodes */
struct dt_node *dt_copy(struct dt_node *node, struct dt_node *parent);

/* Add a property node, various forms. */
struct dt_property *dt_add_property(struct dt_node *node,
				    const char *name,
				    const void *val, size_t size);
struct dt_property *dt_add_property_string(struct dt_node *node,
					   const char *name,
					   const char *value);
struct dt_property *dt_add_property_nstr(struct dt_node *node,
					 const char *name,
					 const char *value, unsigned int vlen);

/* Given out enough GCC extensions, we will achieve enlightenment! */
#define dt_add_property_strings(node, name, ...)			\
	__dt_add_property_strings((node), ((name)),			\
			    sizeof((const char *[]) { __VA_ARGS__ })/sizeof(const char *), \
			    __VA_ARGS__)

struct dt_property *__dt_add_property_strings(struct dt_node *node,
					      const char *name,
					      int count, ...);

/* Given out enough GCC extensions, we will achieve enlightenment! */
#define dt_add_property_cells(node, name, ...)				\
	__dt_add_property_cells((node), ((name)),			\
			    sizeof((u32[]) { __VA_ARGS__ })/sizeof(u32), \
			    __VA_ARGS__)

struct dt_property *__dt_add_property_cells(struct dt_node *node,
					    const char *name,
					    int count, ...);

#define dt_add_property_u64s(node, name, ...)				\
	__dt_add_property_u64s((node), ((name)),			\
			       sizeof((u64[]) { __VA_ARGS__ })/sizeof(u64), \
			       __VA_ARGS__)

struct dt_property *__dt_add_property_u64s(struct dt_node *node,
					   const char *name,
					   int count, ...);

static inline struct dt_property *dt_add_property_u64(struct dt_node *node,
						      const char *name, u64 val)
{
	return dt_add_property_cells(node, name, (u32)(val >> 32), (u32)val);
}

void dt_del_property(struct dt_node *node, struct dt_property *prop);

/* Warning: moves *prop! */
void dt_resize_property(struct dt_property **prop, size_t len);

u32 dt_property_get_cell(const struct dt_property *prop, u32 index);

/* First child of this node. */
struct dt_node *dt_first(const struct dt_node *root);

/* Return next node, or NULL. */
struct dt_node *dt_next(const struct dt_node *root, const struct dt_node *prev);

/* Iterate nodes */
#define dt_for_each_node(root, node) \
	for (node = dt_first(root); node; node = dt_next(root, node))

#define dt_for_each_child(parent, node) \
	list_for_each(&parent->children, node, list)

/* Find a string in a string list */
bool dt_prop_find_string(const struct dt_property *p, const char *s);

/* Check a compatible property */
bool dt_node_is_compatible(const struct dt_node *node, const char *compat);

/* Find a node based on compatible property */
struct dt_node *dt_find_compatible_node(struct dt_node *root,
					struct dt_node *prev,
					const char *compat);

#define dt_for_each_compatible(root, node, compat)	\
	for (node = NULL; 			        \
	     (node = dt_find_compatible_node(root, node, compat)) != NULL;)

struct dt_node *dt_find_compatible_node_on_chip(struct dt_node *root,
						struct dt_node *prev,
						const char *compat,
						uint32_t chip_id);

#define dt_for_each_compatible_on_chip(root, node, compat, chip_id)	\
	for (node = NULL; 			        \
	     (node = dt_find_compatible_node_on_chip(root, node,\
						     compat, chip_id)) != NULL;)

/* Build the full path for a node. Return a new block of memory, caller
 * shall free() it
 */
char *dt_get_path(const struct dt_node *node);

/* Find a node by path */
struct dt_node *dt_find_by_path(struct dt_node *root, const char *path);

/* Find a child node by name */
struct dt_node *dt_find_by_name(struct dt_node *root, const char *name);

/* Find a node by phandle */
struct dt_node *dt_find_by_phandle(struct dt_node *root, u32 phandle);

/* Find a property by name. */
const struct dt_property *dt_find_property(const struct dt_node *node,\
					   const char *name);
const struct dt_property *dt_require_property(const struct dt_node *node,
					      const char *name, int wanted_len);

/* non-const variant */
struct dt_property *__dt_find_property(struct dt_node *node, const char *name);

/* Find a property by name, check if it's the same as val. */
bool dt_has_node_property(const struct dt_node *node,
			  const char *name, const char *val);

/* Free a node (and any children). */
void dt_free(struct dt_node *node);

/* Parse an initial fdt */
void dt_expand(const void *fdt);
int dt_expand_node(struct dt_node *node, const void *fdt, int fdt_node) __warn_unused_result;

/* Simplified accessors */
u64 dt_prop_get_u64(const struct dt_node *node, const char *prop);
u64 dt_prop_get_u64_def(const struct dt_node *node, const char *prop, u64 def);
u32 dt_prop_get_u32(const struct dt_node *node, const char *prop);
u32 dt_prop_get_u32_def(const struct dt_node *node, const char *prop, u32 def);
const void *dt_prop_get(const struct dt_node *node, const char *prop);
const void *dt_prop_get_def(const struct dt_node *node, const char *prop,
			    void *def);
const void *dt_prop_get_def_size(const struct dt_node *node, const char *prop,
				void *def, size_t *len);
u32 dt_prop_get_cell(const struct dt_node *node, const char *prop, u32 cell);
u32 dt_prop_get_cell_def(const struct dt_node *node, const char *prop, u32 cell, u32 def);

/* Parsing helpers */
u32 dt_n_address_cells(const struct dt_node *node);
u32 dt_n_size_cells(const struct dt_node *node);
u64 dt_get_number(const void *pdata, unsigned int cells);

/* Find an ibm,chip-id property in this node; if not found, walk up the parent
 * nodes. Returns -1 if no chip-id property exists. */
u32 dt_get_chip_id(const struct dt_node *node);

/* Address accessors ("reg" properties parsing). No translation,
 * only support "simple" address forms (1 or 2 cells). Asserts
 * if address doesn't exist
 */
u64 dt_get_address(const struct dt_node *node, unsigned int index,
		   u64 *out_size);

/* Count "reg" property entries */
unsigned int dt_count_addresses(const struct dt_node *node);

/* Address translation
 *
 * WARNING: Current implementation is simplified and will not
 * handle complex address formats with address space indicators
 * nor will it handle "ranges" translations yet... (XX TODO)
 */
u64 dt_translate_address(const struct dt_node *node, unsigned int index,
			 u64 *out_size);

/* compare function used to sort child nodes by name when added to the
 * tree. This is mainly here for testing.
 */
int dt_cmp_subnodes(const struct dt_node *a,  const struct dt_node *b);

#endif /* __DEVICE_H */