fdt_overlay.c revision 1.1.1.1 1 1.1 skrll /* $NetBSD: fdt_overlay.c,v 1.1.1.1 2017/06/08 15:53:12 skrll Exp $ */
2 1.1 skrll
3 1.1 skrll #include "libfdt_env.h"
4 1.1 skrll
5 1.1 skrll #include <fdt.h>
6 1.1 skrll #include <libfdt.h>
7 1.1 skrll
8 1.1 skrll #include "libfdt_internal.h"
9 1.1 skrll
10 1.1 skrll /**
11 1.1 skrll * overlay_get_target_phandle - retrieves the target phandle of a fragment
12 1.1 skrll * @fdto: pointer to the device tree overlay blob
13 1.1 skrll * @fragment: node offset of the fragment in the overlay
14 1.1 skrll *
15 1.1 skrll * overlay_get_target_phandle() retrieves the target phandle of an
16 1.1 skrll * overlay fragment when that fragment uses a phandle (target
17 1.1 skrll * property) instead of a path (target-path property).
18 1.1 skrll *
19 1.1 skrll * returns:
20 1.1 skrll * the phandle pointed by the target property
21 1.1 skrll * 0, if the phandle was not found
22 1.1 skrll * -1, if the phandle was malformed
23 1.1 skrll */
24 1.1 skrll static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
25 1.1 skrll {
26 1.1 skrll const fdt32_t *val;
27 1.1 skrll int len;
28 1.1 skrll
29 1.1 skrll val = fdt_getprop(fdto, fragment, "target", &len);
30 1.1 skrll if (!val)
31 1.1 skrll return 0;
32 1.1 skrll
33 1.1 skrll if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
34 1.1 skrll return (uint32_t)-1;
35 1.1 skrll
36 1.1 skrll return fdt32_to_cpu(*val);
37 1.1 skrll }
38 1.1 skrll
39 1.1 skrll /**
40 1.1 skrll * overlay_get_target - retrieves the offset of a fragment's target
41 1.1 skrll * @fdt: Base device tree blob
42 1.1 skrll * @fdto: Device tree overlay blob
43 1.1 skrll * @fragment: node offset of the fragment in the overlay
44 1.1 skrll *
45 1.1 skrll * overlay_get_target() retrieves the target offset in the base
46 1.1 skrll * device tree of a fragment, no matter how the actual targetting is
47 1.1 skrll * done (through a phandle or a path)
48 1.1 skrll *
49 1.1 skrll * returns:
50 1.1 skrll * the targetted node offset in the base device tree
51 1.1 skrll * Negative error code on error
52 1.1 skrll */
53 1.1 skrll static int overlay_get_target(const void *fdt, const void *fdto,
54 1.1 skrll int fragment)
55 1.1 skrll {
56 1.1 skrll uint32_t phandle;
57 1.1 skrll const char *path;
58 1.1 skrll int path_len;
59 1.1 skrll
60 1.1 skrll /* Try first to do a phandle based lookup */
61 1.1 skrll phandle = overlay_get_target_phandle(fdto, fragment);
62 1.1 skrll if (phandle == (uint32_t)-1)
63 1.1 skrll return -FDT_ERR_BADPHANDLE;
64 1.1 skrll
65 1.1 skrll if (phandle)
66 1.1 skrll return fdt_node_offset_by_phandle(fdt, phandle);
67 1.1 skrll
68 1.1 skrll /* And then a path based lookup */
69 1.1 skrll path = fdt_getprop(fdto, fragment, "target-path", &path_len);
70 1.1 skrll if (!path) {
71 1.1 skrll /*
72 1.1 skrll * If we haven't found either a target or a
73 1.1 skrll * target-path property in a node that contains a
74 1.1 skrll * __overlay__ subnode (we wouldn't be called
75 1.1 skrll * otherwise), consider it a improperly written
76 1.1 skrll * overlay
77 1.1 skrll */
78 1.1 skrll if (path_len == -FDT_ERR_NOTFOUND)
79 1.1 skrll return -FDT_ERR_BADOVERLAY;
80 1.1 skrll
81 1.1 skrll return path_len;
82 1.1 skrll }
83 1.1 skrll
84 1.1 skrll return fdt_path_offset(fdt, path);
85 1.1 skrll }
86 1.1 skrll
87 1.1 skrll /**
88 1.1 skrll * overlay_phandle_add_offset - Increases a phandle by an offset
89 1.1 skrll * @fdt: Base device tree blob
90 1.1 skrll * @node: Device tree overlay blob
91 1.1 skrll * @name: Name of the property to modify (phandle or linux,phandle)
92 1.1 skrll * @delta: offset to apply
93 1.1 skrll *
94 1.1 skrll * overlay_phandle_add_offset() increments a node phandle by a given
95 1.1 skrll * offset.
96 1.1 skrll *
97 1.1 skrll * returns:
98 1.1 skrll * 0 on success.
99 1.1 skrll * Negative error code on error
100 1.1 skrll */
101 1.1 skrll static int overlay_phandle_add_offset(void *fdt, int node,
102 1.1 skrll const char *name, uint32_t delta)
103 1.1 skrll {
104 1.1 skrll const fdt32_t *val;
105 1.1 skrll uint32_t adj_val;
106 1.1 skrll int len;
107 1.1 skrll
108 1.1 skrll val = fdt_getprop(fdt, node, name, &len);
109 1.1 skrll if (!val)
110 1.1 skrll return len;
111 1.1 skrll
112 1.1 skrll if (len != sizeof(*val))
113 1.1 skrll return -FDT_ERR_BADPHANDLE;
114 1.1 skrll
115 1.1 skrll adj_val = fdt32_to_cpu(*val);
116 1.1 skrll if ((adj_val + delta) < adj_val)
117 1.1 skrll return -FDT_ERR_NOPHANDLES;
118 1.1 skrll
119 1.1 skrll adj_val += delta;
120 1.1 skrll if (adj_val == (uint32_t)-1)
121 1.1 skrll return -FDT_ERR_NOPHANDLES;
122 1.1 skrll
123 1.1 skrll return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
124 1.1 skrll }
125 1.1 skrll
126 1.1 skrll /**
127 1.1 skrll * overlay_adjust_node_phandles - Offsets the phandles of a node
128 1.1 skrll * @fdto: Device tree overlay blob
129 1.1 skrll * @node: Offset of the node we want to adjust
130 1.1 skrll * @delta: Offset to shift the phandles of
131 1.1 skrll *
132 1.1 skrll * overlay_adjust_node_phandles() adds a constant to all the phandles
133 1.1 skrll * of a given node. This is mainly use as part of the overlay
134 1.1 skrll * application process, when we want to update all the overlay
135 1.1 skrll * phandles to not conflict with the overlays of the base device tree.
136 1.1 skrll *
137 1.1 skrll * returns:
138 1.1 skrll * 0 on success
139 1.1 skrll * Negative error code on failure
140 1.1 skrll */
141 1.1 skrll static int overlay_adjust_node_phandles(void *fdto, int node,
142 1.1 skrll uint32_t delta)
143 1.1 skrll {
144 1.1 skrll int child;
145 1.1 skrll int ret;
146 1.1 skrll
147 1.1 skrll ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
148 1.1 skrll if (ret && ret != -FDT_ERR_NOTFOUND)
149 1.1 skrll return ret;
150 1.1 skrll
151 1.1 skrll ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
152 1.1 skrll if (ret && ret != -FDT_ERR_NOTFOUND)
153 1.1 skrll return ret;
154 1.1 skrll
155 1.1 skrll fdt_for_each_subnode(child, fdto, node) {
156 1.1 skrll ret = overlay_adjust_node_phandles(fdto, child, delta);
157 1.1 skrll if (ret)
158 1.1 skrll return ret;
159 1.1 skrll }
160 1.1 skrll
161 1.1 skrll return 0;
162 1.1 skrll }
163 1.1 skrll
164 1.1 skrll /**
165 1.1 skrll * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
166 1.1 skrll * @fdto: Device tree overlay blob
167 1.1 skrll * @delta: Offset to shift the phandles of
168 1.1 skrll *
169 1.1 skrll * overlay_adjust_local_phandles() adds a constant to all the
170 1.1 skrll * phandles of an overlay. This is mainly use as part of the overlay
171 1.1 skrll * application process, when we want to update all the overlay
172 1.1 skrll * phandles to not conflict with the overlays of the base device tree.
173 1.1 skrll *
174 1.1 skrll * returns:
175 1.1 skrll * 0 on success
176 1.1 skrll * Negative error code on failure
177 1.1 skrll */
178 1.1 skrll static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
179 1.1 skrll {
180 1.1 skrll /*
181 1.1 skrll * Start adjusting the phandles from the overlay root
182 1.1 skrll */
183 1.1 skrll return overlay_adjust_node_phandles(fdto, 0, delta);
184 1.1 skrll }
185 1.1 skrll
186 1.1 skrll /**
187 1.1 skrll * overlay_update_local_node_references - Adjust the overlay references
188 1.1 skrll * @fdto: Device tree overlay blob
189 1.1 skrll * @tree_node: Node offset of the node to operate on
190 1.1 skrll * @fixup_node: Node offset of the matching local fixups node
191 1.1 skrll * @delta: Offset to shift the phandles of
192 1.1 skrll *
193 1.1 skrll * overlay_update_local_nodes_references() update the phandles
194 1.1 skrll * pointing to a node within the device tree overlay by adding a
195 1.1 skrll * constant delta.
196 1.1 skrll *
197 1.1 skrll * This is mainly used as part of a device tree application process,
198 1.1 skrll * where you want the device tree overlays phandles to not conflict
199 1.1 skrll * with the ones from the base device tree before merging them.
200 1.1 skrll *
201 1.1 skrll * returns:
202 1.1 skrll * 0 on success
203 1.1 skrll * Negative error code on failure
204 1.1 skrll */
205 1.1 skrll static int overlay_update_local_node_references(void *fdto,
206 1.1 skrll int tree_node,
207 1.1 skrll int fixup_node,
208 1.1 skrll uint32_t delta)
209 1.1 skrll {
210 1.1 skrll int fixup_prop;
211 1.1 skrll int fixup_child;
212 1.1 skrll int ret;
213 1.1 skrll
214 1.1 skrll fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
215 1.1 skrll const fdt32_t *fixup_val;
216 1.1 skrll const char *tree_val;
217 1.1 skrll const char *name;
218 1.1 skrll int fixup_len;
219 1.1 skrll int tree_len;
220 1.1 skrll int i;
221 1.1 skrll
222 1.1 skrll fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
223 1.1 skrll &name, &fixup_len);
224 1.1 skrll if (!fixup_val)
225 1.1 skrll return fixup_len;
226 1.1 skrll
227 1.1 skrll if (fixup_len % sizeof(uint32_t))
228 1.1 skrll return -FDT_ERR_BADOVERLAY;
229 1.1 skrll
230 1.1 skrll tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
231 1.1 skrll if (!tree_val) {
232 1.1 skrll if (tree_len == -FDT_ERR_NOTFOUND)
233 1.1 skrll return -FDT_ERR_BADOVERLAY;
234 1.1 skrll
235 1.1 skrll return tree_len;
236 1.1 skrll }
237 1.1 skrll
238 1.1 skrll for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
239 1.1 skrll fdt32_t adj_val;
240 1.1 skrll uint32_t poffset;
241 1.1 skrll
242 1.1 skrll poffset = fdt32_to_cpu(fixup_val[i]);
243 1.1 skrll
244 1.1 skrll /*
245 1.1 skrll * phandles to fixup can be unaligned.
246 1.1 skrll *
247 1.1 skrll * Use a memcpy for the architectures that do
248 1.1 skrll * not support unaligned accesses.
249 1.1 skrll */
250 1.1 skrll memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
251 1.1 skrll
252 1.1 skrll adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
253 1.1 skrll
254 1.1 skrll ret = fdt_setprop_inplace_namelen_partial(fdto,
255 1.1 skrll tree_node,
256 1.1 skrll name,
257 1.1 skrll strlen(name),
258 1.1 skrll poffset,
259 1.1 skrll &adj_val,
260 1.1 skrll sizeof(adj_val));
261 1.1 skrll if (ret == -FDT_ERR_NOSPACE)
262 1.1 skrll return -FDT_ERR_BADOVERLAY;
263 1.1 skrll
264 1.1 skrll if (ret)
265 1.1 skrll return ret;
266 1.1 skrll }
267 1.1 skrll }
268 1.1 skrll
269 1.1 skrll fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
270 1.1 skrll const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
271 1.1 skrll NULL);
272 1.1 skrll int tree_child;
273 1.1 skrll
274 1.1 skrll tree_child = fdt_subnode_offset(fdto, tree_node,
275 1.1 skrll fixup_child_name);
276 1.1 skrll if (tree_child == -FDT_ERR_NOTFOUND)
277 1.1 skrll return -FDT_ERR_BADOVERLAY;
278 1.1 skrll if (tree_child < 0)
279 1.1 skrll return tree_child;
280 1.1 skrll
281 1.1 skrll ret = overlay_update_local_node_references(fdto,
282 1.1 skrll tree_child,
283 1.1 skrll fixup_child,
284 1.1 skrll delta);
285 1.1 skrll if (ret)
286 1.1 skrll return ret;
287 1.1 skrll }
288 1.1 skrll
289 1.1 skrll return 0;
290 1.1 skrll }
291 1.1 skrll
292 1.1 skrll /**
293 1.1 skrll * overlay_update_local_references - Adjust the overlay references
294 1.1 skrll * @fdto: Device tree overlay blob
295 1.1 skrll * @delta: Offset to shift the phandles of
296 1.1 skrll *
297 1.1 skrll * overlay_update_local_references() update all the phandles pointing
298 1.1 skrll * to a node within the device tree overlay by adding a constant
299 1.1 skrll * delta to not conflict with the base overlay.
300 1.1 skrll *
301 1.1 skrll * This is mainly used as part of a device tree application process,
302 1.1 skrll * where you want the device tree overlays phandles to not conflict
303 1.1 skrll * with the ones from the base device tree before merging them.
304 1.1 skrll *
305 1.1 skrll * returns:
306 1.1 skrll * 0 on success
307 1.1 skrll * Negative error code on failure
308 1.1 skrll */
309 1.1 skrll static int overlay_update_local_references(void *fdto, uint32_t delta)
310 1.1 skrll {
311 1.1 skrll int fixups;
312 1.1 skrll
313 1.1 skrll fixups = fdt_path_offset(fdto, "/__local_fixups__");
314 1.1 skrll if (fixups < 0) {
315 1.1 skrll /* There's no local phandles to adjust, bail out */
316 1.1 skrll if (fixups == -FDT_ERR_NOTFOUND)
317 1.1 skrll return 0;
318 1.1 skrll
319 1.1 skrll return fixups;
320 1.1 skrll }
321 1.1 skrll
322 1.1 skrll /*
323 1.1 skrll * Update our local references from the root of the tree
324 1.1 skrll */
325 1.1 skrll return overlay_update_local_node_references(fdto, 0, fixups,
326 1.1 skrll delta);
327 1.1 skrll }
328 1.1 skrll
329 1.1 skrll /**
330 1.1 skrll * overlay_fixup_one_phandle - Set an overlay phandle to the base one
331 1.1 skrll * @fdt: Base Device Tree blob
332 1.1 skrll * @fdto: Device tree overlay blob
333 1.1 skrll * @symbols_off: Node offset of the symbols node in the base device tree
334 1.1 skrll * @path: Path to a node holding a phandle in the overlay
335 1.1 skrll * @path_len: number of path characters to consider
336 1.1 skrll * @name: Name of the property holding the phandle reference in the overlay
337 1.1 skrll * @name_len: number of name characters to consider
338 1.1 skrll * @poffset: Offset within the overlay property where the phandle is stored
339 1.1 skrll * @label: Label of the node referenced by the phandle
340 1.1 skrll *
341 1.1 skrll * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
342 1.1 skrll * a node in the base device tree.
343 1.1 skrll *
344 1.1 skrll * This is part of the device tree overlay application process, when
345 1.1 skrll * you want all the phandles in the overlay to point to the actual
346 1.1 skrll * base dt nodes.
347 1.1 skrll *
348 1.1 skrll * returns:
349 1.1 skrll * 0 on success
350 1.1 skrll * Negative error code on failure
351 1.1 skrll */
352 1.1 skrll static int overlay_fixup_one_phandle(void *fdt, void *fdto,
353 1.1 skrll int symbols_off,
354 1.1 skrll const char *path, uint32_t path_len,
355 1.1 skrll const char *name, uint32_t name_len,
356 1.1 skrll int poffset, const char *label)
357 1.1 skrll {
358 1.1 skrll const char *symbol_path;
359 1.1 skrll uint32_t phandle;
360 1.1 skrll fdt32_t phandle_prop;
361 1.1 skrll int symbol_off, fixup_off;
362 1.1 skrll int prop_len;
363 1.1 skrll
364 1.1 skrll if (symbols_off < 0)
365 1.1 skrll return symbols_off;
366 1.1 skrll
367 1.1 skrll symbol_path = fdt_getprop(fdt, symbols_off, label,
368 1.1 skrll &prop_len);
369 1.1 skrll if (!symbol_path)
370 1.1 skrll return prop_len;
371 1.1 skrll
372 1.1 skrll symbol_off = fdt_path_offset(fdt, symbol_path);
373 1.1 skrll if (symbol_off < 0)
374 1.1 skrll return symbol_off;
375 1.1 skrll
376 1.1 skrll phandle = fdt_get_phandle(fdt, symbol_off);
377 1.1 skrll if (!phandle)
378 1.1 skrll return -FDT_ERR_NOTFOUND;
379 1.1 skrll
380 1.1 skrll fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
381 1.1 skrll if (fixup_off == -FDT_ERR_NOTFOUND)
382 1.1 skrll return -FDT_ERR_BADOVERLAY;
383 1.1 skrll if (fixup_off < 0)
384 1.1 skrll return fixup_off;
385 1.1 skrll
386 1.1 skrll phandle_prop = cpu_to_fdt32(phandle);
387 1.1 skrll return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
388 1.1 skrll name, name_len, poffset,
389 1.1 skrll &phandle_prop,
390 1.1 skrll sizeof(phandle_prop));
391 1.1 skrll };
392 1.1 skrll
393 1.1 skrll /**
394 1.1 skrll * overlay_fixup_phandle - Set an overlay phandle to the base one
395 1.1 skrll * @fdt: Base Device Tree blob
396 1.1 skrll * @fdto: Device tree overlay blob
397 1.1 skrll * @symbols_off: Node offset of the symbols node in the base device tree
398 1.1 skrll * @property: Property offset in the overlay holding the list of fixups
399 1.1 skrll *
400 1.1 skrll * overlay_fixup_phandle() resolves all the overlay phandles pointed
401 1.1 skrll * to in a __fixups__ property, and updates them to match the phandles
402 1.1 skrll * in use in the base device tree.
403 1.1 skrll *
404 1.1 skrll * This is part of the device tree overlay application process, when
405 1.1 skrll * you want all the phandles in the overlay to point to the actual
406 1.1 skrll * base dt nodes.
407 1.1 skrll *
408 1.1 skrll * returns:
409 1.1 skrll * 0 on success
410 1.1 skrll * Negative error code on failure
411 1.1 skrll */
412 1.1 skrll static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
413 1.1 skrll int property)
414 1.1 skrll {
415 1.1 skrll const char *value;
416 1.1 skrll const char *label;
417 1.1 skrll int len;
418 1.1 skrll
419 1.1 skrll value = fdt_getprop_by_offset(fdto, property,
420 1.1 skrll &label, &len);
421 1.1 skrll if (!value) {
422 1.1 skrll if (len == -FDT_ERR_NOTFOUND)
423 1.1 skrll return -FDT_ERR_INTERNAL;
424 1.1 skrll
425 1.1 skrll return len;
426 1.1 skrll }
427 1.1 skrll
428 1.1 skrll do {
429 1.1 skrll const char *path, *name, *fixup_end;
430 1.1 skrll const char *fixup_str = value;
431 1.1 skrll uint32_t path_len, name_len;
432 1.1 skrll uint32_t fixup_len;
433 1.1 skrll char *sep, *endptr;
434 1.1 skrll int poffset, ret;
435 1.1 skrll
436 1.1 skrll fixup_end = memchr(value, '\0', len);
437 1.1 skrll if (!fixup_end)
438 1.1 skrll return -FDT_ERR_BADOVERLAY;
439 1.1 skrll fixup_len = fixup_end - fixup_str;
440 1.1 skrll
441 1.1 skrll len -= fixup_len + 1;
442 1.1 skrll value += fixup_len + 1;
443 1.1 skrll
444 1.1 skrll path = fixup_str;
445 1.1 skrll sep = memchr(fixup_str, ':', fixup_len);
446 1.1 skrll if (!sep || *sep != ':')
447 1.1 skrll return -FDT_ERR_BADOVERLAY;
448 1.1 skrll
449 1.1 skrll path_len = sep - path;
450 1.1 skrll if (path_len == (fixup_len - 1))
451 1.1 skrll return -FDT_ERR_BADOVERLAY;
452 1.1 skrll
453 1.1 skrll fixup_len -= path_len + 1;
454 1.1 skrll name = sep + 1;
455 1.1 skrll sep = memchr(name, ':', fixup_len);
456 1.1 skrll if (!sep || *sep != ':')
457 1.1 skrll return -FDT_ERR_BADOVERLAY;
458 1.1 skrll
459 1.1 skrll name_len = sep - name;
460 1.1 skrll if (!name_len)
461 1.1 skrll return -FDT_ERR_BADOVERLAY;
462 1.1 skrll
463 1.1 skrll poffset = strtoul(sep + 1, &endptr, 10);
464 1.1 skrll if ((*endptr != '\0') || (endptr <= (sep + 1)))
465 1.1 skrll return -FDT_ERR_BADOVERLAY;
466 1.1 skrll
467 1.1 skrll ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
468 1.1 skrll path, path_len, name, name_len,
469 1.1 skrll poffset, label);
470 1.1 skrll if (ret)
471 1.1 skrll return ret;
472 1.1 skrll } while (len > 0);
473 1.1 skrll
474 1.1 skrll return 0;
475 1.1 skrll }
476 1.1 skrll
477 1.1 skrll /**
478 1.1 skrll * overlay_fixup_phandles - Resolve the overlay phandles to the base
479 1.1 skrll * device tree
480 1.1 skrll * @fdt: Base Device Tree blob
481 1.1 skrll * @fdto: Device tree overlay blob
482 1.1 skrll *
483 1.1 skrll * overlay_fixup_phandles() resolves all the overlay phandles pointing
484 1.1 skrll * to nodes in the base device tree.
485 1.1 skrll *
486 1.1 skrll * This is one of the steps of the device tree overlay application
487 1.1 skrll * process, when you want all the phandles in the overlay to point to
488 1.1 skrll * the actual base dt nodes.
489 1.1 skrll *
490 1.1 skrll * returns:
491 1.1 skrll * 0 on success
492 1.1 skrll * Negative error code on failure
493 1.1 skrll */
494 1.1 skrll static int overlay_fixup_phandles(void *fdt, void *fdto)
495 1.1 skrll {
496 1.1 skrll int fixups_off, symbols_off;
497 1.1 skrll int property;
498 1.1 skrll
499 1.1 skrll /* We can have overlays without any fixups */
500 1.1 skrll fixups_off = fdt_path_offset(fdto, "/__fixups__");
501 1.1 skrll if (fixups_off == -FDT_ERR_NOTFOUND)
502 1.1 skrll return 0; /* nothing to do */
503 1.1 skrll if (fixups_off < 0)
504 1.1 skrll return fixups_off;
505 1.1 skrll
506 1.1 skrll /* And base DTs without symbols */
507 1.1 skrll symbols_off = fdt_path_offset(fdt, "/__symbols__");
508 1.1 skrll if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
509 1.1 skrll return symbols_off;
510 1.1 skrll
511 1.1 skrll fdt_for_each_property_offset(property, fdto, fixups_off) {
512 1.1 skrll int ret;
513 1.1 skrll
514 1.1 skrll ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
515 1.1 skrll if (ret)
516 1.1 skrll return ret;
517 1.1 skrll }
518 1.1 skrll
519 1.1 skrll return 0;
520 1.1 skrll }
521 1.1 skrll
522 1.1 skrll /**
523 1.1 skrll * overlay_apply_node - Merges a node into the base device tree
524 1.1 skrll * @fdt: Base Device Tree blob
525 1.1 skrll * @target: Node offset in the base device tree to apply the fragment to
526 1.1 skrll * @fdto: Device tree overlay blob
527 1.1 skrll * @node: Node offset in the overlay holding the changes to merge
528 1.1 skrll *
529 1.1 skrll * overlay_apply_node() merges a node into a target base device tree
530 1.1 skrll * node pointed.
531 1.1 skrll *
532 1.1 skrll * This is part of the final step in the device tree overlay
533 1.1 skrll * application process, when all the phandles have been adjusted and
534 1.1 skrll * resolved and you just have to merge overlay into the base device
535 1.1 skrll * tree.
536 1.1 skrll *
537 1.1 skrll * returns:
538 1.1 skrll * 0 on success
539 1.1 skrll * Negative error code on failure
540 1.1 skrll */
541 1.1 skrll static int overlay_apply_node(void *fdt, int target,
542 1.1 skrll void *fdto, int node)
543 1.1 skrll {
544 1.1 skrll int property;
545 1.1 skrll int subnode;
546 1.1 skrll
547 1.1 skrll fdt_for_each_property_offset(property, fdto, node) {
548 1.1 skrll const char *name;
549 1.1 skrll const void *prop;
550 1.1 skrll int prop_len;
551 1.1 skrll int ret;
552 1.1 skrll
553 1.1 skrll prop = fdt_getprop_by_offset(fdto, property, &name,
554 1.1 skrll &prop_len);
555 1.1 skrll if (prop_len == -FDT_ERR_NOTFOUND)
556 1.1 skrll return -FDT_ERR_INTERNAL;
557 1.1 skrll if (prop_len < 0)
558 1.1 skrll return prop_len;
559 1.1 skrll
560 1.1 skrll ret = fdt_setprop(fdt, target, name, prop, prop_len);
561 1.1 skrll if (ret)
562 1.1 skrll return ret;
563 1.1 skrll }
564 1.1 skrll
565 1.1 skrll fdt_for_each_subnode(subnode, fdto, node) {
566 1.1 skrll const char *name = fdt_get_name(fdto, subnode, NULL);
567 1.1 skrll int nnode;
568 1.1 skrll int ret;
569 1.1 skrll
570 1.1 skrll nnode = fdt_add_subnode(fdt, target, name);
571 1.1 skrll if (nnode == -FDT_ERR_EXISTS) {
572 1.1 skrll nnode = fdt_subnode_offset(fdt, target, name);
573 1.1 skrll if (nnode == -FDT_ERR_NOTFOUND)
574 1.1 skrll return -FDT_ERR_INTERNAL;
575 1.1 skrll }
576 1.1 skrll
577 1.1 skrll if (nnode < 0)
578 1.1 skrll return nnode;
579 1.1 skrll
580 1.1 skrll ret = overlay_apply_node(fdt, nnode, fdto, subnode);
581 1.1 skrll if (ret)
582 1.1 skrll return ret;
583 1.1 skrll }
584 1.1 skrll
585 1.1 skrll return 0;
586 1.1 skrll }
587 1.1 skrll
588 1.1 skrll /**
589 1.1 skrll * overlay_merge - Merge an overlay into its base device tree
590 1.1 skrll * @fdt: Base Device Tree blob
591 1.1 skrll * @fdto: Device tree overlay blob
592 1.1 skrll *
593 1.1 skrll * overlay_merge() merges an overlay into its base device tree.
594 1.1 skrll *
595 1.1 skrll * This is the final step in the device tree overlay application
596 1.1 skrll * process, when all the phandles have been adjusted and resolved and
597 1.1 skrll * you just have to merge overlay into the base device tree.
598 1.1 skrll *
599 1.1 skrll * returns:
600 1.1 skrll * 0 on success
601 1.1 skrll * Negative error code on failure
602 1.1 skrll */
603 1.1 skrll static int overlay_merge(void *fdt, void *fdto)
604 1.1 skrll {
605 1.1 skrll int fragment;
606 1.1 skrll
607 1.1 skrll fdt_for_each_subnode(fragment, fdto, 0) {
608 1.1 skrll int overlay;
609 1.1 skrll int target;
610 1.1 skrll int ret;
611 1.1 skrll
612 1.1 skrll /*
613 1.1 skrll * Each fragments will have an __overlay__ node. If
614 1.1 skrll * they don't, it's not supposed to be merged
615 1.1 skrll */
616 1.1 skrll overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
617 1.1 skrll if (overlay == -FDT_ERR_NOTFOUND)
618 1.1 skrll continue;
619 1.1 skrll
620 1.1 skrll if (overlay < 0)
621 1.1 skrll return overlay;
622 1.1 skrll
623 1.1 skrll target = overlay_get_target(fdt, fdto, fragment);
624 1.1 skrll if (target < 0)
625 1.1 skrll return target;
626 1.1 skrll
627 1.1 skrll ret = overlay_apply_node(fdt, target, fdto, overlay);
628 1.1 skrll if (ret)
629 1.1 skrll return ret;
630 1.1 skrll }
631 1.1 skrll
632 1.1 skrll return 0;
633 1.1 skrll }
634 1.1 skrll
635 1.1 skrll int fdt_overlay_apply(void *fdt, void *fdto)
636 1.1 skrll {
637 1.1 skrll uint32_t delta = fdt_get_max_phandle(fdt);
638 1.1 skrll int ret;
639 1.1 skrll
640 1.1 skrll FDT_CHECK_HEADER(fdt);
641 1.1 skrll FDT_CHECK_HEADER(fdto);
642 1.1 skrll
643 1.1 skrll ret = overlay_adjust_local_phandles(fdto, delta);
644 1.1 skrll if (ret)
645 1.1 skrll goto err;
646 1.1 skrll
647 1.1 skrll ret = overlay_update_local_references(fdto, delta);
648 1.1 skrll if (ret)
649 1.1 skrll goto err;
650 1.1 skrll
651 1.1 skrll ret = overlay_fixup_phandles(fdt, fdto);
652 1.1 skrll if (ret)
653 1.1 skrll goto err;
654 1.1 skrll
655 1.1 skrll ret = overlay_merge(fdt, fdto);
656 1.1 skrll if (ret)
657 1.1 skrll goto err;
658 1.1 skrll
659 1.1 skrll /*
660 1.1 skrll * The overlay has been damaged, erase its magic.
661 1.1 skrll */
662 1.1 skrll fdt_set_magic(fdto, ~0);
663 1.1 skrll
664 1.1 skrll return 0;
665 1.1 skrll
666 1.1 skrll err:
667 1.1 skrll /*
668 1.1 skrll * The overlay might have been damaged, erase its magic.
669 1.1 skrll */
670 1.1 skrll fdt_set_magic(fdto, ~0);
671 1.1 skrll
672 1.1 skrll /*
673 1.1 skrll * The base device tree might have been damaged, erase its
674 1.1 skrll * magic.
675 1.1 skrll */
676 1.1 skrll fdt_set_magic(fdt, ~0);
677 1.1 skrll
678 1.1 skrll return ret;
679 1.1 skrll }
680