[U-Boot] [PATCH v2 5/6] PPC 85xx: Find PCI host controllers on ppce500 from device tree

Alexander Graf agraf at suse.de
Fri Jan 31 12:16:08 CET 2014


The definition of our ppce500 PV machine is that every address is dynamically
determined through device tree bindings.

So don't hardcode where PCI devices are in our physical memory layout but instead
read them dynamically from the device tree we get passed on boot.

Signed-off-by: Alexander Graf <agraf at suse.de>
---
 board/freescale/qemu-ppce500/qemu-ppce500.c |  193 ++++++++++++++++++++++++---
 board/freescale/qemu-ppce500/tlb.c          |   13 --
 include/configs/qemu-ppce500.h              |   12 --
 3 files changed, 175 insertions(+), 43 deletions(-)

diff --git a/board/freescale/qemu-ppce500/qemu-ppce500.c b/board/freescale/qemu-ppce500/qemu-ppce500.c
index 6491ae9..5d4dd64 100644
--- a/board/freescale/qemu-ppce500/qemu-ppce500.c
+++ b/board/freescale/qemu-ppce500/qemu-ppce500.c
@@ -19,7 +19,51 @@
 #include <malloc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
-static struct pci_controller pci1_hose;
+
+static uint64_t myfdt_readcells(const void *fdt, int node, const char *property,
+				int num, int off, uint64_t defval)
+{
+	int len;
+	const uint32_t *prop;
+
+	prop = fdt_getprop(fdt, node, property, &len);
+
+	if (!prop)
+		return defval;
+
+	if (len < ((off + num) * sizeof(uint32_t)))
+		panic("Invalid fdt");
+
+	prop += off;
+
+	switch (num) {
+	case 1:
+		return *prop;
+	case 2:
+		return *(const uint64_t *)prop;
+	}
+
+	panic("Invalid cell size");
+}
+
+static uint32_t myfdt_one_cell(const void *fdt, int node, const char *property,
+			       uint32_t defval)
+{
+	return myfdt_readcells(fdt, node, property, 1, 0, defval);
+}
+
+static int myfdt_count_compatibles(const void *fdt, const char *compat)
+{
+	int node, num = 0;
+
+	node = fdt_node_offset_by_compatible(fdt, -1, compat);
+	while (node != -FDT_ERR_NOTFOUND) {
+		node = fdt_node_offset_by_compatible(fdt, node, compat);
+		num++;
+	}
+
+	return num;
+}
 
 static const void *get_fdt(void)
 {
@@ -39,13 +83,9 @@ uint64_t get_phys_ccsrbar_addr(void)
 	uint64_t r = 0;
 
 	/* Read CCSRBAR address length and size from device tree */
-	prop = fdt_getprop(fdt, root_node, "#address-cells", &len);
-	if (prop && (len >= 4))
-		root_address_cells = prop[0];
-
-	prop = fdt_getprop(fdt, soc_node, "#address-cells", &len);
-	if (prop && (len >= 4))
-		address_cells = prop[0];
+	root_address_cells = myfdt_one_cell(fdt, root_node, "#address-cells", 1);
+	address_cells = myfdt_one_cell(fdt, soc_node, "#address-cells",
+				       root_address_cells);
 
 	/* Read CCSRBAR address from device tree */
 	prop = fdt_getprop(fdt, soc_node, "ranges", &len);
@@ -114,27 +154,144 @@ int checkboard(void)
 	return 0;
 }
 
