112869ecdSRob Herring // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
29130ba88SRob Herring /*
39130ba88SRob Herring * libfdt - Flat Device Tree manipulation
49130ba88SRob Herring * Copyright (C) 2016 Free Electrons
59130ba88SRob Herring * Copyright (C) 2016 NextThing Co.
69130ba88SRob Herring */
74201d057SRob Herring #include "libfdt_env.h"
84201d057SRob Herring
94201d057SRob Herring #include <fdt.h>
104201d057SRob Herring #include <libfdt.h>
114201d057SRob Herring
124201d057SRob Herring #include "libfdt_internal.h"
134201d057SRob Herring
144201d057SRob Herring /**
154201d057SRob Herring * overlay_get_target_phandle - retrieves the target phandle of a fragment
164201d057SRob Herring * @fdto: pointer to the device tree overlay blob
174201d057SRob Herring * @fragment: node offset of the fragment in the overlay
184201d057SRob Herring *
194201d057SRob Herring * overlay_get_target_phandle() retrieves the target phandle of an
204201d057SRob Herring * overlay fragment when that fragment uses a phandle (target
214201d057SRob Herring * property) instead of a path (target-path property).
224201d057SRob Herring *
234201d057SRob Herring * returns:
244201d057SRob Herring * the phandle pointed by the target property
254201d057SRob Herring * 0, if the phandle was not found
264201d057SRob Herring * -1, if the phandle was malformed
274201d057SRob Herring */
overlay_get_target_phandle(const void * fdto,int fragment)284201d057SRob Herring static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
294201d057SRob Herring {
304201d057SRob Herring const fdt32_t *val;
314201d057SRob Herring int len;
324201d057SRob Herring
334201d057SRob Herring val = fdt_getprop(fdto, fragment, "target", &len);
344201d057SRob Herring if (!val)
354201d057SRob Herring return 0;
364201d057SRob Herring
374201d057SRob Herring if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
384201d057SRob Herring return (uint32_t)-1;
394201d057SRob Herring
404201d057SRob Herring return fdt32_to_cpu(*val);
414201d057SRob Herring }
424201d057SRob Herring
fdt_overlay_target_offset(const void * fdt,const void * fdto,int fragment_offset,char const ** pathp)43*ea3723a5SRob Herring int fdt_overlay_target_offset(const void *fdt, const void *fdto,
44*ea3723a5SRob Herring int fragment_offset, char const **pathp)
454201d057SRob Herring {
464201d057SRob Herring uint32_t phandle;
474201d057SRob Herring const char *path = NULL;
484201d057SRob Herring int path_len = 0, ret;
494201d057SRob Herring
504201d057SRob Herring /* Try first to do a phandle based lookup */
51*ea3723a5SRob Herring phandle = overlay_get_target_phandle(fdto, fragment_offset);
524201d057SRob Herring if (phandle == (uint32_t)-1)
534201d057SRob Herring return -FDT_ERR_BADPHANDLE;
544201d057SRob Herring
554201d057SRob Herring /* no phandle, try path */
564201d057SRob Herring if (!phandle) {
574201d057SRob Herring /* And then a path based lookup */
58*ea3723a5SRob Herring path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len);
594201d057SRob Herring if (path)
604201d057SRob Herring ret = fdt_path_offset(fdt, path);
614201d057SRob Herring else
624201d057SRob Herring ret = path_len;
634201d057SRob Herring } else
644201d057SRob Herring ret = fdt_node_offset_by_phandle(fdt, phandle);
654201d057SRob Herring
664201d057SRob Herring /*
674201d057SRob Herring * If we haven't found either a target or a
684201d057SRob Herring * target-path property in a node that contains a
694201d057SRob Herring * __overlay__ subnode (we wouldn't be called
704201d057SRob Herring * otherwise), consider it a improperly written
714201d057SRob Herring * overlay
724201d057SRob Herring */
734201d057SRob Herring if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
744201d057SRob Herring ret = -FDT_ERR_BADOVERLAY;
754201d057SRob Herring
764201d057SRob Herring /* return on error */
774201d057SRob Herring if (ret < 0)
784201d057SRob Herring return ret;
794201d057SRob Herring
804201d057SRob Herring /* return pointer to path (if available) */
814201d057SRob Herring if (pathp)
824201d057SRob Herring *pathp = path ? path : NULL;
834201d057SRob Herring
844201d057SRob Herring return ret;
854201d057SRob Herring }
864201d057SRob Herring
874201d057SRob Herring /**
884201d057SRob Herring * overlay_phandle_add_offset - Increases a phandle by an offset
894201d057SRob Herring * @fdt: Base device tree blob
904201d057SRob Herring * @node: Device tree overlay blob
914201d057SRob Herring * @name: Name of the property to modify (phandle or linux,phandle)
924201d057SRob Herring * @delta: offset to apply
934201d057SRob Herring *
944201d057SRob Herring * overlay_phandle_add_offset() increments a node phandle by a given
954201d057SRob Herring * offset.
964201d057SRob Herring *
974201d057SRob Herring * returns:
984201d057SRob Herring * 0 on success.
994201d057SRob Herring * Negative error code on error
1004201d057SRob Herring */
overlay_phandle_add_offset(void * fdt,int node,const char * name,uint32_t delta)1014201d057SRob Herring static int overlay_phandle_add_offset(void *fdt, int node,
1024201d057SRob Herring const char *name, uint32_t delta)
1034201d057SRob Herring {
1044201d057SRob Herring const fdt32_t *val;
1054201d057SRob Herring uint32_t adj_val;
1064201d057SRob Herring int len;
1074201d057SRob Herring
1084201d057SRob Herring val = fdt_getprop(fdt, node, name, &len);
1094201d057SRob Herring if (!val)
1104201d057SRob Herring return len;
1114201d057SRob Herring
1124201d057SRob Herring if (len != sizeof(*val))
1134201d057SRob Herring return -FDT_ERR_BADPHANDLE;
1144201d057SRob Herring
1154201d057SRob Herring adj_val = fdt32_to_cpu(*val);
1164201d057SRob Herring if ((adj_val + delta) < adj_val)
1174201d057SRob Herring return -FDT_ERR_NOPHANDLES;
1184201d057SRob Herring
1194201d057SRob Herring adj_val += delta;
1204201d057SRob Herring if (adj_val == (uint32_t)-1)
1214201d057SRob Herring return -FDT_ERR_NOPHANDLES;
1224201d057SRob Herring
1234201d057SRob Herring return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
1244201d057SRob Herring }
1254201d057SRob Herring
1264201d057SRob Herring /**
1274201d057SRob Herring * overlay_adjust_node_phandles - Offsets the phandles of a node
1284201d057SRob Herring * @fdto: Device tree overlay blob
1294201d057SRob Herring * @node: Offset of the node we want to adjust
1304201d057SRob Herring * @delta: Offset to shift the phandles of
1314201d057SRob Herring *
1324201d057SRob Herring * overlay_adjust_node_phandles() adds a constant to all the phandles
1334201d057SRob Herring * of a given node. This is mainly use as part of the overlay
1344201d057SRob Herring * application process, when we want to update all the overlay
1354201d057SRob Herring * phandles to not conflict with the overlays of the base device tree.
1364201d057SRob Herring *
1374201d057SRob Herring * returns:
1384201d057SRob Herring * 0 on success
1394201d057SRob Herring * Negative error code on failure
1404201d057SRob Herring */
overlay_adjust_node_phandles(void * fdto,int node,uint32_t delta)1414201d057SRob Herring static int overlay_adjust_node_phandles(void *fdto, int node,
1424201d057SRob Herring uint32_t delta)
1434201d057SRob Herring {
1444201d057SRob Herring int child;
1454201d057SRob Herring int ret;
1464201d057SRob Herring
1474201d057SRob Herring ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
1484201d057SRob Herring if (ret && ret != -FDT_ERR_NOTFOUND)
1494201d057SRob Herring return ret;
1504201d057SRob Herring
1514201d057SRob Herring ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
1524201d057SRob Herring if (ret && ret != -FDT_ERR_NOTFOUND)
1534201d057SRob Herring return ret;
1544201d057SRob Herring
1554201d057SRob Herring fdt_for_each_subnode(child, fdto, node) {
1564201d057SRob Herring ret = overlay_adjust_node_phandles(fdto, child, delta);
1574201d057SRob Herring if (ret)
1584201d057SRob Herring return ret;
1594201d057SRob Herring }
1604201d057SRob Herring
1614201d057SRob Herring return 0;
1624201d057SRob Herring }
1634201d057SRob Herring
1644201d057SRob Herring /**
1654201d057SRob Herring * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
1664201d057SRob Herring * @fdto: Device tree overlay blob
1674201d057SRob Herring * @delta: Offset to shift the phandles of
1684201d057SRob Herring *
1694201d057SRob Herring * overlay_adjust_local_phandles() adds a constant to all the
1704201d057SRob Herring * phandles of an overlay. This is mainly use as part of the overlay
1714201d057SRob Herring * application process, when we want to update all the overlay
1724201d057SRob Herring * phandles to not conflict with the overlays of the base device tree.
1734201d057SRob Herring *
1744201d057SRob Herring * returns:
1754201d057SRob Herring * 0 on success
1764201d057SRob Herring * Negative error code on failure
1774201d057SRob Herring */
overlay_adjust_local_phandles(void * fdto,uint32_t delta)1784201d057SRob Herring static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
1794201d057SRob Herring {
1804201d057SRob Herring /*
1814201d057SRob Herring * Start adjusting the phandles from the overlay root
1824201d057SRob Herring */
1834201d057SRob Herring return overlay_adjust_node_phandles(fdto, 0, delta);
1844201d057SRob Herring }
1854201d057SRob Herring
1864201d057SRob Herring /**
1874201d057SRob Herring * overlay_update_local_node_references - Adjust the overlay references
1884201d057SRob Herring * @fdto: Device tree overlay blob
1894201d057SRob Herring * @tree_node: Node offset of the node to operate on
1904201d057SRob Herring * @fixup_node: Node offset of the matching local fixups node
1914201d057SRob Herring * @delta: Offset to shift the phandles of
1924201d057SRob Herring *
1934201d057SRob Herring * overlay_update_local_nodes_references() update the phandles
1944201d057SRob Herring * pointing to a node within the device tree overlay by adding a
1954201d057SRob Herring * constant delta.
1964201d057SRob Herring *
1974201d057SRob Herring * This is mainly used as part of a device tree application process,
1984201d057SRob Herring * where you want the device tree overlays phandles to not conflict
1994201d057SRob Herring * with the ones from the base device tree before merging them.
2004201d057SRob Herring *
2014201d057SRob Herring * returns:
2024201d057SRob Herring * 0 on success
2034201d057SRob Herring * Negative error code on failure
2044201d057SRob Herring */
overlay_update_local_node_references(void * fdto,int tree_node,int fixup_node,uint32_t delta)2054201d057SRob Herring static int overlay_update_local_node_references(void *fdto,
2064201d057SRob Herring int tree_node,
2074201d057SRob Herring int fixup_node,
2084201d057SRob Herring uint32_t delta)
2094201d057SRob Herring {
2104201d057SRob Herring int fixup_prop;
2114201d057SRob Herring int fixup_child;
2124201d057SRob Herring int ret;
2134201d057SRob Herring
2144201d057SRob Herring fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
2154201d057SRob Herring const fdt32_t *fixup_val;
2164201d057SRob Herring const char *tree_val;
2174201d057SRob Herring const char *name;
2184201d057SRob Herring int fixup_len;
2194201d057SRob Herring int tree_len;
2204201d057SRob Herring int i;
2214201d057SRob Herring
2224201d057SRob Herring fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
2234201d057SRob Herring &name, &fixup_len);
2244201d057SRob Herring if (!fixup_val)
2254201d057SRob Herring return fixup_len;
2264201d057SRob Herring
2274201d057SRob Herring if (fixup_len % sizeof(uint32_t))
2284201d057SRob Herring return -FDT_ERR_BADOVERLAY;
2296e9c9686SRob Herring fixup_len /= sizeof(uint32_t);
2304201d057SRob Herring
2314201d057SRob Herring tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
2324201d057SRob Herring if (!tree_val) {
2334201d057SRob Herring if (tree_len == -FDT_ERR_NOTFOUND)
2344201d057SRob Herring return -FDT_ERR_BADOVERLAY;
2354201d057SRob Herring
2364201d057SRob Herring return tree_len;
2374201d057SRob Herring }
2384201d057SRob Herring
2396e9c9686SRob Herring for (i = 0; i < fixup_len; i++) {
2404201d057SRob Herring fdt32_t adj_val;
2414201d057SRob Herring uint32_t poffset;
2424201d057SRob Herring
2434201d057SRob Herring poffset = fdt32_to_cpu(fixup_val[i]);
2444201d057SRob Herring
2454201d057SRob Herring /*
2464201d057SRob Herring * phandles to fixup can be unaligned.
2474201d057SRob Herring *
2484201d057SRob Herring * Use a memcpy for the architectures that do
2494201d057SRob Herring * not support unaligned accesses.
2504201d057SRob Herring */
2514201d057SRob Herring memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
2524201d057SRob Herring
2534201d057SRob Herring adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
2544201d057SRob Herring
2554201d057SRob Herring ret = fdt_setprop_inplace_namelen_partial(fdto,
2564201d057SRob Herring tree_node,
2574201d057SRob Herring name,
2584201d057SRob Herring strlen(name),
2594201d057SRob Herring poffset,
2604201d057SRob Herring &adj_val,
2614201d057SRob Herring sizeof(adj_val));
2624201d057SRob Herring if (ret == -FDT_ERR_NOSPACE)
2634201d057SRob Herring return -FDT_ERR_BADOVERLAY;
2644201d057SRob Herring
2654201d057SRob Herring if (ret)
2664201d057SRob Herring return ret;
2674201d057SRob Herring }
2684201d057SRob Herring }
2694201d057SRob Herring
2704201d057SRob Herring fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
2714201d057SRob Herring const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
2724201d057SRob Herring NULL);
2734201d057SRob Herring int tree_child;
2744201d057SRob Herring
2754201d057SRob Herring tree_child = fdt_subnode_offset(fdto, tree_node,
2764201d057SRob Herring fixup_child_name);
2774201d057SRob Herring if (tree_child == -FDT_ERR_NOTFOUND)
2784201d057SRob Herring return -FDT_ERR_BADOVERLAY;
2794201d057SRob Herring if (tree_child < 0)
2804201d057SRob Herring return tree_child;
2814201d057SRob Herring
2824201d057SRob Herring ret = overlay_update_local_node_references(fdto,
2834201d057SRob Herring tree_child,
2844201d057SRob Herring fixup_child,
2854201d057SRob Herring delta);
2864201d057SRob Herring if (ret)
2874201d057SRob Herring return ret;
2884201d057SRob Herring }
2894201d057SRob Herring
2904201d057SRob Herring return 0;
2914201d057SRob Herring }
2924201d057SRob Herring
2934201d057SRob Herring /**
2944201d057SRob Herring * overlay_update_local_references - Adjust the overlay references
2954201d057SRob Herring * @fdto: Device tree overlay blob
2964201d057SRob Herring * @delta: Offset to shift the phandles of
2974201d057SRob Herring *
2984201d057SRob Herring * overlay_update_local_references() update all the phandles pointing
2994201d057SRob Herring * to a node within the device tree overlay by adding a constant
3004201d057SRob Herring * delta to not conflict with the base overlay.
3014201d057SRob Herring *
3024201d057SRob Herring * This is mainly used as part of a device tree application process,
3034201d057SRob Herring * where you want the device tree overlays phandles to not conflict
3044201d057SRob Herring * with the ones from the base device tree before merging them.
3054201d057SRob Herring *
3064201d057SRob Herring * returns:
3074201d057SRob Herring * 0 on success
3084201d057SRob Herring * Negative error code on failure
3094201d057SRob Herring */
overlay_update_local_references(void * fdto,uint32_t delta)3104201d057SRob Herring static int overlay_update_local_references(void *fdto, uint32_t delta)
3114201d057SRob Herring {
3124201d057SRob Herring int fixups;
3134201d057SRob Herring
3144201d057SRob Herring fixups = fdt_path_offset(fdto, "/__local_fixups__");
3154201d057SRob Herring if (fixups < 0) {
3164201d057SRob Herring /* There's no local phandles to adjust, bail out */
3174201d057SRob Herring if (fixups == -FDT_ERR_NOTFOUND)
3184201d057SRob Herring return 0;
3194201d057SRob Herring
3204201d057SRob Herring return fixups;
3214201d057SRob Herring }
3224201d057SRob Herring
3234201d057SRob Herring /*
3244201d057SRob Herring * Update our local references from the root of the tree
3254201d057SRob Herring */
3264201d057SRob Herring return overlay_update_local_node_references(fdto, 0, fixups,
3274201d057SRob Herring delta);
3284201d057SRob Herring }
3294201d057SRob Herring
3304201d057SRob Herring /**
3314201d057SRob Herring * overlay_fixup_one_phandle - Set an overlay phandle to the base one
3324201d057SRob Herring * @fdt: Base Device Tree blob
3334201d057SRob Herring * @fdto: Device tree overlay blob
3344201d057SRob Herring * @symbols_off: Node offset of the symbols node in the base device tree
3354201d057SRob Herring * @path: Path to a node holding a phandle in the overlay
3364201d057SRob Herring * @path_len: number of path characters to consider
3374201d057SRob Herring * @name: Name of the property holding the phandle reference in the overlay
3384201d057SRob Herring * @name_len: number of name characters to consider
3394201d057SRob Herring * @poffset: Offset within the overlay property where the phandle is stored
3404201d057SRob Herring * @label: Label of the node referenced by the phandle
3414201d057SRob Herring *
3424201d057SRob Herring * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
3434201d057SRob Herring * a node in the base device tree.
3444201d057SRob Herring *
3454201d057SRob Herring * This is part of the device tree overlay application process, when
3464201d057SRob Herring * you want all the phandles in the overlay to point to the actual
3474201d057SRob Herring * base dt nodes.
3484201d057SRob Herring *
3494201d057SRob Herring * returns:
3504201d057SRob Herring * 0 on success
3514201d057SRob Herring * Negative error code on failure
3524201d057SRob Herring */
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)3534201d057SRob Herring static int overlay_fixup_one_phandle(void *fdt, void *fdto,
3544201d057SRob Herring int symbols_off,
3554201d057SRob Herring const char *path, uint32_t path_len,
3564201d057SRob Herring const char *name, uint32_t name_len,
3574201d057SRob Herring int poffset, const char *label)
3584201d057SRob Herring {
3594201d057SRob Herring const char *symbol_path;
3604201d057SRob Herring uint32_t phandle;
3614201d057SRob Herring fdt32_t phandle_prop;
3624201d057SRob Herring int symbol_off, fixup_off;
3634201d057SRob Herring int prop_len;
3644201d057SRob Herring
3654201d057SRob Herring if (symbols_off < 0)
3664201d057SRob Herring return symbols_off;
3674201d057SRob Herring
3684201d057SRob Herring symbol_path = fdt_getprop(fdt, symbols_off, label,
3694201d057SRob Herring &prop_len);
3704201d057SRob Herring if (!symbol_path)
3714201d057SRob Herring return prop_len;
3724201d057SRob Herring
3734201d057SRob Herring symbol_off = fdt_path_offset(fdt, symbol_path);
3744201d057SRob Herring if (symbol_off < 0)
3754201d057SRob Herring return symbol_off;
3764201d057SRob Herring
3774201d057SRob Herring phandle = fdt_get_phandle(fdt, symbol_off);
3784201d057SRob Herring if (!phandle)
3794201d057SRob Herring return -FDT_ERR_NOTFOUND;
3804201d057SRob Herring
3814201d057SRob Herring fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
3824201d057SRob Herring if (fixup_off == -FDT_ERR_NOTFOUND)
3834201d057SRob Herring return -FDT_ERR_BADOVERLAY;
3844201d057SRob Herring if (fixup_off < 0)
3854201d057SRob Herring return fixup_off;
3864201d057SRob Herring
3874201d057SRob Herring phandle_prop = cpu_to_fdt32(phandle);
3884201d057SRob Herring return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
3894201d057SRob Herring name, name_len, poffset,
3904201d057SRob Herring &phandle_prop,
3914201d057SRob Herring sizeof(phandle_prop));
3924201d057SRob Herring };
3934201d057SRob Herring
3944201d057SRob Herring /**
3954201d057SRob Herring * overlay_fixup_phandle - Set an overlay phandle to the base one
3964201d057SRob Herring * @fdt: Base Device Tree blob
3974201d057SRob Herring * @fdto: Device tree overlay blob
3984201d057SRob Herring * @symbols_off: Node offset of the symbols node in the base device tree
3994201d057SRob Herring * @property: Property offset in the overlay holding the list of fixups
4004201d057SRob Herring *
4014201d057SRob Herring * overlay_fixup_phandle() resolves all the overlay phandles pointed
4024201d057SRob Herring * to in a __fixups__ property, and updates them to match the phandles
4034201d057SRob Herring * in use in the base device tree.
4044201d057SRob Herring *
4054201d057SRob Herring * This is part of the device tree overlay application process, when
4064201d057SRob Herring * you want all the phandles in the overlay to point to the actual
4074201d057SRob Herring * base dt nodes.
4084201d057SRob Herring *
4094201d057SRob Herring * returns:
4104201d057SRob Herring * 0 on success
4114201d057SRob Herring * Negative error code on failure
4124201d057SRob Herring */
overlay_fixup_phandle(void * fdt,void * fdto,int symbols_off,int property)4134201d057SRob Herring static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
4144201d057SRob Herring int property)
4154201d057SRob Herring {
4164201d057SRob Herring const char *value;
4174201d057SRob Herring const char *label;
4184201d057SRob Herring int len;
4194201d057SRob Herring
4204201d057SRob Herring value = fdt_getprop_by_offset(fdto, property,
4214201d057SRob Herring &label, &len);
4224201d057SRob Herring if (!value) {
4234201d057SRob Herring if (len == -FDT_ERR_NOTFOUND)
4244201d057SRob Herring return -FDT_ERR_INTERNAL;
4254201d057SRob Herring
4264201d057SRob Herring return len;
4274201d057SRob Herring }
4284201d057SRob Herring
4294201d057SRob Herring do {
4304201d057SRob Herring const char *path, *name, *fixup_end;
4314201d057SRob Herring const char *fixup_str = value;
4324201d057SRob Herring uint32_t path_len, name_len;
4334201d057SRob Herring uint32_t fixup_len;
4344201d057SRob Herring char *sep, *endptr;
4354201d057SRob Herring int poffset, ret;
4364201d057SRob Herring
4374201d057SRob Herring fixup_end = memchr(value, '\0', len);
4384201d057SRob Herring if (!fixup_end)
4394201d057SRob Herring return -FDT_ERR_BADOVERLAY;
4404201d057SRob Herring fixup_len = fixup_end - fixup_str;
4414201d057SRob Herring
4424201d057SRob Herring len -= fixup_len + 1;
4434201d057SRob Herring value += fixup_len + 1;
4444201d057SRob Herring
4454201d057SRob Herring path = fixup_str;
4464201d057SRob Herring sep = memchr(fixup_str, ':', fixup_len);
4474201d057SRob Herring if (!sep || *sep != ':')
4484201d057SRob Herring return -FDT_ERR_BADOVERLAY;
4494201d057SRob Herring
4504201d057SRob Herring path_len = sep - path;
4514201d057SRob Herring if (path_len == (fixup_len - 1))
4524201d057SRob Herring return -FDT_ERR_BADOVERLAY;
4534201d057SRob Herring
4544201d057SRob Herring fixup_len -= path_len + 1;
4554201d057SRob Herring name = sep + 1;
4564201d057SRob Herring sep = memchr(name, ':', fixup_len);
4574201d057SRob Herring if (!sep || *sep != ':')
4584201d057SRob Herring return -FDT_ERR_BADOVERLAY;
4594201d057SRob Herring
4604201d057SRob Herring name_len = sep - name;
4614201d057SRob Herring if (!name_len)
4624201d057SRob Herring return -FDT_ERR_BADOVERLAY;
4634201d057SRob Herring
4644201d057SRob Herring poffset = strtoul(sep + 1, &endptr, 10);
4654201d057SRob Herring if ((*endptr != '\0') || (endptr <= (sep + 1)))
4664201d057SRob Herring return -FDT_ERR_BADOVERLAY;
4674201d057SRob Herring
4684201d057SRob Herring ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
4694201d057SRob Herring path, path_len, name, name_len,
4704201d057SRob Herring poffset, label);
4714201d057SRob Herring if (ret)
4724201d057SRob Herring return ret;
4734201d057SRob Herring } while (len > 0);
4744201d057SRob Herring
4754201d057SRob Herring return 0;
4764201d057SRob Herring }
4774201d057SRob Herring
4784201d057SRob Herring /**
4794201d057SRob Herring * overlay_fixup_phandles - Resolve the overlay phandles to the base
4804201d057SRob Herring * device tree
4814201d057SRob Herring * @fdt: Base Device Tree blob
4824201d057SRob Herring * @fdto: Device tree overlay blob
4834201d057SRob Herring *
4844201d057SRob Herring * overlay_fixup_phandles() resolves all the overlay phandles pointing
4854201d057SRob Herring * to nodes in the base device tree.
4864201d057SRob Herring *
4874201d057SRob Herring * This is one of the steps of the device tree overlay application
4884201d057SRob Herring * process, when you want all the phandles in the overlay to point to
4894201d057SRob Herring * the actual base dt nodes.
4904201d057SRob Herring *
4914201d057SRob Herring * returns:
4924201d057SRob Herring * 0 on success
4934201d057SRob Herring * Negative error code on failure
4944201d057SRob Herring */
overlay_fixup_phandles(void * fdt,void * fdto)4954201d057SRob Herring static int overlay_fixup_phandles(void *fdt, void *fdto)
4964201d057SRob Herring {
4974201d057SRob Herring int fixups_off, symbols_off;
4984201d057SRob Herring int property;
4994201d057SRob Herring
5004201d057SRob Herring /* We can have overlays without any fixups */
5014201d057SRob Herring fixups_off = fdt_path_offset(fdto, "/__fixups__");
5024201d057SRob Herring if (fixups_off == -FDT_ERR_NOTFOUND)
5034201d057SRob Herring return 0; /* nothing to do */
5044201d057SRob Herring if (fixups_off < 0)
5054201d057SRob Herring return fixups_off;
5064201d057SRob Herring
5074201d057SRob Herring /* And base DTs without symbols */
5084201d057SRob Herring symbols_off = fdt_path_offset(fdt, "/__symbols__");
5094201d057SRob Herring if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
5104201d057SRob Herring return symbols_off;
5114201d057SRob Herring
5124201d057SRob Herring fdt_for_each_property_offset(property, fdto, fixups_off) {
5134201d057SRob Herring int ret;
5144201d057SRob Herring
5154201d057SRob Herring ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
5164201d057SRob Herring if (ret)
5174201d057SRob Herring return ret;
5184201d057SRob Herring }
5194201d057SRob Herring
5204201d057SRob Herring return 0;
5214201d057SRob Herring }
5224201d057SRob Herring
5234201d057SRob Herring /**
5244201d057SRob Herring * overlay_apply_node - Merges a node into the base device tree
5254201d057SRob Herring * @fdt: Base Device Tree blob
5264201d057SRob Herring * @target: Node offset in the base device tree to apply the fragment to
5274201d057SRob Herring * @fdto: Device tree overlay blob
5284201d057SRob Herring * @node: Node offset in the overlay holding the changes to merge
5294201d057SRob Herring *
5304201d057SRob Herring * overlay_apply_node() merges a node into a target base device tree
5314201d057SRob Herring * node pointed.
5324201d057SRob Herring *
5334201d057SRob Herring * This is part of the final step in the device tree overlay
5344201d057SRob Herring * application process, when all the phandles have been adjusted and
5354201d057SRob Herring * resolved and you just have to merge overlay into the base device
5364201d057SRob Herring * tree.
5374201d057SRob Herring *
5384201d057SRob Herring * returns:
5394201d057SRob Herring * 0 on success
5404201d057SRob Herring * Negative error code on failure
5414201d057SRob Herring */
overlay_apply_node(void * fdt,int target,void * fdto,int node)5424201d057SRob Herring static int overlay_apply_node(void *fdt, int target,
5434201d057SRob Herring void *fdto, int node)
5444201d057SRob Herring {
5454201d057SRob Herring int property;
5464201d057SRob Herring int subnode;
5474201d057SRob Herring
5484201d057SRob Herring fdt_for_each_property_offset(property, fdto, node) {
5494201d057SRob Herring const char *name;
5504201d057SRob Herring const void *prop;
5514201d057SRob Herring int prop_len;
5524201d057SRob Herring int ret;
5534201d057SRob Herring
5544201d057SRob Herring prop = fdt_getprop_by_offset(fdto, property, &name,
5554201d057SRob Herring &prop_len);
5564201d057SRob Herring if (prop_len == -FDT_ERR_NOTFOUND)
5574201d057SRob Herring return -FDT_ERR_INTERNAL;
5584201d057SRob Herring if (prop_len < 0)
5594201d057SRob Herring return prop_len;
5604201d057SRob Herring
5614201d057SRob Herring ret = fdt_setprop(fdt, target, name, prop, prop_len);
5624201d057SRob Herring if (ret)
5634201d057SRob Herring return ret;
5644201d057SRob Herring }
5654201d057SRob Herring
5664201d057SRob Herring fdt_for_each_subnode(subnode, fdto, node) {
5674201d057SRob Herring const char *name = fdt_get_name(fdto, subnode, NULL);
5684201d057SRob Herring int nnode;
5694201d057SRob Herring int ret;
5704201d057SRob Herring
5714201d057SRob Herring nnode = fdt_add_subnode(fdt, target, name);
5724201d057SRob Herring if (nnode == -FDT_ERR_EXISTS) {
5734201d057SRob Herring nnode = fdt_subnode_offset(fdt, target, name);
5744201d057SRob Herring if (nnode == -FDT_ERR_NOTFOUND)
5754201d057SRob Herring return -FDT_ERR_INTERNAL;
5764201d057SRob Herring }
5774201d057SRob Herring
5784201d057SRob Herring if (nnode < 0)
5794201d057SRob Herring return nnode;
5804201d057SRob Herring
5814201d057SRob Herring ret = overlay_apply_node(fdt, nnode, fdto, subnode);
5824201d057SRob Herring if (ret)
5834201d057SRob Herring return ret;
5844201d057SRob Herring }
5854201d057SRob Herring
5864201d057SRob Herring return 0;
5874201d057SRob Herring }
5884201d057SRob Herring
5894201d057SRob Herring /**
5904201d057SRob Herring * overlay_merge - Merge an overlay into its base device tree
5914201d057SRob Herring * @fdt: Base Device Tree blob
5924201d057SRob Herring * @fdto: Device tree overlay blob
5934201d057SRob Herring *
5944201d057SRob Herring * overlay_merge() merges an overlay into its base device tree.
5954201d057SRob Herring *
5964201d057SRob Herring * This is the next to last step in the device tree overlay application
5974201d057SRob Herring * process, when all the phandles have been adjusted and resolved and
5984201d057SRob Herring * you just have to merge overlay into the base device tree.
5994201d057SRob Herring *
6004201d057SRob Herring * returns:
6014201d057SRob Herring * 0 on success
6024201d057SRob Herring * Negative error code on failure
6034201d057SRob Herring */
overlay_merge(void * fdt,void * fdto)6044201d057SRob Herring static int overlay_merge(void *fdt, void *fdto)
6054201d057SRob Herring {
6064201d057SRob Herring int fragment;
6074201d057SRob Herring
6084201d057SRob Herring fdt_for_each_subnode(fragment, fdto, 0) {
6094201d057SRob Herring int overlay;
6104201d057SRob Herring int target;
6114201d057SRob Herring int ret;
6124201d057SRob Herring
6134201d057SRob Herring /*
6144201d057SRob Herring * Each fragments will have an __overlay__ node. If
6154201d057SRob Herring * they don't, it's not supposed to be merged
6164201d057SRob Herring */
6174201d057SRob Herring overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
6184201d057SRob Herring if (overlay == -FDT_ERR_NOTFOUND)
6194201d057SRob Herring continue;
6204201d057SRob Herring
6214201d057SRob Herring if (overlay < 0)
6224201d057SRob Herring return overlay;
6234201d057SRob Herring
624*ea3723a5SRob Herring target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
6254201d057SRob Herring if (target < 0)
6264201d057SRob Herring return target;
6274201d057SRob Herring
6284201d057SRob Herring ret = overlay_apply_node(fdt, target, fdto, overlay);
6294201d057SRob Herring if (ret)
6304201d057SRob Herring return ret;
6314201d057SRob Herring }
6324201d057SRob Herring
6334201d057SRob Herring return 0;
6344201d057SRob Herring }
6354201d057SRob Herring
get_path_len(const void * fdt,int nodeoffset)6364201d057SRob Herring static int get_path_len(const void *fdt, int nodeoffset)
6374201d057SRob Herring {
6384201d057SRob Herring int len = 0, namelen;
6394201d057SRob Herring const char *name;
6404201d057SRob Herring
641f858927fSRob Herring FDT_RO_PROBE(fdt);
6424201d057SRob Herring
6434201d057SRob Herring for (;;) {
6444201d057SRob Herring name = fdt_get_name(fdt, nodeoffset, &namelen);
6454201d057SRob Herring if (!name)
6464201d057SRob Herring return namelen;
6474201d057SRob Herring
6484201d057SRob Herring /* root? we're done */
6494201d057SRob Herring if (namelen == 0)
6504201d057SRob Herring break;
6514201d057SRob Herring
6524201d057SRob Herring nodeoffset = fdt_parent_offset(fdt, nodeoffset);
6534201d057SRob Herring if (nodeoffset < 0)
6544201d057SRob Herring return nodeoffset;
6554201d057SRob Herring len += namelen + 1;
6564201d057SRob Herring }
6574201d057SRob Herring
6584201d057SRob Herring /* in case of root pretend it's "/" */
6594201d057SRob Herring if (len == 0)
6604201d057SRob Herring len++;
6614201d057SRob Herring return len;
6624201d057SRob Herring }
6634201d057SRob Herring
6644201d057SRob Herring /**
6654201d057SRob Herring * overlay_symbol_update - Update the symbols of base tree after a merge
6664201d057SRob Herring * @fdt: Base Device Tree blob
6674201d057SRob Herring * @fdto: Device tree overlay blob
6684201d057SRob Herring *
6694201d057SRob Herring * overlay_symbol_update() updates the symbols of the base tree with the
6704201d057SRob Herring * symbols of the applied overlay
6714201d057SRob Herring *
6724201d057SRob Herring * This is the last step in the device tree overlay application
6734201d057SRob Herring * process, allowing the reference of overlay symbols by subsequent
6744201d057SRob Herring * overlay operations.
6754201d057SRob Herring *
6764201d057SRob Herring * returns:
6774201d057SRob Herring * 0 on success
6784201d057SRob Herring * Negative error code on failure
6794201d057SRob Herring */
overlay_symbol_update(void * fdt,void * fdto)6804201d057SRob Herring static int overlay_symbol_update(void *fdt, void *fdto)
6814201d057SRob Herring {
6824201d057SRob Herring int root_sym, ov_sym, prop, path_len, fragment, target;
6834201d057SRob Herring int len, frag_name_len, ret, rel_path_len;
6844201d057SRob Herring const char *s, *e;
6854201d057SRob Herring const char *path;
6864201d057SRob Herring const char *name;
6874201d057SRob Herring const char *frag_name;
6884201d057SRob Herring const char *rel_path;
6894201d057SRob Herring const char *target_path;
6904201d057SRob Herring char *buf;
6914201d057SRob Herring void *p;
6924201d057SRob Herring
6934201d057SRob Herring ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
6944201d057SRob Herring
6954201d057SRob Herring /* if no overlay symbols exist no problem */
6964201d057SRob Herring if (ov_sym < 0)
6974201d057SRob Herring return 0;
6984201d057SRob Herring
6994201d057SRob Herring root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
7004201d057SRob Herring
7014201d057SRob Herring /* it no root symbols exist we should create them */
7024201d057SRob Herring if (root_sym == -FDT_ERR_NOTFOUND)
7034201d057SRob Herring root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
7044201d057SRob Herring
7054201d057SRob Herring /* any error is fatal now */
7064201d057SRob Herring if (root_sym < 0)
7074201d057SRob Herring return root_sym;
7084201d057SRob Herring
7094201d057SRob Herring /* iterate over each overlay symbol */
7104201d057SRob Herring fdt_for_each_property_offset(prop, fdto, ov_sym) {
7114201d057SRob Herring path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
7124201d057SRob Herring if (!path)
7134201d057SRob Herring return path_len;
7144201d057SRob Herring
7154201d057SRob Herring /* verify it's a string property (terminated by a single \0) */
7164201d057SRob Herring if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
7174201d057SRob Herring return -FDT_ERR_BADVALUE;
7184201d057SRob Herring
7194201d057SRob Herring /* keep end marker to avoid strlen() */
7204201d057SRob Herring e = path + path_len;
7214201d057SRob Herring
7224201d057SRob Herring if (*path != '/')
7234201d057SRob Herring return -FDT_ERR_BADVALUE;
7244201d057SRob Herring
7254201d057SRob Herring /* get fragment name first */
7264201d057SRob Herring s = strchr(path + 1, '/');
7270cec114eSRob Herring if (!s) {
7280cec114eSRob Herring /* Symbol refers to something that won't end
7290cec114eSRob Herring * up in the target tree */
7300cec114eSRob Herring continue;
7310cec114eSRob Herring }
7324201d057SRob Herring
7334201d057SRob Herring frag_name = path + 1;
7344201d057SRob Herring frag_name_len = s - path - 1;
7354201d057SRob Herring
7364201d057SRob Herring /* verify format; safe since "s" lies in \0 terminated prop */
7374201d057SRob Herring len = sizeof("/__overlay__/") - 1;
7380cec114eSRob Herring if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
7390cec114eSRob Herring /* /<fragment-name>/__overlay__/<relative-subnode-path> */
7404201d057SRob Herring rel_path = s + len;
7410cec114eSRob Herring rel_path_len = e - rel_path - 1;
7420cec114eSRob Herring } else if ((e - s) == len
7430cec114eSRob Herring && (memcmp(s, "/__overlay__", len - 1) == 0)) {
7440cec114eSRob Herring /* /<fragment-name>/__overlay__ */
7450cec114eSRob Herring rel_path = "";
7460cec114eSRob Herring rel_path_len = 0;
7470cec114eSRob Herring } else {
7480cec114eSRob Herring /* Symbol refers to something that won't end
7490cec114eSRob Herring * up in the target tree */
7500cec114eSRob Herring continue;
7510cec114eSRob Herring }
7524201d057SRob Herring
7534201d057SRob Herring /* find the fragment index in which the symbol lies */
7544201d057SRob Herring ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
7554201d057SRob Herring frag_name_len);
7564201d057SRob Herring /* not found? */
7574201d057SRob Herring if (ret < 0)
7584201d057SRob Herring return -FDT_ERR_BADOVERLAY;
7594201d057SRob Herring fragment = ret;
7604201d057SRob Herring
7614201d057SRob Herring /* an __overlay__ subnode must exist */
7624201d057SRob Herring ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
7634201d057SRob Herring if (ret < 0)
7644201d057SRob Herring return -FDT_ERR_BADOVERLAY;
7654201d057SRob Herring
7664201d057SRob Herring /* get the target of the fragment */
767*ea3723a5SRob Herring ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
7684201d057SRob Herring if (ret < 0)
7694201d057SRob Herring return ret;
7704201d057SRob Herring target = ret;
7714201d057SRob Herring
7724201d057SRob Herring /* if we have a target path use */
7734201d057SRob Herring if (!target_path) {
7744201d057SRob Herring ret = get_path_len(fdt, target);
7754201d057SRob Herring if (ret < 0)
7764201d057SRob Herring return ret;
7774201d057SRob Herring len = ret;
7784201d057SRob Herring } else {
7794201d057SRob Herring len = strlen(target_path);
7804201d057SRob Herring }
7814201d057SRob Herring
7824201d057SRob Herring ret = fdt_setprop_placeholder(fdt, root_sym, name,
7834201d057SRob Herring len + (len > 1) + rel_path_len + 1, &p);
7844201d057SRob Herring if (ret < 0)
7854201d057SRob Herring return ret;
7864201d057SRob Herring
7874201d057SRob Herring if (!target_path) {
7884201d057SRob Herring /* again in case setprop_placeholder changed it */
789*ea3723a5SRob Herring ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
7904201d057SRob Herring if (ret < 0)
7914201d057SRob Herring return ret;
7924201d057SRob Herring target = ret;
7934201d057SRob Herring }
7944201d057SRob Herring
7954201d057SRob Herring buf = p;
7964201d057SRob Herring if (len > 1) { /* target is not root */
7974201d057SRob Herring if (!target_path) {
7984201d057SRob Herring ret = fdt_get_path(fdt, target, buf, len + 1);
7994201d057SRob Herring if (ret < 0)
8004201d057SRob Herring return ret;
8014201d057SRob Herring } else
8024201d057SRob Herring memcpy(buf, target_path, len + 1);
8034201d057SRob Herring
8044201d057SRob Herring } else
8054201d057SRob Herring len--;
8064201d057SRob Herring
8074201d057SRob Herring buf[len] = '/';
8084201d057SRob Herring memcpy(buf + len + 1, rel_path, rel_path_len);
8094201d057SRob Herring buf[len + 1 + rel_path_len] = '\0';
8104201d057SRob Herring }
8114201d057SRob Herring
8124201d057SRob Herring return 0;
8134201d057SRob Herring }
8144201d057SRob Herring
fdt_overlay_apply(void * fdt,void * fdto)8154201d057SRob Herring int fdt_overlay_apply(void *fdt, void *fdto)
8164201d057SRob Herring {
8179bb9c6a1SRob Herring uint32_t delta;
8184201d057SRob Herring int ret;
8194201d057SRob Herring
820f858927fSRob Herring FDT_RO_PROBE(fdt);
821f858927fSRob Herring FDT_RO_PROBE(fdto);
8224201d057SRob Herring
8239bb9c6a1SRob Herring ret = fdt_find_max_phandle(fdt, &delta);
8249bb9c6a1SRob Herring if (ret)
8259bb9c6a1SRob Herring goto err;
8269bb9c6a1SRob Herring
8274201d057SRob Herring ret = overlay_adjust_local_phandles(fdto, delta);
8284201d057SRob Herring if (ret)
8294201d057SRob Herring goto err;
8304201d057SRob Herring
8314201d057SRob Herring ret = overlay_update_local_references(fdto, delta);
8324201d057SRob Herring if (ret)
8334201d057SRob Herring goto err;
8344201d057SRob Herring
8354201d057SRob Herring ret = overlay_fixup_phandles(fdt, fdto);
8364201d057SRob Herring if (ret)
8374201d057SRob Herring goto err;
8384201d057SRob Herring
8394201d057SRob Herring ret = overlay_merge(fdt, fdto);
8404201d057SRob Herring if (ret)
8414201d057SRob Herring goto err;
8424201d057SRob Herring
8434201d057SRob Herring ret = overlay_symbol_update(fdt, fdto);
8444201d057SRob Herring if (ret)
8454201d057SRob Herring goto err;
8464201d057SRob Herring
8474201d057SRob Herring /*
8484201d057SRob Herring * The overlay has been damaged, erase its magic.
8494201d057SRob Herring */
8504201d057SRob Herring fdt_set_magic(fdto, ~0);
8514201d057SRob Herring
8524201d057SRob Herring return 0;
8534201d057SRob Herring
8544201d057SRob Herring err:
8554201d057SRob Herring /*
8564201d057SRob Herring * The overlay might have been damaged, erase its magic.
8574201d057SRob Herring */
8584201d057SRob Herring fdt_set_magic(fdto, ~0);
8594201d057SRob Herring
8604201d057SRob Herring /*
8614201d057SRob Herring * The base device tree might have been damaged, erase its
8624201d057SRob Herring * magic.
8634201d057SRob Herring */
8644201d057SRob Herring fdt_set_magic(fdt, ~0);
8654201d057SRob Herring
8664201d057SRob Herring return ret;
8674201d057SRob Herring }
868