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