]>
git.ipfire.org Git - people/ms/u-boot.git/blob - lib/libfdt/fdt_overlay.c
1 #include "libfdt_env.h"
6 #include "libfdt_internal.h"
9 * overlay_get_target_phandle - retrieves the target phandle of a fragment
10 * @fdto: pointer to the device tree overlay blob
11 * @fragment: node offset of the fragment in the overlay
13 * overlay_get_target_phandle() retrieves the target phandle of an
14 * overlay fragment when that fragment uses a phandle (target
15 * property) instead of a path (target-path property).
18 * the phandle pointed by the target property
19 * 0, if the phandle was not found
20 * -1, if the phandle was malformed
22 static uint32_t overlay_get_target_phandle(const void *fdto
, int fragment
)
27 val
= fdt_getprop(fdto
, fragment
, "target", &len
);
31 if ((*val
== (uint32_t)-1) || (len
!= sizeof(*val
)))
34 return fdt32_to_cpu(*val
);
38 * overlay_get_target - retrieves the target phandle of a fragment
39 * @fdt: Base device tree blob
40 * @fdto: Device tree overlay blob
41 * @fragment: node offset of the fragment in the overlay
43 * overlay_get_target() retrieves the target phandle in the base
44 * device tree of a fragment, no matter how the actual targetting is
45 * done (through a phandle or a path)
48 * the targetted node offset in the base device tree
49 * Negative error code on error
51 static int overlay_get_target(const void *fdt
, const void *fdto
,
57 /* Try first to do a phandle based lookup */
58 phandle
= overlay_get_target_phandle(fdto
, fragment
);
59 if (phandle
== (uint32_t)-1)
60 return -FDT_ERR_BADPHANDLE
;
63 return fdt_node_offset_by_phandle(fdt
, phandle
);
65 /* And then a path based lookup */
66 path
= fdt_getprop(fdto
, fragment
, "target-path", NULL
);
68 return -FDT_ERR_NOTFOUND
;
70 return fdt_path_offset(fdt
, path
);
74 * overlay_phandle_add_offset - Increases a phandle by an offset
75 * @fdt: Base device tree blob
76 * @node: Device tree overlay blob
77 * @name: Name of the property to modify (phandle or linux,phandle)
78 * @delta: offset to apply
80 * overlay_phandle_add_offset() increments a node phandle by a given
85 * Negative error code on error
87 static int overlay_phandle_add_offset(void *fdt
, int node
,
88 const char *name
, uint32_t delta
)
94 val
= fdt_getprop(fdt
, node
, name
, &len
);
98 if (len
!= sizeof(*val
))
99 return -FDT_ERR_BADSTRUCTURE
;
101 adj_val
= fdt32_to_cpu(*val
);
102 if ((adj_val
+ delta
) < adj_val
)
103 return -FDT_ERR_BADPHANDLE
;
106 return fdt_setprop_inplace_u32(fdt
, node
, name
, adj_val
);
110 * overlay_adjust_node_phandles - Offsets the phandles of a node
111 * @fdto: Device tree overlay blob
112 * @node: Offset of the node we want to adjust
113 * @delta: Offset to shift the phandles of
115 * overlay_adjust_node_phandles() adds a constant to all the phandles
116 * of a given node. This is mainly use as part of the overlay
117 * application process, when we want to update all the overlay
118 * phandles to not conflict with the overlays of the base device tree.
122 * Negative error code on failure
124 static int overlay_adjust_node_phandles(void *fdto
, int node
,
131 ret
= overlay_phandle_add_offset(fdto
, node
, "phandle", delta
);
132 if (ret
&& ret
!= -FDT_ERR_NOTFOUND
)
138 ret
= overlay_phandle_add_offset(fdto
, node
, "linux,phandle", delta
);
139 if (ret
&& ret
!= -FDT_ERR_NOTFOUND
)
143 * If neither phandle nor linux,phandle have been found return
149 fdt_for_each_subnode(fdto
, child
, node
)
150 overlay_adjust_node_phandles(fdto
, child
, delta
);
156 * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
157 * @fdto: Device tree overlay blob
158 * @delta: Offset to shift the phandles of
160 * overlay_adjust_local_phandles() adds a constant to all the
161 * phandles of an overlay. This is mainly use as part of the overlay
162 * application process, when we want to update all the overlay
163 * phandles to not conflict with the overlays of the base device tree.
167 * Negative error code on failure
169 static int overlay_adjust_local_phandles(void *fdto
, uint32_t delta
)
172 * Start adjusting the phandles from the overlay root
174 return overlay_adjust_node_phandles(fdto
, 0, delta
);
178 * overlay_update_local_node_references - Adjust the overlay references
179 * @fdto: Device tree overlay blob
180 * @tree_node: Node offset of the node to operate on
181 * @fixup_node: Node offset of the matching local fixups node
182 * @delta: Offset to shift the phandles of
184 * overlay_update_local_nodes_references() update the phandles
185 * pointing to a node within the device tree overlay by adding a
188 * This is mainly used as part of a device tree application process,
189 * where you want the device tree overlays phandles to not conflict
190 * with the ones from the base device tree before merging them.
194 * Negative error code on failure
196 static int overlay_update_local_node_references(void *fdto
,
205 fdt_for_each_property_offset(fixup_prop
, fdto
, fixup_node
) {
206 const unsigned char *fixup_val
, *tree_val
;
212 fixup_val
= fdt_getprop_by_offset(fdto
, fixup_prop
,
217 tree_val
= fdt_getprop(fdto
, tree_node
, name
, &tree_len
);
221 for (i
= 0; i
< fixup_len
; i
+= sizeof(uint32_t)) {
222 uint32_t adj_val
, index
;
224 index
= *(uint32_t *)(fixup_val
+ i
);
225 index
= fdt32_to_cpu(index
);
228 * phandles to fixup can be unaligned.
230 * Use a memcpy for the architectures that do
231 * not support unaligned accesses.
233 memcpy(&adj_val
, tree_val
+ index
, sizeof(uint32_t));
235 adj_val
= fdt32_to_cpu(adj_val
);
237 adj_val
= cpu_to_fdt32(adj_val
);
239 ret
= fdt_setprop_inplace_namelen_partial(fdto
,
251 fdt_for_each_subnode(fdto
, fixup_child
, fixup_node
) {
252 const char *fixup_child_name
= fdt_get_name(fdto
, fixup_child
,
256 tree_child
= fdt_subnode_offset(fdto
, tree_node
,
261 ret
= overlay_update_local_node_references(fdto
,
273 * overlay_update_local_references - Adjust the overlay references
274 * @fdto: Device tree overlay blob
275 * @delta: Offset to shift the phandles of
277 * overlay_update_local_references() update all the phandles pointing
278 * to a node within the device tree overlay by adding a constant
279 * delta to not conflict with the base overlay.
281 * This is mainly used as part of a device tree application process,
282 * where you want the device tree overlays phandles to not conflict
283 * with the ones from the base device tree before merging them.
287 * Negative error code on failure
289 static int overlay_update_local_references(void *fdto
, uint32_t delta
)
293 fixups
= fdt_path_offset(fdto
, "/__local_fixups__");
295 /* There's no local phandles to adjust, bail out */
296 if (fixups
== -FDT_ERR_NOTFOUND
)
303 * Update our local references from the root of the tree
305 return overlay_update_local_node_references(fdto
, 0, fixups
,
310 * overlay_fixup_one_phandle - Set an overlay phandle to the base one
311 * @fdt: Base Device Tree blob
312 * @fdto: Device tree overlay blob
313 * @symbols_off: Node offset of the symbols node in the base device tree
314 * @path: Path to a node holding a phandle in the overlay
315 * @path_len: number of path characters to consider
316 * @name: Name of the property holding the phandle reference in the overlay
317 * @name_len: number of name characters to consider
318 * @index: Index in the overlay property where the phandle is stored
319 * @label: Label of the node referenced by the phandle
321 * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
322 * a node in the base device tree.
324 * This is part of the device tree overlay application process, when
325 * you want all the phandles in the overlay to point to the actual
330 * Negative error code on failure
332 static int overlay_fixup_one_phandle(void *fdt
, void *fdto
,
334 const char *path
, uint32_t path_len
,
335 const char *name
, uint32_t name_len
,
336 int index
, const char *label
)
338 const char *symbol_path
;
340 int symbol_off
, fixup_off
;
343 symbol_path
= fdt_getprop(fdt
, symbols_off
, label
,
346 return -FDT_ERR_NOTFOUND
;
348 symbol_off
= fdt_path_offset(fdt
, symbol_path
);
352 phandle
= fdt_get_phandle(fdt
, symbol_off
);
354 return -FDT_ERR_NOTFOUND
;
356 fixup_off
= fdt_path_offset_namelen(fdto
, path
, path_len
);
360 phandle
= cpu_to_fdt32(phandle
);
361 return fdt_setprop_inplace_namelen_partial(fdto
, fixup_off
,
362 name
, name_len
, index
,
363 &phandle
, sizeof(phandle
));
367 * overlay_fixup_phandle - Set an overlay phandle to the base one
368 * @fdt: Base Device Tree blob
369 * @fdto: Device tree overlay blob
370 * @symbols_off: Node offset of the symbols node in the base device tree
371 * @property: Property offset in the overlay holding the list of fixups
373 * overlay_fixup_phandle() resolves all the overlay phandles pointed
374 * to in a __local_fixup__ property, and updates them to match the
375 * phandles in use in the base device tree.
377 * This is part of the device tree overlay application process, when
378 * you want all the phandles in the overlay to point to the actual
383 * Negative error code on failure
385 static int overlay_fixup_phandle(void *fdt
, void *fdto
, int symbols_off
,
392 value
= fdt_getprop_by_offset(fdto
, property
,
398 const char *prop_string
= value
;
399 const char *path
, *name
;
400 uint32_t prop_len
= strlen(value
);
401 uint32_t path_len
, name_len
;
407 sep
= memchr(prop_string
, ':', prop_len
);
409 return -FDT_ERR_BADSTRUCTURE
;
410 path_len
= sep
- path
;
413 sep
= memchr(name
, ':', prop_len
);
415 return -FDT_ERR_BADSTRUCTURE
;
416 name_len
= sep
- name
;
418 index
= strtoul(sep
+ 1, &endptr
, 10);
419 if ((*endptr
!= '\0') || (endptr
<= (sep
+ 1)))
420 return -FDT_ERR_BADSTRUCTURE
;
423 value
+= prop_len
+ 1;
425 ret
= overlay_fixup_one_phandle(fdt
, fdto
, symbols_off
,
426 path
, path_len
, name
, name_len
,
436 * overlay_fixup_phandles - Resolve the overlay phandles to the base
438 * @fdt: Base Device Tree blob
439 * @fdto: Device tree overlay blob
441 * overlay_fixup_phandles() resolves all the overlay phandles pointing
442 * to nodes in the base device tree.
444 * This is one of the steps of the device tree overlay application
445 * process, when you want all the phandles in the overlay to point to
446 * the actual base dt nodes.
450 * Negative error code on failure
452 static int overlay_fixup_phandles(void *fdt
, void *fdto
)
454 int fixups_off
, symbols_off
;
457 symbols_off
= fdt_path_offset(fdt
, "/__symbols__");
458 fixups_off
= fdt_path_offset(fdto
, "/__fixups__");
460 fdt_for_each_property_offset(property
, fdto
, fixups_off
) {
463 ret
= overlay_fixup_phandle(fdt
, fdto
, symbols_off
, property
);
472 * overlay_apply_node - Merge an overlay fragment into the base device tree
473 * @fdt: Base Device Tree blob
474 * @target: Node offset in the base device tree to apply the fragment to
475 * @fdto: Device tree overlay blob
476 * @fragment: Node offset in the overlay holding the changes to merge
478 * overlay_apply_node() merges an overlay fragment into a target base
479 * device tree node pointed.
481 * This is part of the final step in the device tree overlay
482 * application process, when all the phandles have been adjusted and
483 * resolved and you just have to merge overlay into the base device
488 * Negative error code on failure
490 static int overlay_apply_node(void *fdt
, int target
,
491 void *fdto
, int fragment
)
496 fdt_for_each_property_offset(property
, fdto
, fragment
) {
502 prop
= fdt_getprop_by_offset(fdto
, property
, &name
,
504 if (prop_len
== -FDT_ERR_NOTFOUND
)
505 return -FDT_ERR_INTERNAL
;
509 ret
= fdt_setprop(fdt
, target
, name
, prop
, prop_len
);
514 fdt_for_each_subnode(fdto
, node
, fragment
) {
515 const char *name
= fdt_get_name(fdto
, node
, NULL
);
519 nnode
= fdt_add_subnode(fdt
, target
, name
);
520 if (nnode
== -FDT_ERR_EXISTS
)
521 nnode
= fdt_subnode_offset(fdt
, target
, name
);
526 ret
= overlay_apply_node(fdt
, nnode
, fdto
, node
);
535 * overlay_merge - Merge an overlay into its base device tree
536 * @fdt: Base Device Tree blob
537 * @fdto: Device tree overlay blob
539 * overlay_merge() merges an overlay into its base device tree.
541 * This is the final step in the device tree overlay application
542 * process, when all the phandles have been adjusted and resolved and
543 * you just have to merge overlay into the base device tree.
547 * Negative error code on failure
549 static int overlay_merge(void *dt
, void *dto
)
553 fdt_for_each_subnode(dto
, fragment
, 0) {
558 target
= overlay_get_target(dt
, dto
, fragment
);
562 overlay
= fdt_subnode_offset(dto
, fragment
, "__overlay__");
566 ret
= overlay_apply_node(dt
, target
, dto
, overlay
);
574 int fdt_overlay_apply(void *fdt
, void *fdto
)
576 uint32_t delta
= fdt_get_max_phandle(fdt
) + 1;
579 FDT_CHECK_HEADER(fdt
);
580 FDT_CHECK_HEADER(fdto
);
582 ret
= overlay_adjust_local_phandles(fdto
, delta
);
586 ret
= overlay_update_local_references(fdto
, delta
);
590 ret
= overlay_fixup_phandles(fdt
, fdto
);
594 ret
= overlay_merge(fdt
, fdto
);
599 * The overlay has been damaged, erase its magic.
601 fdt_set_magic(fdto
, ~0);
607 * The overlay might have been damaged, erase its magic.
609 fdt_set_magic(fdto
, ~0);
612 * The base device tree might have been damaged, erase its
615 fdt_set_magic(fdt
, ~0);