diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/fdt_support.c | 107 | ||||
| -rw-r--r-- | common/image.c | 60 | 
2 files changed, 156 insertions, 11 deletions
| diff --git a/common/fdt_support.c b/common/fdt_support.c index 496040b54..19b2ef6ea 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1195,6 +1195,46 @@ int fdt_alloc_phandle(void *blob)  	return phandle + 1;  } +/* + * fdt_create_phandle: Create a phandle property for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + * @phandle: phandle value to set (must be unique) +*/ +int fdt_create_phandle(void *fdt, int nodeoffset, uint32_t phandle) +{ +	int ret; + +#ifdef DEBUG +	int off = fdt_node_offset_by_phandle(fdt, phandle); + +	if ((off >= 0) && (off != nodeoffset)) { +		char buf[64]; + +		fdt_get_path(fdt, nodeoffset, buf, sizeof(buf)); +		printf("Trying to update node %s with phandle %u ", +		       buf, phandle); + +		fdt_get_path(fdt, off, buf, sizeof(buf)); +		printf("that already exists in node %s.\n", buf); +		return -FDT_ERR_BADPHANDLE; +	} +#endif + +	ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle); +	if (ret < 0) +		return ret; + +	/* +	 * For now, also set the deprecated "linux,phandle" property, so that we +	 * don't break older kernels. +	 */ +	ret = fdt_setprop_cell(fdt, nodeoffset, "linux,phandle", phandle); + +	return ret; +} +  #if defined(CONFIG_VIDEO)  int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)  { @@ -1223,3 +1263,70 @@ err_size:  	return ret;  }  #endif + +/* + * Verify the physical address of device tree node for a given alias + * + * This function locates the device tree node of a given alias, and then + * verifies that the physical address of that device matches the given + * parameter.  It displays a message if there is a mismatch. + * + * Returns 1 on success, 0 on failure + */ +int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr) +{ +	const char *path; +	const u32 *reg; +	int node, len; +	u64 dt_addr; + +	path = fdt_getprop(fdt, anode, alias, NULL); +	if (!path) { +		/* If there's no such alias, then it's not a failure */ +		return 1; +	} + +	node = fdt_path_offset(fdt, path); +	if (node < 0) { +		printf("Warning: device tree alias '%s' points to invalid " +		       "node %s.\n", alias, path); +		return 0; +	} + +	reg = fdt_getprop(fdt, node, "reg", &len); +	if (!reg) { +		printf("Warning: device tree node '%s' has no address.\n", +		       path); +		return 0; +	} + +	dt_addr = fdt_translate_address(fdt, node, reg); +	if (addr != dt_addr) { +		printf("Warning: U-Boot configured device %s at address %llx,\n" +		       " but the device tree has it address %llx.\n", +		       alias, addr, dt_addr); +		return 0; +	} + +	return 1; +} + +/* + * Returns the base address of an SOC or PCI node + */ +u64 fdt_get_base_address(void *fdt, int node) +{ +	int size; +	u32 naddr; +	const u32 *prop; + +	prop = fdt_getprop(fdt, node, "#address-cells", &size); +	if (prop && size == 4) +		naddr = *prop; +	else +		naddr = 2; + +	prop = fdt_getprop(fdt, node, "ranges", &size); + +	return prop ? fdt_translate_address(fdt, node, prop + naddr) : 0; +} diff --git a/common/image.c b/common/image.c index e542a5736..c6cd85ef9 100644 --- a/common/image.c +++ b/common/image.c @@ -1234,8 +1234,10 @@ int boot_relocate_fdt (struct lmb *lmb, char **of_flat_tree, ulong *of_size)  {  	void	*fdt_blob = *of_flat_tree;  	void	*of_start = 0; +	char	*fdt_high;  	ulong	of_len = 0;  	int	err; +	int	disable_relocation = 0;  	/* nothing to do */  	if (*of_size == 0) @@ -1249,26 +1251,62 @@ int boot_relocate_fdt (struct lmb *lmb, char **of_flat_tree, ulong *of_size)  	/* position on a 4K boundary before the alloc_current */  	/* Pad the FDT by a specified amount */  	of_len = *of_size + CONFIG_SYS_FDT_PAD; -	of_start = (void *)(unsigned long)lmb_alloc_base(lmb, of_len, 0x1000, -			getenv_bootm_mapsize() + getenv_bootm_low()); + +	/* If fdt_high is set use it to select the relocation address */ +	fdt_high = getenv("fdt_high"); +	if (fdt_high) { +		void *desired_addr = (void *)simple_strtoul(fdt_high, NULL, 16); + +		if (((ulong) desired_addr) == ~0UL) { +			/* All ones means use fdt in place */ +			desired_addr = fdt_blob; +			disable_relocation = 1; +		} +		if (desired_addr) { +			of_start = +			    (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000, +							   ((ulong) +							    desired_addr) +							   + of_len); +			if (desired_addr && of_start != desired_addr) { +				puts("Failed using fdt_high value for Device Tree"); +				goto error; +			} +		} else { +			of_start = +			    (void *)(ulong) mb_alloc(lmb, of_len, 0x1000); +		} +	} else { +		of_start = +		    (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000, +						   getenv_bootm_mapsize() +						   + getenv_bootm_low()); +	}  	if (of_start == 0) {  		puts("device tree - allocation error\n");  		goto error;  	} -	debug ("## device tree at %p ... %p (len=%ld [0x%lX])\n", -		fdt_blob, fdt_blob + *of_size - 1, of_len, of_len); +	if (disable_relocation) { +		/* We assume there is space after the existing fdt to use for padding */ +		fdt_set_totalsize(of_start, of_len); +		printf("   Using Device Tree in place at %p, end %p\n", +		       of_start, of_start + of_len - 1); +	} else { +		debug ("## device tree at %p ... %p (len=%ld [0x%lX])\n", +			fdt_blob, fdt_blob + *of_size - 1, of_len, of_len); -	printf ("   Loading Device Tree to %p, end %p ... ", -		of_start, of_start + of_len - 1); +		printf ("   Loading Device Tree to %p, end %p ... ", +			of_start, of_start + of_len - 1); -	err = fdt_open_into (fdt_blob, of_start, of_len); -	if (err != 0) { -		fdt_error ("fdt move failed"); -		goto error; +		err = fdt_open_into (fdt_blob, of_start, of_len); +		if (err != 0) { +			fdt_error ("fdt move failed"); +			goto error; +		} +		puts ("OK\n");  	} -	puts ("OK\n");  	*of_flat_tree = of_start;  	*of_size = of_len; |