18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * PCI / PCI-X / PCI-Express support for 4xx parts 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Most PCI Express code is coming from Stefan Roese implementation for 78c2ecf20Sopenharmony_ci * arch/ppc in the Denx tree, slightly reworked by me. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Some of that comes itself from a previous implementation for 440SPE only 128c2ecf20Sopenharmony_ci * by Roland Dreier: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Copyright (c) 2005 Cisco Systems. All rights reserved. 158c2ecf20Sopenharmony_ci * Roland Dreier <rolandd@cisco.com> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#undef DEBUG 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/init.h> 248c2ecf20Sopenharmony_ci#include <linux/of.h> 258c2ecf20Sopenharmony_ci#include <linux/delay.h> 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <asm/io.h> 298c2ecf20Sopenharmony_ci#include <asm/pci-bridge.h> 308c2ecf20Sopenharmony_ci#include <asm/machdep.h> 318c2ecf20Sopenharmony_ci#include <asm/dcr.h> 328c2ecf20Sopenharmony_ci#include <asm/dcr-regs.h> 338c2ecf20Sopenharmony_ci#include <mm/mmu_decl.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "pci.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int dma_offset_set; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL)) 408c2ecf20Sopenharmony_ci#define U64_TO_U32_HIGH(val) ((u32)((val) >> 32)) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define RES_TO_U32_LOW(val) \ 438c2ecf20Sopenharmony_ci ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_LOW(val) : (val)) 448c2ecf20Sopenharmony_ci#define RES_TO_U32_HIGH(val) \ 458c2ecf20Sopenharmony_ci ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_HIGH(val) : (0)) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline int ppc440spe_revA(void) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci /* Catch both 440SPe variants, with and without RAID6 support */ 508c2ecf20Sopenharmony_ci if ((mfspr(SPRN_PVR) & 0xffefffff) == 0x53421890) 518c2ecf20Sopenharmony_ci return 1; 528c2ecf20Sopenharmony_ci else 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct pci_controller *hose; 598c2ecf20Sopenharmony_ci int i; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (dev->devfn != 0 || dev->bus->self != NULL) 628c2ecf20Sopenharmony_ci return; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci hose = pci_bus_to_host(dev->bus); 658c2ecf20Sopenharmony_ci if (hose == NULL) 668c2ecf20Sopenharmony_ci return; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!of_device_is_compatible(hose->dn, "ibm,plb-pciex") && 698c2ecf20Sopenharmony_ci !of_device_is_compatible(hose->dn, "ibm,plb-pcix") && 708c2ecf20Sopenharmony_ci !of_device_is_compatible(hose->dn, "ibm,plb-pci")) 718c2ecf20Sopenharmony_ci return; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (of_device_is_compatible(hose->dn, "ibm,plb440epx-pci") || 748c2ecf20Sopenharmony_ci of_device_is_compatible(hose->dn, "ibm,plb440grx-pci")) { 758c2ecf20Sopenharmony_ci hose->indirect_type |= PPC_INDIRECT_TYPE_BROKEN_MRM; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Hide the PCI host BARs from the kernel as their content doesn't 798c2ecf20Sopenharmony_ci * fit well in the resource management 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 828c2ecf20Sopenharmony_ci dev->resource[i].start = dev->resource[i].end = 0; 838c2ecf20Sopenharmony_ci dev->resource[i].flags = 0; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n", 878c2ecf20Sopenharmony_ci pci_name(dev)); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, 928c2ecf20Sopenharmony_ci void __iomem *reg, 938c2ecf20Sopenharmony_ci struct resource *res) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci u64 size; 968c2ecf20Sopenharmony_ci const u32 *ranges; 978c2ecf20Sopenharmony_ci int rlen; 988c2ecf20Sopenharmony_ci int pna = of_n_addr_cells(hose->dn); 998c2ecf20Sopenharmony_ci int np = pna + 5; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Default */ 1028c2ecf20Sopenharmony_ci res->start = 0; 1038c2ecf20Sopenharmony_ci size = 0x80000000; 1048c2ecf20Sopenharmony_ci res->end = size - 1; 1058c2ecf20Sopenharmony_ci res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Get dma-ranges property */ 1088c2ecf20Sopenharmony_ci ranges = of_get_property(hose->dn, "dma-ranges", &rlen); 1098c2ecf20Sopenharmony_ci if (ranges == NULL) 1108c2ecf20Sopenharmony_ci goto out; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Walk it */ 1138c2ecf20Sopenharmony_ci while ((rlen -= np * 4) >= 0) { 1148c2ecf20Sopenharmony_ci u32 pci_space = ranges[0]; 1158c2ecf20Sopenharmony_ci u64 pci_addr = of_read_number(ranges + 1, 2); 1168c2ecf20Sopenharmony_ci u64 cpu_addr = of_translate_dma_address(hose->dn, ranges + 3); 1178c2ecf20Sopenharmony_ci size = of_read_number(ranges + pna + 3, 2); 1188c2ecf20Sopenharmony_ci ranges += np; 1198c2ecf20Sopenharmony_ci if (cpu_addr == OF_BAD_ADDR || size == 0) 1208c2ecf20Sopenharmony_ci continue; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* We only care about memory */ 1238c2ecf20Sopenharmony_ci if ((pci_space & 0x03000000) != 0x02000000) 1248c2ecf20Sopenharmony_ci continue; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* We currently only support memory at 0, and pci_addr 1278c2ecf20Sopenharmony_ci * within 32 bits space 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci if (cpu_addr != 0 || pci_addr > 0xffffffff) { 1308c2ecf20Sopenharmony_ci printk(KERN_WARNING "%pOF: Ignored unsupported dma range" 1318c2ecf20Sopenharmony_ci " 0x%016llx...0x%016llx -> 0x%016llx\n", 1328c2ecf20Sopenharmony_ci hose->dn, 1338c2ecf20Sopenharmony_ci pci_addr, pci_addr + size - 1, cpu_addr); 1348c2ecf20Sopenharmony_ci continue; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Check if not prefetchable */ 1388c2ecf20Sopenharmony_ci if (!(pci_space & 0x40000000)) 1398c2ecf20Sopenharmony_ci res->flags &= ~IORESOURCE_PREFETCH; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* Use that */ 1438c2ecf20Sopenharmony_ci res->start = pci_addr; 1448c2ecf20Sopenharmony_ci /* Beware of 32 bits resources */ 1458c2ecf20Sopenharmony_ci if (sizeof(resource_size_t) == sizeof(u32) && 1468c2ecf20Sopenharmony_ci (pci_addr + size) > 0x100000000ull) 1478c2ecf20Sopenharmony_ci res->end = 0xffffffff; 1488c2ecf20Sopenharmony_ci else 1498c2ecf20Sopenharmony_ci res->end = res->start + size - 1; 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* We only support one global DMA offset */ 1548c2ecf20Sopenharmony_ci if (dma_offset_set && pci_dram_offset != res->start) { 1558c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: dma-ranges(s) mismatch\n", hose->dn); 1568c2ecf20Sopenharmony_ci return -ENXIO; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Check that we can fit all of memory as we don't support 1608c2ecf20Sopenharmony_ci * DMA bounce buffers 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci if (size < total_memory) { 1638c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: dma-ranges too small " 1648c2ecf20Sopenharmony_ci "(size=%llx total_memory=%llx)\n", 1658c2ecf20Sopenharmony_ci hose->dn, size, (u64)total_memory); 1668c2ecf20Sopenharmony_ci return -ENXIO; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Check we are a power of 2 size and that base is a multiple of size*/ 1708c2ecf20Sopenharmony_ci if ((size & (size - 1)) != 0 || 1718c2ecf20Sopenharmony_ci (res->start & (size - 1)) != 0) { 1728c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: dma-ranges unaligned\n", hose->dn); 1738c2ecf20Sopenharmony_ci return -ENXIO; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* Check that we are fully contained within 32 bits space if we are not 1778c2ecf20Sopenharmony_ci * running on a 460sx or 476fpe which have 64 bit bus addresses. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci if (res->end > 0xffffffff && 1808c2ecf20Sopenharmony_ci !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx") 1818c2ecf20Sopenharmony_ci || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) { 1828c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: dma-ranges outside of 32 bits space\n", 1838c2ecf20Sopenharmony_ci hose->dn); 1848c2ecf20Sopenharmony_ci return -ENXIO; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci out: 1878c2ecf20Sopenharmony_ci dma_offset_set = 1; 1888c2ecf20Sopenharmony_ci pci_dram_offset = res->start; 1898c2ecf20Sopenharmony_ci hose->dma_window_base_cur = res->start; 1908c2ecf20Sopenharmony_ci hose->dma_window_size = resource_size(res); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci printk(KERN_INFO "4xx PCI DMA offset set to 0x%08lx\n", 1938c2ecf20Sopenharmony_ci pci_dram_offset); 1948c2ecf20Sopenharmony_ci printk(KERN_INFO "4xx PCI DMA window base to 0x%016llx\n", 1958c2ecf20Sopenharmony_ci (unsigned long long)hose->dma_window_base_cur); 1968c2ecf20Sopenharmony_ci printk(KERN_INFO "DMA window size 0x%016llx\n", 1978c2ecf20Sopenharmony_ci (unsigned long long)hose->dma_window_size); 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* 2028c2ecf20Sopenharmony_ci * 4xx PCI 2.x part 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose, 2068c2ecf20Sopenharmony_ci void __iomem *reg, 2078c2ecf20Sopenharmony_ci u64 plb_addr, 2088c2ecf20Sopenharmony_ci u64 pci_addr, 2098c2ecf20Sopenharmony_ci u64 size, 2108c2ecf20Sopenharmony_ci unsigned int flags, 2118c2ecf20Sopenharmony_ci int index) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci u32 ma, pcila, pciha; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Hack warning ! The "old" PCI 2.x cell only let us configure the low 2168c2ecf20Sopenharmony_ci * 32-bit of incoming PLB addresses. The top 4 bits of the 36-bit 2178c2ecf20Sopenharmony_ci * address are actually hard wired to a value that appears to depend 2188c2ecf20Sopenharmony_ci * on the specific SoC. For example, it's 0 on 440EP and 1 on 440EPx. 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * The trick here is we just crop those top bits and ignore them when 2218c2ecf20Sopenharmony_ci * programming the chip. That means the device-tree has to be right 2228c2ecf20Sopenharmony_ci * for the specific part used (we don't print a warning if it's wrong 2238c2ecf20Sopenharmony_ci * but on the other hand, you'll crash quickly enough), but at least 2248c2ecf20Sopenharmony_ci * this code should work whatever the hard coded value is 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci plb_addr &= 0xffffffffull; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Note: Due to the above hack, the test below doesn't actually test 2298c2ecf20Sopenharmony_ci * if you address is above 4G, but it tests that address and 2308c2ecf20Sopenharmony_ci * (address + size) are both contained in the same 4G 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) || 2338c2ecf20Sopenharmony_ci size < 0x1000 || (plb_addr & (size - 1)) != 0) { 2348c2ecf20Sopenharmony_ci printk(KERN_WARNING "%pOF: Resource out of range\n", hose->dn); 2358c2ecf20Sopenharmony_ci return -1; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci ma = (0xffffffffu << ilog2(size)) | 1; 2388c2ecf20Sopenharmony_ci if (flags & IORESOURCE_PREFETCH) 2398c2ecf20Sopenharmony_ci ma |= 2; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci pciha = RES_TO_U32_HIGH(pci_addr); 2428c2ecf20Sopenharmony_ci pcila = RES_TO_U32_LOW(pci_addr); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index)); 2458c2ecf20Sopenharmony_ci writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index)); 2468c2ecf20Sopenharmony_ci writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index)); 2478c2ecf20Sopenharmony_ci writel(ma, reg + PCIL0_PMM0MA + (0x10 * index)); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, 2538c2ecf20Sopenharmony_ci void __iomem *reg) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci int i, j, found_isa_hole = 0; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Setup outbound memory windows */ 2588c2ecf20Sopenharmony_ci for (i = j = 0; i < 3; i++) { 2598c2ecf20Sopenharmony_ci struct resource *res = &hose->mem_resources[i]; 2608c2ecf20Sopenharmony_ci resource_size_t offset = hose->mem_offset[i]; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* we only care about memory windows */ 2638c2ecf20Sopenharmony_ci if (!(res->flags & IORESOURCE_MEM)) 2648c2ecf20Sopenharmony_ci continue; 2658c2ecf20Sopenharmony_ci if (j > 2) { 2668c2ecf20Sopenharmony_ci printk(KERN_WARNING "%pOF: Too many ranges\n", hose->dn); 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Configure the resource */ 2718c2ecf20Sopenharmony_ci if (ppc4xx_setup_one_pci_PMM(hose, reg, 2728c2ecf20Sopenharmony_ci res->start, 2738c2ecf20Sopenharmony_ci res->start - offset, 2748c2ecf20Sopenharmony_ci resource_size(res), 2758c2ecf20Sopenharmony_ci res->flags, 2768c2ecf20Sopenharmony_ci j) == 0) { 2778c2ecf20Sopenharmony_ci j++; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* If the resource PCI address is 0 then we have our 2808c2ecf20Sopenharmony_ci * ISA memory hole 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ci if (res->start == offset) 2838c2ecf20Sopenharmony_ci found_isa_hole = 1; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Handle ISA memory hole if not already covered */ 2888c2ecf20Sopenharmony_ci if (j <= 2 && !found_isa_hole && hose->isa_mem_size) 2898c2ecf20Sopenharmony_ci if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0, 2908c2ecf20Sopenharmony_ci hose->isa_mem_size, 0, j) == 0) 2918c2ecf20Sopenharmony_ci printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n", 2928c2ecf20Sopenharmony_ci hose->dn); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, 2968c2ecf20Sopenharmony_ci void __iomem *reg, 2978c2ecf20Sopenharmony_ci const struct resource *res) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci resource_size_t size = resource_size(res); 3008c2ecf20Sopenharmony_ci u32 sa; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* Calculate window size */ 3038c2ecf20Sopenharmony_ci sa = (0xffffffffu << ilog2(size)) | 1; 3048c2ecf20Sopenharmony_ci sa |= 0x1; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* RAM is always at 0 local for now */ 3078c2ecf20Sopenharmony_ci writel(0, reg + PCIL0_PTM1LA); 3088c2ecf20Sopenharmony_ci writel(sa, reg + PCIL0_PTM1MS); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Map on PCI side */ 3118c2ecf20Sopenharmony_ci early_write_config_dword(hose, hose->first_busno, 0, 3128c2ecf20Sopenharmony_ci PCI_BASE_ADDRESS_1, res->start); 3138c2ecf20Sopenharmony_ci early_write_config_dword(hose, hose->first_busno, 0, 3148c2ecf20Sopenharmony_ci PCI_BASE_ADDRESS_2, 0x00000000); 3158c2ecf20Sopenharmony_ci early_write_config_word(hose, hose->first_busno, 0, 3168c2ecf20Sopenharmony_ci PCI_COMMAND, 0x0006); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void __init ppc4xx_probe_pci_bridge(struct device_node *np) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci /* NYI */ 3228c2ecf20Sopenharmony_ci struct resource rsrc_cfg; 3238c2ecf20Sopenharmony_ci struct resource rsrc_reg; 3248c2ecf20Sopenharmony_ci struct resource dma_window; 3258c2ecf20Sopenharmony_ci struct pci_controller *hose = NULL; 3268c2ecf20Sopenharmony_ci void __iomem *reg = NULL; 3278c2ecf20Sopenharmony_ci const int *bus_range; 3288c2ecf20Sopenharmony_ci int primary = 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Check if device is enabled */ 3318c2ecf20Sopenharmony_ci if (!of_device_is_available(np)) { 3328c2ecf20Sopenharmony_ci printk(KERN_INFO "%pOF: Port disabled via device-tree\n", np); 3338c2ecf20Sopenharmony_ci return; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Fetch config space registers address */ 3378c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 0, &rsrc_cfg)) { 3388c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't get PCI config register base !", 3398c2ecf20Sopenharmony_ci np); 3408c2ecf20Sopenharmony_ci return; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci /* Fetch host bridge internal registers address */ 3438c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 3, &rsrc_reg)) { 3448c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't get PCI internal register base !", 3458c2ecf20Sopenharmony_ci np); 3468c2ecf20Sopenharmony_ci return; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* Check if primary bridge */ 3508c2ecf20Sopenharmony_ci if (of_get_property(np, "primary", NULL)) 3518c2ecf20Sopenharmony_ci primary = 1; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* Get bus range if any */ 3548c2ecf20Sopenharmony_ci bus_range = of_get_property(np, "bus-range", NULL); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Map registers */ 3578c2ecf20Sopenharmony_ci reg = ioremap(rsrc_reg.start, resource_size(&rsrc_reg)); 3588c2ecf20Sopenharmony_ci if (reg == NULL) { 3598c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't map registers !", np); 3608c2ecf20Sopenharmony_ci goto fail; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Allocate the host controller data structure */ 3648c2ecf20Sopenharmony_ci hose = pcibios_alloc_controller(np); 3658c2ecf20Sopenharmony_ci if (!hose) 3668c2ecf20Sopenharmony_ci goto fail; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci hose->first_busno = bus_range ? bus_range[0] : 0x0; 3698c2ecf20Sopenharmony_ci hose->last_busno = bus_range ? bus_range[1] : 0xff; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* Setup config space */ 3728c2ecf20Sopenharmony_ci setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 0); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Disable all windows */ 3758c2ecf20Sopenharmony_ci writel(0, reg + PCIL0_PMM0MA); 3768c2ecf20Sopenharmony_ci writel(0, reg + PCIL0_PMM1MA); 3778c2ecf20Sopenharmony_ci writel(0, reg + PCIL0_PMM2MA); 3788c2ecf20Sopenharmony_ci writel(0, reg + PCIL0_PTM1MS); 3798c2ecf20Sopenharmony_ci writel(0, reg + PCIL0_PTM2MS); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Parse outbound mapping resources */ 3828c2ecf20Sopenharmony_ci pci_process_bridge_OF_ranges(hose, np, primary); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Parse inbound mapping resources */ 3858c2ecf20Sopenharmony_ci if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0) 3868c2ecf20Sopenharmony_ci goto fail; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Configure outbound ranges POMs */ 3898c2ecf20Sopenharmony_ci ppc4xx_configure_pci_PMMs(hose, reg); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Configure inbound ranges PIMs */ 3928c2ecf20Sopenharmony_ci ppc4xx_configure_pci_PTMs(hose, reg, &dma_window); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* We don't need the registers anymore */ 3958c2ecf20Sopenharmony_ci iounmap(reg); 3968c2ecf20Sopenharmony_ci return; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci fail: 3998c2ecf20Sopenharmony_ci if (hose) 4008c2ecf20Sopenharmony_ci pcibios_free_controller(hose); 4018c2ecf20Sopenharmony_ci if (reg) 4028c2ecf20Sopenharmony_ci iounmap(reg); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci * 4xx PCI-X part 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int __init ppc4xx_setup_one_pcix_POM(struct pci_controller *hose, 4108c2ecf20Sopenharmony_ci void __iomem *reg, 4118c2ecf20Sopenharmony_ci u64 plb_addr, 4128c2ecf20Sopenharmony_ci u64 pci_addr, 4138c2ecf20Sopenharmony_ci u64 size, 4148c2ecf20Sopenharmony_ci unsigned int flags, 4158c2ecf20Sopenharmony_ci int index) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci u32 lah, lal, pciah, pcial, sa; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (!is_power_of_2(size) || size < 0x1000 || 4208c2ecf20Sopenharmony_ci (plb_addr & (size - 1)) != 0) { 4218c2ecf20Sopenharmony_ci printk(KERN_WARNING "%pOF: Resource out of range\n", 4228c2ecf20Sopenharmony_ci hose->dn); 4238c2ecf20Sopenharmony_ci return -1; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Calculate register values */ 4278c2ecf20Sopenharmony_ci lah = RES_TO_U32_HIGH(plb_addr); 4288c2ecf20Sopenharmony_ci lal = RES_TO_U32_LOW(plb_addr); 4298c2ecf20Sopenharmony_ci pciah = RES_TO_U32_HIGH(pci_addr); 4308c2ecf20Sopenharmony_ci pcial = RES_TO_U32_LOW(pci_addr); 4318c2ecf20Sopenharmony_ci sa = (0xffffffffu << ilog2(size)) | 0x1; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Program register values */ 4348c2ecf20Sopenharmony_ci if (index == 0) { 4358c2ecf20Sopenharmony_ci writel(lah, reg + PCIX0_POM0LAH); 4368c2ecf20Sopenharmony_ci writel(lal, reg + PCIX0_POM0LAL); 4378c2ecf20Sopenharmony_ci writel(pciah, reg + PCIX0_POM0PCIAH); 4388c2ecf20Sopenharmony_ci writel(pcial, reg + PCIX0_POM0PCIAL); 4398c2ecf20Sopenharmony_ci writel(sa, reg + PCIX0_POM0SA); 4408c2ecf20Sopenharmony_ci } else { 4418c2ecf20Sopenharmony_ci writel(lah, reg + PCIX0_POM1LAH); 4428c2ecf20Sopenharmony_ci writel(lal, reg + PCIX0_POM1LAL); 4438c2ecf20Sopenharmony_ci writel(pciah, reg + PCIX0_POM1PCIAH); 4448c2ecf20Sopenharmony_ci writel(pcial, reg + PCIX0_POM1PCIAL); 4458c2ecf20Sopenharmony_ci writel(sa, reg + PCIX0_POM1SA); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, 4528c2ecf20Sopenharmony_ci void __iomem *reg) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci int i, j, found_isa_hole = 0; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* Setup outbound memory windows */ 4578c2ecf20Sopenharmony_ci for (i = j = 0; i < 3; i++) { 4588c2ecf20Sopenharmony_ci struct resource *res = &hose->mem_resources[i]; 4598c2ecf20Sopenharmony_ci resource_size_t offset = hose->mem_offset[i]; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* we only care about memory windows */ 4628c2ecf20Sopenharmony_ci if (!(res->flags & IORESOURCE_MEM)) 4638c2ecf20Sopenharmony_ci continue; 4648c2ecf20Sopenharmony_ci if (j > 1) { 4658c2ecf20Sopenharmony_ci printk(KERN_WARNING "%pOF: Too many ranges\n", hose->dn); 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Configure the resource */ 4708c2ecf20Sopenharmony_ci if (ppc4xx_setup_one_pcix_POM(hose, reg, 4718c2ecf20Sopenharmony_ci res->start, 4728c2ecf20Sopenharmony_ci res->start - offset, 4738c2ecf20Sopenharmony_ci resource_size(res), 4748c2ecf20Sopenharmony_ci res->flags, 4758c2ecf20Sopenharmony_ci j) == 0) { 4768c2ecf20Sopenharmony_ci j++; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* If the resource PCI address is 0 then we have our 4798c2ecf20Sopenharmony_ci * ISA memory hole 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci if (res->start == offset) 4828c2ecf20Sopenharmony_ci found_isa_hole = 1; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* Handle ISA memory hole if not already covered */ 4878c2ecf20Sopenharmony_ci if (j <= 1 && !found_isa_hole && hose->isa_mem_size) 4888c2ecf20Sopenharmony_ci if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0, 4898c2ecf20Sopenharmony_ci hose->isa_mem_size, 0, j) == 0) 4908c2ecf20Sopenharmony_ci printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n", 4918c2ecf20Sopenharmony_ci hose->dn); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, 4958c2ecf20Sopenharmony_ci void __iomem *reg, 4968c2ecf20Sopenharmony_ci const struct resource *res, 4978c2ecf20Sopenharmony_ci int big_pim, 4988c2ecf20Sopenharmony_ci int enable_msi_hole) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci resource_size_t size = resource_size(res); 5018c2ecf20Sopenharmony_ci u32 sa; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* RAM is always at 0 */ 5048c2ecf20Sopenharmony_ci writel(0x00000000, reg + PCIX0_PIM0LAH); 5058c2ecf20Sopenharmony_ci writel(0x00000000, reg + PCIX0_PIM0LAL); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Calculate window size */ 5088c2ecf20Sopenharmony_ci sa = (0xffffffffu << ilog2(size)) | 1; 5098c2ecf20Sopenharmony_ci sa |= 0x1; 5108c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_PREFETCH) 5118c2ecf20Sopenharmony_ci sa |= 0x2; 5128c2ecf20Sopenharmony_ci if (enable_msi_hole) 5138c2ecf20Sopenharmony_ci sa |= 0x4; 5148c2ecf20Sopenharmony_ci writel(sa, reg + PCIX0_PIM0SA); 5158c2ecf20Sopenharmony_ci if (big_pim) 5168c2ecf20Sopenharmony_ci writel(0xffffffff, reg + PCIX0_PIM0SAH); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* Map on PCI side */ 5198c2ecf20Sopenharmony_ci writel(0x00000000, reg + PCIX0_BAR0H); 5208c2ecf20Sopenharmony_ci writel(res->start, reg + PCIX0_BAR0L); 5218c2ecf20Sopenharmony_ci writew(0x0006, reg + PCIX0_COMMAND); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic void __init ppc4xx_probe_pcix_bridge(struct device_node *np) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct resource rsrc_cfg; 5278c2ecf20Sopenharmony_ci struct resource rsrc_reg; 5288c2ecf20Sopenharmony_ci struct resource dma_window; 5298c2ecf20Sopenharmony_ci struct pci_controller *hose = NULL; 5308c2ecf20Sopenharmony_ci void __iomem *reg = NULL; 5318c2ecf20Sopenharmony_ci const int *bus_range; 5328c2ecf20Sopenharmony_ci int big_pim = 0, msi = 0, primary = 0; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Fetch config space registers address */ 5358c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 0, &rsrc_cfg)) { 5368c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't get PCI-X config register base !", 5378c2ecf20Sopenharmony_ci np); 5388c2ecf20Sopenharmony_ci return; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci /* Fetch host bridge internal registers address */ 5418c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 3, &rsrc_reg)) { 5428c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't get PCI-X internal register base !", 5438c2ecf20Sopenharmony_ci np); 5448c2ecf20Sopenharmony_ci return; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Check if it supports large PIMs (440GX) */ 5488c2ecf20Sopenharmony_ci if (of_get_property(np, "large-inbound-windows", NULL)) 5498c2ecf20Sopenharmony_ci big_pim = 1; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* Check if we should enable MSIs inbound hole */ 5528c2ecf20Sopenharmony_ci if (of_get_property(np, "enable-msi-hole", NULL)) 5538c2ecf20Sopenharmony_ci msi = 1; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* Check if primary bridge */ 5568c2ecf20Sopenharmony_ci if (of_get_property(np, "primary", NULL)) 5578c2ecf20Sopenharmony_ci primary = 1; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Get bus range if any */ 5608c2ecf20Sopenharmony_ci bus_range = of_get_property(np, "bus-range", NULL); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Map registers */ 5638c2ecf20Sopenharmony_ci reg = ioremap(rsrc_reg.start, resource_size(&rsrc_reg)); 5648c2ecf20Sopenharmony_ci if (reg == NULL) { 5658c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't map registers !", np); 5668c2ecf20Sopenharmony_ci goto fail; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* Allocate the host controller data structure */ 5708c2ecf20Sopenharmony_ci hose = pcibios_alloc_controller(np); 5718c2ecf20Sopenharmony_ci if (!hose) 5728c2ecf20Sopenharmony_ci goto fail; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci hose->first_busno = bus_range ? bus_range[0] : 0x0; 5758c2ecf20Sopenharmony_ci hose->last_busno = bus_range ? bus_range[1] : 0xff; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* Setup config space */ 5788c2ecf20Sopenharmony_ci setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 5798c2ecf20Sopenharmony_ci PPC_INDIRECT_TYPE_SET_CFG_TYPE); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* Disable all windows */ 5828c2ecf20Sopenharmony_ci writel(0, reg + PCIX0_POM0SA); 5838c2ecf20Sopenharmony_ci writel(0, reg + PCIX0_POM1SA); 5848c2ecf20Sopenharmony_ci writel(0, reg + PCIX0_POM2SA); 5858c2ecf20Sopenharmony_ci writel(0, reg + PCIX0_PIM0SA); 5868c2ecf20Sopenharmony_ci writel(0, reg + PCIX0_PIM1SA); 5878c2ecf20Sopenharmony_ci writel(0, reg + PCIX0_PIM2SA); 5888c2ecf20Sopenharmony_ci if (big_pim) { 5898c2ecf20Sopenharmony_ci writel(0, reg + PCIX0_PIM0SAH); 5908c2ecf20Sopenharmony_ci writel(0, reg + PCIX0_PIM2SAH); 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* Parse outbound mapping resources */ 5948c2ecf20Sopenharmony_ci pci_process_bridge_OF_ranges(hose, np, primary); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* Parse inbound mapping resources */ 5978c2ecf20Sopenharmony_ci if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0) 5988c2ecf20Sopenharmony_ci goto fail; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Configure outbound ranges POMs */ 6018c2ecf20Sopenharmony_ci ppc4xx_configure_pcix_POMs(hose, reg); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* Configure inbound ranges PIMs */ 6048c2ecf20Sopenharmony_ci ppc4xx_configure_pcix_PIMs(hose, reg, &dma_window, big_pim, msi); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* We don't need the registers anymore */ 6078c2ecf20Sopenharmony_ci iounmap(reg); 6088c2ecf20Sopenharmony_ci return; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci fail: 6118c2ecf20Sopenharmony_ci if (hose) 6128c2ecf20Sopenharmony_ci pcibios_free_controller(hose); 6138c2ecf20Sopenharmony_ci if (reg) 6148c2ecf20Sopenharmony_ci iounmap(reg); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC4xx_PCI_EXPRESS 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/* 6208c2ecf20Sopenharmony_ci * 4xx PCI-Express part 6218c2ecf20Sopenharmony_ci * 6228c2ecf20Sopenharmony_ci * We support 3 parts currently based on the compatible property: 6238c2ecf20Sopenharmony_ci * 6248c2ecf20Sopenharmony_ci * ibm,plb-pciex-440spe 6258c2ecf20Sopenharmony_ci * ibm,plb-pciex-405ex 6268c2ecf20Sopenharmony_ci * ibm,plb-pciex-460ex 6278c2ecf20Sopenharmony_ci * 6288c2ecf20Sopenharmony_ci * Anything else will be rejected for now as they are all subtly 6298c2ecf20Sopenharmony_ci * different unfortunately. 6308c2ecf20Sopenharmony_ci * 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci#define MAX_PCIE_BUS_MAPPED 0x40 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistruct ppc4xx_pciex_port 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct pci_controller *hose; 6388c2ecf20Sopenharmony_ci struct device_node *node; 6398c2ecf20Sopenharmony_ci unsigned int index; 6408c2ecf20Sopenharmony_ci int endpoint; 6418c2ecf20Sopenharmony_ci int link; 6428c2ecf20Sopenharmony_ci int has_ibpre; 6438c2ecf20Sopenharmony_ci unsigned int sdr_base; 6448c2ecf20Sopenharmony_ci dcr_host_t dcrs; 6458c2ecf20Sopenharmony_ci struct resource cfg_space; 6468c2ecf20Sopenharmony_ci struct resource utl_regs; 6478c2ecf20Sopenharmony_ci void __iomem *utl_base; 6488c2ecf20Sopenharmony_ci}; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_port *ppc4xx_pciex_ports; 6518c2ecf20Sopenharmony_cistatic unsigned int ppc4xx_pciex_port_count; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistruct ppc4xx_pciex_hwops 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci bool want_sdr; 6568c2ecf20Sopenharmony_ci int (*core_init)(struct device_node *np); 6578c2ecf20Sopenharmony_ci int (*port_init_hw)(struct ppc4xx_pciex_port *port); 6588c2ecf20Sopenharmony_ci int (*setup_utl)(struct ppc4xx_pciex_port *port); 6598c2ecf20Sopenharmony_ci void (*check_link)(struct ppc4xx_pciex_port *port); 6608c2ecf20Sopenharmony_ci}; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port, 6658c2ecf20Sopenharmony_ci unsigned int sdr_offset, 6668c2ecf20Sopenharmony_ci unsigned int mask, 6678c2ecf20Sopenharmony_ci unsigned int value, 6688c2ecf20Sopenharmony_ci int timeout_ms) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci u32 val; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci while(timeout_ms--) { 6738c2ecf20Sopenharmony_ci val = mfdcri(SDR0, port->sdr_base + sdr_offset); 6748c2ecf20Sopenharmony_ci if ((val & mask) == value) { 6758c2ecf20Sopenharmony_ci pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n", 6768c2ecf20Sopenharmony_ci port->index, sdr_offset, timeout_ms, val); 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci msleep(1); 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci return -1; 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci /* Wait for reset to complete */ 6878c2ecf20Sopenharmony_ci if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) { 6888c2ecf20Sopenharmony_ci printk(KERN_WARNING "PCIE%d: PGRST failed\n", 6898c2ecf20Sopenharmony_ci port->index); 6908c2ecf20Sopenharmony_ci return -1; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci return 0; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: Checking link...\n", port->index); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Check for card presence detect if supported, if not, just wait for 7018c2ecf20Sopenharmony_ci * link unconditionally. 7028c2ecf20Sopenharmony_ci * 7038c2ecf20Sopenharmony_ci * note that we don't fail if there is no link, we just filter out 7048c2ecf20Sopenharmony_ci * config space accesses. That way, it will be easier to implement 7058c2ecf20Sopenharmony_ci * hotplug later on. 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_ci if (!port->has_ibpre || 7088c2ecf20Sopenharmony_ci !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, 7098c2ecf20Sopenharmony_ci 1 << 28, 1 << 28, 100)) { 7108c2ecf20Sopenharmony_ci printk(KERN_INFO 7118c2ecf20Sopenharmony_ci "PCIE%d: Device detected, waiting for link...\n", 7128c2ecf20Sopenharmony_ci port->index); 7138c2ecf20Sopenharmony_ci if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, 7148c2ecf20Sopenharmony_ci 0x1000, 0x1000, 2000)) 7158c2ecf20Sopenharmony_ci printk(KERN_WARNING 7168c2ecf20Sopenharmony_ci "PCIE%d: Link up failed\n", port->index); 7178c2ecf20Sopenharmony_ci else { 7188c2ecf20Sopenharmony_ci printk(KERN_INFO 7198c2ecf20Sopenharmony_ci "PCIE%d: link is up !\n", port->index); 7208c2ecf20Sopenharmony_ci port->link = 1; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci } else 7238c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: No device detected.\n", port->index); 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci#ifdef CONFIG_44x 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci/* Check various reset bits of the 440SPe PCIe core */ 7298c2ecf20Sopenharmony_cistatic int __init ppc440spe_pciex_check_reset(struct device_node *np) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci u32 valPE0, valPE1, valPE2; 7328c2ecf20Sopenharmony_ci int err = 0; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* SDR0_PEGPLLLCT1 reset */ 7358c2ecf20Sopenharmony_ci if (!(mfdcri(SDR0, PESDR0_PLLLCT1) & 0x01000000)) { 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * the PCIe core was probably already initialised 7388c2ecf20Sopenharmony_ci * by firmware - let's re-reset RCSSET regs 7398c2ecf20Sopenharmony_ci * 7408c2ecf20Sopenharmony_ci * -- Shouldn't we also re-reset the whole thing ? -- BenH 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_ci pr_debug("PCIE: SDR0_PLLLCT1 already reset.\n"); 7438c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_440SPE_RCSSET, 0x01010000); 7448c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_440SPE_RCSSET, 0x01010000); 7458c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_440SPE_RCSSET, 0x01010000); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci valPE0 = mfdcri(SDR0, PESDR0_440SPE_RCSSET); 7498c2ecf20Sopenharmony_ci valPE1 = mfdcri(SDR0, PESDR1_440SPE_RCSSET); 7508c2ecf20Sopenharmony_ci valPE2 = mfdcri(SDR0, PESDR2_440SPE_RCSSET); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* SDR0_PExRCSSET rstgu */ 7538c2ecf20Sopenharmony_ci if (!(valPE0 & 0x01000000) || 7548c2ecf20Sopenharmony_ci !(valPE1 & 0x01000000) || 7558c2ecf20Sopenharmony_ci !(valPE2 & 0x01000000)) { 7568c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstgu error\n"); 7578c2ecf20Sopenharmony_ci err = -1; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* SDR0_PExRCSSET rstdl */ 7618c2ecf20Sopenharmony_ci if (!(valPE0 & 0x00010000) || 7628c2ecf20Sopenharmony_ci !(valPE1 & 0x00010000) || 7638c2ecf20Sopenharmony_ci !(valPE2 & 0x00010000)) { 7648c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstdl error\n"); 7658c2ecf20Sopenharmony_ci err = -1; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* SDR0_PExRCSSET rstpyn */ 7698c2ecf20Sopenharmony_ci if ((valPE0 & 0x00001000) || 7708c2ecf20Sopenharmony_ci (valPE1 & 0x00001000) || 7718c2ecf20Sopenharmony_ci (valPE2 & 0x00001000)) { 7728c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstpyn error\n"); 7738c2ecf20Sopenharmony_ci err = -1; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* SDR0_PExRCSSET hldplb */ 7778c2ecf20Sopenharmony_ci if ((valPE0 & 0x10000000) || 7788c2ecf20Sopenharmony_ci (valPE1 & 0x10000000) || 7798c2ecf20Sopenharmony_ci (valPE2 & 0x10000000)) { 7808c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE: SDR0_PExRCSSET hldplb error\n"); 7818c2ecf20Sopenharmony_ci err = -1; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* SDR0_PExRCSSET rdy */ 7858c2ecf20Sopenharmony_ci if ((valPE0 & 0x00100000) || 7868c2ecf20Sopenharmony_ci (valPE1 & 0x00100000) || 7878c2ecf20Sopenharmony_ci (valPE2 & 0x00100000)) { 7888c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE: SDR0_PExRCSSET rdy error\n"); 7898c2ecf20Sopenharmony_ci err = -1; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* SDR0_PExRCSSET shutdown */ 7938c2ecf20Sopenharmony_ci if ((valPE0 & 0x00000100) || 7948c2ecf20Sopenharmony_ci (valPE1 & 0x00000100) || 7958c2ecf20Sopenharmony_ci (valPE2 & 0x00000100)) { 7968c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE: SDR0_PExRCSSET shutdown error\n"); 7978c2ecf20Sopenharmony_ci err = -1; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return err; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci/* Global PCIe core initializations for 440SPe core */ 8048c2ecf20Sopenharmony_cistatic int __init ppc440spe_pciex_core_init(struct device_node *np) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci int time_out = 20; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Set PLL clock receiver to LVPECL */ 8098c2ecf20Sopenharmony_ci dcri_clrset(SDR0, PESDR0_PLLLCT1, 0, 1 << 28); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* Shouldn't we do all the calibration stuff etc... here ? */ 8128c2ecf20Sopenharmony_ci if (ppc440spe_pciex_check_reset(np)) 8138c2ecf20Sopenharmony_ci return -ENXIO; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (!(mfdcri(SDR0, PESDR0_PLLLCT2) & 0x10000)) { 8168c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE: PESDR_PLLCT2 resistance calibration " 8178c2ecf20Sopenharmony_ci "failed (0x%08x)\n", 8188c2ecf20Sopenharmony_ci mfdcri(SDR0, PESDR0_PLLLCT2)); 8198c2ecf20Sopenharmony_ci return -1; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* De-assert reset of PCIe PLL, wait for lock */ 8238c2ecf20Sopenharmony_ci dcri_clrset(SDR0, PESDR0_PLLLCT1, 1 << 24, 0); 8248c2ecf20Sopenharmony_ci udelay(3); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci while (time_out) { 8278c2ecf20Sopenharmony_ci if (!(mfdcri(SDR0, PESDR0_PLLLCT3) & 0x10000000)) { 8288c2ecf20Sopenharmony_ci time_out--; 8298c2ecf20Sopenharmony_ci udelay(1); 8308c2ecf20Sopenharmony_ci } else 8318c2ecf20Sopenharmony_ci break; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci if (!time_out) { 8348c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE: VCO output not locked\n"); 8358c2ecf20Sopenharmony_ci return -1; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci pr_debug("PCIE initialization OK\n"); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci return 3; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int __init ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci u32 val = 1 << 24; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (port->endpoint) 8488c2ecf20Sopenharmony_ci val = PTYPE_LEGACY_ENDPOINT << 20; 8498c2ecf20Sopenharmony_ci else 8508c2ecf20Sopenharmony_ci val = PTYPE_ROOT_PORT << 20; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (port->index == 0) 8538c2ecf20Sopenharmony_ci val |= LNKW_X8 << 12; 8548c2ecf20Sopenharmony_ci else 8558c2ecf20Sopenharmony_ci val |= LNKW_X4 << 12; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); 8588c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x20222222); 8598c2ecf20Sopenharmony_ci if (ppc440spe_revA()) 8608c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x11000000); 8618c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL0SET1, 0x35000000); 8628c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL1SET1, 0x35000000); 8638c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL2SET1, 0x35000000); 8648c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL3SET1, 0x35000000); 8658c2ecf20Sopenharmony_ci if (port->index == 0) { 8668c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL4SET1, 8678c2ecf20Sopenharmony_ci 0x35000000); 8688c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL5SET1, 8698c2ecf20Sopenharmony_ci 0x35000000); 8708c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL6SET1, 8718c2ecf20Sopenharmony_ci 0x35000000); 8728c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL7SET1, 8738c2ecf20Sopenharmony_ci 0x35000000); 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 8768c2ecf20Sopenharmony_ci (1 << 24) | (1 << 16), 1 << 12); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci return ppc4xx_pciex_port_reset_sdr(port); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int __init ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci return ppc440spe_pciex_init_port_hw(port); 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic int __init ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci int rc = ppc440spe_pciex_init_port_hw(port); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci port->has_ibpre = 1; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci return rc; 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic int ppc440speA_pciex_init_utl(struct ppc4xx_pciex_port *port) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci /* XXX Check what that value means... I hate magic */ 8988c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x68782800); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* 9018c2ecf20Sopenharmony_ci * Set buffer allocations and then assert VRB and TXE. 9028c2ecf20Sopenharmony_ci */ 9038c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_OUTTR, 0x08000000); 9048c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_INTR, 0x02000000); 9058c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_OPDBSZ, 0x10000000); 9068c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PBBSZ, 0x53000000); 9078c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_IPHBSZ, 0x08000000); 9088c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_IPDBSZ, 0x10000000); 9098c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000); 9108c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PCTL, 0x80800066); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci return 0; 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_cistatic int ppc440speB_pciex_init_utl(struct ppc4xx_pciex_port *port) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci /* Report CRS to the operating system */ 9188c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PBCTL, 0x08000000); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return 0; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata = 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci .want_sdr = true, 9268c2ecf20Sopenharmony_ci .core_init = ppc440spe_pciex_core_init, 9278c2ecf20Sopenharmony_ci .port_init_hw = ppc440speA_pciex_init_port_hw, 9288c2ecf20Sopenharmony_ci .setup_utl = ppc440speA_pciex_init_utl, 9298c2ecf20Sopenharmony_ci .check_link = ppc4xx_pciex_check_link_sdr, 9308c2ecf20Sopenharmony_ci}; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci .want_sdr = true, 9358c2ecf20Sopenharmony_ci .core_init = ppc440spe_pciex_core_init, 9368c2ecf20Sopenharmony_ci .port_init_hw = ppc440speB_pciex_init_port_hw, 9378c2ecf20Sopenharmony_ci .setup_utl = ppc440speB_pciex_init_utl, 9388c2ecf20Sopenharmony_ci .check_link = ppc4xx_pciex_check_link_sdr, 9398c2ecf20Sopenharmony_ci}; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic int __init ppc460ex_pciex_core_init(struct device_node *np) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci /* Nothing to do, return 2 ports */ 9448c2ecf20Sopenharmony_ci return 2; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int __init ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci u32 val; 9508c2ecf20Sopenharmony_ci u32 utlset1; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (port->endpoint) 9538c2ecf20Sopenharmony_ci val = PTYPE_LEGACY_ENDPOINT << 20; 9548c2ecf20Sopenharmony_ci else 9558c2ecf20Sopenharmony_ci val = PTYPE_ROOT_PORT << 20; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (port->index == 0) { 9588c2ecf20Sopenharmony_ci val |= LNKW_X1 << 12; 9598c2ecf20Sopenharmony_ci utlset1 = 0x20000000; 9608c2ecf20Sopenharmony_ci } else { 9618c2ecf20Sopenharmony_ci val |= LNKW_X4 << 12; 9628c2ecf20Sopenharmony_ci utlset1 = 0x20101101; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); 9668c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, utlset1); 9678c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01210000); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci switch (port->index) { 9708c2ecf20Sopenharmony_ci case 0: 9718c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230); 9728c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130); 9738c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000); 9768c2ecf20Sopenharmony_ci break; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci case 1: 9798c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L0CDRCTL, 0x00003230); 9808c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230); 9818c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230); 9828c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230); 9838c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000130); 9848c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000130); 9858c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000130); 9868c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000130); 9878c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006); 9888c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006); 9898c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006); 9908c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_L3CLK, 0x00000006); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460EX_PHY_CTL_RST,0x10000000); 9938c2ecf20Sopenharmony_ci break; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 9978c2ecf20Sopenharmony_ci mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | 9988c2ecf20Sopenharmony_ci (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN)); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci /* Poll for PHY reset */ 10018c2ecf20Sopenharmony_ci /* XXX FIXME add timeout */ 10028c2ecf20Sopenharmony_ci switch (port->index) { 10038c2ecf20Sopenharmony_ci case 0: 10048c2ecf20Sopenharmony_ci while (!(mfdcri(SDR0, PESDR0_460EX_RSTSTA) & 0x1)) 10058c2ecf20Sopenharmony_ci udelay(10); 10068c2ecf20Sopenharmony_ci break; 10078c2ecf20Sopenharmony_ci case 1: 10088c2ecf20Sopenharmony_ci while (!(mfdcri(SDR0, PESDR1_460EX_RSTSTA) & 0x1)) 10098c2ecf20Sopenharmony_ci udelay(10); 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 10148c2ecf20Sopenharmony_ci (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) & 10158c2ecf20Sopenharmony_ci ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) | 10168c2ecf20Sopenharmony_ci PESDRx_RCSSET_RSTPYN); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci port->has_ibpre = 1; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return ppc4xx_pciex_port_reset_sdr(port); 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* 10288c2ecf20Sopenharmony_ci * Set buffer allocations and then assert VRB and TXE. 10298c2ecf20Sopenharmony_ci */ 10308c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PBCTL, 0x0800000c); 10318c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_OUTTR, 0x08000000); 10328c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_INTR, 0x02000000); 10338c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_OPDBSZ, 0x04000000); 10348c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PBBSZ, 0x00000000); 10358c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_IPHBSZ, 0x02000000); 10368c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_IPDBSZ, 0x04000000); 10378c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_RCIRQEN,0x00f00000); 10388c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PCTL, 0x80800066); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return 0; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci .want_sdr = true, 10468c2ecf20Sopenharmony_ci .core_init = ppc460ex_pciex_core_init, 10478c2ecf20Sopenharmony_ci .port_init_hw = ppc460ex_pciex_init_port_hw, 10488c2ecf20Sopenharmony_ci .setup_utl = ppc460ex_pciex_init_utl, 10498c2ecf20Sopenharmony_ci .check_link = ppc4xx_pciex_check_link_sdr, 10508c2ecf20Sopenharmony_ci}; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_cistatic int __init apm821xx_pciex_core_init(struct device_node *np) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci /* Return the number of pcie port */ 10558c2ecf20Sopenharmony_ci return 1; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cistatic int __init apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci u32 val; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* 10638c2ecf20Sopenharmony_ci * Do a software reset on PCIe ports. 10648c2ecf20Sopenharmony_ci * This code is to fix the issue that pci drivers doesn't re-assign 10658c2ecf20Sopenharmony_ci * bus number for PCIE devices after Uboot 10668c2ecf20Sopenharmony_ci * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000 10678c2ecf20Sopenharmony_ci * PT quad port, SAS LSI 1064E) 10688c2ecf20Sopenharmony_ci */ 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0); 10718c2ecf20Sopenharmony_ci mdelay(10); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (port->endpoint) 10748c2ecf20Sopenharmony_ci val = PTYPE_LEGACY_ENDPOINT << 20; 10758c2ecf20Sopenharmony_ci else 10768c2ecf20Sopenharmony_ci val = PTYPE_ROOT_PORT << 20; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci val |= LNKW_X1 << 12; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); 10818c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000); 10828c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230); 10858c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130); 10868c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000); 10898c2ecf20Sopenharmony_ci mdelay(50); 10908c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 10938c2ecf20Sopenharmony_ci mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | 10948c2ecf20Sopenharmony_ci (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN)); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* Poll for PHY reset */ 10978c2ecf20Sopenharmony_ci val = PESDR0_460EX_RSTSTA - port->sdr_base; 10988c2ecf20Sopenharmony_ci if (ppc4xx_pciex_wait_on_sdr(port, val, 0x1, 1, 100)) { 10998c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: PCIE: Can't reset PHY\n", __func__); 11008c2ecf20Sopenharmony_ci return -EBUSY; 11018c2ecf20Sopenharmony_ci } else { 11028c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 11038c2ecf20Sopenharmony_ci (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) & 11048c2ecf20Sopenharmony_ci ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) | 11058c2ecf20Sopenharmony_ci PESDRx_RCSSET_RSTPYN); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci port->has_ibpre = 1; 11088c2ecf20Sopenharmony_ci return 0; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_hwops apm821xx_pcie_hwops __initdata = { 11138c2ecf20Sopenharmony_ci .want_sdr = true, 11148c2ecf20Sopenharmony_ci .core_init = apm821xx_pciex_core_init, 11158c2ecf20Sopenharmony_ci .port_init_hw = apm821xx_pciex_init_port_hw, 11168c2ecf20Sopenharmony_ci .setup_utl = ppc460ex_pciex_init_utl, 11178c2ecf20Sopenharmony_ci .check_link = ppc4xx_pciex_check_link_sdr, 11188c2ecf20Sopenharmony_ci}; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic int __init ppc460sx_pciex_core_init(struct device_node *np) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci /* HSS drive amplitude */ 11238c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL0DAMP, 0xB9843211); 11248c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL1DAMP, 0xB9843211); 11258c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL2DAMP, 0xB9843211); 11268c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL3DAMP, 0xB9843211); 11278c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL4DAMP, 0xB9843211); 11288c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL5DAMP, 0xB9843211); 11298c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL6DAMP, 0xB9843211); 11308c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL7DAMP, 0xB9843211); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL0DAMP, 0xB9843211); 11338c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL1DAMP, 0xB9843211); 11348c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL2DAMP, 0xB9843211); 11358c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL3DAMP, 0xB9843211); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL0DAMP, 0xB9843211); 11388c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL1DAMP, 0xB9843211); 11398c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL2DAMP, 0xB9843211); 11408c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL3DAMP, 0xB9843211); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* HSS TX pre-emphasis */ 11438c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL0COEFA, 0xDCB98987); 11448c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL1COEFA, 0xDCB98987); 11458c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL2COEFA, 0xDCB98987); 11468c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL3COEFA, 0xDCB98987); 11478c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL4COEFA, 0xDCB98987); 11488c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL5COEFA, 0xDCB98987); 11498c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL6COEFA, 0xDCB98987); 11508c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL7COEFA, 0xDCB98987); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL0COEFA, 0xDCB98987); 11538c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL1COEFA, 0xDCB98987); 11548c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL2COEFA, 0xDCB98987); 11558c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL3COEFA, 0xDCB98987); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL0COEFA, 0xDCB98987); 11588c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL1COEFA, 0xDCB98987); 11598c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL2COEFA, 0xDCB98987); 11608c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL3COEFA, 0xDCB98987); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* HSS TX calibration control */ 11638c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSL1CALDRV, 0x22222222); 11648c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSL1CALDRV, 0x22220000); 11658c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSL1CALDRV, 0x22220000); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci /* HSS TX slew control */ 11688c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSSLEW, 0xFFFFFFFF); 11698c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_HSSSLEW, 0xFFFF0000); 11708c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSSLEW, 0xFFFF0000); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Set HSS PRBS enabled */ 11738c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_HSSCTLSET, 0x00001130); 11748c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_HSSCTLSET, 0x00001130); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci udelay(100); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* De-assert PLLRESET */ 11798c2ecf20Sopenharmony_ci dcri_clrset(SDR0, PESDR0_PLLLCT2, 0x00000100, 0); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* Reset DL, UTL, GPL before configuration */ 11828c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR0_460SX_RCSSET, 11838c2ecf20Sopenharmony_ci PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU); 11848c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR1_460SX_RCSSET, 11858c2ecf20Sopenharmony_ci PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU); 11868c2ecf20Sopenharmony_ci mtdcri(SDR0, PESDR2_460SX_RCSSET, 11878c2ecf20Sopenharmony_ci PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci udelay(100); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* 11928c2ecf20Sopenharmony_ci * If bifurcation is not enabled, u-boot would have disabled the 11938c2ecf20Sopenharmony_ci * third PCIe port 11948c2ecf20Sopenharmony_ci */ 11958c2ecf20Sopenharmony_ci if (((mfdcri(SDR0, PESDR1_460SX_HSSCTLSET) & 0x00000001) == 11968c2ecf20Sopenharmony_ci 0x00000001)) { 11978c2ecf20Sopenharmony_ci printk(KERN_INFO "PCI: PCIE bifurcation setup successfully.\n"); 11988c2ecf20Sopenharmony_ci printk(KERN_INFO "PCI: Total 3 PCIE ports are present\n"); 11998c2ecf20Sopenharmony_ci return 3; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci printk(KERN_INFO "PCI: Total 2 PCIE ports are present\n"); 12038c2ecf20Sopenharmony_ci return 2; 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cistatic int __init ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (port->endpoint) 12108c2ecf20Sopenharmony_ci dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2, 12118c2ecf20Sopenharmony_ci 0x01000000, 0); 12128c2ecf20Sopenharmony_ci else 12138c2ecf20Sopenharmony_ci dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2, 12148c2ecf20Sopenharmony_ci 0, 0x01000000); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 12178c2ecf20Sopenharmony_ci (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL), 12188c2ecf20Sopenharmony_ci PESDRx_RCSSET_RSTPYN); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci port->has_ibpre = 1; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci return ppc4xx_pciex_port_reset_sdr(port); 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci /* Max 128 Bytes */ 12288c2ecf20Sopenharmony_ci out_be32 (port->utl_base + PEUTL_PBBSZ, 0x00000000); 12298c2ecf20Sopenharmony_ci /* Assert VRB and TXE - per datasheet turn off addr validation */ 12308c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PCTL, 0x80800000); 12318c2ecf20Sopenharmony_ci return 0; 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cistatic void __init ppc460sx_pciex_check_link(struct ppc4xx_pciex_port *port) 12358c2ecf20Sopenharmony_ci{ 12368c2ecf20Sopenharmony_ci void __iomem *mbase; 12378c2ecf20Sopenharmony_ci int attempt = 50; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci port->link = 0; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); 12428c2ecf20Sopenharmony_ci if (mbase == NULL) { 12438c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't map internal config space !", 12448c2ecf20Sopenharmony_ci port->node); 12458c2ecf20Sopenharmony_ci return; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci while (attempt && (0 == (in_le32(mbase + PECFG_460SX_DLLSTA) 12498c2ecf20Sopenharmony_ci & PECFG_460SX_DLLSTA_LINKUP))) { 12508c2ecf20Sopenharmony_ci attempt--; 12518c2ecf20Sopenharmony_ci mdelay(10); 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci if (attempt) 12548c2ecf20Sopenharmony_ci port->link = 1; 12558c2ecf20Sopenharmony_ci iounmap(mbase); 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = { 12598c2ecf20Sopenharmony_ci .want_sdr = true, 12608c2ecf20Sopenharmony_ci .core_init = ppc460sx_pciex_core_init, 12618c2ecf20Sopenharmony_ci .port_init_hw = ppc460sx_pciex_init_port_hw, 12628c2ecf20Sopenharmony_ci .setup_utl = ppc460sx_pciex_init_utl, 12638c2ecf20Sopenharmony_ci .check_link = ppc460sx_pciex_check_link, 12648c2ecf20Sopenharmony_ci}; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci#endif /* CONFIG_44x */ 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci#ifdef CONFIG_40x 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_cistatic int __init ppc405ex_pciex_core_init(struct device_node *np) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci /* Nothing to do, return 2 ports */ 12738c2ecf20Sopenharmony_ci return 2; 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cistatic void ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci /* Assert the PE0_PHY reset */ 12798c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01010000); 12808c2ecf20Sopenharmony_ci msleep(1); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci /* deassert the PE0_hotreset */ 12838c2ecf20Sopenharmony_ci if (port->endpoint) 12848c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01111000); 12858c2ecf20Sopenharmony_ci else 12868c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01101000); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci /* poll for phy !reset */ 12898c2ecf20Sopenharmony_ci /* XXX FIXME add timeout */ 12908c2ecf20Sopenharmony_ci while (!(mfdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSTA) & 0x00001000)) 12918c2ecf20Sopenharmony_ci ; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* deassert the PE0_gpl_utl_reset */ 12948c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000); 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic int __init ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci u32 val; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if (port->endpoint) 13028c2ecf20Sopenharmony_ci val = PTYPE_LEGACY_ENDPOINT; 13038c2ecf20Sopenharmony_ci else 13048c2ecf20Sopenharmony_ci val = PTYPE_ROOT_PORT; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, 13078c2ecf20Sopenharmony_ci 1 << 24 | val << 20 | LNKW_X1 << 12); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000); 13108c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000); 13118c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET1, 0x720F0000); 13128c2ecf20Sopenharmony_ci mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET2, 0x70600003); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* 13158c2ecf20Sopenharmony_ci * Only reset the PHY when no link is currently established. 13168c2ecf20Sopenharmony_ci * This is for the Atheros PCIe board which has problems to establish 13178c2ecf20Sopenharmony_ci * the link (again) after this PHY reset. All other currently tested 13188c2ecf20Sopenharmony_ci * PCIe boards don't show this problem. 13198c2ecf20Sopenharmony_ci * This has to be re-tested and fixed in a later release! 13208c2ecf20Sopenharmony_ci */ 13218c2ecf20Sopenharmony_ci val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); 13228c2ecf20Sopenharmony_ci if (!(val & 0x00001000)) 13238c2ecf20Sopenharmony_ci ppc405ex_pcie_phy_reset(port); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_CFG, 0x10000000); /* guarded on */ 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci port->has_ibpre = 1; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci return ppc4xx_pciex_port_reset_sdr(port); 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci /* 13378c2ecf20Sopenharmony_ci * Set buffer allocations and then assert VRB and TXE. 13388c2ecf20Sopenharmony_ci */ 13398c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_OUTTR, 0x02000000); 13408c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_INTR, 0x02000000); 13418c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_OPDBSZ, 0x04000000); 13428c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PBBSZ, 0x21000000); 13438c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_IPHBSZ, 0x02000000); 13448c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_IPDBSZ, 0x04000000); 13458c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000); 13468c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PCTL, 0x80800066); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_PBCTL, 0x08000000); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci return 0; 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata = 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci .want_sdr = true, 13568c2ecf20Sopenharmony_ci .core_init = ppc405ex_pciex_core_init, 13578c2ecf20Sopenharmony_ci .port_init_hw = ppc405ex_pciex_init_port_hw, 13588c2ecf20Sopenharmony_ci .setup_utl = ppc405ex_pciex_init_utl, 13598c2ecf20Sopenharmony_ci .check_link = ppc4xx_pciex_check_link_sdr, 13608c2ecf20Sopenharmony_ci}; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci#endif /* CONFIG_40x */ 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci#ifdef CONFIG_476FPE 13658c2ecf20Sopenharmony_cistatic int __init ppc_476fpe_pciex_core_init(struct device_node *np) 13668c2ecf20Sopenharmony_ci{ 13678c2ecf20Sopenharmony_ci return 4; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic void __init ppc_476fpe_pciex_check_link(struct ppc4xx_pciex_port *port) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci u32 timeout_ms = 20; 13738c2ecf20Sopenharmony_ci u32 val = 0, mask = (PECFG_TLDLP_LNKUP|PECFG_TLDLP_PRESENT); 13748c2ecf20Sopenharmony_ci void __iomem *mbase = ioremap(port->cfg_space.start + 0x10000000, 13758c2ecf20Sopenharmony_ci 0x1000); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: Checking link...\n", port->index); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (mbase == NULL) { 13808c2ecf20Sopenharmony_ci printk(KERN_WARNING "PCIE%d: failed to get cfg space\n", 13818c2ecf20Sopenharmony_ci port->index); 13828c2ecf20Sopenharmony_ci return; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci while (timeout_ms--) { 13868c2ecf20Sopenharmony_ci val = in_le32(mbase + PECFG_TLDLP); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if ((val & mask) == mask) 13898c2ecf20Sopenharmony_ci break; 13908c2ecf20Sopenharmony_ci msleep(10); 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (val & PECFG_TLDLP_PRESENT) { 13948c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: link is up !\n", port->index); 13958c2ecf20Sopenharmony_ci port->link = 1; 13968c2ecf20Sopenharmony_ci } else 13978c2ecf20Sopenharmony_ci printk(KERN_WARNING "PCIE%d: Link up failed\n", port->index); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci iounmap(mbase); 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic struct ppc4xx_pciex_hwops ppc_476fpe_pcie_hwops __initdata = 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci .core_init = ppc_476fpe_pciex_core_init, 14058c2ecf20Sopenharmony_ci .check_link = ppc_476fpe_pciex_check_link, 14068c2ecf20Sopenharmony_ci}; 14078c2ecf20Sopenharmony_ci#endif /* CONFIG_476FPE */ 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci/* Check that the core has been initied and if not, do it */ 14108c2ecf20Sopenharmony_cistatic int __init ppc4xx_pciex_check_core_init(struct device_node *np) 14118c2ecf20Sopenharmony_ci{ 14128c2ecf20Sopenharmony_ci static int core_init; 14138c2ecf20Sopenharmony_ci int count = -ENODEV; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (core_init++) 14168c2ecf20Sopenharmony_ci return 0; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci#ifdef CONFIG_44x 14198c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "ibm,plb-pciex-440spe")) { 14208c2ecf20Sopenharmony_ci if (ppc440spe_revA()) 14218c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops; 14228c2ecf20Sopenharmony_ci else 14238c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "ibm,plb-pciex-460ex")) 14268c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops; 14278c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "ibm,plb-pciex-460sx")) 14288c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops; 14298c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx")) 14308c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops = &apm821xx_pcie_hwops; 14318c2ecf20Sopenharmony_ci#endif /* CONFIG_44x */ 14328c2ecf20Sopenharmony_ci#ifdef CONFIG_40x 14338c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) 14348c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops; 14358c2ecf20Sopenharmony_ci#endif 14368c2ecf20Sopenharmony_ci#ifdef CONFIG_476FPE 14378c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe") 14388c2ecf20Sopenharmony_ci || of_device_is_compatible(np, "ibm,plb-pciex-476gtr")) 14398c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops = &ppc_476fpe_pcie_hwops; 14408c2ecf20Sopenharmony_ci#endif 14418c2ecf20Sopenharmony_ci if (ppc4xx_pciex_hwops == NULL) { 14428c2ecf20Sopenharmony_ci printk(KERN_WARNING "PCIE: unknown host type %pOF\n", np); 14438c2ecf20Sopenharmony_ci return -ENODEV; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci count = ppc4xx_pciex_hwops->core_init(np); 14478c2ecf20Sopenharmony_ci if (count > 0) { 14488c2ecf20Sopenharmony_ci ppc4xx_pciex_ports = 14498c2ecf20Sopenharmony_ci kcalloc(count, sizeof(struct ppc4xx_pciex_port), 14508c2ecf20Sopenharmony_ci GFP_KERNEL); 14518c2ecf20Sopenharmony_ci if (ppc4xx_pciex_ports) { 14528c2ecf20Sopenharmony_ci ppc4xx_pciex_port_count = count; 14538c2ecf20Sopenharmony_ci return 0; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci printk(KERN_WARNING "PCIE: failed to allocate ports array\n"); 14568c2ecf20Sopenharmony_ci return -ENOMEM; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci return -ENODEV; 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_cistatic void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port) 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci /* We map PCI Express configuration based on the reg property */ 14648c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_CFGBAH, 14658c2ecf20Sopenharmony_ci RES_TO_U32_HIGH(port->cfg_space.start)); 14668c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_CFGBAL, 14678c2ecf20Sopenharmony_ci RES_TO_U32_LOW(port->cfg_space.start)); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci /* XXX FIXME: Use size from reg property. For now, map 512M */ 14708c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_CFGMSK, 0xe0000001); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci /* We map UTL registers based on the reg property */ 14738c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_REGBAH, 14748c2ecf20Sopenharmony_ci RES_TO_U32_HIGH(port->utl_regs.start)); 14758c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_REGBAL, 14768c2ecf20Sopenharmony_ci RES_TO_U32_LOW(port->utl_regs.start)); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* XXX FIXME: Use size from reg property */ 14798c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_REGMSK, 0x00007001); 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci /* Disable all other outbound windows */ 14828c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 0); 14838c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, 0); 14848c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0); 14858c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_cistatic int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) 14898c2ecf20Sopenharmony_ci{ 14908c2ecf20Sopenharmony_ci int rc = 0; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* Init HW */ 14938c2ecf20Sopenharmony_ci if (ppc4xx_pciex_hwops->port_init_hw) 14948c2ecf20Sopenharmony_ci rc = ppc4xx_pciex_hwops->port_init_hw(port); 14958c2ecf20Sopenharmony_ci if (rc != 0) 14968c2ecf20Sopenharmony_ci return rc; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci /* 14998c2ecf20Sopenharmony_ci * Initialize mapping: disable all regions and configure 15008c2ecf20Sopenharmony_ci * CFG and REG regions based on resources in the device tree 15018c2ecf20Sopenharmony_ci */ 15028c2ecf20Sopenharmony_ci ppc4xx_pciex_port_init_mapping(port); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci if (ppc4xx_pciex_hwops->check_link) 15058c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops->check_link(port); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* 15088c2ecf20Sopenharmony_ci * Map UTL 15098c2ecf20Sopenharmony_ci */ 15108c2ecf20Sopenharmony_ci port->utl_base = ioremap(port->utl_regs.start, 0x100); 15118c2ecf20Sopenharmony_ci BUG_ON(port->utl_base == NULL); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci /* 15148c2ecf20Sopenharmony_ci * Setup UTL registers --BenH. 15158c2ecf20Sopenharmony_ci */ 15168c2ecf20Sopenharmony_ci if (ppc4xx_pciex_hwops->setup_utl) 15178c2ecf20Sopenharmony_ci ppc4xx_pciex_hwops->setup_utl(port); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* 15208c2ecf20Sopenharmony_ci * Check for VC0 active or PLL Locked and assert RDY. 15218c2ecf20Sopenharmony_ci */ 15228c2ecf20Sopenharmony_ci if (port->sdr_base) { 15238c2ecf20Sopenharmony_ci if (of_device_is_compatible(port->node, 15248c2ecf20Sopenharmony_ci "ibm,plb-pciex-460sx")){ 15258c2ecf20Sopenharmony_ci if (port->link && ppc4xx_pciex_wait_on_sdr(port, 15268c2ecf20Sopenharmony_ci PESDRn_RCSSTS, 15278c2ecf20Sopenharmony_ci 1 << 12, 1 << 12, 5000)) { 15288c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: PLL not locked\n", 15298c2ecf20Sopenharmony_ci port->index); 15308c2ecf20Sopenharmony_ci port->link = 0; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci } else if (port->link && 15338c2ecf20Sopenharmony_ci ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 15348c2ecf20Sopenharmony_ci 1 << 16, 1 << 16, 5000)) { 15358c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: VC0 not active\n", 15368c2ecf20Sopenharmony_ci port->index); 15378c2ecf20Sopenharmony_ci port->link = 0; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20); 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci msleep(100); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci return 0; 15468c2ecf20Sopenharmony_ci} 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_cistatic int ppc4xx_pciex_validate_bdf(struct ppc4xx_pciex_port *port, 15498c2ecf20Sopenharmony_ci struct pci_bus *bus, 15508c2ecf20Sopenharmony_ci unsigned int devfn) 15518c2ecf20Sopenharmony_ci{ 15528c2ecf20Sopenharmony_ci static int message; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci /* Endpoint can not generate upstream(remote) config cycles */ 15558c2ecf20Sopenharmony_ci if (port->endpoint && bus->number != port->hose->first_busno) 15568c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci /* Check we are within the mapped range */ 15598c2ecf20Sopenharmony_ci if (bus->number > port->hose->last_busno) { 15608c2ecf20Sopenharmony_ci if (!message) { 15618c2ecf20Sopenharmony_ci printk(KERN_WARNING "Warning! Probing bus %u" 15628c2ecf20Sopenharmony_ci " out of range !\n", bus->number); 15638c2ecf20Sopenharmony_ci message++; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* The root complex has only one device / function */ 15698c2ecf20Sopenharmony_ci if (bus->number == port->hose->first_busno && devfn != 0) 15708c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci /* The other side of the RC has only one device as well */ 15738c2ecf20Sopenharmony_ci if (bus->number == (port->hose->first_busno + 1) && 15748c2ecf20Sopenharmony_ci PCI_SLOT(devfn) != 0) 15758c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci /* Check if we have a link */ 15788c2ecf20Sopenharmony_ci if ((bus->number != port->hose->first_busno) && !port->link) 15798c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci return 0; 15828c2ecf20Sopenharmony_ci} 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_cistatic void __iomem *ppc4xx_pciex_get_config_base(struct ppc4xx_pciex_port *port, 15858c2ecf20Sopenharmony_ci struct pci_bus *bus, 15868c2ecf20Sopenharmony_ci unsigned int devfn) 15878c2ecf20Sopenharmony_ci{ 15888c2ecf20Sopenharmony_ci int relbus; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci /* Remove the casts when we finally remove the stupid volatile 15918c2ecf20Sopenharmony_ci * in struct pci_controller 15928c2ecf20Sopenharmony_ci */ 15938c2ecf20Sopenharmony_ci if (bus->number == port->hose->first_busno) 15948c2ecf20Sopenharmony_ci return (void __iomem *)port->hose->cfg_addr; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci relbus = bus->number - (port->hose->first_busno + 1); 15978c2ecf20Sopenharmony_ci return (void __iomem *)port->hose->cfg_data + 15988c2ecf20Sopenharmony_ci ((relbus << 20) | (devfn << 12)); 15998c2ecf20Sopenharmony_ci} 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_cistatic int ppc4xx_pciex_read_config(struct pci_bus *bus, unsigned int devfn, 16028c2ecf20Sopenharmony_ci int offset, int len, u32 *val) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci struct pci_controller *hose = pci_bus_to_host(bus); 16058c2ecf20Sopenharmony_ci struct ppc4xx_pciex_port *port = 16068c2ecf20Sopenharmony_ci &ppc4xx_pciex_ports[hose->indirect_type]; 16078c2ecf20Sopenharmony_ci void __iomem *addr; 16088c2ecf20Sopenharmony_ci u32 gpl_cfg; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci BUG_ON(hose != port->hose); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) 16138c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci addr = ppc4xx_pciex_get_config_base(port, bus, devfn); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci /* 16188c2ecf20Sopenharmony_ci * Reading from configuration space of non-existing device can 16198c2ecf20Sopenharmony_ci * generate transaction errors. For the read duration we suppress 16208c2ecf20Sopenharmony_ci * assertion of machine check exceptions to avoid those. 16218c2ecf20Sopenharmony_ci */ 16228c2ecf20Sopenharmony_ci gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG); 16238c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci /* Make sure no CRS is recorded */ 16268c2ecf20Sopenharmony_ci out_be32(port->utl_base + PEUTL_RCSTA, 0x00040000); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci switch (len) { 16298c2ecf20Sopenharmony_ci case 1: 16308c2ecf20Sopenharmony_ci *val = in_8((u8 *)(addr + offset)); 16318c2ecf20Sopenharmony_ci break; 16328c2ecf20Sopenharmony_ci case 2: 16338c2ecf20Sopenharmony_ci *val = in_le16((u16 *)(addr + offset)); 16348c2ecf20Sopenharmony_ci break; 16358c2ecf20Sopenharmony_ci default: 16368c2ecf20Sopenharmony_ci *val = in_le32((u32 *)(addr + offset)); 16378c2ecf20Sopenharmony_ci break; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci pr_debug("pcie-config-read: bus=%3d [%3d..%3d] devfn=0x%04x" 16418c2ecf20Sopenharmony_ci " offset=0x%04x len=%d, addr=0x%p val=0x%08x\n", 16428c2ecf20Sopenharmony_ci bus->number, hose->first_busno, hose->last_busno, 16438c2ecf20Sopenharmony_ci devfn, offset, len, addr + offset, *val); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* Check for CRS (440SPe rev B does that for us but heh ..) */ 16468c2ecf20Sopenharmony_ci if (in_be32(port->utl_base + PEUTL_RCSTA) & 0x00040000) { 16478c2ecf20Sopenharmony_ci pr_debug("Got CRS !\n"); 16488c2ecf20Sopenharmony_ci if (len != 4 || offset != 0) 16498c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 16508c2ecf20Sopenharmony_ci *val = 0xffff0001; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg); 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic int ppc4xx_pciex_write_config(struct pci_bus *bus, unsigned int devfn, 16598c2ecf20Sopenharmony_ci int offset, int len, u32 val) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci struct pci_controller *hose = pci_bus_to_host(bus); 16628c2ecf20Sopenharmony_ci struct ppc4xx_pciex_port *port = 16638c2ecf20Sopenharmony_ci &ppc4xx_pciex_ports[hose->indirect_type]; 16648c2ecf20Sopenharmony_ci void __iomem *addr; 16658c2ecf20Sopenharmony_ci u32 gpl_cfg; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) 16688c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci addr = ppc4xx_pciex_get_config_base(port, bus, devfn); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci /* 16738c2ecf20Sopenharmony_ci * Reading from configuration space of non-existing device can 16748c2ecf20Sopenharmony_ci * generate transaction errors. For the read duration we suppress 16758c2ecf20Sopenharmony_ci * assertion of machine check exceptions to avoid those. 16768c2ecf20Sopenharmony_ci */ 16778c2ecf20Sopenharmony_ci gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG); 16788c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci pr_debug("pcie-config-write: bus=%3d [%3d..%3d] devfn=0x%04x" 16818c2ecf20Sopenharmony_ci " offset=0x%04x len=%d, addr=0x%p val=0x%08x\n", 16828c2ecf20Sopenharmony_ci bus->number, hose->first_busno, hose->last_busno, 16838c2ecf20Sopenharmony_ci devfn, offset, len, addr + offset, val); 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci switch (len) { 16868c2ecf20Sopenharmony_ci case 1: 16878c2ecf20Sopenharmony_ci out_8((u8 *)(addr + offset), val); 16888c2ecf20Sopenharmony_ci break; 16898c2ecf20Sopenharmony_ci case 2: 16908c2ecf20Sopenharmony_ci out_le16((u16 *)(addr + offset), val); 16918c2ecf20Sopenharmony_ci break; 16928c2ecf20Sopenharmony_ci default: 16938c2ecf20Sopenharmony_ci out_le32((u32 *)(addr + offset), val); 16948c2ecf20Sopenharmony_ci break; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic struct pci_ops ppc4xx_pciex_pci_ops = 17038c2ecf20Sopenharmony_ci{ 17048c2ecf20Sopenharmony_ci .read = ppc4xx_pciex_read_config, 17058c2ecf20Sopenharmony_ci .write = ppc4xx_pciex_write_config, 17068c2ecf20Sopenharmony_ci}; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_cistatic int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, 17098c2ecf20Sopenharmony_ci struct pci_controller *hose, 17108c2ecf20Sopenharmony_ci void __iomem *mbase, 17118c2ecf20Sopenharmony_ci u64 plb_addr, 17128c2ecf20Sopenharmony_ci u64 pci_addr, 17138c2ecf20Sopenharmony_ci u64 size, 17148c2ecf20Sopenharmony_ci unsigned int flags, 17158c2ecf20Sopenharmony_ci int index) 17168c2ecf20Sopenharmony_ci{ 17178c2ecf20Sopenharmony_ci u32 lah, lal, pciah, pcial, sa; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (!is_power_of_2(size) || 17208c2ecf20Sopenharmony_ci (index < 2 && size < 0x100000) || 17218c2ecf20Sopenharmony_ci (index == 2 && size < 0x100) || 17228c2ecf20Sopenharmony_ci (plb_addr & (size - 1)) != 0) { 17238c2ecf20Sopenharmony_ci printk(KERN_WARNING "%pOF: Resource out of range\n", hose->dn); 17248c2ecf20Sopenharmony_ci return -1; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci /* Calculate register values */ 17288c2ecf20Sopenharmony_ci lah = RES_TO_U32_HIGH(plb_addr); 17298c2ecf20Sopenharmony_ci lal = RES_TO_U32_LOW(plb_addr); 17308c2ecf20Sopenharmony_ci pciah = RES_TO_U32_HIGH(pci_addr); 17318c2ecf20Sopenharmony_ci pcial = RES_TO_U32_LOW(pci_addr); 17328c2ecf20Sopenharmony_ci sa = (0xffffffffu << ilog2(size)) | 0x1; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci /* Program register values */ 17358c2ecf20Sopenharmony_ci switch (index) { 17368c2ecf20Sopenharmony_ci case 0: 17378c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_POM0LAH, pciah); 17388c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_POM0LAL, pcial); 17398c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); 17408c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); 17418c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); 17428c2ecf20Sopenharmony_ci /*Enabled and single region */ 17438c2ecf20Sopenharmony_ci if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) 17448c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 17458c2ecf20Sopenharmony_ci sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT 17468c2ecf20Sopenharmony_ci | DCRO_PEGPL_OMRxMSKL_VAL); 17478c2ecf20Sopenharmony_ci else if (of_device_is_compatible( 17488c2ecf20Sopenharmony_ci port->node, "ibm,plb-pciex-476fpe") || 17498c2ecf20Sopenharmony_ci of_device_is_compatible( 17508c2ecf20Sopenharmony_ci port->node, "ibm,plb-pciex-476gtr")) 17518c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 17528c2ecf20Sopenharmony_ci sa | DCRO_PEGPL_476FPE_OMR1MSKL_UOT 17538c2ecf20Sopenharmony_ci | DCRO_PEGPL_OMRxMSKL_VAL); 17548c2ecf20Sopenharmony_ci else 17558c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 17568c2ecf20Sopenharmony_ci sa | DCRO_PEGPL_OMR1MSKL_UOT 17578c2ecf20Sopenharmony_ci | DCRO_PEGPL_OMRxMSKL_VAL); 17588c2ecf20Sopenharmony_ci break; 17598c2ecf20Sopenharmony_ci case 1: 17608c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_POM1LAH, pciah); 17618c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_POM1LAL, pcial); 17628c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); 17638c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); 17648c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); 17658c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, 17668c2ecf20Sopenharmony_ci sa | DCRO_PEGPL_OMRxMSKL_VAL); 17678c2ecf20Sopenharmony_ci break; 17688c2ecf20Sopenharmony_ci case 2: 17698c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_POM2LAH, pciah); 17708c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_POM2LAL, pcial); 17718c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); 17728c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); 17738c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); 17748c2ecf20Sopenharmony_ci /* Note that 3 here means enabled | IO space !!! */ 17758c2ecf20Sopenharmony_ci dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 17768c2ecf20Sopenharmony_ci sa | DCRO_PEGPL_OMR3MSKL_IO 17778c2ecf20Sopenharmony_ci | DCRO_PEGPL_OMRxMSKL_VAL); 17788c2ecf20Sopenharmony_ci break; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci return 0; 17828c2ecf20Sopenharmony_ci} 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_cistatic void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, 17858c2ecf20Sopenharmony_ci struct pci_controller *hose, 17868c2ecf20Sopenharmony_ci void __iomem *mbase) 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci int i, j, found_isa_hole = 0; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci /* Setup outbound memory windows */ 17918c2ecf20Sopenharmony_ci for (i = j = 0; i < 3; i++) { 17928c2ecf20Sopenharmony_ci struct resource *res = &hose->mem_resources[i]; 17938c2ecf20Sopenharmony_ci resource_size_t offset = hose->mem_offset[i]; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci /* we only care about memory windows */ 17968c2ecf20Sopenharmony_ci if (!(res->flags & IORESOURCE_MEM)) 17978c2ecf20Sopenharmony_ci continue; 17988c2ecf20Sopenharmony_ci if (j > 1) { 17998c2ecf20Sopenharmony_ci printk(KERN_WARNING "%pOF: Too many ranges\n", 18008c2ecf20Sopenharmony_ci port->node); 18018c2ecf20Sopenharmony_ci break; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci /* Configure the resource */ 18058c2ecf20Sopenharmony_ci if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, 18068c2ecf20Sopenharmony_ci res->start, 18078c2ecf20Sopenharmony_ci res->start - offset, 18088c2ecf20Sopenharmony_ci resource_size(res), 18098c2ecf20Sopenharmony_ci res->flags, 18108c2ecf20Sopenharmony_ci j) == 0) { 18118c2ecf20Sopenharmony_ci j++; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci /* If the resource PCI address is 0 then we have our 18148c2ecf20Sopenharmony_ci * ISA memory hole 18158c2ecf20Sopenharmony_ci */ 18168c2ecf20Sopenharmony_ci if (res->start == offset) 18178c2ecf20Sopenharmony_ci found_isa_hole = 1; 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* Handle ISA memory hole if not already covered */ 18228c2ecf20Sopenharmony_ci if (j <= 1 && !found_isa_hole && hose->isa_mem_size) 18238c2ecf20Sopenharmony_ci if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, 18248c2ecf20Sopenharmony_ci hose->isa_mem_phys, 0, 18258c2ecf20Sopenharmony_ci hose->isa_mem_size, 0, j) == 0) 18268c2ecf20Sopenharmony_ci printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n", 18278c2ecf20Sopenharmony_ci hose->dn); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci /* Configure IO, always 64K starting at 0. We hard wire it to 64K ! 18308c2ecf20Sopenharmony_ci * Note also that it -has- to be region index 2 on this HW 18318c2ecf20Sopenharmony_ci */ 18328c2ecf20Sopenharmony_ci if (hose->io_resource.flags & IORESOURCE_IO) 18338c2ecf20Sopenharmony_ci ppc4xx_setup_one_pciex_POM(port, hose, mbase, 18348c2ecf20Sopenharmony_ci hose->io_base_phys, 0, 18358c2ecf20Sopenharmony_ci 0x10000, IORESOURCE_IO, 2); 18368c2ecf20Sopenharmony_ci} 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_cistatic void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, 18398c2ecf20Sopenharmony_ci struct pci_controller *hose, 18408c2ecf20Sopenharmony_ci void __iomem *mbase, 18418c2ecf20Sopenharmony_ci struct resource *res) 18428c2ecf20Sopenharmony_ci{ 18438c2ecf20Sopenharmony_ci resource_size_t size = resource_size(res); 18448c2ecf20Sopenharmony_ci u64 sa; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci if (port->endpoint) { 18478c2ecf20Sopenharmony_ci resource_size_t ep_addr = 0; 18488c2ecf20Sopenharmony_ci resource_size_t ep_size = 32 << 20; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci /* Currently we map a fixed 64MByte window to PLB address 18518c2ecf20Sopenharmony_ci * 0 (SDRAM). This should probably be configurable via a dts 18528c2ecf20Sopenharmony_ci * property. 18538c2ecf20Sopenharmony_ci */ 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* Calculate window size */ 18568c2ecf20Sopenharmony_ci sa = (0xffffffffffffffffull << ilog2(ep_size)); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci /* Setup BAR0 */ 18598c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); 18608c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa) | 18618c2ecf20Sopenharmony_ci PCI_BASE_ADDRESS_MEM_TYPE_64); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci /* Disable BAR1 & BAR2 */ 18648c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_BAR1MPA, 0); 18658c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_BAR2HMPA, 0); 18668c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_BAR2LMPA, 0); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIM01SAH, RES_TO_U32_HIGH(sa)); 18698c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIM01SAL, RES_TO_U32_LOW(sa)); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(ep_addr)); 18728c2ecf20Sopenharmony_ci out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr)); 18738c2ecf20Sopenharmony_ci } else { 18748c2ecf20Sopenharmony_ci /* Calculate window size */ 18758c2ecf20Sopenharmony_ci sa = (0xffffffffffffffffull << ilog2(size)); 18768c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_PREFETCH) 18778c2ecf20Sopenharmony_ci sa |= PCI_BASE_ADDRESS_MEM_PREFETCH; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx") || 18808c2ecf20Sopenharmony_ci of_device_is_compatible( 18818c2ecf20Sopenharmony_ci port->node, "ibm,plb-pciex-476fpe") || 18828c2ecf20Sopenharmony_ci of_device_is_compatible( 18838c2ecf20Sopenharmony_ci port->node, "ibm,plb-pciex-476gtr")) 18848c2ecf20Sopenharmony_ci sa |= PCI_BASE_ADDRESS_MEM_TYPE_64; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); 18878c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci /* The setup of the split looks weird to me ... let's see 18908c2ecf20Sopenharmony_ci * if it works 18918c2ecf20Sopenharmony_ci */ 18928c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIM0LAL, 0x00000000); 18938c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIM0LAH, 0x00000000); 18948c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIM1LAL, 0x00000000); 18958c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIM1LAH, 0x00000000); 18968c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); 18978c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIM01SAL, 0x00000000); 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start)); 19008c2ecf20Sopenharmony_ci out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start)); 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci /* Enable inbound mapping */ 19048c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIMEN, 0x1); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci /* Enable I/O, Mem, and Busmaster cycles */ 19078c2ecf20Sopenharmony_ci out_le16(mbase + PCI_COMMAND, 19088c2ecf20Sopenharmony_ci in_le16(mbase + PCI_COMMAND) | 19098c2ecf20Sopenharmony_ci PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cistatic void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci struct resource dma_window; 19158c2ecf20Sopenharmony_ci struct pci_controller *hose = NULL; 19168c2ecf20Sopenharmony_ci const int *bus_range; 19178c2ecf20Sopenharmony_ci int primary = 0, busses; 19188c2ecf20Sopenharmony_ci void __iomem *mbase = NULL, *cfg_data = NULL; 19198c2ecf20Sopenharmony_ci const u32 *pval; 19208c2ecf20Sopenharmony_ci u32 val; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci /* Check if primary bridge */ 19238c2ecf20Sopenharmony_ci if (of_get_property(port->node, "primary", NULL)) 19248c2ecf20Sopenharmony_ci primary = 1; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci /* Get bus range if any */ 19278c2ecf20Sopenharmony_ci bus_range = of_get_property(port->node, "bus-range", NULL); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci /* Allocate the host controller data structure */ 19308c2ecf20Sopenharmony_ci hose = pcibios_alloc_controller(port->node); 19318c2ecf20Sopenharmony_ci if (!hose) 19328c2ecf20Sopenharmony_ci goto fail; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci /* We stick the port number in "indirect_type" so the config space 19358c2ecf20Sopenharmony_ci * ops can retrieve the port data structure easily 19368c2ecf20Sopenharmony_ci */ 19378c2ecf20Sopenharmony_ci hose->indirect_type = port->index; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci /* Get bus range */ 19408c2ecf20Sopenharmony_ci hose->first_busno = bus_range ? bus_range[0] : 0x0; 19418c2ecf20Sopenharmony_ci hose->last_busno = bus_range ? bus_range[1] : 0xff; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci /* Because of how big mapping the config space is (1M per bus), we 19448c2ecf20Sopenharmony_ci * limit how many busses we support. In the long run, we could replace 19458c2ecf20Sopenharmony_ci * that with something akin to kmap_atomic instead. We set aside 1 bus 19468c2ecf20Sopenharmony_ci * for the host itself too. 19478c2ecf20Sopenharmony_ci */ 19488c2ecf20Sopenharmony_ci busses = hose->last_busno - hose->first_busno; /* This is off by 1 */ 19498c2ecf20Sopenharmony_ci if (busses > MAX_PCIE_BUS_MAPPED) { 19508c2ecf20Sopenharmony_ci busses = MAX_PCIE_BUS_MAPPED; 19518c2ecf20Sopenharmony_ci hose->last_busno = hose->first_busno + busses; 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci if (!port->endpoint) { 19558c2ecf20Sopenharmony_ci /* Only map the external config space in cfg_data for 19568c2ecf20Sopenharmony_ci * PCIe root-complexes. External space is 1M per bus 19578c2ecf20Sopenharmony_ci */ 19588c2ecf20Sopenharmony_ci cfg_data = ioremap(port->cfg_space.start + 19598c2ecf20Sopenharmony_ci (hose->first_busno + 1) * 0x100000, 19608c2ecf20Sopenharmony_ci busses * 0x100000); 19618c2ecf20Sopenharmony_ci if (cfg_data == NULL) { 19628c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't map external config space !", 19638c2ecf20Sopenharmony_ci port->node); 19648c2ecf20Sopenharmony_ci goto fail; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci hose->cfg_data = cfg_data; 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci /* Always map the host config space in cfg_addr. 19708c2ecf20Sopenharmony_ci * Internal space is 4K 19718c2ecf20Sopenharmony_ci */ 19728c2ecf20Sopenharmony_ci mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); 19738c2ecf20Sopenharmony_ci if (mbase == NULL) { 19748c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't map internal config space !", 19758c2ecf20Sopenharmony_ci port->node); 19768c2ecf20Sopenharmony_ci goto fail; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci hose->cfg_addr = mbase; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci pr_debug("PCIE %pOF, bus %d..%d\n", port->node, 19818c2ecf20Sopenharmony_ci hose->first_busno, hose->last_busno); 19828c2ecf20Sopenharmony_ci pr_debug(" config space mapped at: root @0x%p, other @0x%p\n", 19838c2ecf20Sopenharmony_ci hose->cfg_addr, hose->cfg_data); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci /* Setup config space */ 19868c2ecf20Sopenharmony_ci hose->ops = &ppc4xx_pciex_pci_ops; 19878c2ecf20Sopenharmony_ci port->hose = hose; 19888c2ecf20Sopenharmony_ci mbase = (void __iomem *)hose->cfg_addr; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci if (!port->endpoint) { 19918c2ecf20Sopenharmony_ci /* 19928c2ecf20Sopenharmony_ci * Set bus numbers on our root port 19938c2ecf20Sopenharmony_ci */ 19948c2ecf20Sopenharmony_ci out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); 19958c2ecf20Sopenharmony_ci out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); 19968c2ecf20Sopenharmony_ci out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci /* 20008c2ecf20Sopenharmony_ci * OMRs are already reset, also disable PIMs 20018c2ecf20Sopenharmony_ci */ 20028c2ecf20Sopenharmony_ci out_le32(mbase + PECFG_PIMEN, 0); 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci /* Parse outbound mapping resources */ 20058c2ecf20Sopenharmony_ci pci_process_bridge_OF_ranges(hose, port->node, primary); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* Parse inbound mapping resources */ 20088c2ecf20Sopenharmony_ci if (ppc4xx_parse_dma_ranges(hose, mbase, &dma_window) != 0) 20098c2ecf20Sopenharmony_ci goto fail; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci /* Configure outbound ranges POMs */ 20128c2ecf20Sopenharmony_ci ppc4xx_configure_pciex_POMs(port, hose, mbase); 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci /* Configure inbound ranges PIMs */ 20158c2ecf20Sopenharmony_ci ppc4xx_configure_pciex_PIMs(port, hose, mbase, &dma_window); 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci /* The root complex doesn't show up if we don't set some vendor 20188c2ecf20Sopenharmony_ci * and device IDs into it. The defaults below are the same bogus 20198c2ecf20Sopenharmony_ci * one that the initial code in arch/ppc had. This can be 20208c2ecf20Sopenharmony_ci * overwritten by setting the "vendor-id/device-id" properties 20218c2ecf20Sopenharmony_ci * in the pciex node. 20228c2ecf20Sopenharmony_ci */ 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci /* Get the (optional) vendor-/device-id from the device-tree */ 20258c2ecf20Sopenharmony_ci pval = of_get_property(port->node, "vendor-id", NULL); 20268c2ecf20Sopenharmony_ci if (pval) { 20278c2ecf20Sopenharmony_ci val = *pval; 20288c2ecf20Sopenharmony_ci } else { 20298c2ecf20Sopenharmony_ci if (!port->endpoint) 20308c2ecf20Sopenharmony_ci val = 0xaaa0 + port->index; 20318c2ecf20Sopenharmony_ci else 20328c2ecf20Sopenharmony_ci val = 0xeee0 + port->index; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci out_le16(mbase + 0x200, val); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci pval = of_get_property(port->node, "device-id", NULL); 20378c2ecf20Sopenharmony_ci if (pval) { 20388c2ecf20Sopenharmony_ci val = *pval; 20398c2ecf20Sopenharmony_ci } else { 20408c2ecf20Sopenharmony_ci if (!port->endpoint) 20418c2ecf20Sopenharmony_ci val = 0xbed0 + port->index; 20428c2ecf20Sopenharmony_ci else 20438c2ecf20Sopenharmony_ci val = 0xfed0 + port->index; 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci out_le16(mbase + 0x202, val); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci /* Enable Bus master, memory, and io space */ 20488c2ecf20Sopenharmony_ci if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) 20498c2ecf20Sopenharmony_ci out_le16(mbase + 0x204, 0x7); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci if (!port->endpoint) { 20528c2ecf20Sopenharmony_ci /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ 20538c2ecf20Sopenharmony_ci out_le32(mbase + 0x208, 0x06040001); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", 20568c2ecf20Sopenharmony_ci port->index); 20578c2ecf20Sopenharmony_ci } else { 20588c2ecf20Sopenharmony_ci /* Set Class Code to Processor/PPC */ 20598c2ecf20Sopenharmony_ci out_le32(mbase + 0x208, 0x0b200001); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: successfully set as endpoint\n", 20628c2ecf20Sopenharmony_ci port->index); 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci return; 20668c2ecf20Sopenharmony_ci fail: 20678c2ecf20Sopenharmony_ci if (hose) 20688c2ecf20Sopenharmony_ci pcibios_free_controller(hose); 20698c2ecf20Sopenharmony_ci if (cfg_data) 20708c2ecf20Sopenharmony_ci iounmap(cfg_data); 20718c2ecf20Sopenharmony_ci if (mbase) 20728c2ecf20Sopenharmony_ci iounmap(mbase); 20738c2ecf20Sopenharmony_ci} 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_cistatic void __init ppc4xx_probe_pciex_bridge(struct device_node *np) 20768c2ecf20Sopenharmony_ci{ 20778c2ecf20Sopenharmony_ci struct ppc4xx_pciex_port *port; 20788c2ecf20Sopenharmony_ci const u32 *pval; 20798c2ecf20Sopenharmony_ci int portno; 20808c2ecf20Sopenharmony_ci unsigned int dcrs; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci /* First, proceed to core initialization as we assume there's 20838c2ecf20Sopenharmony_ci * only one PCIe core in the system 20848c2ecf20Sopenharmony_ci */ 20858c2ecf20Sopenharmony_ci if (ppc4xx_pciex_check_core_init(np)) 20868c2ecf20Sopenharmony_ci return; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci /* Get the port number from the device-tree */ 20898c2ecf20Sopenharmony_ci pval = of_get_property(np, "port", NULL); 20908c2ecf20Sopenharmony_ci if (pval == NULL) { 20918c2ecf20Sopenharmony_ci printk(KERN_ERR "PCIE: Can't find port number for %pOF\n", np); 20928c2ecf20Sopenharmony_ci return; 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci portno = *pval; 20958c2ecf20Sopenharmony_ci if (portno >= ppc4xx_pciex_port_count) { 20968c2ecf20Sopenharmony_ci printk(KERN_ERR "PCIE: port number out of range for %pOF\n", 20978c2ecf20Sopenharmony_ci np); 20988c2ecf20Sopenharmony_ci return; 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci port = &ppc4xx_pciex_ports[portno]; 21018c2ecf20Sopenharmony_ci port->index = portno; 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci /* 21048c2ecf20Sopenharmony_ci * Check if device is enabled 21058c2ecf20Sopenharmony_ci */ 21068c2ecf20Sopenharmony_ci if (!of_device_is_available(np)) { 21078c2ecf20Sopenharmony_ci printk(KERN_INFO "PCIE%d: Port disabled via device-tree\n", port->index); 21088c2ecf20Sopenharmony_ci return; 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci port->node = of_node_get(np); 21128c2ecf20Sopenharmony_ci if (ppc4xx_pciex_hwops->want_sdr) { 21138c2ecf20Sopenharmony_ci pval = of_get_property(np, "sdr-base", NULL); 21148c2ecf20Sopenharmony_ci if (pval == NULL) { 21158c2ecf20Sopenharmony_ci printk(KERN_ERR "PCIE: missing sdr-base for %pOF\n", 21168c2ecf20Sopenharmony_ci np); 21178c2ecf20Sopenharmony_ci return; 21188c2ecf20Sopenharmony_ci } 21198c2ecf20Sopenharmony_ci port->sdr_base = *pval; 21208c2ecf20Sopenharmony_ci } 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci /* Check if device_type property is set to "pci" or "pci-endpoint". 21238c2ecf20Sopenharmony_ci * Resulting from this setup this PCIe port will be configured 21248c2ecf20Sopenharmony_ci * as root-complex or as endpoint. 21258c2ecf20Sopenharmony_ci */ 21268c2ecf20Sopenharmony_ci if (of_node_is_type(port->node, "pci-endpoint")) { 21278c2ecf20Sopenharmony_ci port->endpoint = 1; 21288c2ecf20Sopenharmony_ci } else if (of_node_is_type(port->node, "pci")) { 21298c2ecf20Sopenharmony_ci port->endpoint = 0; 21308c2ecf20Sopenharmony_ci } else { 21318c2ecf20Sopenharmony_ci printk(KERN_ERR "PCIE: missing or incorrect device_type for %pOF\n", 21328c2ecf20Sopenharmony_ci np); 21338c2ecf20Sopenharmony_ci return; 21348c2ecf20Sopenharmony_ci } 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci /* Fetch config space registers address */ 21378c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 0, &port->cfg_space)) { 21388c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't get PCI-E config space !", np); 21398c2ecf20Sopenharmony_ci return; 21408c2ecf20Sopenharmony_ci } 21418c2ecf20Sopenharmony_ci /* Fetch host bridge internal registers address */ 21428c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 1, &port->utl_regs)) { 21438c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't get UTL register base !", np); 21448c2ecf20Sopenharmony_ci return; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* Map DCRs */ 21488c2ecf20Sopenharmony_ci dcrs = dcr_resource_start(np, 0); 21498c2ecf20Sopenharmony_ci if (dcrs == 0) { 21508c2ecf20Sopenharmony_ci printk(KERN_ERR "%pOF: Can't get DCR register base !", np); 21518c2ecf20Sopenharmony_ci return; 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci port->dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0)); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci /* Initialize the port specific registers */ 21568c2ecf20Sopenharmony_ci if (ppc4xx_pciex_port_init(port)) { 21578c2ecf20Sopenharmony_ci printk(KERN_WARNING "PCIE%d: Port init failed\n", port->index); 21588c2ecf20Sopenharmony_ci return; 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci /* Setup the linux hose data structure */ 21628c2ecf20Sopenharmony_ci ppc4xx_pciex_port_setup_hose(port); 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC4xx_PCI_EXPRESS */ 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_cistatic int __init ppc4xx_pci_find_bridges(void) 21688c2ecf20Sopenharmony_ci{ 21698c2ecf20Sopenharmony_ci struct device_node *np; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci pci_add_flags(PCI_ENABLE_PROC_DOMAINS | PCI_COMPAT_DOMAIN_0); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC4xx_PCI_EXPRESS 21748c2ecf20Sopenharmony_ci for_each_compatible_node(np, NULL, "ibm,plb-pciex") 21758c2ecf20Sopenharmony_ci ppc4xx_probe_pciex_bridge(np); 21768c2ecf20Sopenharmony_ci#endif 21778c2ecf20Sopenharmony_ci for_each_compatible_node(np, NULL, "ibm,plb-pcix") 21788c2ecf20Sopenharmony_ci ppc4xx_probe_pcix_bridge(np); 21798c2ecf20Sopenharmony_ci for_each_compatible_node(np, NULL, "ibm,plb-pci") 21808c2ecf20Sopenharmony_ci ppc4xx_probe_pci_bridge(np); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci return 0; 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ciarch_initcall(ppc4xx_pci_find_bridges); 21858c2ecf20Sopenharmony_ci 2186