xref: /DragonStub/apps/lib/libfdt/fdt_overlay.c (revision 3e6106c4d60a23aae3c0740979c5e6fb728b63c3)
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