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