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