diff options
Diffstat (limited to 'common/fdt_support.c')
| -rw-r--r-- | common/fdt_support.c | 107 | 
1 files changed, 102 insertions, 5 deletions
| diff --git a/common/fdt_support.c b/common/fdt_support.c index a7773aba0..5a83bca48 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -35,6 +35,33 @@   */  DECLARE_GLOBAL_DATA_PTR; +/** + * fdt_getprop_u32_default - Find a node and return it's property or a default + * + * @fdt: ptr to device tree + * @path: path of node + * @prop: property name + * @dflt: default value if the property isn't found + * + * Convenience function to find a node and return it's property or a + * default value if it doesn't exist. + */ +u32 fdt_getprop_u32_default(void *fdt, const char *path, const char *prop, +				const u32 dflt) +{ +	const u32 *val; +	int off; + +	off = fdt_path_offset(fdt, path); +	if (off < 0) +		return dflt; + +	val = fdt_getprop(fdt, off, prop, NULL); +	if (val) +		return *val; +	else +		return dflt; +}  /**   * fdt_find_and_setprop: Find a node and set it's property @@ -165,7 +192,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force)  	return 0;  } -int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) +int fdt_chosen(void *fdt, int force)  {  	int   nodeoffset;  	int   err; @@ -215,8 +242,6 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)  		}  	} -	fdt_initrd(fdt, initrd_start, initrd_end, force); -  #ifdef CONFIG_OF_STDOUT_VIA_ALIAS  	path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);  	if ((path == NULL) || force) @@ -577,9 +602,12 @@ int fdt_resize(void *blob)  		}  	} -	/* Calculate the actual size of the fdt */ +	/* +	 * Calculate the actual size of the fdt +	 * plus the size needed for fdt_add_mem_rsv +	 */  	actualsize = fdt_off_dt_strings(blob) + -		fdt_size_dt_strings(blob); +		fdt_size_dt_strings(blob) + sizeof(struct fdt_reserve_entry);  	/* Make it so the fdt ends on a page boundary */  	actualsize = ALIGN(actualsize, 0x1000); @@ -595,3 +623,72 @@ int fdt_resize(void *blob)  	return actualsize;  } + +#ifdef CONFIG_PCI +#define CONFIG_SYS_PCI_NR_INBOUND_WIN 3 + +#define FDT_PCI_PREFETCH	(0x40000000) +#define FDT_PCI_MEM32		(0x02000000) +#define FDT_PCI_IO		(0x01000000) +#define FDT_PCI_MEM64		(0x03000000) + +int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) { + +	int addrcell, sizecell, len, r; +	u32 *dma_range; +	/* sized based on pci addr cells, size-cells, & address-cells */ +	u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN]; + +	addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1); +	sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1); + +	dma_range = &dma_ranges[0]; +	for (r = 0; r < hose->region_count; r++) { +		u64 bus_start, phys_start, size; + +		/* skip if !PCI_REGION_MEMORY */ +		if (!(hose->regions[r].flags & PCI_REGION_MEMORY)) +			continue; + +		bus_start = (u64)hose->regions[r].bus_start; +		phys_start = (u64)hose->regions[r].phys_start; +		size = (u64)hose->regions[r].size; + +		dma_range[0] = 0; +		if (size > 0x100000000ull) +			dma_range[0] |= FDT_PCI_MEM64; +		else +			dma_range[0] |= FDT_PCI_MEM32; +		if (hose->regions[r].flags & PCI_REGION_PREFETCH) +			dma_range[0] |= FDT_PCI_PREFETCH; +#ifdef CONFIG_SYS_PCI_64BIT +		dma_range[1] = bus_start >> 32; +#else +		dma_range[1] = 0; +#endif +		dma_range[2] = bus_start & 0xffffffff; + +		if (addrcell == 2) { +			dma_range[3] = phys_start >> 32; +			dma_range[4] = phys_start & 0xffffffff; +		} else { +			dma_range[3] = phys_start & 0xffffffff; +		} + +		if (sizecell == 2) { +			dma_range[3 + addrcell + 0] = size >> 32; +			dma_range[3 + addrcell + 1] = size & 0xffffffff; +		} else { +			dma_range[3 + addrcell + 0] = size & 0xffffffff; +		} + +		dma_range += (3 + addrcell + sizecell); +	} + +	len = dma_range - &dma_ranges[0]; +	if (len) +		fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4); + +	return 0; +} +#endif |