From patchwork Fri Jan 31 11:16:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 315557 X-Patchwork-Delegate: yorksun@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 46FF92C00C9 for ; Fri, 31 Jan 2014 22:17:27 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id BB0B94B5B7; Fri, 31 Jan 2014 12:17:15 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Kdp2ftom6LpO; Fri, 31 Jan 2014 12:17:15 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B15A24B5C5; Fri, 31 Jan 2014 12:16:57 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A530A4B57E for ; Fri, 31 Jan 2014 12:16:22 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aHdt+tZADw54 for ; Fri, 31 Jan 2014 12:16:20 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mx2.suse.de (cantor2.suse.de [195.135.220.15]) by theia.denx.de (Postfix) with ESMTPS id 7D67A4B57F for ; Fri, 31 Jan 2014 12:16:17 +0100 (CET) Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 15ECAACB1; Fri, 31 Jan 2014 11:16:14 +0000 (UTC) From: Alexander Graf To: u-boot@lists.denx.de Date: Fri, 31 Jan 2014 12:16:08 +0100 Message-Id: <1391166969-25845-6-git-send-email-agraf@suse.de> X-Mailer: git-send-email 1.8.1.4 In-Reply-To: <1391166969-25845-1-git-send-email-agraf@suse.de> References: <1391166969-25845-1-git-send-email-agraf@suse.de> Cc: Scott Wood , qemu-ppc@nongnu.org, York Sun Subject: [U-Boot] [PATCH v2 5/6] PPC 85xx: Find PCI host controllers on ppce500 from device tree X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 --- 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 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 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