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