+static void map_tlb1_io(ulong virt_addr, uint64_t phys_addr, uint64_t size)
+{
+	unsigned int max_cam, tsize_mask;
+	int i;
+
+	if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) {
+		/* Convert (4^max) kB to (2^max) bytes */
+		max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10;
+		tsize_mask = ~1U;
+	} else {
+		/* Convert (2^max) kB to (2^max) bytes */
+		max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10;
+		tsize_mask = ~0U;
+	}
+
+	for (i = 0; size && i < 8; i++) {
+		int tlb_index = find_free_tlbcam();
+		u32 camsize = __ilog2_u64(size) & tsize_mask;
+		u32 align = __ilog2(virt_addr) & tsize_mask;
+		unsigned int tlb_size;
+
+		if (tlb_index == -1)
+			break;
+
+		if (align == -2) align = max_cam;
+		if (camsize > align)
+			camsize = align;
+
+		if (camsize > max_cam)
+			camsize = max_cam;
+
+		tlb_size = camsize - 10;
+
+		set_tlb(1, virt_addr, phys_addr,
+			MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+			0, tlb_index, tlb_size, 1);
+
+		/* Remember the mapping in our address map */
+		addrmap_set_entry(virt_addr, phys_addr, 1ULL << camsize,
+				  tlb_index);
+
+		size -= 1ULL << camsize;
+		virt_addr += 1UL << camsize;
+		phys_addr += 1UL << camsize;
+	}
+
+}
+
 void pci_init_board(void)
 {
-	struct fsl_pci_info pci_info;
+	struct pci_controller *pci_hoses;
 	const void *fdt = get_fdt();
 	int pci_node;
+	int pci_num = 0;
+	int pci_count;
+	const char *compat = "fsl,mpc8540-pci";
+	ulong map_addr;
 
 	puts("\n");
 
-	pci_node = fdt_path_offset(fdt, "/pci");
-	if (pci_node < 0) {
+	/* Start MMIO and PIO range maps above RAM */
+	map_addr = CONFIG_MAX_MEM_MAPPED;
+
+	/* Count and allocate PCI buses */
+	pci_count = myfdt_count_compatibles(fdt, compat);
+
+	if (pci_count) {
+		pci_hoses = malloc(sizeof(struct pci_controller) * pci_count);
+	} else {
 		printf("PCI: disabled\n\n");
 		return;
 	}
 
-	SET_STD_PCI_INFO(pci_info, 1);
-
-	fsl_setup_hose(&pci1_hose, pci_info.regs);
-	printf("PCI: 32 bit, 66 MHz, async, host, base address %lx\n",
-		pci_info.regs);
-
-	fsl_pci_init_port(&pci_info, &pci1_hose, 0);
+	/* Spawn PCI buses based on device tree */
+	pci_node = fdt_node_offset_by_compatible(fdt, -1, compat);
+	while (pci_node != -FDT_ERR_NOTFOUND) {
+		struct fsl_pci_info pci_info = { };
+		uint64_t phys_addr;
+		int pnode = fdt_parent_offset(fdt, pci_node);
+		int paddress_cells;
+		int address_cells;
+		int size_cells;
+		int off = 0;
+
+		paddress_cells = myfdt_one_cell(fdt, pnode, "#address-cells", 1);
+		address_cells = myfdt_one_cell(fdt, pci_node, "#address-cells", 1);
+		size_cells = myfdt_one_cell(fdt, pci_node, "#size-cells", 1);
+
+		pci_info.regs = myfdt_readcells(fdt, pci_node, "reg",
+						paddress_cells, 0, 0);
+
+		/* MMIO range */
+		off += address_cells;
+		phys_addr = myfdt_readcells(fdt, pci_node, "ranges",
+					    paddress_cells, off, 0);
+		off += paddress_cells;
+		pci_info.mem_size = myfdt_readcells(fdt, pci_node, "ranges",
+			size_cells, off, 0);
+		off += size_cells;
+
+		/* Align virtual region */
+		map_addr += pci_info.mem_size - 1;
+		map_addr &= ~(pci_info.mem_size - 1);
+		/* Map virtual memory for MMIO range */
+		map_tlb1_io(map_addr, phys_addr, pci_info.mem_size);
+		pci_info.mem_bus = phys_addr;
+		pci_info.mem_phys = phys_addr;
+		map_addr += pci_info.mem_size;
+
+		/* PIO range */
+		off += address_cells;
+		pci_info.io_phys = myfdt_readcells(fdt, pci_node, "ranges",
+			paddress_cells, off, 0);
+		off += paddress_cells;
+		pci_info.io_size = myfdt_readcells(fdt, pci_node, "ranges",
+			size_cells, off, 0);
+
+		/* Align virtual region */
+		map_addr += pci_info.io_size - 1;
+		map_addr &= ~(pci_info.io_size - 1);
+		/* Map virtual memory for MMIO range */
+		map_tlb1_io(map_addr, pci_info.io_phys, pci_info.io_size);
+		pci_info.io_bus = map_addr;
+		map_addr += pci_info.io_size;
+
+		/* Instantiate */
+		pci_info.pci_num = pci_num + 1;
+
+		fsl_setup_hose(&pci_hoses[pci_num], pci_info.regs);
+		printf("PCI: 32 bit, 66 MHz, async, host, base address %lx\n",
+			pci_info.regs);
+
+		fsl_pci_init_port(&pci_info, &pci_hoses[pci_num], pci_num);
+
+		/* Jump to next PCI node */
+		pci_node = fdt_node_offset_by_compatible(fdt, pci_node, compat);
+		pci_num++;
+	}
 
 	puts("\n");
 }
diff --git a/board/freescale/qemu-ppce500/tlb.c b/board/freescale/qemu-ppce500/tlb.c
index a600296..cf51d0e 100644
--- a/board/freescale/qemu-ppce500/tlb.c
+++ b/board/freescale/qemu-ppce500/tlb.c
@@ -11,19 +11,6 @@
 #include <asm/mmu.h>
 
 struct fsl_e_tlb_entry tlb_table[] = {
-	/*
-	 * TLB 1:	256M	Non-cacheable, guarded
-	 */
-	SET_TLB_ENTRY(1, CONFIG_SYS_PCI_VIRT, CONFIG_SYS_PCI_PHYS,
-		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
-		      0, 1, BOOKE_PAGESZ_256M, 1),
-
-	/*
-	 * TLB 2:	256M	Non-cacheable, guarded
-	 */
-	SET_TLB_ENTRY(1, CONFIG_SYS_PCI_VIRT + 0x10000000, CONFIG_SYS_PCI_PHYS + 0x10000000,
-		      MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
-		      0, 2, BOOKE_PAGESZ_256M, 1),
 };
 
 int num_tlb_entries = ARRAY_SIZE(tlb_table);
diff --git a/include/configs/qemu-ppce500.h b/include/configs/qemu-ppce500.h
index 7ef7235..f7e59bc 100644
--- a/include/configs/qemu-ppce500.h
+++ b/include/configs/qemu-ppce500.h
@@ -127,18 +127,6 @@ extern unsigned long long get_phys_ccsrbar_addr_early(void);
  * Memory space is mapped 1-1, but I/O space must start from 0.
  */
 
-#define CONFIG_SYS_PCI_VIRT		0xc0000000	/* 512M PCI TLB */
-#define CONFIG_SYS_PCI_PHYS		0xc0000000	/* 512M PCI TLB */
-
-#define CONFIG_SYS_PCI1_MEM_VIRT	0xc0000000
-#define CONFIG_SYS_PCI1_MEM_BUS	0xc0000000
-#define CONFIG_SYS_PCI1_MEM_PHYS	0xc0000000
-#define CONFIG_SYS_PCI1_MEM_SIZE	0x20000000	/* 512M */
-#define CONFIG_SYS_PCI1_IO_VIRT	0xe1000000
-#define CONFIG_SYS_PCI1_IO_BUS	0x00000000
-#define CONFIG_SYS_PCI1_IO_PHYS	0xe1000000
-#define CONFIG_SYS_PCI1_IO_SIZE	0x00010000	/* 64k */
-
 #ifdef CONFIG_PCI
 #define CONFIG_PCI_INDIRECT_BRIDGE
 #define CONFIG_NET_MULTI
-- 
1.7.10.4



More information about the U-Boot mailing list