diff options
| author | 2017-11-28 16:19:52 +0000 | |
|---|---|---|
| committer | 2017-11-28 16:19:52 +0000 | |
| commit | 69830d3909849dee33b9a2de88ece3d59c75a1b8 (patch) | |
| tree | 67e22ac989e782ddc104f186dee54d1675e76923 /scripts/dtc/libfdt | |
| parent | ASoC: rk3399_gru_sound: Map BTN_0 to KEY_PLAYPAUSE (diff) | |
| parent | ASoC: add snd_soc_disconnect_sync() (diff) | |
| download | linux-dev-69830d3909849dee33b9a2de88ece3d59c75a1b8.tar.xz linux-dev-69830d3909849dee33b9a2de88ece3d59c75a1b8.zip  | |
Merge branch 'topic/disconnect' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-rcar
Diffstat (limited to 'scripts/dtc/libfdt')
| -rw-r--r-- | scripts/dtc/libfdt/fdt_addresses.c | 96 | ||||
| -rw-r--r-- | scripts/dtc/libfdt/fdt_empty_tree.c | 1 | ||||
| -rw-r--r-- | scripts/dtc/libfdt/fdt_overlay.c | 861 | ||||
| -rw-r--r-- | scripts/dtc/libfdt/fdt_ro.c | 4 | ||||
| -rw-r--r-- | scripts/dtc/libfdt/fdt_rw.c | 24 | ||||
| -rw-r--r-- | scripts/dtc/libfdt/fdt_sw.c | 16 | ||||
| -rw-r--r-- | scripts/dtc/libfdt/fdt_wip.c | 4 | ||||
| -rw-r--r-- | scripts/dtc/libfdt/libfdt.h | 47 | 
8 files changed, 1041 insertions, 12 deletions
diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c new file mode 100644 index 000000000000..eff4dbcc729d --- /dev/null +++ b/scripts/dtc/libfdt/fdt_addresses.c @@ -0,0 +1,96 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_address_cells(const void *fdt, int nodeoffset) +{ +	const fdt32_t *ac; +	int val; +	int len; + +	ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); +	if (!ac) +		return 2; + +	if (len != sizeof(*ac)) +		return -FDT_ERR_BADNCELLS; + +	val = fdt32_to_cpu(*ac); +	if ((val <= 0) || (val > FDT_MAX_NCELLS)) +		return -FDT_ERR_BADNCELLS; + +	return val; +} + +int fdt_size_cells(const void *fdt, int nodeoffset) +{ +	const fdt32_t *sc; +	int val; +	int len; + +	sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); +	if (!sc) +		return 2; + +	if (len != sizeof(*sc)) +		return -FDT_ERR_BADNCELLS; + +	val = fdt32_to_cpu(*sc); +	if ((val < 0) || (val > FDT_MAX_NCELLS)) +		return -FDT_ERR_BADNCELLS; + +	return val; +} diff --git a/scripts/dtc/libfdt/fdt_empty_tree.c b/scripts/dtc/libfdt/fdt_empty_tree.c index f72d13b1d19c..f2ae9b77c285 100644 --- a/scripts/dtc/libfdt/fdt_empty_tree.c +++ b/scripts/dtc/libfdt/fdt_empty_tree.c @@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize)  	return fdt_open_into(buf, buf, bufsize);  } - diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c new file mode 100644 index 000000000000..bd81241e6658 --- /dev/null +++ b/scripts/dtc/libfdt/fdt_overlay.c @@ -0,0 +1,861 @@ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +/** + * overlay_get_target_phandle - retrieves the target phandle of a fragment + * @fdto: pointer to the device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * + * overlay_get_target_phandle() retrieves the target phandle of an + * overlay fragment when that fragment uses a phandle (target + * property) instead of a path (target-path property). + * + * returns: + *      the phandle pointed by the target property + *      0, if the phandle was not found + *	-1, if the phandle was malformed + */ +static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) +{ +	const fdt32_t *val; +	int len; + +	val = fdt_getprop(fdto, fragment, "target", &len); +	if (!val) +		return 0; + +	if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) +		return (uint32_t)-1; + +	return fdt32_to_cpu(*val); +} + +/** + * overlay_get_target - retrieves the offset of a fragment's target + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * @pathp: pointer which receives the path of the target (or NULL) + * + * overlay_get_target() retrieves the target offset in the base + * device tree of a fragment, no matter how the actual targetting is + * done (through a phandle or a path) + * + * returns: + *      the targetted node offset in the base device tree + *      Negative error code on error + */ +static int overlay_get_target(const void *fdt, const void *fdto, +			      int fragment, char const **pathp) +{ +	uint32_t phandle; +	const char *path = NULL; +	int path_len = 0, ret; + +	/* Try first to do a phandle based lookup */ +	phandle = overlay_get_target_phandle(fdto, fragment); +	if (phandle == (uint32_t)-1) +		return -FDT_ERR_BADPHANDLE; + +	/* no phandle, try path */ +	if (!phandle) { +		/* And then a path based lookup */ +		path = fdt_getprop(fdto, fragment, "target-path", &path_len); +		if (path) +			ret = fdt_path_offset(fdt, path); +		else +			ret = path_len; +	} else +		ret = fdt_node_offset_by_phandle(fdt, phandle); + +	/* +	* If we haven't found either a target or a +	* target-path property in a node that contains a +	* __overlay__ subnode (we wouldn't be called +	* otherwise), consider it a improperly written +	* overlay +	*/ +	if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) +		ret = -FDT_ERR_BADOVERLAY; + +	/* return on error */ +	if (ret < 0) +		return ret; + +	/* return pointer to path (if available) */ +	if (pathp) +		*pathp = path ? path : NULL; + +	return ret; +} + +/** + * overlay_phandle_add_offset - Increases a phandle by an offset + * @fdt: Base device tree blob + * @node: Device tree overlay blob + * @name: Name of the property to modify (phandle or linux,phandle) + * @delta: offset to apply + * + * overlay_phandle_add_offset() increments a node phandle by a given + * offset. + * + * returns: + *      0 on success. + *      Negative error code on error + */ +static int overlay_phandle_add_offset(void *fdt, int node, +				      const char *name, uint32_t delta) +{ +	const fdt32_t *val; +	uint32_t adj_val; +	int len; + +	val = fdt_getprop(fdt, node, name, &len); +	if (!val) +		return len; + +	if (len != sizeof(*val)) +		return -FDT_ERR_BADPHANDLE; + +	adj_val = fdt32_to_cpu(*val); +	if ((adj_val + delta) < adj_val) +		return -FDT_ERR_NOPHANDLES; + +	adj_val += delta; +	if (adj_val == (uint32_t)-1) +		return -FDT_ERR_NOPHANDLES; + +	return fdt_setprop_inplace_u32(fdt, node, name, adj_val); +} + +/** + * overlay_adjust_node_phandles - Offsets the phandles of a node + * @fdto: Device tree overlay blob + * @node: Offset of the node we want to adjust + * @delta: Offset to shift the phandles of + * + * overlay_adjust_node_phandles() adds a constant to all the phandles + * of a given node. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_adjust_node_phandles(void *fdto, int node, +					uint32_t delta) +{ +	int child; +	int ret; + +	ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); +	if (ret && ret != -FDT_ERR_NOTFOUND) +		return ret; + +	ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); +	if (ret && ret != -FDT_ERR_NOTFOUND) +		return ret; + +	fdt_for_each_subnode(child, fdto, node) { +		ret = overlay_adjust_node_phandles(fdto, child, delta); +		if (ret) +			return ret; +	} + +	return 0; +} + +/** + * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_adjust_local_phandles() adds a constant to all the + * phandles of an overlay. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) +{ +	/* +	 * Start adjusting the phandles from the overlay root +	 */ +	return overlay_adjust_node_phandles(fdto, 0, delta); +} + +/** + * overlay_update_local_node_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @tree_node: Node offset of the node to operate on + * @fixup_node: Node offset of the matching local fixups node + * @delta: Offset to shift the phandles of + * + * overlay_update_local_nodes_references() update the phandles + * pointing to a node within the device tree overlay by adding a + * constant delta. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_update_local_node_references(void *fdto, +						int tree_node, +						int fixup_node, +						uint32_t delta) +{ +	int fixup_prop; +	int fixup_child; +	int ret; + +	fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { +		const fdt32_t *fixup_val; +		const char *tree_val; +		const char *name; +		int fixup_len; +		int tree_len; +		int i; + +		fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, +						  &name, &fixup_len); +		if (!fixup_val) +			return fixup_len; + +		if (fixup_len % sizeof(uint32_t)) +			return -FDT_ERR_BADOVERLAY; + +		tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); +		if (!tree_val) { +			if (tree_len == -FDT_ERR_NOTFOUND) +				return -FDT_ERR_BADOVERLAY; + +			return tree_len; +		} + +		for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { +			fdt32_t adj_val; +			uint32_t poffset; + +			poffset = fdt32_to_cpu(fixup_val[i]); + +			/* +			 * phandles to fixup can be unaligned. +			 * +			 * Use a memcpy for the architectures that do +			 * not support unaligned accesses. +			 */ +			memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); + +			adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); + +			ret = fdt_setprop_inplace_namelen_partial(fdto, +								  tree_node, +								  name, +								  strlen(name), +								  poffset, +								  &adj_val, +								  sizeof(adj_val)); +			if (ret == -FDT_ERR_NOSPACE) +				return -FDT_ERR_BADOVERLAY; + +			if (ret) +				return ret; +		} +	} + +	fdt_for_each_subnode(fixup_child, fdto, fixup_node) { +		const char *fixup_child_name = fdt_get_name(fdto, fixup_child, +							    NULL); +		int tree_child; + +		tree_child = fdt_subnode_offset(fdto, tree_node, +						fixup_child_name); +		if (tree_child == -FDT_ERR_NOTFOUND) +			return -FDT_ERR_BADOVERLAY; +		if (tree_child < 0) +			return tree_child; + +		ret = overlay_update_local_node_references(fdto, +							   tree_child, +							   fixup_child, +							   delta); +		if (ret) +			return ret; +	} + +	return 0; +} + +/** + * overlay_update_local_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_update_local_references() update all the phandles pointing + * to a node within the device tree overlay by adding a constant + * delta to not conflict with the base overlay. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_update_local_references(void *fdto, uint32_t delta) +{ +	int fixups; + +	fixups = fdt_path_offset(fdto, "/__local_fixups__"); +	if (fixups < 0) { +		/* There's no local phandles to adjust, bail out */ +		if (fixups == -FDT_ERR_NOTFOUND) +			return 0; + +		return fixups; +	} + +	/* +	 * Update our local references from the root of the tree +	 */ +	return overlay_update_local_node_references(fdto, 0, fixups, +						    delta); +} + +/** + * overlay_fixup_one_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @path: Path to a node holding a phandle in the overlay + * @path_len: number of path characters to consider + * @name: Name of the property holding the phandle reference in the overlay + * @name_len: number of name characters to consider + * @poffset: Offset within the overlay property where the phandle is stored + * @label: Label of the node referenced by the phandle + * + * overlay_fixup_one_phandle() resolves an overlay phandle pointing to + * a node in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_fixup_one_phandle(void *fdt, void *fdto, +				     int symbols_off, +				     const char *path, uint32_t path_len, +				     const char *name, uint32_t name_len, +				     int poffset, const char *label) +{ +	const char *symbol_path; +	uint32_t phandle; +	fdt32_t phandle_prop; +	int symbol_off, fixup_off; +	int prop_len; + +	if (symbols_off < 0) +		return symbols_off; + +	symbol_path = fdt_getprop(fdt, symbols_off, label, +				  &prop_len); +	if (!symbol_path) +		return prop_len; + +	symbol_off = fdt_path_offset(fdt, symbol_path); +	if (symbol_off < 0) +		return symbol_off; + +	phandle = fdt_get_phandle(fdt, symbol_off); +	if (!phandle) +		return -FDT_ERR_NOTFOUND; + +	fixup_off = fdt_path_offset_namelen(fdto, path, path_len); +	if (fixup_off == -FDT_ERR_NOTFOUND) +		return -FDT_ERR_BADOVERLAY; +	if (fixup_off < 0) +		return fixup_off; + +	phandle_prop = cpu_to_fdt32(phandle); +	return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, +						   name, name_len, poffset, +						   &phandle_prop, +						   sizeof(phandle_prop)); +}; + +/** + * overlay_fixup_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @property: Property offset in the overlay holding the list of fixups + * + * overlay_fixup_phandle() resolves all the overlay phandles pointed + * to in a __fixups__ property, and updates them to match the phandles + * in use in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, +				 int property) +{ +	const char *value; +	const char *label; +	int len; + +	value = fdt_getprop_by_offset(fdto, property, +				      &label, &len); +	if (!value) { +		if (len == -FDT_ERR_NOTFOUND) +			return -FDT_ERR_INTERNAL; + +		return len; +	} + +	do { +		const char *path, *name, *fixup_end; +		const char *fixup_str = value; +		uint32_t path_len, name_len; +		uint32_t fixup_len; +		char *sep, *endptr; +		int poffset, ret; + +		fixup_end = memchr(value, '\0', len); +		if (!fixup_end) +			return -FDT_ERR_BADOVERLAY; +		fixup_len = fixup_end - fixup_str; + +		len -= fixup_len + 1; +		value += fixup_len + 1; + +		path = fixup_str; +		sep = memchr(fixup_str, ':', fixup_len); +		if (!sep || *sep != ':') +			return -FDT_ERR_BADOVERLAY; + +		path_len = sep - path; +		if (path_len == (fixup_len - 1)) +			return -FDT_ERR_BADOVERLAY; + +		fixup_len -= path_len + 1; +		name = sep + 1; +		sep = memchr(name, ':', fixup_len); +		if (!sep || *sep != ':') +			return -FDT_ERR_BADOVERLAY; + +		name_len = sep - name; +		if (!name_len) +			return -FDT_ERR_BADOVERLAY; + +		poffset = strtoul(sep + 1, &endptr, 10); +		if ((*endptr != '\0') || (endptr <= (sep + 1))) +			return -FDT_ERR_BADOVERLAY; + +		ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, +						path, path_len, name, name_len, +						poffset, label); +		if (ret) +			return ret; +	} while (len > 0); + +	return 0; +} + +/** + * overlay_fixup_phandles - Resolve the overlay phandles to the base + *                          device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_fixup_phandles() resolves all the overlay phandles pointing + * to nodes in the base device tree. + * + * This is one of the steps of the device tree overlay application + * process, when you want all the phandles in the overlay to point to + * the actual base dt nodes. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_fixup_phandles(void *fdt, void *fdto) +{ +	int fixups_off, symbols_off; +	int property; + +	/* We can have overlays without any fixups */ +	fixups_off = fdt_path_offset(fdto, "/__fixups__"); +	if (fixups_off == -FDT_ERR_NOTFOUND) +		return 0; /* nothing to do */ +	if (fixups_off < 0) +		return fixups_off; + +	/* And base DTs without symbols */ +	symbols_off = fdt_path_offset(fdt, "/__symbols__"); +	if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) +		return symbols_off; + +	fdt_for_each_property_offset(property, fdto, fixups_off) { +		int ret; + +		ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); +		if (ret) +			return ret; +	} + +	return 0; +} + +/** + * overlay_apply_node - Merges a node into the base device tree + * @fdt: Base Device Tree blob + * @target: Node offset in the base device tree to apply the fragment to + * @fdto: Device tree overlay blob + * @node: Node offset in the overlay holding the changes to merge + * + * overlay_apply_node() merges a node into a target base device tree + * node pointed. + * + * This is part of the final step in the device tree overlay + * application process, when all the phandles have been adjusted and + * resolved and you just have to merge overlay into the base device + * tree. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_apply_node(void *fdt, int target, +			      void *fdto, int node) +{ +	int property; +	int subnode; + +	fdt_for_each_property_offset(property, fdto, node) { +		const char *name; +		const void *prop; +		int prop_len; +		int ret; + +		prop = fdt_getprop_by_offset(fdto, property, &name, +					     &prop_len); +		if (prop_len == -FDT_ERR_NOTFOUND) +			return -FDT_ERR_INTERNAL; +		if (prop_len < 0) +			return prop_len; + +		ret = fdt_setprop(fdt, target, name, prop, prop_len); +		if (ret) +			return ret; +	} + +	fdt_for_each_subnode(subnode, fdto, node) { +		const char *name = fdt_get_name(fdto, subnode, NULL); +		int nnode; +		int ret; + +		nnode = fdt_add_subnode(fdt, target, name); +		if (nnode == -FDT_ERR_EXISTS) { +			nnode = fdt_subnode_offset(fdt, target, name); +			if (nnode == -FDT_ERR_NOTFOUND) +				return -FDT_ERR_INTERNAL; +		} + +		if (nnode < 0) +			return nnode; + +		ret = overlay_apply_node(fdt, nnode, fdto, subnode); +		if (ret) +			return ret; +	} + +	return 0; +} + +/** + * overlay_merge - Merge an overlay into its base device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_merge() merges an overlay into its base device tree. + * + * This is the next to last step in the device tree overlay application + * process, when all the phandles have been adjusted and resolved and + * you just have to merge overlay into the base device tree. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_merge(void *fdt, void *fdto) +{ +	int fragment; + +	fdt_for_each_subnode(fragment, fdto, 0) { +		int overlay; +		int target; +		int ret; + +		/* +		 * Each fragments will have an __overlay__ node. If +		 * they don't, it's not supposed to be merged +		 */ +		overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); +		if (overlay == -FDT_ERR_NOTFOUND) +			continue; + +		if (overlay < 0) +			return overlay; + +		target = overlay_get_target(fdt, fdto, fragment, NULL); +		if (target < 0) +			return target; + +		ret = overlay_apply_node(fdt, target, fdto, overlay); +		if (ret) +			return ret; +	} + +	return 0; +} + +static int get_path_len(const void *fdt, int nodeoffset) +{ +	int len = 0, namelen; +	const char *name; + +	FDT_CHECK_HEADER(fdt); + +	for (;;) { +		name = fdt_get_name(fdt, nodeoffset, &namelen); +		if (!name) +			return namelen; + +		/* root? we're done */ +		if (namelen == 0) +			break; + +		nodeoffset = fdt_parent_offset(fdt, nodeoffset); +		if (nodeoffset < 0) +			return nodeoffset; +		len += namelen + 1; +	} + +	/* in case of root pretend it's "/" */ +	if (len == 0) +		len++; +	return len; +} + +/** + * overlay_symbol_update - Update the symbols of base tree after a merge + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_symbol_update() updates the symbols of the base tree with the + * symbols of the applied overlay + * + * This is the last step in the device tree overlay application + * process, allowing the reference of overlay symbols by subsequent + * overlay operations. + * + * returns: + *      0 on success + *      Negative error code on failure + */ +static int overlay_symbol_update(void *fdt, void *fdto) +{ +	int root_sym, ov_sym, prop, path_len, fragment, target; +	int len, frag_name_len, ret, rel_path_len; +	const char *s, *e; +	const char *path; +	const char *name; +	const char *frag_name; +	const char *rel_path; +	const char *target_path; +	char *buf; +	void *p; + +	ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); + +	/* if no overlay symbols exist no problem */ +	if (ov_sym < 0) +		return 0; + +	root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); + +	/* it no root symbols exist we should create them */ +	if (root_sym == -FDT_ERR_NOTFOUND) +		root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); + +	/* any error is fatal now */ +	if (root_sym < 0) +		return root_sym; + +	/* iterate over each overlay symbol */ +	fdt_for_each_property_offset(prop, fdto, ov_sym) { +		path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); +		if (!path) +			return path_len; + +		/* verify it's a string property (terminated by a single \0) */ +		if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) +			return -FDT_ERR_BADVALUE; + +		/* keep end marker to avoid strlen() */ +		e = path + path_len; + +		/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */ + +		if (*path != '/') +			return -FDT_ERR_BADVALUE; + +		/* get fragment name first */ +		s = strchr(path + 1, '/'); +		if (!s) +			return -FDT_ERR_BADOVERLAY; + +		frag_name = path + 1; +		frag_name_len = s - path - 1; + +		/* verify format; safe since "s" lies in \0 terminated prop */ +		len = sizeof("/__overlay__/") - 1; +		if ((e - s) < len || memcmp(s, "/__overlay__/", len)) +			return -FDT_ERR_BADOVERLAY; + +		rel_path = s + len; +		rel_path_len = e - rel_path; + +		/* find the fragment index in which the symbol lies */ +		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, +					       frag_name_len); +		/* not found? */ +		if (ret < 0) +			return -FDT_ERR_BADOVERLAY; +		fragment = ret; + +		/* an __overlay__ subnode must exist */ +		ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); +		if (ret < 0) +			return -FDT_ERR_BADOVERLAY; + +		/* get the target of the fragment */ +		ret = overlay_get_target(fdt, fdto, fragment, &target_path); +		if (ret < 0) +			return ret; +		target = ret; + +		/* if we have a target path use */ +		if (!target_path) { +			ret = get_path_len(fdt, target); +			if (ret < 0) +				return ret; +			len = ret; +		} else { +			len = strlen(target_path); +		} + +		ret = fdt_setprop_placeholder(fdt, root_sym, name, +				len + (len > 1) + rel_path_len + 1, &p); +		if (ret < 0) +			return ret; + +		if (!target_path) { +			/* again in case setprop_placeholder changed it */ +			ret = overlay_get_target(fdt, fdto, fragment, &target_path); +			if (ret < 0) +				return ret; +			target = ret; +		} + +		buf = p; +		if (len > 1) { /* target is not root */ +			if (!target_path) { +				ret = fdt_get_path(fdt, target, buf, len + 1); +				if (ret < 0) +					return ret; +			} else +				memcpy(buf, target_path, len + 1); + +		} else +			len--; + +		buf[len] = '/'; +		memcpy(buf + len + 1, rel_path, rel_path_len); +		buf[len + 1 + rel_path_len] = '\0'; +	} + +	return 0; +} + +int fdt_overlay_apply(void *fdt, void *fdto) +{ +	uint32_t delta = fdt_get_max_phandle(fdt); +	int ret; + +	FDT_CHECK_HEADER(fdt); +	FDT_CHECK_HEADER(fdto); + +	ret = overlay_adjust_local_phandles(fdto, delta); +	if (ret) +		goto err; + +	ret = overlay_update_local_references(fdto, delta); +	if (ret) +		goto err; + +	ret = overlay_fixup_phandles(fdt, fdto); +	if (ret) +		goto err; + +	ret = overlay_merge(fdt, fdto); +	if (ret) +		goto err; + +	ret = overlay_symbol_update(fdt, fdto); +	if (ret) +		goto err; + +	/* +	 * The overlay has been damaged, erase its magic. +	 */ +	fdt_set_magic(fdto, ~0); + +	return 0; + +err: +	/* +	 * The overlay might have been damaged, erase its magic. +	 */ +	fdt_set_magic(fdto, ~0); + +	/* +	 * The base device tree might have been damaged, erase its +	 * magic. +	 */ +	fdt_set_magic(fdt, ~0); + +	return ret; +} diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 3d00d2eee0e3..08de2cce674d 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -60,7 +60,7 @@ static int _fdt_nodename_eq(const void *fdt, int offset,  {  	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); -	if (! p) +	if (!p)  		/* short match */  		return 0; @@ -327,7 +327,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,  	const struct fdt_property *prop;  	prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); -	if (! prop) +	if (!prop)  		return NULL;  	return prop->data; diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 3fd5847377c9..5c3a2bb0bc6b 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -207,7 +207,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,  	int err;  	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); -	if (! (*prop)) +	if (!*prop)  		return oldlen;  	if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), @@ -269,8 +269,8 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)  	return 0;  } -int fdt_setprop(void *fdt, int nodeoffset, const char *name, -		const void *val, int len) +int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, +			    int len, void **prop_data)  {  	struct fdt_property *prop;  	int err; @@ -283,8 +283,22 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,  	if (err)  		return err; +	*prop_data = prop->data; +	return 0; +} + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, +		const void *val, int len) +{ +	void *prop_data; +	int err; + +	err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); +	if (err) +		return err; +  	if (len) -		memcpy(prop->data, val, len); +		memcpy(prop_data, val, len);  	return 0;  } @@ -323,7 +337,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)  	FDT_RW_CHECK_HEADER(fdt);  	prop = fdt_get_property_w(fdt, nodeoffset, name, &len); -	if (! prop) +	if (!prop)  		return len;  	proplen = sizeof(*prop) + FDT_TAGALIGN(len); diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c index 6a804859fd0c..2bd15e7aef87 100644 --- a/scripts/dtc/libfdt/fdt_sw.c +++ b/scripts/dtc/libfdt/fdt_sw.c @@ -220,7 +220,7 @@ static int _fdt_find_add_string(void *fdt, const char *s)  	return offset;  } -int fdt_property(void *fdt, const char *name, const void *val, int len) +int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)  {  	struct fdt_property *prop;  	int nameoff; @@ -238,7 +238,19 @@ int fdt_property(void *fdt, const char *name, const void *val, int len)  	prop->tag = cpu_to_fdt32(FDT_PROP);  	prop->nameoff = cpu_to_fdt32(nameoff);  	prop->len = cpu_to_fdt32(len); -	memcpy(prop->data, val, len); +	*valp = prop->data; +	return 0; +} + +int fdt_property(void *fdt, const char *name, const void *val, int len) +{ +	void *ptr; +	int ret; + +	ret = fdt_property_placeholder(fdt, name, len, &ptr); +	if (ret) +		return ret; +	memcpy(ptr, val, len);  	return 0;  } diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c index 6aaab399929c..5e859198622b 100644 --- a/scripts/dtc/libfdt/fdt_wip.c +++ b/scripts/dtc/libfdt/fdt_wip.c @@ -82,7 +82,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,  	int proplen;  	propval = fdt_getprop(fdt, nodeoffset, name, &proplen); -	if (! propval) +	if (!propval)  		return proplen;  	if (proplen != len) @@ -107,7 +107,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)  	int len;  	prop = fdt_get_property_w(fdt, nodeoffset, name, &len); -	if (! prop) +	if (!prop)  		return len;  	_fdt_nop_region(prop, len + sizeof(*prop)); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index ba86caa73d01..7f83023ee109 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -1314,6 +1314,22 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)  {  	return fdt_property_u32(fdt, name, val);  } + +/** + * fdt_property_placeholder - add a new property and return a ptr to its value + * + * @fdt: pointer to the device tree blob + * @name: name of property to add + * @len: length of property value in bytes + * @valp: returns a pointer to where where the value should be placed + * + * returns: + *	0, on success + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_NOSPACE, standard meanings + */ +int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp); +  #define fdt_property_string(fdt, name, str) \  	fdt_property(fdt, name, str, strlen(str)+1)  int fdt_end_node(void *fdt); @@ -1433,6 +1449,37 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,  		const void *val, int len);  /** + * fdt_setprop _placeholder - allocate space for a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @len: length of the property value + * @prop_data: return pointer to property data + * + * fdt_setprop_placeholer() allocates the named property in the given node. + * If the property exists it is resized. In either case a pointer to the + * property data is returned. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + *	0, on success + *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to + *		contain the new property value + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, +			    int len, void **prop_data); + +/**   * fdt_setprop_u32 - set a property to a 32-bit integer   * @fdt: pointer to the device tree blob   * @nodeoffset: offset of the node whose property to change  | 
