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