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