1*3e6106c4SLoGin // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2*3e6106c4SLoGin /*
3*3e6106c4SLoGin * libfdt - Flat Device Tree manipulation
4*3e6106c4SLoGin * Copyright (C) 2016 Free Electrons
5*3e6106c4SLoGin * Copyright (C) 2016 NextThing Co.
6*3e6106c4SLoGin */
7*3e6106c4SLoGin #include "libfdt_env.h"
8*3e6106c4SLoGin #include <dragonstub/dragonstub.h>
9*3e6106c4SLoGin #include <fdt.h>
10*3e6106c4SLoGin #include <libfdt.h>
11*3e6106c4SLoGin
12*3e6106c4SLoGin #include "libfdt_internal.h"
13*3e6106c4SLoGin
14*3e6106c4SLoGin /**
15*3e6106c4SLoGin * overlay_get_target_phandle - retrieves the target phandle of a fragment
16*3e6106c4SLoGin * @fdto: pointer to the device tree overlay blob
17*3e6106c4SLoGin * @fragment: node offset of the fragment in the overlay
18*3e6106c4SLoGin *
19*3e6106c4SLoGin * overlay_get_target_phandle() retrieves the target phandle of an
20*3e6106c4SLoGin * overlay fragment when that fragment uses a phandle (target
21*3e6106c4SLoGin * property) instead of a path (target-path property).
22*3e6106c4SLoGin *
23*3e6106c4SLoGin * returns:
24*3e6106c4SLoGin * the phandle pointed by the target property
25*3e6106c4SLoGin * 0, if the phandle was not found
26*3e6106c4SLoGin * -1, if the phandle was malformed
27*3e6106c4SLoGin */
overlay_get_target_phandle(const void * fdto,int fragment)28*3e6106c4SLoGin static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
29*3e6106c4SLoGin {
30*3e6106c4SLoGin const fdt32_t *val;
31*3e6106c4SLoGin int len;
32*3e6106c4SLoGin
33*3e6106c4SLoGin val = fdt_getprop(fdto, fragment, "target", &len);
34*3e6106c4SLoGin if (!val)
35*3e6106c4SLoGin return 0;
36*3e6106c4SLoGin
37*3e6106c4SLoGin if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
38*3e6106c4SLoGin return (uint32_t)-1;
39*3e6106c4SLoGin
40*3e6106c4SLoGin return fdt32_to_cpu(*val);
41*3e6106c4SLoGin }
42*3e6106c4SLoGin
fdt_overlay_target_offset(const void * fdt,const void * fdto,int fragment_offset,char const ** pathp)43*3e6106c4SLoGin int fdt_overlay_target_offset(const void *fdt, const void *fdto,
44*3e6106c4SLoGin int fragment_offset, char const **pathp)
45*3e6106c4SLoGin {
46*3e6106c4SLoGin uint32_t phandle;
47*3e6106c4SLoGin const char *path = NULL;
48*3e6106c4SLoGin int path_len = 0, ret;
49*3e6106c4SLoGin
50*3e6106c4SLoGin /* Try first to do a phandle based lookup */
51*3e6106c4SLoGin phandle = overlay_get_target_phandle(fdto, fragment_offset);
52*3e6106c4SLoGin if (phandle == (uint32_t)-1)
53*3e6106c4SLoGin return -FDT_ERR_BADPHANDLE;
54*3e6106c4SLoGin
55*3e6106c4SLoGin /* no phandle, try path */
56*3e6106c4SLoGin if (!phandle) {
57*3e6106c4SLoGin /* And then a path based lookup */
58*3e6106c4SLoGin path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len);
59*3e6106c4SLoGin if (path)
60*3e6106c4SLoGin ret = fdt_path_offset(fdt, path);
61*3e6106c4SLoGin else
62*3e6106c4SLoGin ret = path_len;
63*3e6106c4SLoGin } else
64*3e6106c4SLoGin ret = fdt_node_offset_by_phandle(fdt, phandle);
65*3e6106c4SLoGin
66*3e6106c4SLoGin /*
67*3e6106c4SLoGin * If we haven't found either a target or a
68*3e6106c4SLoGin * target-path property in a node that contains a
69*3e6106c4SLoGin * __overlay__ subnode (we wouldn't be called
70*3e6106c4SLoGin * otherwise), consider it a improperly written
71*3e6106c4SLoGin * overlay
72*3e6106c4SLoGin */
73*3e6106c4SLoGin if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
74*3e6106c4SLoGin ret = -FDT_ERR_BADOVERLAY;
75*3e6106c4SLoGin
76*3e6106c4SLoGin /* return on error */
77*3e6106c4SLoGin if (ret < 0)
78*3e6106c4SLoGin return ret;
79*3e6106c4SLoGin
80*3e6106c4SLoGin /* return pointer to path (if available) */
81*3e6106c4SLoGin if (pathp)
82*3e6106c4SLoGin *pathp = path ? path : NULL;
83*3e6106c4SLoGin
84*3e6106c4SLoGin return ret;
85*3e6106c4SLoGin }
86*3e6106c4SLoGin
87*3e6106c4SLoGin /**
88*3e6106c4SLoGin * overlay_phandle_add_offset - Increases a phandle by an offset
89*3e6106c4SLoGin * @fdt: Base device tree blob
90*3e6106c4SLoGin * @node: Device tree overlay blob
91*3e6106c4SLoGin * @name: Name of the property to modify (phandle or linux,phandle)
92*3e6106c4SLoGin * @delta: offset to apply
93*3e6106c4SLoGin *
94*3e6106c4SLoGin * overlay_phandle_add_offset() increments a node phandle by a given
95*3e6106c4SLoGin * offset.
96*3e6106c4SLoGin *
97*3e6106c4SLoGin * returns:
98*3e6106c4SLoGin * 0 on success.
99*3e6106c4SLoGin * Negative error code on error
100*3e6106c4SLoGin */
overlay_phandle_add_offset(void * fdt,int node,const char * name,uint32_t delta)101*3e6106c4SLoGin static int overlay_phandle_add_offset(void *fdt, int node,
102*3e6106c4SLoGin const char *name, uint32_t delta)
103*3e6106c4SLoGin {
104*3e6106c4SLoGin const fdt32_t *val;
105*3e6106c4SLoGin uint32_t adj_val;
106*3e6106c4SLoGin int len;
107*3e6106c4SLoGin
108*3e6106c4SLoGin val = fdt_getprop(fdt, node, name, &len);
109*3e6106c4SLoGin if (!val)
110*3e6106c4SLoGin return len;
111*3e6106c4SLoGin
112*3e6106c4SLoGin if (len != sizeof(*val))
113*3e6106c4SLoGin return -FDT_ERR_BADPHANDLE;
114*3e6106c4SLoGin
115*3e6106c4SLoGin adj_val = fdt32_to_cpu(*val);
116*3e6106c4SLoGin if ((adj_val + delta) < adj_val)
117*3e6106c4SLoGin return -FDT_ERR_NOPHANDLES;
118*3e6106c4SLoGin
119*3e6106c4SLoGin adj_val += delta;
120*3e6106c4SLoGin if (adj_val == (uint32_t)-1)
121*3e6106c4SLoGin return -FDT_ERR_NOPHANDLES;
122*3e6106c4SLoGin
123*3e6106c4SLoGin return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
124*3e6106c4SLoGin }
125*3e6106c4SLoGin
126*3e6106c4SLoGin /**
127*3e6106c4SLoGin * overlay_adjust_node_phandles - Offsets the phandles of a node
128*3e6106c4SLoGin * @fdto: Device tree overlay blob
129*3e6106c4SLoGin * @node: Offset of the node we want to adjust
130*3e6106c4SLoGin * @delta: Offset to shift the phandles of
131*3e6106c4SLoGin *
132*3e6106c4SLoGin * overlay_adjust_node_phandles() adds a constant to all the phandles
133*3e6106c4SLoGin * of a given node. This is mainly use as part of the overlay
134*3e6106c4SLoGin * application process, when we want to update all the overlay
135*3e6106c4SLoGin * phandles to not conflict with the overlays of the base device tree.
136*3e6106c4SLoGin *
137*3e6106c4SLoGin * returns:
138*3e6106c4SLoGin * 0 on success
139*3e6106c4SLoGin * Negative error code on failure
140*3e6106c4SLoGin */
overlay_adjust_node_phandles(void * fdto,int node,uint32_t delta)141*3e6106c4SLoGin static int overlay_adjust_node_phandles(void *fdto, int node,
142*3e6106c4SLoGin uint32_t delta)
143*3e6106c4SLoGin {
144*3e6106c4SLoGin int child;
145*3e6106c4SLoGin int ret;
146*3e6106c4SLoGin
147*3e6106c4SLoGin ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
148*3e6106c4SLoGin if (ret && ret != -FDT_ERR_NOTFOUND)
149*3e6106c4SLoGin return ret;
150*3e6106c4SLoGin
151*3e6106c4SLoGin ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
152*3e6106c4SLoGin if (ret && ret != -FDT_ERR_NOTFOUND)
153*3e6106c4SLoGin return ret;
154*3e6106c4SLoGin
155*3e6106c4SLoGin fdt_for_each_subnode(child, fdto, node) {
156*3e6106c4SLoGin ret = overlay_adjust_node_phandles(fdto, child, delta);
157*3e6106c4SLoGin if (ret)
158*3e6106c4SLoGin return ret;
159*3e6106c4SLoGin }
160*3e6106c4SLoGin
161*3e6106c4SLoGin return 0;
162*3e6106c4SLoGin }
163*3e6106c4SLoGin
164*3e6106c4SLoGin /**
165*3e6106c4SLoGin * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
166*3e6106c4SLoGin * @fdto: Device tree overlay blob
167*3e6106c4SLoGin * @delta: Offset to shift the phandles of
168*3e6106c4SLoGin *
169*3e6106c4SLoGin * overlay_adjust_local_phandles() adds a constant to all the
170*3e6106c4SLoGin * phandles of an overlay. This is mainly use as part of the overlay
171*3e6106c4SLoGin * application process, when we want to update all the overlay
172*3e6106c4SLoGin * phandles to not conflict with the overlays of the base device tree.
173*3e6106c4SLoGin *
174*3e6106c4SLoGin * returns:
175*3e6106c4SLoGin * 0 on success
176*3e6106c4SLoGin * Negative error code on failure
177*3e6106c4SLoGin */
overlay_adjust_local_phandles(void * fdto,uint32_t delta)178*3e6106c4SLoGin static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
179*3e6106c4SLoGin {
180*3e6106c4SLoGin /*
181*3e6106c4SLoGin * Start adjusting the phandles from the overlay root
182*3e6106c4SLoGin */
183*3e6106c4SLoGin return overlay_adjust_node_phandles(fdto, 0, delta);
184*3e6106c4SLoGin }
185*3e6106c4SLoGin
186*3e6106c4SLoGin /**
187*3e6106c4SLoGin * overlay_update_local_node_references - Adjust the overlay references
188*3e6106c4SLoGin * @fdto: Device tree overlay blob
189*3e6106c4SLoGin * @tree_node: Node offset of the node to operate on
190*3e6106c4SLoGin * @fixup_node: Node offset of the matching local fixups node
191*3e6106c4SLoGin * @delta: Offset to shift the phandles of
192*3e6106c4SLoGin *
193*3e6106c4SLoGin * overlay_update_local_nodes_references() update the phandles
194*3e6106c4SLoGin * pointing to a node within the device tree overlay by adding a
195*3e6106c4SLoGin * constant delta.
196*3e6106c4SLoGin *
197*3e6106c4SLoGin * This is mainly used as part of a device tree application process,
198*3e6106c4SLoGin * where you want the device tree overlays phandles to not conflict
199*3e6106c4SLoGin * with the ones from the base device tree before merging them.
200*3e6106c4SLoGin *
201*3e6106c4SLoGin * returns:
202*3e6106c4SLoGin * 0 on success
203*3e6106c4SLoGin * Negative error code on failure
204*3e6106c4SLoGin */
overlay_update_local_node_references(void * fdto,int tree_node,int fixup_node,uint32_t delta)205*3e6106c4SLoGin static int overlay_update_local_node_references(void *fdto,
206*3e6106c4SLoGin int tree_node,
207*3e6106c4SLoGin int fixup_node,
208*3e6106c4SLoGin uint32_t delta)
209*3e6106c4SLoGin {
210*3e6106c4SLoGin int fixup_prop;
211*3e6106c4SLoGin int fixup_child;
212*3e6106c4SLoGin int ret;
213*3e6106c4SLoGin
214*3e6106c4SLoGin fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
215*3e6106c4SLoGin const fdt32_t *fixup_val;
216*3e6106c4SLoGin const char *tree_val;
217*3e6106c4SLoGin const char *name;
218*3e6106c4SLoGin int fixup_len;
219*3e6106c4SLoGin int tree_len;
220*3e6106c4SLoGin int i;
221*3e6106c4SLoGin
222*3e6106c4SLoGin fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
223*3e6106c4SLoGin &name, &fixup_len);
224*3e6106c4SLoGin if (!fixup_val)
225*3e6106c4SLoGin return fixup_len;
226*3e6106c4SLoGin
227*3e6106c4SLoGin if (fixup_len % sizeof(uint32_t))
228*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
229*3e6106c4SLoGin fixup_len /= sizeof(uint32_t);
230*3e6106c4SLoGin
231*3e6106c4SLoGin tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
232*3e6106c4SLoGin if (!tree_val) {
233*3e6106c4SLoGin if (tree_len == -FDT_ERR_NOTFOUND)
234*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
235*3e6106c4SLoGin
236*3e6106c4SLoGin return tree_len;
237*3e6106c4SLoGin }
238*3e6106c4SLoGin
239*3e6106c4SLoGin for (i = 0; i < fixup_len; i++) {
240*3e6106c4SLoGin fdt32_t adj_val;
241*3e6106c4SLoGin uint32_t poffset;
242*3e6106c4SLoGin
243*3e6106c4SLoGin poffset = fdt32_to_cpu(fixup_val[i]);
244*3e6106c4SLoGin
245*3e6106c4SLoGin /*
246*3e6106c4SLoGin * phandles to fixup can be unaligned.
247*3e6106c4SLoGin *
248*3e6106c4SLoGin * Use a memcpy for the architectures that do
249*3e6106c4SLoGin * not support unaligned accesses.
250*3e6106c4SLoGin */
251*3e6106c4SLoGin memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
252*3e6106c4SLoGin
253*3e6106c4SLoGin adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
254*3e6106c4SLoGin
255*3e6106c4SLoGin ret = fdt_setprop_inplace_namelen_partial(fdto,
256*3e6106c4SLoGin tree_node,
257*3e6106c4SLoGin name,
258*3e6106c4SLoGin strlen(name),
259*3e6106c4SLoGin poffset,
260*3e6106c4SLoGin &adj_val,
261*3e6106c4SLoGin sizeof(adj_val));
262*3e6106c4SLoGin if (ret == -FDT_ERR_NOSPACE)
263*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
264*3e6106c4SLoGin
265*3e6106c4SLoGin if (ret)
266*3e6106c4SLoGin return ret;
267*3e6106c4SLoGin }
268*3e6106c4SLoGin }
269*3e6106c4SLoGin
270*3e6106c4SLoGin fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
271*3e6106c4SLoGin const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
272*3e6106c4SLoGin NULL);
273*3e6106c4SLoGin int tree_child;
274*3e6106c4SLoGin
275*3e6106c4SLoGin tree_child = fdt_subnode_offset(fdto, tree_node,
276*3e6106c4SLoGin fixup_child_name);
277*3e6106c4SLoGin if (tree_child == -FDT_ERR_NOTFOUND)
278*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
279*3e6106c4SLoGin if (tree_child < 0)
280*3e6106c4SLoGin return tree_child;
281*3e6106c4SLoGin
282*3e6106c4SLoGin ret = overlay_update_local_node_references(fdto,
283*3e6106c4SLoGin tree_child,
284*3e6106c4SLoGin fixup_child,
285*3e6106c4SLoGin delta);
286*3e6106c4SLoGin if (ret)
287*3e6106c4SLoGin return ret;
288*3e6106c4SLoGin }
289*3e6106c4SLoGin
290*3e6106c4SLoGin return 0;
291*3e6106c4SLoGin }
292*3e6106c4SLoGin
293*3e6106c4SLoGin /**
294*3e6106c4SLoGin * overlay_update_local_references - Adjust the overlay references
295*3e6106c4SLoGin * @fdto: Device tree overlay blob
296*3e6106c4SLoGin * @delta: Offset to shift the phandles of
297*3e6106c4SLoGin *
298*3e6106c4SLoGin * overlay_update_local_references() update all the phandles pointing
299*3e6106c4SLoGin * to a node within the device tree overlay by adding a constant
300*3e6106c4SLoGin * delta to not conflict with the base overlay.
301*3e6106c4SLoGin *
302*3e6106c4SLoGin * This is mainly used as part of a device tree application process,
303*3e6106c4SLoGin * where you want the device tree overlays phandles to not conflict
304*3e6106c4SLoGin * with the ones from the base device tree before merging them.
305*3e6106c4SLoGin *
306*3e6106c4SLoGin * returns:
307*3e6106c4SLoGin * 0 on success
308*3e6106c4SLoGin * Negative error code on failure
309*3e6106c4SLoGin */
overlay_update_local_references(void * fdto,uint32_t delta)310*3e6106c4SLoGin static int overlay_update_local_references(void *fdto, uint32_t delta)
311*3e6106c4SLoGin {
312*3e6106c4SLoGin int fixups;
313*3e6106c4SLoGin
314*3e6106c4SLoGin fixups = fdt_path_offset(fdto, "/__local_fixups__");
315*3e6106c4SLoGin if (fixups < 0) {
316*3e6106c4SLoGin /* There's no local phandles to adjust, bail out */
317*3e6106c4SLoGin if (fixups == -FDT_ERR_NOTFOUND)
318*3e6106c4SLoGin return 0;
319*3e6106c4SLoGin
320*3e6106c4SLoGin return fixups;
321*3e6106c4SLoGin }
322*3e6106c4SLoGin
323*3e6106c4SLoGin /*
324*3e6106c4SLoGin * Update our local references from the root of the tree
325*3e6106c4SLoGin */
326*3e6106c4SLoGin return overlay_update_local_node_references(fdto, 0, fixups,
327*3e6106c4SLoGin delta);
328*3e6106c4SLoGin }
329*3e6106c4SLoGin
330*3e6106c4SLoGin /**
331*3e6106c4SLoGin * overlay_fixup_one_phandle - Set an overlay phandle to the base one
332*3e6106c4SLoGin * @fdt: Base Device Tree blob
333*3e6106c4SLoGin * @fdto: Device tree overlay blob
334*3e6106c4SLoGin * @symbols_off: Node offset of the symbols node in the base device tree
335*3e6106c4SLoGin * @path: Path to a node holding a phandle in the overlay
336*3e6106c4SLoGin * @path_len: number of path characters to consider
337*3e6106c4SLoGin * @name: Name of the property holding the phandle reference in the overlay
338*3e6106c4SLoGin * @name_len: number of name characters to consider
339*3e6106c4SLoGin * @poffset: Offset within the overlay property where the phandle is stored
340*3e6106c4SLoGin * @label: Label of the node referenced by the phandle
341*3e6106c4SLoGin *
342*3e6106c4SLoGin * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
343*3e6106c4SLoGin * a node in the base device tree.
344*3e6106c4SLoGin *
345*3e6106c4SLoGin * This is part of the device tree overlay application process, when
346*3e6106c4SLoGin * you want all the phandles in the overlay to point to the actual
347*3e6106c4SLoGin * base dt nodes.
348*3e6106c4SLoGin *
349*3e6106c4SLoGin * returns:
350*3e6106c4SLoGin * 0 on success
351*3e6106c4SLoGin * Negative error code on failure
352*3e6106c4SLoGin */
overlay_fixup_one_phandle(void * fdt,void * fdto,int symbols_off,const char * path,uint32_t path_len,const char * name,uint32_t name_len,int poffset,const char * label)353*3e6106c4SLoGin static int overlay_fixup_one_phandle(void *fdt, void *fdto,
354*3e6106c4SLoGin int symbols_off,
355*3e6106c4SLoGin const char *path, uint32_t path_len,
356*3e6106c4SLoGin const char *name, uint32_t name_len,
357*3e6106c4SLoGin int poffset, const char *label)
358*3e6106c4SLoGin {
359*3e6106c4SLoGin const char *symbol_path;
360*3e6106c4SLoGin uint32_t phandle;
361*3e6106c4SLoGin fdt32_t phandle_prop;
362*3e6106c4SLoGin int symbol_off, fixup_off;
363*3e6106c4SLoGin int prop_len;
364*3e6106c4SLoGin
365*3e6106c4SLoGin if (symbols_off < 0)
366*3e6106c4SLoGin return symbols_off;
367*3e6106c4SLoGin
368*3e6106c4SLoGin symbol_path = fdt_getprop(fdt, symbols_off, label,
369*3e6106c4SLoGin &prop_len);
370*3e6106c4SLoGin if (!symbol_path)
371*3e6106c4SLoGin return prop_len;
372*3e6106c4SLoGin
373*3e6106c4SLoGin symbol_off = fdt_path_offset(fdt, symbol_path);
374*3e6106c4SLoGin if (symbol_off < 0)
375*3e6106c4SLoGin return symbol_off;
376*3e6106c4SLoGin
377*3e6106c4SLoGin phandle = fdt_get_phandle(fdt, symbol_off);
378*3e6106c4SLoGin if (!phandle)
379*3e6106c4SLoGin return -FDT_ERR_NOTFOUND;
380*3e6106c4SLoGin
381*3e6106c4SLoGin fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
382*3e6106c4SLoGin if (fixup_off == -FDT_ERR_NOTFOUND)
383*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
384*3e6106c4SLoGin if (fixup_off < 0)
385*3e6106c4SLoGin return fixup_off;
386*3e6106c4SLoGin
387*3e6106c4SLoGin phandle_prop = cpu_to_fdt32(phandle);
388*3e6106c4SLoGin return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
389*3e6106c4SLoGin name, name_len, poffset,
390*3e6106c4SLoGin &phandle_prop,
391*3e6106c4SLoGin sizeof(phandle_prop));
392*3e6106c4SLoGin };
393*3e6106c4SLoGin
394*3e6106c4SLoGin /**
395*3e6106c4SLoGin * overlay_fixup_phandle - Set an overlay phandle to the base one
396*3e6106c4SLoGin * @fdt: Base Device Tree blob
397*3e6106c4SLoGin * @fdto: Device tree overlay blob
398*3e6106c4SLoGin * @symbols_off: Node offset of the symbols node in the base device tree
399*3e6106c4SLoGin * @property: Property offset in the overlay holding the list of fixups
400*3e6106c4SLoGin *
401*3e6106c4SLoGin * overlay_fixup_phandle() resolves all the overlay phandles pointed
402*3e6106c4SLoGin * to in a __fixups__ property, and updates them to match the phandles
403*3e6106c4SLoGin * in use in the base device tree.
404*3e6106c4SLoGin *
405*3e6106c4SLoGin * This is part of the device tree overlay application process, when
406*3e6106c4SLoGin * you want all the phandles in the overlay to point to the actual
407*3e6106c4SLoGin * base dt nodes.
408*3e6106c4SLoGin *
409*3e6106c4SLoGin * returns:
410*3e6106c4SLoGin * 0 on success
411*3e6106c4SLoGin * Negative error code on failure
412*3e6106c4SLoGin */
overlay_fixup_phandle(void * fdt,void * fdto,int symbols_off,int property)413*3e6106c4SLoGin static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
414*3e6106c4SLoGin int property)
415*3e6106c4SLoGin {
416*3e6106c4SLoGin const char *value;
417*3e6106c4SLoGin const char *label;
418*3e6106c4SLoGin int len;
419*3e6106c4SLoGin
420*3e6106c4SLoGin value = fdt_getprop_by_offset(fdto, property,
421*3e6106c4SLoGin &label, &len);
422*3e6106c4SLoGin if (!value) {
423*3e6106c4SLoGin if (len == -FDT_ERR_NOTFOUND)
424*3e6106c4SLoGin return -FDT_ERR_INTERNAL;
425*3e6106c4SLoGin
426*3e6106c4SLoGin return len;
427*3e6106c4SLoGin }
428*3e6106c4SLoGin
429*3e6106c4SLoGin do {
430*3e6106c4SLoGin const char *path, *name, *fixup_end;
431*3e6106c4SLoGin const char *fixup_str = value;
432*3e6106c4SLoGin uint32_t path_len, name_len;
433*3e6106c4SLoGin uint32_t fixup_len;
434*3e6106c4SLoGin char *sep, *endptr;
435*3e6106c4SLoGin int poffset, ret;
436*3e6106c4SLoGin
437*3e6106c4SLoGin fixup_end = memchr(value, '\0', len);
438*3e6106c4SLoGin if (!fixup_end)
439*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
440*3e6106c4SLoGin fixup_len = fixup_end - fixup_str;
441*3e6106c4SLoGin
442*3e6106c4SLoGin len -= fixup_len + 1;
443*3e6106c4SLoGin value += fixup_len + 1;
444*3e6106c4SLoGin
445*3e6106c4SLoGin path = fixup_str;
446*3e6106c4SLoGin sep = memchr(fixup_str, ':', fixup_len);
447*3e6106c4SLoGin if (!sep || *sep != ':')
448*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
449*3e6106c4SLoGin
450*3e6106c4SLoGin path_len = sep - path;
451*3e6106c4SLoGin if (path_len == (fixup_len - 1))
452*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
453*3e6106c4SLoGin
454*3e6106c4SLoGin fixup_len -= path_len + 1;
455*3e6106c4SLoGin name = sep + 1;
456*3e6106c4SLoGin sep = memchr(name, ':', fixup_len);
457*3e6106c4SLoGin if (!sep || *sep != ':')
458*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
459*3e6106c4SLoGin
460*3e6106c4SLoGin name_len = sep - name;
461*3e6106c4SLoGin if (!name_len)
462*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
463*3e6106c4SLoGin
464*3e6106c4SLoGin poffset = strtoul(sep + 1, &endptr, 10);
465*3e6106c4SLoGin if ((*endptr != '\0') || (endptr <= (sep + 1)))
466*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
467*3e6106c4SLoGin
468*3e6106c4SLoGin ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
469*3e6106c4SLoGin path, path_len, name, name_len,
470*3e6106c4SLoGin poffset, label);
471*3e6106c4SLoGin if (ret)
472*3e6106c4SLoGin return ret;
473*3e6106c4SLoGin } while (len > 0);
474*3e6106c4SLoGin
475*3e6106c4SLoGin return 0;
476*3e6106c4SLoGin }
477*3e6106c4SLoGin
478*3e6106c4SLoGin /**
479*3e6106c4SLoGin * overlay_fixup_phandles - Resolve the overlay phandles to the base
480*3e6106c4SLoGin * device tree
481*3e6106c4SLoGin * @fdt: Base Device Tree blob
482*3e6106c4SLoGin * @fdto: Device tree overlay blob
483*3e6106c4SLoGin *
484*3e6106c4SLoGin * overlay_fixup_phandles() resolves all the overlay phandles pointing
485*3e6106c4SLoGin * to nodes in the base device tree.
486*3e6106c4SLoGin *
487*3e6106c4SLoGin * This is one of the steps of the device tree overlay application
488*3e6106c4SLoGin * process, when you want all the phandles in the overlay to point to
489*3e6106c4SLoGin * the actual base dt nodes.
490*3e6106c4SLoGin *
491*3e6106c4SLoGin * returns:
492*3e6106c4SLoGin * 0 on success
493*3e6106c4SLoGin * Negative error code on failure
494*3e6106c4SLoGin */
overlay_fixup_phandles(void * fdt,void * fdto)495*3e6106c4SLoGin static int overlay_fixup_phandles(void *fdt, void *fdto)
496*3e6106c4SLoGin {
497*3e6106c4SLoGin int fixups_off, symbols_off;
498*3e6106c4SLoGin int property;
499*3e6106c4SLoGin
500*3e6106c4SLoGin /* We can have overlays without any fixups */
501*3e6106c4SLoGin fixups_off = fdt_path_offset(fdto, "/__fixups__");
502*3e6106c4SLoGin if (fixups_off == -FDT_ERR_NOTFOUND)
503*3e6106c4SLoGin return 0; /* nothing to do */
504*3e6106c4SLoGin if (fixups_off < 0)
505*3e6106c4SLoGin return fixups_off;
506*3e6106c4SLoGin
507*3e6106c4SLoGin /* And base DTs without symbols */
508*3e6106c4SLoGin symbols_off = fdt_path_offset(fdt, "/__symbols__");
509*3e6106c4SLoGin if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
510*3e6106c4SLoGin return symbols_off;
511*3e6106c4SLoGin
512*3e6106c4SLoGin fdt_for_each_property_offset(property, fdto, fixups_off) {
513*3e6106c4SLoGin int ret;
514*3e6106c4SLoGin
515*3e6106c4SLoGin ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
516*3e6106c4SLoGin if (ret)
517*3e6106c4SLoGin return ret;
518*3e6106c4SLoGin }
519*3e6106c4SLoGin
520*3e6106c4SLoGin return 0;
521*3e6106c4SLoGin }
522*3e6106c4SLoGin
523*3e6106c4SLoGin /**
524*3e6106c4SLoGin * overlay_apply_node - Merges a node into the base device tree
525*3e6106c4SLoGin * @fdt: Base Device Tree blob
526*3e6106c4SLoGin * @target: Node offset in the base device tree to apply the fragment to
527*3e6106c4SLoGin * @fdto: Device tree overlay blob
528*3e6106c4SLoGin * @node: Node offset in the overlay holding the changes to merge
529*3e6106c4SLoGin *
530*3e6106c4SLoGin * overlay_apply_node() merges a node into a target base device tree
531*3e6106c4SLoGin * node pointed.
532*3e6106c4SLoGin *
533*3e6106c4SLoGin * This is part of the final step in the device tree overlay
534*3e6106c4SLoGin * application process, when all the phandles have been adjusted and
535*3e6106c4SLoGin * resolved and you just have to merge overlay into the base device
536*3e6106c4SLoGin * tree.
537*3e6106c4SLoGin *
538*3e6106c4SLoGin * returns:
539*3e6106c4SLoGin * 0 on success
540*3e6106c4SLoGin * Negative error code on failure
541*3e6106c4SLoGin */
overlay_apply_node(void * fdt,int target,void * fdto,int node)542*3e6106c4SLoGin static int overlay_apply_node(void *fdt, int target,
543*3e6106c4SLoGin void *fdto, int node)
544*3e6106c4SLoGin {
545*3e6106c4SLoGin int property;
546*3e6106c4SLoGin int subnode;
547*3e6106c4SLoGin
548*3e6106c4SLoGin fdt_for_each_property_offset(property, fdto, node) {
549*3e6106c4SLoGin const char *name;
550*3e6106c4SLoGin const void *prop;
551*3e6106c4SLoGin int prop_len;
552*3e6106c4SLoGin int ret;
553*3e6106c4SLoGin
554*3e6106c4SLoGin prop = fdt_getprop_by_offset(fdto, property, &name,
555*3e6106c4SLoGin &prop_len);
556*3e6106c4SLoGin if (prop_len == -FDT_ERR_NOTFOUND)
557*3e6106c4SLoGin return -FDT_ERR_INTERNAL;
558*3e6106c4SLoGin if (prop_len < 0)
559*3e6106c4SLoGin return prop_len;
560*3e6106c4SLoGin
561*3e6106c4SLoGin ret = fdt_setprop(fdt, target, name, prop, prop_len);
562*3e6106c4SLoGin if (ret)
563*3e6106c4SLoGin return ret;
564*3e6106c4SLoGin }
565*3e6106c4SLoGin
566*3e6106c4SLoGin fdt_for_each_subnode(subnode, fdto, node) {
567*3e6106c4SLoGin const char *name = fdt_get_name(fdto, subnode, NULL);
568*3e6106c4SLoGin int nnode;
569*3e6106c4SLoGin int ret;
570*3e6106c4SLoGin
571*3e6106c4SLoGin nnode = fdt_add_subnode(fdt, target, name);
572*3e6106c4SLoGin if (nnode == -FDT_ERR_EXISTS) {
573*3e6106c4SLoGin nnode = fdt_subnode_offset(fdt, target, name);
574*3e6106c4SLoGin if (nnode == -FDT_ERR_NOTFOUND)
575*3e6106c4SLoGin return -FDT_ERR_INTERNAL;
576*3e6106c4SLoGin }
577*3e6106c4SLoGin
578*3e6106c4SLoGin if (nnode < 0)
579*3e6106c4SLoGin return nnode;
580*3e6106c4SLoGin
581*3e6106c4SLoGin ret = overlay_apply_node(fdt, nnode, fdto, subnode);
582*3e6106c4SLoGin if (ret)
583*3e6106c4SLoGin return ret;
584*3e6106c4SLoGin }
585*3e6106c4SLoGin
586*3e6106c4SLoGin return 0;
587*3e6106c4SLoGin }
588*3e6106c4SLoGin
589*3e6106c4SLoGin /**
590*3e6106c4SLoGin * overlay_merge - Merge an overlay into its base device tree
591*3e6106c4SLoGin * @fdt: Base Device Tree blob
592*3e6106c4SLoGin * @fdto: Device tree overlay blob
593*3e6106c4SLoGin *
594*3e6106c4SLoGin * overlay_merge() merges an overlay into its base device tree.
595*3e6106c4SLoGin *
596*3e6106c4SLoGin * This is the next to last step in the device tree overlay application
597*3e6106c4SLoGin * process, when all the phandles have been adjusted and resolved and
598*3e6106c4SLoGin * you just have to merge overlay into the base device tree.
599*3e6106c4SLoGin *
600*3e6106c4SLoGin * returns:
601*3e6106c4SLoGin * 0 on success
602*3e6106c4SLoGin * Negative error code on failure
603*3e6106c4SLoGin */
overlay_merge(void * fdt,void * fdto)604*3e6106c4SLoGin static int overlay_merge(void *fdt, void *fdto)
605*3e6106c4SLoGin {
606*3e6106c4SLoGin int fragment;
607*3e6106c4SLoGin
608*3e6106c4SLoGin fdt_for_each_subnode(fragment, fdto, 0) {
609*3e6106c4SLoGin int overlay;
610*3e6106c4SLoGin int target;
611*3e6106c4SLoGin int ret;
612*3e6106c4SLoGin
613*3e6106c4SLoGin /*
614*3e6106c4SLoGin * Each fragments will have an __overlay__ node. If
615*3e6106c4SLoGin * they don't, it's not supposed to be merged
616*3e6106c4SLoGin */
617*3e6106c4SLoGin overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
618*3e6106c4SLoGin if (overlay == -FDT_ERR_NOTFOUND)
619*3e6106c4SLoGin continue;
620*3e6106c4SLoGin
621*3e6106c4SLoGin if (overlay < 0)
622*3e6106c4SLoGin return overlay;
623*3e6106c4SLoGin
624*3e6106c4SLoGin target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
625*3e6106c4SLoGin if (target < 0)
626*3e6106c4SLoGin return target;
627*3e6106c4SLoGin
628*3e6106c4SLoGin ret = overlay_apply_node(fdt, target, fdto, overlay);
629*3e6106c4SLoGin if (ret)
630*3e6106c4SLoGin return ret;
631*3e6106c4SLoGin }
632*3e6106c4SLoGin
633*3e6106c4SLoGin return 0;
634*3e6106c4SLoGin }
635*3e6106c4SLoGin
get_path_len(const void * fdt,int nodeoffset)636*3e6106c4SLoGin static int get_path_len(const void *fdt, int nodeoffset)
637*3e6106c4SLoGin {
638*3e6106c4SLoGin int len = 0, namelen;
639*3e6106c4SLoGin const char *name;
640*3e6106c4SLoGin
641*3e6106c4SLoGin FDT_RO_PROBE(fdt);
642*3e6106c4SLoGin
643*3e6106c4SLoGin for (;;) {
644*3e6106c4SLoGin name = fdt_get_name(fdt, nodeoffset, &namelen);
645*3e6106c4SLoGin if (!name)
646*3e6106c4SLoGin return namelen;
647*3e6106c4SLoGin
648*3e6106c4SLoGin /* root? we're done */
649*3e6106c4SLoGin if (namelen == 0)
650*3e6106c4SLoGin break;
651*3e6106c4SLoGin
652*3e6106c4SLoGin nodeoffset = fdt_parent_offset(fdt, nodeoffset);
653*3e6106c4SLoGin if (nodeoffset < 0)
654*3e6106c4SLoGin return nodeoffset;
655*3e6106c4SLoGin len += namelen + 1;
656*3e6106c4SLoGin }
657*3e6106c4SLoGin
658*3e6106c4SLoGin /* in case of root pretend it's "/" */
659*3e6106c4SLoGin if (len == 0)
660*3e6106c4SLoGin len++;
661*3e6106c4SLoGin return len;
662*3e6106c4SLoGin }
663*3e6106c4SLoGin
664*3e6106c4SLoGin /**
665*3e6106c4SLoGin * overlay_symbol_update - Update the symbols of base tree after a merge
666*3e6106c4SLoGin * @fdt: Base Device Tree blob
667*3e6106c4SLoGin * @fdto: Device tree overlay blob
668*3e6106c4SLoGin *
669*3e6106c4SLoGin * overlay_symbol_update() updates the symbols of the base tree with the
670*3e6106c4SLoGin * symbols of the applied overlay
671*3e6106c4SLoGin *
672*3e6106c4SLoGin * This is the last step in the device tree overlay application
673*3e6106c4SLoGin * process, allowing the reference of overlay symbols by subsequent
674*3e6106c4SLoGin * overlay operations.
675*3e6106c4SLoGin *
676*3e6106c4SLoGin * returns:
677*3e6106c4SLoGin * 0 on success
678*3e6106c4SLoGin * Negative error code on failure
679*3e6106c4SLoGin */
overlay_symbol_update(void * fdt,void * fdto)680*3e6106c4SLoGin static int overlay_symbol_update(void *fdt, void *fdto)
681*3e6106c4SLoGin {
682*3e6106c4SLoGin int root_sym, ov_sym, prop, path_len, fragment, target;
683*3e6106c4SLoGin int len, frag_name_len, ret, rel_path_len;
684*3e6106c4SLoGin const char *s, *e;
685*3e6106c4SLoGin const char *path;
686*3e6106c4SLoGin const char *name;
687*3e6106c4SLoGin const char *frag_name;
688*3e6106c4SLoGin const char *rel_path;
689*3e6106c4SLoGin const char *target_path;
690*3e6106c4SLoGin char *buf;
691*3e6106c4SLoGin void *p;
692*3e6106c4SLoGin
693*3e6106c4SLoGin ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
694*3e6106c4SLoGin
695*3e6106c4SLoGin /* if no overlay symbols exist no problem */
696*3e6106c4SLoGin if (ov_sym < 0)
697*3e6106c4SLoGin return 0;
698*3e6106c4SLoGin
699*3e6106c4SLoGin root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
700*3e6106c4SLoGin
701*3e6106c4SLoGin /* it no root symbols exist we should create them */
702*3e6106c4SLoGin if (root_sym == -FDT_ERR_NOTFOUND)
703*3e6106c4SLoGin root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
704*3e6106c4SLoGin
705*3e6106c4SLoGin /* any error is fatal now */
706*3e6106c4SLoGin if (root_sym < 0)
707*3e6106c4SLoGin return root_sym;
708*3e6106c4SLoGin
709*3e6106c4SLoGin /* iterate over each overlay symbol */
710*3e6106c4SLoGin fdt_for_each_property_offset(prop, fdto, ov_sym) {
711*3e6106c4SLoGin path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
712*3e6106c4SLoGin if (!path)
713*3e6106c4SLoGin return path_len;
714*3e6106c4SLoGin
715*3e6106c4SLoGin /* verify it's a string property (terminated by a single \0) */
716*3e6106c4SLoGin if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
717*3e6106c4SLoGin return -FDT_ERR_BADVALUE;
718*3e6106c4SLoGin
719*3e6106c4SLoGin /* keep end marker to avoid strlen() */
720*3e6106c4SLoGin e = path + path_len;
721*3e6106c4SLoGin
722*3e6106c4SLoGin if (*path != '/')
723*3e6106c4SLoGin return -FDT_ERR_BADVALUE;
724*3e6106c4SLoGin
725*3e6106c4SLoGin /* get fragment name first */
726*3e6106c4SLoGin s = strchr(path + 1, '/');
727*3e6106c4SLoGin if (!s) {
728*3e6106c4SLoGin /* Symbol refers to something that won't end
729*3e6106c4SLoGin * up in the target tree */
730*3e6106c4SLoGin continue;
731*3e6106c4SLoGin }
732*3e6106c4SLoGin
733*3e6106c4SLoGin frag_name = path + 1;
734*3e6106c4SLoGin frag_name_len = s - path - 1;
735*3e6106c4SLoGin
736*3e6106c4SLoGin /* verify format; safe since "s" lies in \0 terminated prop */
737*3e6106c4SLoGin len = sizeof("/__overlay__/") - 1;
738*3e6106c4SLoGin if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
739*3e6106c4SLoGin /* /<fragment-name>/__overlay__/<relative-subnode-path> */
740*3e6106c4SLoGin rel_path = s + len;
741*3e6106c4SLoGin rel_path_len = e - rel_path - 1;
742*3e6106c4SLoGin } else if ((e - s) == len
743*3e6106c4SLoGin && (memcmp(s, "/__overlay__", len - 1) == 0)) {
744*3e6106c4SLoGin /* /<fragment-name>/__overlay__ */
745*3e6106c4SLoGin rel_path = "";
746*3e6106c4SLoGin rel_path_len = 0;
747*3e6106c4SLoGin } else {
748*3e6106c4SLoGin /* Symbol refers to something that won't end
749*3e6106c4SLoGin * up in the target tree */
750*3e6106c4SLoGin continue;
751*3e6106c4SLoGin }
752*3e6106c4SLoGin
753*3e6106c4SLoGin /* find the fragment index in which the symbol lies */
754*3e6106c4SLoGin ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
755*3e6106c4SLoGin frag_name_len);
756*3e6106c4SLoGin /* not found? */
757*3e6106c4SLoGin if (ret < 0)
758*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
759*3e6106c4SLoGin fragment = ret;
760*3e6106c4SLoGin
761*3e6106c4SLoGin /* an __overlay__ subnode must exist */
762*3e6106c4SLoGin ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
763*3e6106c4SLoGin if (ret < 0)
764*3e6106c4SLoGin return -FDT_ERR_BADOVERLAY;
765*3e6106c4SLoGin
766*3e6106c4SLoGin /* get the target of the fragment */
767*3e6106c4SLoGin ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
768*3e6106c4SLoGin if (ret < 0)
769*3e6106c4SLoGin return ret;
770*3e6106c4SLoGin target = ret;
771*3e6106c4SLoGin
772*3e6106c4SLoGin /* if we have a target path use */
773*3e6106c4SLoGin if (!target_path) {
774*3e6106c4SLoGin ret = get_path_len(fdt, target);
775*3e6106c4SLoGin if (ret < 0)
776*3e6106c4SLoGin return ret;
777*3e6106c4SLoGin len = ret;
778*3e6106c4SLoGin } else {
779*3e6106c4SLoGin len = strlen(target_path);
780*3e6106c4SLoGin }
781*3e6106c4SLoGin
782*3e6106c4SLoGin ret = fdt_setprop_placeholder(fdt, root_sym, name,
783*3e6106c4SLoGin len + (len > 1) + rel_path_len + 1, &p);
784*3e6106c4SLoGin if (ret < 0)
785*3e6106c4SLoGin return ret;
786*3e6106c4SLoGin
787*3e6106c4SLoGin if (!target_path) {
788*3e6106c4SLoGin /* again in case setprop_placeholder changed it */
789*3e6106c4SLoGin ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
790*3e6106c4SLoGin if (ret < 0)
791*3e6106c4SLoGin return ret;
792*3e6106c4SLoGin target = ret;
793*3e6106c4SLoGin }
794*3e6106c4SLoGin
795*3e6106c4SLoGin buf = p;
796*3e6106c4SLoGin if (len > 1) { /* target is not root */
797*3e6106c4SLoGin if (!target_path) {
798*3e6106c4SLoGin ret = fdt_get_path(fdt, target, buf, len + 1);
799*3e6106c4SLoGin if (ret < 0)
800*3e6106c4SLoGin return ret;
801*3e6106c4SLoGin } else
802*3e6106c4SLoGin memcpy(buf, target_path, len + 1);
803*3e6106c4SLoGin
804*3e6106c4SLoGin } else
805*3e6106c4SLoGin len--;
806*3e6106c4SLoGin
807*3e6106c4SLoGin buf[len] = '/';
808*3e6106c4SLoGin memcpy(buf + len + 1, rel_path, rel_path_len);
809*3e6106c4SLoGin buf[len + 1 + rel_path_len] = '\0';
810*3e6106c4SLoGin }
811*3e6106c4SLoGin
812*3e6106c4SLoGin return 0;
813*3e6106c4SLoGin }
814*3e6106c4SLoGin
fdt_overlay_apply(void * fdt,void * fdto)815*3e6106c4SLoGin int fdt_overlay_apply(void *fdt, void *fdto)
816*3e6106c4SLoGin {
817*3e6106c4SLoGin uint32_t delta;
818*3e6106c4SLoGin int ret;
819*3e6106c4SLoGin
820*3e6106c4SLoGin FDT_RO_PROBE(fdt);
821*3e6106c4SLoGin FDT_RO_PROBE(fdto);
822*3e6106c4SLoGin
823*3e6106c4SLoGin ret = fdt_find_max_phandle(fdt, &delta);
824*3e6106c4SLoGin if (ret)
825*3e6106c4SLoGin goto err;
826*3e6106c4SLoGin
827*3e6106c4SLoGin ret = overlay_adjust_local_phandles(fdto, delta);
828*3e6106c4SLoGin if (ret)
829*3e6106c4SLoGin goto err;
830*3e6106c4SLoGin
831*3e6106c4SLoGin ret = overlay_update_local_references(fdto, delta);
832*3e6106c4SLoGin if (ret)
833*3e6106c4SLoGin goto err;
834*3e6106c4SLoGin
835*3e6106c4SLoGin ret = overlay_fixup_phandles(fdt, fdto);
836*3e6106c4SLoGin if (ret)
837*3e6106c4SLoGin goto err;
838*3e6106c4SLoGin
839*3e6106c4SLoGin ret = overlay_merge(fdt, fdto);
840*3e6106c4SLoGin if (ret)
841*3e6106c4SLoGin goto err;
842*3e6106c4SLoGin
843*3e6106c4SLoGin ret = overlay_symbol_update(fdt, fdto);
844*3e6106c4SLoGin if (ret)
845*3e6106c4SLoGin goto err;
846*3e6106c4SLoGin
847*3e6106c4SLoGin /*
848*3e6106c4SLoGin * The overlay has been damaged, erase its magic.
849*3e6106c4SLoGin */
850*3e6106c4SLoGin fdt_set_magic(fdto, ~0);
851*3e6106c4SLoGin
852*3e6106c4SLoGin return 0;
853*3e6106c4SLoGin
854*3e6106c4SLoGin err:
855*3e6106c4SLoGin /*
856*3e6106c4SLoGin * The overlay might have been damaged, erase its magic.
857*3e6106c4SLoGin */
858*3e6106c4SLoGin fdt_set_magic(fdto, ~0);
859*3e6106c4SLoGin
860*3e6106c4SLoGin /*
861*3e6106c4SLoGin * The base device tree might have been damaged, erase its
862*3e6106c4SLoGin * magic.
863*3e6106c4SLoGin */
864*3e6106c4SLoGin fdt_set_magic(fdt, ~0);
865*3e6106c4SLoGin
866*3e6106c4SLoGin return ret;
867*3e6106c4SLoGin }
868