diff options
Diffstat (limited to 'common/fdt_support.c')
| -rw-r--r-- | common/fdt_support.c | 69 | 
1 files changed, 69 insertions, 0 deletions
| diff --git a/common/fdt_support.c b/common/fdt_support.c index f4307774d..d483d66f1 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -620,3 +620,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 |