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