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