162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * MPC83xx/85xx/86xx PCI/PCIE support routing.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2007-2012 Freescale Semiconductor, Inc.
662306a36Sopenharmony_ci * Copyright 2008-2009 MontaVista Software, Inc.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Initial author: Xianghua Xiao <x.xiao@freescale.com>
962306a36Sopenharmony_ci * Recode: ZHANG WEI <wei.zhang@freescale.com>
1062306a36Sopenharmony_ci * Rewrite the routing for Frescale PCI and PCI Express
1162306a36Sopenharmony_ci * 	Roy Zang <tie-fei.zang@freescale.com>
1262306a36Sopenharmony_ci * MPC83xx PCI-Express support:
1362306a36Sopenharmony_ci * 	Tony Li <tony.li@freescale.com>
1462306a36Sopenharmony_ci * 	Anton Vorontsov <avorontsov@ru.mvista.com>
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/pci.h>
1862306a36Sopenharmony_ci#include <linux/delay.h>
1962306a36Sopenharmony_ci#include <linux/string.h>
2062306a36Sopenharmony_ci#include <linux/fsl/edac.h>
2162306a36Sopenharmony_ci#include <linux/init.h>
2262306a36Sopenharmony_ci#include <linux/interrupt.h>
2362306a36Sopenharmony_ci#include <linux/memblock.h>
2462306a36Sopenharmony_ci#include <linux/log2.h>
2562306a36Sopenharmony_ci#include <linux/of_address.h>
2662306a36Sopenharmony_ci#include <linux/of_irq.h>
2762306a36Sopenharmony_ci#include <linux/platform_device.h>
2862306a36Sopenharmony_ci#include <linux/slab.h>
2962306a36Sopenharmony_ci#include <linux/suspend.h>
3062306a36Sopenharmony_ci#include <linux/syscore_ops.h>
3162306a36Sopenharmony_ci#include <linux/uaccess.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <asm/io.h>
3462306a36Sopenharmony_ci#include <asm/pci-bridge.h>
3562306a36Sopenharmony_ci#include <asm/ppc-pci.h>
3662306a36Sopenharmony_ci#include <asm/machdep.h>
3762306a36Sopenharmony_ci#include <asm/mpc85xx.h>
3862306a36Sopenharmony_ci#include <asm/disassemble.h>
3962306a36Sopenharmony_ci#include <asm/ppc-opcode.h>
4062306a36Sopenharmony_ci#include <asm/swiotlb.h>
4162306a36Sopenharmony_ci#include <asm/setup.h>
4262306a36Sopenharmony_ci#include <sysdev/fsl_soc.h>
4362306a36Sopenharmony_ci#include <sysdev/fsl_pci.h>
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int fsl_pcie_bus_fixup, is_mpc83xx_pci;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic void quirk_fsl_pcie_early(struct pci_dev *dev)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	u8 hdr_type;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* if we aren't a PCIe don't bother */
5262306a36Sopenharmony_ci	if (!pci_is_pcie(dev))
5362306a36Sopenharmony_ci		return;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* if we aren't in host mode don't bother */
5662306a36Sopenharmony_ci	pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
5762306a36Sopenharmony_ci	if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
5862306a36Sopenharmony_ci		return;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
6162306a36Sopenharmony_ci	fsl_pcie_bus_fixup = 1;
6262306a36Sopenharmony_ci	return;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic int fsl_indirect_read_config(struct pci_bus *, unsigned int,
6662306a36Sopenharmony_ci				    int, int, u32 *);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int fsl_pcie_check_link(struct pci_controller *hose)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	u32 val = 0;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (hose->indirect_type & PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK) {
7362306a36Sopenharmony_ci		if (hose->ops->read == fsl_indirect_read_config)
7462306a36Sopenharmony_ci			__indirect_read_config(hose, hose->first_busno, 0,
7562306a36Sopenharmony_ci					       PCIE_LTSSM, 4, &val);
7662306a36Sopenharmony_ci		else
7762306a36Sopenharmony_ci			early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
7862306a36Sopenharmony_ci		if (val < PCIE_LTSSM_L0)
7962306a36Sopenharmony_ci			return 1;
8062306a36Sopenharmony_ci	} else {
8162306a36Sopenharmony_ci		struct ccsr_pci __iomem *pci = hose->private_data;
8262306a36Sopenharmony_ci		/* for PCIe IP rev 3.0 or greater use CSR0 for link state */
8362306a36Sopenharmony_ci		val = (in_be32(&pci->pex_csr0) & PEX_CSR0_LTSSM_MASK)
8462306a36Sopenharmony_ci				>> PEX_CSR0_LTSSM_SHIFT;
8562306a36Sopenharmony_ci		if (val != PEX_CSR0_LTSSM_L0)
8662306a36Sopenharmony_ci			return 1;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return 0;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic int fsl_indirect_read_config(struct pci_bus *bus, unsigned int devfn,
9362306a36Sopenharmony_ci				    int offset, int len, u32 *val)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(bus);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (fsl_pcie_check_link(hose))
9862306a36Sopenharmony_ci		hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
9962306a36Sopenharmony_ci	else
10062306a36Sopenharmony_ci		hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return indirect_read_config(bus, devfn, offset, len, val);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic struct pci_ops fsl_indirect_pcie_ops =
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	.read = fsl_indirect_read_config,
11062306a36Sopenharmony_ci	.write = indirect_write_config,
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic u64 pci64_dma_offset;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#ifdef CONFIG_SWIOTLB
11662306a36Sopenharmony_cistatic void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(pdev->bus);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	pdev->dev.bus_dma_limit =
12162306a36Sopenharmony_ci		hose->dma_window_base_cur + hose->dma_window_size - 1;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void setup_swiotlb_ops(struct pci_controller *hose)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	if (ppc_swiotlb_enable)
12762306a36Sopenharmony_ci		hose->controller_ops.dma_dev_setup = pci_dma_dev_setup_swiotlb;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci#else
13062306a36Sopenharmony_cistatic inline void setup_swiotlb_ops(struct pci_controller *hose) {}
13162306a36Sopenharmony_ci#endif
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	/*
13662306a36Sopenharmony_ci	 * Fix up PCI devices that are able to DMA to the large inbound
13762306a36Sopenharmony_ci	 * mapping that allows addressing any RAM address from across PCI.
13862306a36Sopenharmony_ci	 */
13962306a36Sopenharmony_ci	if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) {
14062306a36Sopenharmony_ci		dev->bus_dma_limit = 0;
14162306a36Sopenharmony_ci		dev->archdata.dma_offset = pci64_dma_offset;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int setup_one_atmu(struct ccsr_pci __iomem *pci,
14662306a36Sopenharmony_ci	unsigned int index, const struct resource *res,
14762306a36Sopenharmony_ci	resource_size_t offset)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	resource_size_t pci_addr = res->start - offset;
15062306a36Sopenharmony_ci	resource_size_t phys_addr = res->start;
15162306a36Sopenharmony_ci	resource_size_t size = resource_size(res);
15262306a36Sopenharmony_ci	u32 flags = 0x80044000; /* enable & mem R/W */
15362306a36Sopenharmony_ci	unsigned int i;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	pr_debug("PCI MEM resource start 0x%016llx, size 0x%016llx.\n",
15662306a36Sopenharmony_ci		(u64)res->start, (u64)size);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (res->flags & IORESOURCE_PREFETCH)
15962306a36Sopenharmony_ci		flags |= 0x10000000; /* enable relaxed ordering */
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	for (i = 0; size > 0; i++) {
16262306a36Sopenharmony_ci		unsigned int bits = min_t(u32, ilog2(size),
16362306a36Sopenharmony_ci					__ffs(pci_addr | phys_addr));
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		if (index + i >= 5)
16662306a36Sopenharmony_ci			return -1;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		out_be32(&pci->pow[index + i].potar, pci_addr >> 12);
16962306a36Sopenharmony_ci		out_be32(&pci->pow[index + i].potear, (u64)pci_addr >> 44);
17062306a36Sopenharmony_ci		out_be32(&pci->pow[index + i].powbar, phys_addr >> 12);
17162306a36Sopenharmony_ci		out_be32(&pci->pow[index + i].powar, flags | (bits - 1));
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		pci_addr += (resource_size_t)1U << bits;
17462306a36Sopenharmony_ci		phys_addr += (resource_size_t)1U << bits;
17562306a36Sopenharmony_ci		size -= (resource_size_t)1U << bits;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return i;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic bool is_kdump(void)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct device_node *node;
18462306a36Sopenharmony_ci	bool ret;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	node = of_find_node_by_type(NULL, "memory");
18762306a36Sopenharmony_ci	if (!node) {
18862306a36Sopenharmony_ci		WARN_ON_ONCE(1);
18962306a36Sopenharmony_ci		return false;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	ret = of_property_read_bool(node, "linux,usable-memory");
19362306a36Sopenharmony_ci	of_node_put(node);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return ret;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* atmu setup for fsl pci/pcie controller */
19962306a36Sopenharmony_cistatic void setup_pci_atmu(struct pci_controller *hose)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct ccsr_pci __iomem *pci = hose->private_data;
20262306a36Sopenharmony_ci	int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4;
20362306a36Sopenharmony_ci	u64 mem, sz, paddr_hi = 0;
20462306a36Sopenharmony_ci	u64 offset = 0, paddr_lo = ULLONG_MAX;
20562306a36Sopenharmony_ci	u32 pcicsrbar = 0, pcicsrbar_sz;
20662306a36Sopenharmony_ci	u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
20762306a36Sopenharmony_ci			PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
20862306a36Sopenharmony_ci	const u64 *reg;
20962306a36Sopenharmony_ci	int len;
21062306a36Sopenharmony_ci	bool setup_inbound;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/*
21362306a36Sopenharmony_ci	 * If this is kdump, we don't want to trigger a bunch of PCI
21462306a36Sopenharmony_ci	 * errors by closing the window on in-flight DMA.
21562306a36Sopenharmony_ci	 *
21662306a36Sopenharmony_ci	 * We still run most of the function's logic so that things like
21762306a36Sopenharmony_ci	 * hose->dma_window_size still get set.
21862306a36Sopenharmony_ci	 */
21962306a36Sopenharmony_ci	setup_inbound = !is_kdump();
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (of_device_is_compatible(hose->dn, "fsl,bsc9132-pcie")) {
22262306a36Sopenharmony_ci		/*
22362306a36Sopenharmony_ci		 * BSC9132 Rev1.0 has an issue where all the PEX inbound
22462306a36Sopenharmony_ci		 * windows have implemented the default target value as 0xf
22562306a36Sopenharmony_ci		 * for CCSR space.In all Freescale legacy devices the target
22662306a36Sopenharmony_ci		 * of 0xf is reserved for local memory space. 9132 Rev1.0
22762306a36Sopenharmony_ci		 * now has local memory space mapped to target 0x0 instead of
22862306a36Sopenharmony_ci		 * 0xf. Hence adding a workaround to remove the target 0xf
22962306a36Sopenharmony_ci		 * defined for memory space from Inbound window attributes.
23062306a36Sopenharmony_ci		 */
23162306a36Sopenharmony_ci		piwar &= ~PIWAR_TGI_LOCAL;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
23562306a36Sopenharmony_ci		if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) {
23662306a36Sopenharmony_ci			win_idx = 2;
23762306a36Sopenharmony_ci			start_idx = 0;
23862306a36Sopenharmony_ci			end_idx = 3;
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* Disable all windows (except powar0 since it's ignored) */
24362306a36Sopenharmony_ci	for(i = 1; i < 5; i++)
24462306a36Sopenharmony_ci		out_be32(&pci->pow[i].powar, 0);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (setup_inbound) {
24762306a36Sopenharmony_ci		for (i = start_idx; i < end_idx; i++)
24862306a36Sopenharmony_ci			out_be32(&pci->piw[i].piwar, 0);
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* Setup outbound MEM window */
25262306a36Sopenharmony_ci	for(i = 0, j = 1; i < 3; i++) {
25362306a36Sopenharmony_ci		if (!(hose->mem_resources[i].flags & IORESOURCE_MEM))
25462306a36Sopenharmony_ci			continue;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start);
25762306a36Sopenharmony_ci		paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		/* We assume all memory resources have the same offset */
26062306a36Sopenharmony_ci		offset = hose->mem_offset[i];
26162306a36Sopenharmony_ci		n = setup_one_atmu(pci, j, &hose->mem_resources[i], offset);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		if (n < 0 || j >= 5) {
26462306a36Sopenharmony_ci			pr_err("Ran out of outbound PCI ATMUs for resource %d!\n", i);
26562306a36Sopenharmony_ci			hose->mem_resources[i].flags |= IORESOURCE_DISABLED;
26662306a36Sopenharmony_ci		} else
26762306a36Sopenharmony_ci			j += n;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* Setup outbound IO window */
27162306a36Sopenharmony_ci	if (hose->io_resource.flags & IORESOURCE_IO) {
27262306a36Sopenharmony_ci		if (j >= 5) {
27362306a36Sopenharmony_ci			pr_err("Ran out of outbound PCI ATMUs for IO resource\n");
27462306a36Sopenharmony_ci		} else {
27562306a36Sopenharmony_ci			pr_debug("PCI IO resource start 0x%016llx, size 0x%016llx, "
27662306a36Sopenharmony_ci				 "phy base 0x%016llx.\n",
27762306a36Sopenharmony_ci				 (u64)hose->io_resource.start,
27862306a36Sopenharmony_ci				 (u64)resource_size(&hose->io_resource),
27962306a36Sopenharmony_ci				 (u64)hose->io_base_phys);
28062306a36Sopenharmony_ci			out_be32(&pci->pow[j].potar, (hose->io_resource.start >> 12));
28162306a36Sopenharmony_ci			out_be32(&pci->pow[j].potear, 0);
28262306a36Sopenharmony_ci			out_be32(&pci->pow[j].powbar, (hose->io_base_phys >> 12));
28362306a36Sopenharmony_ci			/* Enable, IO R/W */
28462306a36Sopenharmony_ci			out_be32(&pci->pow[j].powar, 0x80088000
28562306a36Sopenharmony_ci				| (ilog2(hose->io_resource.end
28662306a36Sopenharmony_ci				- hose->io_resource.start + 1) - 1));
28762306a36Sopenharmony_ci		}
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* convert to pci address space */
29162306a36Sopenharmony_ci	paddr_hi -= offset;
29262306a36Sopenharmony_ci	paddr_lo -= offset;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (paddr_hi == paddr_lo) {
29562306a36Sopenharmony_ci		pr_err("%pOF: No outbound window space\n", hose->dn);
29662306a36Sopenharmony_ci		return;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (paddr_lo == 0) {
30062306a36Sopenharmony_ci		pr_err("%pOF: No space for inbound window\n", hose->dn);
30162306a36Sopenharmony_ci		return;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/* setup PCSRBAR/PEXCSRBAR */
30562306a36Sopenharmony_ci	early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff);
30662306a36Sopenharmony_ci	early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
30762306a36Sopenharmony_ci	pcicsrbar_sz = ~pcicsrbar_sz + 1;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (paddr_hi < (0x100000000ull - pcicsrbar_sz) ||
31062306a36Sopenharmony_ci		(paddr_lo > 0x100000000ull))
31162306a36Sopenharmony_ci		pcicsrbar = 0x100000000ull - pcicsrbar_sz;
31262306a36Sopenharmony_ci	else
31362306a36Sopenharmony_ci		pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz;
31462306a36Sopenharmony_ci	early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	paddr_lo = min(paddr_lo, (u64)pcicsrbar);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	pr_info("%pOF: PCICSRBAR @ 0x%x\n", hose->dn, pcicsrbar);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Setup inbound mem window */
32162306a36Sopenharmony_ci	mem = memblock_end_of_DRAM();
32262306a36Sopenharmony_ci	pr_info("%s: end of DRAM %llx\n", __func__, mem);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/*
32562306a36Sopenharmony_ci	 * The msi-address-64 property, if it exists, indicates the physical
32662306a36Sopenharmony_ci	 * address of the MSIIR register.  Normally, this register is located
32762306a36Sopenharmony_ci	 * inside CCSR, so the ATMU that covers all of CCSR is used. But if
32862306a36Sopenharmony_ci	 * this property exists, then we normally need to create a new ATMU
32962306a36Sopenharmony_ci	 * for it.  For now, however, we cheat.  The only entity that creates
33062306a36Sopenharmony_ci	 * this property is the Freescale hypervisor, and the address is
33162306a36Sopenharmony_ci	 * specified in the partition configuration.  Typically, the address
33262306a36Sopenharmony_ci	 * is located in the page immediately after the end of DDR.  If so, we
33362306a36Sopenharmony_ci	 * can avoid allocating a new ATMU by extending the DDR ATMU by one
33462306a36Sopenharmony_ci	 * page.
33562306a36Sopenharmony_ci	 */
33662306a36Sopenharmony_ci	reg = of_get_property(hose->dn, "msi-address-64", &len);
33762306a36Sopenharmony_ci	if (reg && (len == sizeof(u64))) {
33862306a36Sopenharmony_ci		u64 address = be64_to_cpup(reg);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci		if ((address >= mem) && (address < (mem + PAGE_SIZE))) {
34162306a36Sopenharmony_ci			pr_info("%pOF: extending DDR ATMU to cover MSIIR", hose->dn);
34262306a36Sopenharmony_ci			mem += PAGE_SIZE;
34362306a36Sopenharmony_ci		} else {
34462306a36Sopenharmony_ci			/* TODO: Create a new ATMU for MSIIR */
34562306a36Sopenharmony_ci			pr_warn("%pOF: msi-address-64 address of %llx is "
34662306a36Sopenharmony_ci				"unsupported\n", hose->dn, address);
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	sz = min(mem, paddr_lo);
35162306a36Sopenharmony_ci	mem_log = ilog2(sz);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* PCIe can overmap inbound & outbound since RX & TX are separated */
35462306a36Sopenharmony_ci	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
35562306a36Sopenharmony_ci		/* Size window to exact size if power-of-two or one size up */
35662306a36Sopenharmony_ci		if ((1ull << mem_log) != mem) {
35762306a36Sopenharmony_ci			mem_log++;
35862306a36Sopenharmony_ci			if ((1ull << mem_log) > mem)
35962306a36Sopenharmony_ci				pr_info("%pOF: Setting PCI inbound window "
36062306a36Sopenharmony_ci					"greater than memory size\n", hose->dn);
36162306a36Sopenharmony_ci		}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		piwar |= ((mem_log - 1) & PIWAR_SZ_MASK);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		if (setup_inbound) {
36662306a36Sopenharmony_ci			/* Setup inbound memory window */
36762306a36Sopenharmony_ci			out_be32(&pci->piw[win_idx].pitar,  0x00000000);
36862306a36Sopenharmony_ci			out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
36962306a36Sopenharmony_ci			out_be32(&pci->piw[win_idx].piwar,  piwar);
37062306a36Sopenharmony_ci		}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		win_idx--;
37362306a36Sopenharmony_ci		hose->dma_window_base_cur = 0x00000000;
37462306a36Sopenharmony_ci		hose->dma_window_size = (resource_size_t)sz;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		/*
37762306a36Sopenharmony_ci		 * if we have >4G of memory setup second PCI inbound window to
37862306a36Sopenharmony_ci		 * let devices that are 64-bit address capable to work w/o
37962306a36Sopenharmony_ci		 * SWIOTLB and access the full range of memory
38062306a36Sopenharmony_ci		 */
38162306a36Sopenharmony_ci		if (sz != mem) {
38262306a36Sopenharmony_ci			mem_log = ilog2(mem);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci			/* Size window up if we dont fit in exact power-of-2 */
38562306a36Sopenharmony_ci			if ((1ull << mem_log) != mem)
38662306a36Sopenharmony_ci				mem_log++;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci			piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1);
38962306a36Sopenharmony_ci			pci64_dma_offset = 1ULL << mem_log;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci			if (setup_inbound) {
39262306a36Sopenharmony_ci				/* Setup inbound memory window */
39362306a36Sopenharmony_ci				out_be32(&pci->piw[win_idx].pitar,  0x00000000);
39462306a36Sopenharmony_ci				out_be32(&pci->piw[win_idx].piwbear,
39562306a36Sopenharmony_ci						pci64_dma_offset >> 44);
39662306a36Sopenharmony_ci				out_be32(&pci->piw[win_idx].piwbar,
39762306a36Sopenharmony_ci						pci64_dma_offset >> 12);
39862306a36Sopenharmony_ci				out_be32(&pci->piw[win_idx].piwar,  piwar);
39962306a36Sopenharmony_ci			}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci			/*
40262306a36Sopenharmony_ci			 * install our own dma_set_mask handler to fixup dma_ops
40362306a36Sopenharmony_ci			 * and dma_offset
40462306a36Sopenharmony_ci			 */
40562306a36Sopenharmony_ci			ppc_md.dma_set_mask = fsl_pci_dma_set_mask;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci			pr_info("%pOF: Setup 64-bit PCI DMA window\n", hose->dn);
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci	} else {
41062306a36Sopenharmony_ci		u64 paddr = 0;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		if (setup_inbound) {
41362306a36Sopenharmony_ci			/* Setup inbound memory window */
41462306a36Sopenharmony_ci			out_be32(&pci->piw[win_idx].pitar,  paddr >> 12);
41562306a36Sopenharmony_ci			out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
41662306a36Sopenharmony_ci			out_be32(&pci->piw[win_idx].piwar,
41762306a36Sopenharmony_ci				 (piwar | (mem_log - 1)));
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci		win_idx--;
42162306a36Sopenharmony_ci		paddr += 1ull << mem_log;
42262306a36Sopenharmony_ci		sz -= 1ull << mem_log;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		if (sz) {
42562306a36Sopenharmony_ci			mem_log = ilog2(sz);
42662306a36Sopenharmony_ci			piwar |= (mem_log - 1);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci			if (setup_inbound) {
42962306a36Sopenharmony_ci				out_be32(&pci->piw[win_idx].pitar,
43062306a36Sopenharmony_ci					 paddr >> 12);
43162306a36Sopenharmony_ci				out_be32(&pci->piw[win_idx].piwbar,
43262306a36Sopenharmony_ci					 paddr >> 12);
43362306a36Sopenharmony_ci				out_be32(&pci->piw[win_idx].piwar, piwar);
43462306a36Sopenharmony_ci			}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci			win_idx--;
43762306a36Sopenharmony_ci			paddr += 1ull << mem_log;
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		hose->dma_window_base_cur = 0x00000000;
44162306a36Sopenharmony_ci		hose->dma_window_size = (resource_size_t)paddr;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (hose->dma_window_size < mem) {
44562306a36Sopenharmony_ci#ifdef CONFIG_SWIOTLB
44662306a36Sopenharmony_ci		ppc_swiotlb_enable = 1;
44762306a36Sopenharmony_ci#else
44862306a36Sopenharmony_ci		pr_err("%pOF: ERROR: Memory size exceeds PCI ATMU ability to "
44962306a36Sopenharmony_ci			"map - enable CONFIG_SWIOTLB to avoid dma errors.\n",
45062306a36Sopenharmony_ci			 hose->dn);
45162306a36Sopenharmony_ci#endif
45262306a36Sopenharmony_ci		/* adjusting outbound windows could reclaim space in mem map */
45362306a36Sopenharmony_ci		if (paddr_hi < 0xffffffffull)
45462306a36Sopenharmony_ci			pr_warn("%pOF: WARNING: Outbound window cfg leaves "
45562306a36Sopenharmony_ci				"gaps in memory map. Adjusting the memory map "
45662306a36Sopenharmony_ci				"could reduce unnecessary bounce buffering.\n",
45762306a36Sopenharmony_ci				hose->dn);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		pr_info("%pOF: DMA window size is 0x%llx\n", hose->dn,
46062306a36Sopenharmony_ci			(u64)hose->dma_window_size);
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic void setup_pci_cmd(struct pci_controller *hose)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	u16 cmd;
46762306a36Sopenharmony_ci	int cap_x;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd);
47062306a36Sopenharmony_ci	cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
47162306a36Sopenharmony_ci		| PCI_COMMAND_IO;
47262306a36Sopenharmony_ci	early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	cap_x = early_find_capability(hose, 0, 0, PCI_CAP_ID_PCIX);
47562306a36Sopenharmony_ci	if (cap_x) {
47662306a36Sopenharmony_ci		int pci_x_cmd = cap_x + PCI_X_CMD;
47762306a36Sopenharmony_ci		cmd = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
47862306a36Sopenharmony_ci			| PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
47962306a36Sopenharmony_ci		early_write_config_word(hose, 0, 0, pci_x_cmd, cmd);
48062306a36Sopenharmony_ci	} else {
48162306a36Sopenharmony_ci		early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_civoid fsl_pcibios_fixup_bus(struct pci_bus *bus)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(bus);
48862306a36Sopenharmony_ci	int i, is_pcie = 0, no_link;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* The root complex bridge comes up with bogus resources,
49162306a36Sopenharmony_ci	 * we copy the PHB ones in.
49262306a36Sopenharmony_ci	 *
49362306a36Sopenharmony_ci	 * With the current generic PCI code, the PHB bus no longer
49462306a36Sopenharmony_ci	 * has bus->resource[0..4] set, so things are a bit more
49562306a36Sopenharmony_ci	 * tricky.
49662306a36Sopenharmony_ci	 */
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (fsl_pcie_bus_fixup)
49962306a36Sopenharmony_ci		is_pcie = early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP);
50062306a36Sopenharmony_ci	no_link = !!(hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (bus->parent == hose->bus && (is_pcie || no_link)) {
50362306a36Sopenharmony_ci		for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; ++i) {
50462306a36Sopenharmony_ci			struct resource *res = bus->resource[i];
50562306a36Sopenharmony_ci			struct resource *par;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci			if (!res)
50862306a36Sopenharmony_ci				continue;
50962306a36Sopenharmony_ci			if (i == 0)
51062306a36Sopenharmony_ci				par = &hose->io_resource;
51162306a36Sopenharmony_ci			else if (i < 4)
51262306a36Sopenharmony_ci				par = &hose->mem_resources[i-1];
51362306a36Sopenharmony_ci			else par = NULL;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci			res->start = par ? par->start : 0;
51662306a36Sopenharmony_ci			res->end   = par ? par->end   : 0;
51762306a36Sopenharmony_ci			res->flags = par ? par->flags : 0;
51862306a36Sopenharmony_ci		}
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int fsl_add_bridge(struct platform_device *pdev, int is_primary)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	int len;
52562306a36Sopenharmony_ci	struct pci_controller *hose;
52662306a36Sopenharmony_ci	struct resource rsrc;
52762306a36Sopenharmony_ci	const int *bus_range;
52862306a36Sopenharmony_ci	u8 hdr_type, progif;
52962306a36Sopenharmony_ci	u32 class_code;
53062306a36Sopenharmony_ci	struct device_node *dev;
53162306a36Sopenharmony_ci	struct ccsr_pci __iomem *pci;
53262306a36Sopenharmony_ci	u16 temp;
53362306a36Sopenharmony_ci	u32 svr = mfspr(SPRN_SVR);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	dev = pdev->dev.of_node;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (!of_device_is_available(dev)) {
53862306a36Sopenharmony_ci		pr_warn("%pOF: disabled\n", dev);
53962306a36Sopenharmony_ci		return -ENODEV;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	pr_debug("Adding PCI host bridge %pOF\n", dev);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* Fetch host bridge registers address */
54562306a36Sopenharmony_ci	if (of_address_to_resource(dev, 0, &rsrc)) {
54662306a36Sopenharmony_ci		printk(KERN_WARNING "Can't get pci register base!");
54762306a36Sopenharmony_ci		return -ENOMEM;
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	/* Get bus range if any */
55162306a36Sopenharmony_ci	bus_range = of_get_property(dev, "bus-range", &len);
55262306a36Sopenharmony_ci	if (bus_range == NULL || len < 2 * sizeof(int))
55362306a36Sopenharmony_ci		printk(KERN_WARNING "Can't get bus-range for %pOF, assume"
55462306a36Sopenharmony_ci			" bus 0\n", dev);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	pci_add_flags(PCI_REASSIGN_ALL_BUS);
55762306a36Sopenharmony_ci	hose = pcibios_alloc_controller(dev);
55862306a36Sopenharmony_ci	if (!hose)
55962306a36Sopenharmony_ci		return -ENOMEM;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/* set platform device as the parent */
56262306a36Sopenharmony_ci	hose->parent = &pdev->dev;
56362306a36Sopenharmony_ci	hose->first_busno = bus_range ? bus_range[0] : 0x0;
56462306a36Sopenharmony_ci	hose->last_busno = bus_range ? bus_range[1] : 0xff;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
56762306a36Sopenharmony_ci		 (u64)rsrc.start, (u64)resource_size(&rsrc));
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	pci = hose->private_data = ioremap(rsrc.start, resource_size(&rsrc));
57062306a36Sopenharmony_ci	if (!hose->private_data)
57162306a36Sopenharmony_ci		goto no_bridge;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4,
57462306a36Sopenharmony_ci			   PPC_INDIRECT_TYPE_BIG_ENDIAN);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (in_be32(&pci->block_rev1) < PCIE_IP_REV_3_0)
57762306a36Sopenharmony_ci		hose->indirect_type |= PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
58062306a36Sopenharmony_ci		/* use fsl_indirect_read_config for PCIe */
58162306a36Sopenharmony_ci		hose->ops = &fsl_indirect_pcie_ops;
58262306a36Sopenharmony_ci		/* For PCIE read HEADER_TYPE to identify controller mode */
58362306a36Sopenharmony_ci		early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type);
58462306a36Sopenharmony_ci		if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
58562306a36Sopenharmony_ci			goto no_bridge;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	} else {
58862306a36Sopenharmony_ci		/* For PCI read PROG to identify controller mode */
58962306a36Sopenharmony_ci		early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif);
59062306a36Sopenharmony_ci		if ((progif & 1) &&
59162306a36Sopenharmony_ci		    !of_property_read_bool(dev, "fsl,pci-agent-force-enum"))
59262306a36Sopenharmony_ci			goto no_bridge;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	setup_pci_cmd(hose);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* check PCI express link status */
59862306a36Sopenharmony_ci	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
59962306a36Sopenharmony_ci		hose->indirect_type |= PPC_INDIRECT_TYPE_EXT_REG |
60062306a36Sopenharmony_ci			PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
60162306a36Sopenharmony_ci		if (fsl_pcie_check_link(hose))
60262306a36Sopenharmony_ci			hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
60362306a36Sopenharmony_ci		/* Fix Class Code to PCI_CLASS_BRIDGE_PCI_NORMAL for pre-3.0 controller */
60462306a36Sopenharmony_ci		if (in_be32(&pci->block_rev1) < PCIE_IP_REV_3_0) {
60562306a36Sopenharmony_ci			early_read_config_dword(hose, 0, 0, PCIE_FSL_CSR_CLASSCODE, &class_code);
60662306a36Sopenharmony_ci			class_code &= 0xff;
60762306a36Sopenharmony_ci			class_code |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8;
60862306a36Sopenharmony_ci			early_write_config_dword(hose, 0, 0, PCIE_FSL_CSR_CLASSCODE, class_code);
60962306a36Sopenharmony_ci		}
61062306a36Sopenharmony_ci	} else {
61162306a36Sopenharmony_ci		/*
61262306a36Sopenharmony_ci		 * Set PBFR(PCI Bus Function Register)[10] = 1 to
61362306a36Sopenharmony_ci		 * disable the combining of crossing cacheline
61462306a36Sopenharmony_ci		 * boundary requests into one burst transaction.
61562306a36Sopenharmony_ci		 * PCI-X operation is not affected.
61662306a36Sopenharmony_ci		 * Fix erratum PCI 5 on MPC8548
61762306a36Sopenharmony_ci		 */
61862306a36Sopenharmony_ci#define PCI_BUS_FUNCTION 0x44
61962306a36Sopenharmony_ci#define PCI_BUS_FUNCTION_MDS 0x400	/* Master disable streaming */
62062306a36Sopenharmony_ci		if (((SVR_SOC_VER(svr) == SVR_8543) ||
62162306a36Sopenharmony_ci		     (SVR_SOC_VER(svr) == SVR_8545) ||
62262306a36Sopenharmony_ci		     (SVR_SOC_VER(svr) == SVR_8547) ||
62362306a36Sopenharmony_ci		     (SVR_SOC_VER(svr) == SVR_8548)) &&
62462306a36Sopenharmony_ci		    !early_find_capability(hose, 0, 0, PCI_CAP_ID_PCIX)) {
62562306a36Sopenharmony_ci			early_read_config_word(hose, 0, 0,
62662306a36Sopenharmony_ci					PCI_BUS_FUNCTION, &temp);
62762306a36Sopenharmony_ci			temp |= PCI_BUS_FUNCTION_MDS;
62862306a36Sopenharmony_ci			early_write_config_word(hose, 0, 0,
62962306a36Sopenharmony_ci					PCI_BUS_FUNCTION, temp);
63062306a36Sopenharmony_ci		}
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
63462306a36Sopenharmony_ci		"Firmware bus number: %d->%d\n",
63562306a36Sopenharmony_ci		(unsigned long long)rsrc.start, hose->first_busno,
63662306a36Sopenharmony_ci		hose->last_busno);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
63962306a36Sopenharmony_ci		hose, hose->cfg_addr, hose->cfg_data);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	/* Interpret the "ranges" property */
64262306a36Sopenharmony_ci	/* This also maps the I/O region and sets isa_io/mem_base */
64362306a36Sopenharmony_ci	pci_process_bridge_OF_ranges(hose, dev, is_primary);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	/* Setup PEX window registers */
64662306a36Sopenharmony_ci	setup_pci_atmu(hose);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* Set up controller operations */
64962306a36Sopenharmony_ci	setup_swiotlb_ops(hose);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	return 0;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cino_bridge:
65462306a36Sopenharmony_ci	iounmap(hose->private_data);
65562306a36Sopenharmony_ci	/* unmap cfg_data & cfg_addr separately if not on same page */
65662306a36Sopenharmony_ci	if (((unsigned long)hose->cfg_data & PAGE_MASK) !=
65762306a36Sopenharmony_ci	    ((unsigned long)hose->cfg_addr & PAGE_MASK))
65862306a36Sopenharmony_ci		iounmap(hose->cfg_data);
65962306a36Sopenharmony_ci	iounmap(hose->cfg_addr);
66062306a36Sopenharmony_ci	pcibios_free_controller(hose);
66162306a36Sopenharmony_ci	return -ENODEV;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci#endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID,
66662306a36Sopenharmony_ci			quirk_fsl_pcie_early);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
66962306a36Sopenharmony_cistruct mpc83xx_pcie_priv {
67062306a36Sopenharmony_ci	void __iomem *cfg_type0;
67162306a36Sopenharmony_ci	void __iomem *cfg_type1;
67262306a36Sopenharmony_ci	u32 dev_base;
67362306a36Sopenharmony_ci};
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistruct pex_inbound_window {
67662306a36Sopenharmony_ci	u32 ar;
67762306a36Sopenharmony_ci	u32 tar;
67862306a36Sopenharmony_ci	u32 barl;
67962306a36Sopenharmony_ci	u32 barh;
68062306a36Sopenharmony_ci};
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci/*
68362306a36Sopenharmony_ci * With the convention of u-boot, the PCIE outbound window 0 serves
68462306a36Sopenharmony_ci * as configuration transactions outbound.
68562306a36Sopenharmony_ci */
68662306a36Sopenharmony_ci#define PEX_OUTWIN0_BAR		0xCA4
68762306a36Sopenharmony_ci#define PEX_OUTWIN0_TAL		0xCA8
68862306a36Sopenharmony_ci#define PEX_OUTWIN0_TAH		0xCAC
68962306a36Sopenharmony_ci#define PEX_RC_INWIN_BASE	0xE60
69062306a36Sopenharmony_ci#define PEX_RCIWARn_EN		0x1
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(bus);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK)
69762306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
69862306a36Sopenharmony_ci	/*
69962306a36Sopenharmony_ci	 * Workaround for the HW bug: for Type 0 configure transactions the
70062306a36Sopenharmony_ci	 * PCI-E controller does not check the device number bits and just
70162306a36Sopenharmony_ci	 * assumes that the device number bits are 0.
70262306a36Sopenharmony_ci	 */
70362306a36Sopenharmony_ci	if (bus->number == hose->first_busno ||
70462306a36Sopenharmony_ci			bus->primary == hose->first_busno) {
70562306a36Sopenharmony_ci		if (devfn & 0xf8)
70662306a36Sopenharmony_ci			return PCIBIOS_DEVICE_NOT_FOUND;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (ppc_md.pci_exclude_device) {
71062306a36Sopenharmony_ci		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
71162306a36Sopenharmony_ci			return PCIBIOS_DEVICE_NOT_FOUND;
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic void __iomem *mpc83xx_pcie_remap_cfg(struct pci_bus *bus,
71862306a36Sopenharmony_ci					    unsigned int devfn, int offset)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(bus);
72162306a36Sopenharmony_ci	struct mpc83xx_pcie_priv *pcie = hose->dn->data;
72262306a36Sopenharmony_ci	u32 dev_base = bus->number << 24 | devfn << 16;
72362306a36Sopenharmony_ci	int ret;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	ret = mpc83xx_pcie_exclude_device(bus, devfn);
72662306a36Sopenharmony_ci	if (ret)
72762306a36Sopenharmony_ci		return NULL;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	offset &= 0xfff;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* Type 0 */
73262306a36Sopenharmony_ci	if (bus->number == hose->first_busno)
73362306a36Sopenharmony_ci		return pcie->cfg_type0 + offset;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	if (pcie->dev_base == dev_base)
73662306a36Sopenharmony_ci		goto mapped;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, dev_base);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	pcie->dev_base = dev_base;
74162306a36Sopenharmony_cimapped:
74262306a36Sopenharmony_ci	return pcie->cfg_type1 + offset;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic int mpc83xx_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
74662306a36Sopenharmony_ci				     int offset, int len, u32 val)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(bus);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS */
75162306a36Sopenharmony_ci	if (offset == PCI_PRIMARY_BUS && bus->number == hose->first_busno)
75262306a36Sopenharmony_ci		val &= 0xffffff00;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	return pci_generic_config_write(bus, devfn, offset, len, val);
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic struct pci_ops mpc83xx_pcie_ops = {
75862306a36Sopenharmony_ci	.map_bus = mpc83xx_pcie_remap_cfg,
75962306a36Sopenharmony_ci	.read = pci_generic_config_read,
76062306a36Sopenharmony_ci	.write = mpc83xx_pcie_write_config,
76162306a36Sopenharmony_ci};
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic int __init mpc83xx_pcie_setup(struct pci_controller *hose,
76462306a36Sopenharmony_ci				     struct resource *reg)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	struct mpc83xx_pcie_priv *pcie;
76762306a36Sopenharmony_ci	u32 cfg_bar;
76862306a36Sopenharmony_ci	int ret = -ENOMEM;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
77162306a36Sopenharmony_ci	if (!pcie)
77262306a36Sopenharmony_ci		return ret;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	pcie->cfg_type0 = ioremap(reg->start, resource_size(reg));
77562306a36Sopenharmony_ci	if (!pcie->cfg_type0)
77662306a36Sopenharmony_ci		goto err0;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	cfg_bar = in_le32(pcie->cfg_type0 + PEX_OUTWIN0_BAR);
77962306a36Sopenharmony_ci	if (!cfg_bar) {
78062306a36Sopenharmony_ci		/* PCI-E isn't configured. */
78162306a36Sopenharmony_ci		ret = -ENODEV;
78262306a36Sopenharmony_ci		goto err1;
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	pcie->cfg_type1 = ioremap(cfg_bar, 0x1000);
78662306a36Sopenharmony_ci	if (!pcie->cfg_type1)
78762306a36Sopenharmony_ci		goto err1;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	WARN_ON(hose->dn->data);
79062306a36Sopenharmony_ci	hose->dn->data = pcie;
79162306a36Sopenharmony_ci	hose->ops = &mpc83xx_pcie_ops;
79262306a36Sopenharmony_ci	hose->indirect_type |= PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAH, 0);
79562306a36Sopenharmony_ci	out_le32(pcie->cfg_type0 + PEX_OUTWIN0_TAL, 0);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (fsl_pcie_check_link(hose))
79862306a36Sopenharmony_ci		hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	return 0;
80162306a36Sopenharmony_cierr1:
80262306a36Sopenharmony_ci	iounmap(pcie->cfg_type0);
80362306a36Sopenharmony_cierr0:
80462306a36Sopenharmony_ci	kfree(pcie);
80562306a36Sopenharmony_ci	return ret;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ciint __init mpc83xx_add_bridge(struct device_node *dev)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	int ret;
81262306a36Sopenharmony_ci	int len;
81362306a36Sopenharmony_ci	struct pci_controller *hose;
81462306a36Sopenharmony_ci	struct resource rsrc_reg;
81562306a36Sopenharmony_ci	struct resource rsrc_cfg;
81662306a36Sopenharmony_ci	const int *bus_range;
81762306a36Sopenharmony_ci	int primary;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	is_mpc83xx_pci = 1;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	if (!of_device_is_available(dev)) {
82262306a36Sopenharmony_ci		pr_warn("%pOF: disabled by the firmware.\n",
82362306a36Sopenharmony_ci			dev);
82462306a36Sopenharmony_ci		return -ENODEV;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci	pr_debug("Adding PCI host bridge %pOF\n", dev);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	/* Fetch host bridge registers address */
82962306a36Sopenharmony_ci	if (of_address_to_resource(dev, 0, &rsrc_reg)) {
83062306a36Sopenharmony_ci		printk(KERN_WARNING "Can't get pci register base!\n");
83162306a36Sopenharmony_ci		return -ENOMEM;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	memset(&rsrc_cfg, 0, sizeof(rsrc_cfg));
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (of_address_to_resource(dev, 1, &rsrc_cfg)) {
83762306a36Sopenharmony_ci		printk(KERN_WARNING
83862306a36Sopenharmony_ci			"No pci config register base in dev tree, "
83962306a36Sopenharmony_ci			"using default\n");
84062306a36Sopenharmony_ci		/*
84162306a36Sopenharmony_ci		 * MPC83xx supports up to two host controllers
84262306a36Sopenharmony_ci		 * 	one at 0x8500 has config space registers at 0x8300
84362306a36Sopenharmony_ci		 * 	one at 0x8600 has config space registers at 0x8380
84462306a36Sopenharmony_ci		 */
84562306a36Sopenharmony_ci		if ((rsrc_reg.start & 0xfffff) == 0x8500)
84662306a36Sopenharmony_ci			rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8300;
84762306a36Sopenharmony_ci		else if ((rsrc_reg.start & 0xfffff) == 0x8600)
84862306a36Sopenharmony_ci			rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8380;
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci	/*
85162306a36Sopenharmony_ci	 * Controller at offset 0x8500 is primary
85262306a36Sopenharmony_ci	 */
85362306a36Sopenharmony_ci	if ((rsrc_reg.start & 0xfffff) == 0x8500)
85462306a36Sopenharmony_ci		primary = 1;
85562306a36Sopenharmony_ci	else
85662306a36Sopenharmony_ci		primary = 0;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	/* Get bus range if any */
85962306a36Sopenharmony_ci	bus_range = of_get_property(dev, "bus-range", &len);
86062306a36Sopenharmony_ci	if (bus_range == NULL || len < 2 * sizeof(int)) {
86162306a36Sopenharmony_ci		printk(KERN_WARNING "Can't get bus-range for %pOF, assume"
86262306a36Sopenharmony_ci		       " bus 0\n", dev);
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	pci_add_flags(PCI_REASSIGN_ALL_BUS);
86662306a36Sopenharmony_ci	hose = pcibios_alloc_controller(dev);
86762306a36Sopenharmony_ci	if (!hose)
86862306a36Sopenharmony_ci		return -ENOMEM;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	hose->first_busno = bus_range ? bus_range[0] : 0;
87162306a36Sopenharmony_ci	hose->last_busno = bus_range ? bus_range[1] : 0xff;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (of_device_is_compatible(dev, "fsl,mpc8314-pcie")) {
87462306a36Sopenharmony_ci		ret = mpc83xx_pcie_setup(hose, &rsrc_reg);
87562306a36Sopenharmony_ci		if (ret)
87662306a36Sopenharmony_ci			goto err0;
87762306a36Sopenharmony_ci	} else {
87862306a36Sopenharmony_ci		setup_indirect_pci(hose, rsrc_cfg.start,
87962306a36Sopenharmony_ci				   rsrc_cfg.start + 4, 0);
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
88362306a36Sopenharmony_ci	       "Firmware bus number: %d->%d\n",
88462306a36Sopenharmony_ci	       (unsigned long long)rsrc_reg.start, hose->first_busno,
88562306a36Sopenharmony_ci	       hose->last_busno);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
88862306a36Sopenharmony_ci	    hose, hose->cfg_addr, hose->cfg_data);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	/* Interpret the "ranges" property */
89162306a36Sopenharmony_ci	/* This also maps the I/O region and sets isa_io/mem_base */
89262306a36Sopenharmony_ci	pci_process_bridge_OF_ranges(hose, dev, primary);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	return 0;
89562306a36Sopenharmony_cierr0:
89662306a36Sopenharmony_ci	pcibios_free_controller(hose);
89762306a36Sopenharmony_ci	return ret;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci#endif /* CONFIG_PPC_83xx */
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ciu64 fsl_pci_immrbar_base(struct pci_controller *hose)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci#ifdef CONFIG_PPC_83xx
90462306a36Sopenharmony_ci	if (is_mpc83xx_pci) {
90562306a36Sopenharmony_ci		struct mpc83xx_pcie_priv *pcie = hose->dn->data;
90662306a36Sopenharmony_ci		struct pex_inbound_window *in;
90762306a36Sopenharmony_ci		int i;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci		/* Walk the Root Complex Inbound windows to match IMMR base */
91062306a36Sopenharmony_ci		in = pcie->cfg_type0 + PEX_RC_INWIN_BASE;
91162306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
91262306a36Sopenharmony_ci			/* not enabled, skip */
91362306a36Sopenharmony_ci			if (!(in_le32(&in[i].ar) & PEX_RCIWARn_EN))
91462306a36Sopenharmony_ci				continue;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci			if (get_immrbase() == in_le32(&in[i].tar))
91762306a36Sopenharmony_ci				return (u64)in_le32(&in[i].barh) << 32 |
91862306a36Sopenharmony_ci					    in_le32(&in[i].barl);
91962306a36Sopenharmony_ci		}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci		printk(KERN_WARNING "could not find PCI BAR matching IMMR\n");
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci#endif
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
92662306a36Sopenharmony_ci	if (!is_mpc83xx_pci) {
92762306a36Sopenharmony_ci		u32 base;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		pci_bus_read_config_dword(hose->bus,
93062306a36Sopenharmony_ci			PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		/*
93362306a36Sopenharmony_ci		 * For PEXCSRBAR, bit 3-0 indicate prefetchable and
93462306a36Sopenharmony_ci		 * address type. So when getting base address, these
93562306a36Sopenharmony_ci		 * bits should be masked
93662306a36Sopenharmony_ci		 */
93762306a36Sopenharmony_ci		base &= PCI_BASE_ADDRESS_MEM_MASK;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		return base;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci#endif
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	return 0;
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci#ifdef CONFIG_PPC_E500
94762306a36Sopenharmony_cistatic int mcheck_handle_load(struct pt_regs *regs, u32 inst)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	unsigned int rd, ra, rb, d;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	rd = get_rt(inst);
95262306a36Sopenharmony_ci	ra = get_ra(inst);
95362306a36Sopenharmony_ci	rb = get_rb(inst);
95462306a36Sopenharmony_ci	d = get_d(inst);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	switch (get_op(inst)) {
95762306a36Sopenharmony_ci	case 31:
95862306a36Sopenharmony_ci		switch (get_xop(inst)) {
95962306a36Sopenharmony_ci		case OP_31_XOP_LWZX:
96062306a36Sopenharmony_ci		case OP_31_XOP_LWBRX:
96162306a36Sopenharmony_ci			regs->gpr[rd] = 0xffffffff;
96262306a36Sopenharmony_ci			break;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci		case OP_31_XOP_LWZUX:
96562306a36Sopenharmony_ci			regs->gpr[rd] = 0xffffffff;
96662306a36Sopenharmony_ci			regs->gpr[ra] += regs->gpr[rb];
96762306a36Sopenharmony_ci			break;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		case OP_31_XOP_LBZX:
97062306a36Sopenharmony_ci			regs->gpr[rd] = 0xff;
97162306a36Sopenharmony_ci			break;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci		case OP_31_XOP_LBZUX:
97462306a36Sopenharmony_ci			regs->gpr[rd] = 0xff;
97562306a36Sopenharmony_ci			regs->gpr[ra] += regs->gpr[rb];
97662306a36Sopenharmony_ci			break;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		case OP_31_XOP_LHZX:
97962306a36Sopenharmony_ci		case OP_31_XOP_LHBRX:
98062306a36Sopenharmony_ci			regs->gpr[rd] = 0xffff;
98162306a36Sopenharmony_ci			break;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci		case OP_31_XOP_LHZUX:
98462306a36Sopenharmony_ci			regs->gpr[rd] = 0xffff;
98562306a36Sopenharmony_ci			regs->gpr[ra] += regs->gpr[rb];
98662306a36Sopenharmony_ci			break;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci		case OP_31_XOP_LHAX:
98962306a36Sopenharmony_ci			regs->gpr[rd] = ~0UL;
99062306a36Sopenharmony_ci			break;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		case OP_31_XOP_LHAUX:
99362306a36Sopenharmony_ci			regs->gpr[rd] = ~0UL;
99462306a36Sopenharmony_ci			regs->gpr[ra] += regs->gpr[rb];
99562306a36Sopenharmony_ci			break;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci		default:
99862306a36Sopenharmony_ci			return 0;
99962306a36Sopenharmony_ci		}
100062306a36Sopenharmony_ci		break;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	case OP_LWZ:
100362306a36Sopenharmony_ci		regs->gpr[rd] = 0xffffffff;
100462306a36Sopenharmony_ci		break;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	case OP_LWZU:
100762306a36Sopenharmony_ci		regs->gpr[rd] = 0xffffffff;
100862306a36Sopenharmony_ci		regs->gpr[ra] += (s16)d;
100962306a36Sopenharmony_ci		break;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	case OP_LBZ:
101262306a36Sopenharmony_ci		regs->gpr[rd] = 0xff;
101362306a36Sopenharmony_ci		break;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	case OP_LBZU:
101662306a36Sopenharmony_ci		regs->gpr[rd] = 0xff;
101762306a36Sopenharmony_ci		regs->gpr[ra] += (s16)d;
101862306a36Sopenharmony_ci		break;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	case OP_LHZ:
102162306a36Sopenharmony_ci		regs->gpr[rd] = 0xffff;
102262306a36Sopenharmony_ci		break;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	case OP_LHZU:
102562306a36Sopenharmony_ci		regs->gpr[rd] = 0xffff;
102662306a36Sopenharmony_ci		regs->gpr[ra] += (s16)d;
102762306a36Sopenharmony_ci		break;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	case OP_LHA:
103062306a36Sopenharmony_ci		regs->gpr[rd] = ~0UL;
103162306a36Sopenharmony_ci		break;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	case OP_LHAU:
103462306a36Sopenharmony_ci		regs->gpr[rd] = ~0UL;
103562306a36Sopenharmony_ci		regs->gpr[ra] += (s16)d;
103662306a36Sopenharmony_ci		break;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	default:
103962306a36Sopenharmony_ci		return 0;
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	return 1;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic int is_in_pci_mem_space(phys_addr_t addr)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct pci_controller *hose;
104862306a36Sopenharmony_ci	struct resource *res;
104962306a36Sopenharmony_ci	int i;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	list_for_each_entry(hose, &hose_list, list_node) {
105262306a36Sopenharmony_ci		if (!(hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG))
105362306a36Sopenharmony_ci			continue;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
105662306a36Sopenharmony_ci			res = &hose->mem_resources[i];
105762306a36Sopenharmony_ci			if ((res->flags & IORESOURCE_MEM) &&
105862306a36Sopenharmony_ci				addr >= res->start && addr <= res->end)
105962306a36Sopenharmony_ci				return 1;
106062306a36Sopenharmony_ci		}
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci	return 0;
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ciint fsl_pci_mcheck_exception(struct pt_regs *regs)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	u32 inst;
106862306a36Sopenharmony_ci	int ret;
106962306a36Sopenharmony_ci	phys_addr_t addr = 0;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	/* Let KVM/QEMU deal with the exception */
107262306a36Sopenharmony_ci	if (regs->msr & MSR_GS)
107362306a36Sopenharmony_ci		return 0;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT
107662306a36Sopenharmony_ci	addr = mfspr(SPRN_MCARU);
107762306a36Sopenharmony_ci	addr <<= 32;
107862306a36Sopenharmony_ci#endif
107962306a36Sopenharmony_ci	addr += mfspr(SPRN_MCAR);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	if (is_in_pci_mem_space(addr)) {
108262306a36Sopenharmony_ci		if (user_mode(regs))
108362306a36Sopenharmony_ci			ret = copy_from_user_nofault(&inst,
108462306a36Sopenharmony_ci					(void __user *)regs->nip, sizeof(inst));
108562306a36Sopenharmony_ci		else
108662306a36Sopenharmony_ci			ret = get_kernel_nofault(inst, (void *)regs->nip);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci		if (!ret && mcheck_handle_load(regs, inst)) {
108962306a36Sopenharmony_ci			regs_add_return_ip(regs, 4);
109062306a36Sopenharmony_ci			return 1;
109162306a36Sopenharmony_ci		}
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	return 0;
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci#endif
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
109962306a36Sopenharmony_cistatic const struct of_device_id pci_ids[] = {
110062306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8540-pci", },
110162306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8548-pcie", },
110262306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8610-pci", },
110362306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8641-pcie", },
110462306a36Sopenharmony_ci	{ .compatible = "fsl,qoriq-pcie", },
110562306a36Sopenharmony_ci	{ .compatible = "fsl,qoriq-pcie-v2.1", },
110662306a36Sopenharmony_ci	{ .compatible = "fsl,qoriq-pcie-v2.2", },
110762306a36Sopenharmony_ci	{ .compatible = "fsl,qoriq-pcie-v2.3", },
110862306a36Sopenharmony_ci	{ .compatible = "fsl,qoriq-pcie-v2.4", },
110962306a36Sopenharmony_ci	{ .compatible = "fsl,qoriq-pcie-v3.0", },
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	/*
111262306a36Sopenharmony_ci	 * The following entries are for compatibility with older device
111362306a36Sopenharmony_ci	 * trees.
111462306a36Sopenharmony_ci	 */
111562306a36Sopenharmony_ci	{ .compatible = "fsl,p1022-pcie", },
111662306a36Sopenharmony_ci	{ .compatible = "fsl,p4080-pcie", },
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	{},
111962306a36Sopenharmony_ci};
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_cistruct device_node *fsl_pci_primary;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_civoid __init fsl_pci_assign_primary(void)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	struct device_node *np;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	/* Callers can specify the primary bus using other means. */
112862306a36Sopenharmony_ci	if (fsl_pci_primary)
112962306a36Sopenharmony_ci		return;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* If a PCI host bridge contains an ISA node, it's primary. */
113262306a36Sopenharmony_ci	np = of_find_node_by_type(NULL, "isa");
113362306a36Sopenharmony_ci	while ((fsl_pci_primary = of_get_parent(np))) {
113462306a36Sopenharmony_ci		of_node_put(np);
113562306a36Sopenharmony_ci		np = fsl_pci_primary;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci		if (of_match_node(pci_ids, np) && of_device_is_available(np))
113862306a36Sopenharmony_ci			return;
113962306a36Sopenharmony_ci	}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/*
114262306a36Sopenharmony_ci	 * If there's no PCI host bridge with ISA then check for
114362306a36Sopenharmony_ci	 * PCI host bridge with alias "pci0" (first PCI host bridge).
114462306a36Sopenharmony_ci	 */
114562306a36Sopenharmony_ci	np = of_find_node_by_path("pci0");
114662306a36Sopenharmony_ci	if (np && of_match_node(pci_ids, np) && of_device_is_available(np)) {
114762306a36Sopenharmony_ci		fsl_pci_primary = np;
114862306a36Sopenharmony_ci		of_node_put(np);
114962306a36Sopenharmony_ci		return;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci	if (np)
115262306a36Sopenharmony_ci		of_node_put(np);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	/*
115562306a36Sopenharmony_ci	 * If there's no PCI host bridge with ISA, arbitrarily
115662306a36Sopenharmony_ci	 * designate one as primary.  This can go away once
115762306a36Sopenharmony_ci	 * various bugs with primary-less systems are fixed.
115862306a36Sopenharmony_ci	 */
115962306a36Sopenharmony_ci	for_each_matching_node(np, pci_ids) {
116062306a36Sopenharmony_ci		if (of_device_is_available(np)) {
116162306a36Sopenharmony_ci			fsl_pci_primary = np;
116262306a36Sopenharmony_ci			return;
116362306a36Sopenharmony_ci		}
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
116862306a36Sopenharmony_cistatic irqreturn_t fsl_pci_pme_handle(int irq, void *dev_id)
116962306a36Sopenharmony_ci{
117062306a36Sopenharmony_ci	struct pci_controller *hose = dev_id;
117162306a36Sopenharmony_ci	struct ccsr_pci __iomem *pci = hose->private_data;
117262306a36Sopenharmony_ci	u32 dr;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	dr = in_be32(&pci->pex_pme_mes_dr);
117562306a36Sopenharmony_ci	if (!dr)
117662306a36Sopenharmony_ci		return IRQ_NONE;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	out_be32(&pci->pex_pme_mes_dr, dr);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	return IRQ_HANDLED;
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic int fsl_pci_pme_probe(struct pci_controller *hose)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct ccsr_pci __iomem *pci;
118662306a36Sopenharmony_ci	struct pci_dev *dev;
118762306a36Sopenharmony_ci	int pme_irq;
118862306a36Sopenharmony_ci	int res;
118962306a36Sopenharmony_ci	u16 pms;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	/* Get hose's pci_dev */
119262306a36Sopenharmony_ci	dev = list_first_entry(&hose->bus->devices, typeof(*dev), bus_list);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	/* PME Disable */
119562306a36Sopenharmony_ci	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms);
119662306a36Sopenharmony_ci	pms &= ~PCI_PM_CTRL_PME_ENABLE;
119762306a36Sopenharmony_ci	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	pme_irq = irq_of_parse_and_map(hose->dn, 0);
120062306a36Sopenharmony_ci	if (!pme_irq) {
120162306a36Sopenharmony_ci		dev_err(&dev->dev, "Failed to map PME interrupt.\n");
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci		return -ENXIO;
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	res = devm_request_irq(hose->parent, pme_irq,
120762306a36Sopenharmony_ci			fsl_pci_pme_handle,
120862306a36Sopenharmony_ci			IRQF_SHARED,
120962306a36Sopenharmony_ci			"[PCI] PME", hose);
121062306a36Sopenharmony_ci	if (res < 0) {
121162306a36Sopenharmony_ci		dev_err(&dev->dev, "Unable to request irq %d for PME\n", pme_irq);
121262306a36Sopenharmony_ci		irq_dispose_mapping(pme_irq);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		return -ENODEV;
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	pci = hose->private_data;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	/* Enable PTOD, ENL23D & EXL23D */
122062306a36Sopenharmony_ci	clrbits32(&pci->pex_pme_mes_disr,
122162306a36Sopenharmony_ci		  PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	out_be32(&pci->pex_pme_mes_ier, 0);
122462306a36Sopenharmony_ci	setbits32(&pci->pex_pme_mes_ier,
122562306a36Sopenharmony_ci		  PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	/* PME Enable */
122862306a36Sopenharmony_ci	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms);
122962306a36Sopenharmony_ci	pms |= PCI_PM_CTRL_PME_ENABLE;
123062306a36Sopenharmony_ci	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	return 0;
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic void send_pme_turnoff_message(struct pci_controller *hose)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct ccsr_pci __iomem *pci = hose->private_data;
123862306a36Sopenharmony_ci	u32 dr;
123962306a36Sopenharmony_ci	int i;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	/* Send PME_Turn_Off Message Request */
124262306a36Sopenharmony_ci	setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	/* Wait trun off done */
124562306a36Sopenharmony_ci	for (i = 0; i < 150; i++) {
124662306a36Sopenharmony_ci		dr = in_be32(&pci->pex_pme_mes_dr);
124762306a36Sopenharmony_ci		if (dr) {
124862306a36Sopenharmony_ci			out_be32(&pci->pex_pme_mes_dr, dr);
124962306a36Sopenharmony_ci			break;
125062306a36Sopenharmony_ci		}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci		udelay(1000);
125362306a36Sopenharmony_ci	}
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	send_pme_turnoff_message(hose);
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic int fsl_pci_syscore_suspend(void)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	struct pci_controller *hose, *tmp;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
126662306a36Sopenharmony_ci		fsl_pci_syscore_do_suspend(hose);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	return 0;
126962306a36Sopenharmony_ci}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic void fsl_pci_syscore_do_resume(struct pci_controller *hose)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	struct ccsr_pci __iomem *pci = hose->private_data;
127462306a36Sopenharmony_ci	u32 dr;
127562306a36Sopenharmony_ci	int i;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	/* Send Exit L2 State Message */
127862306a36Sopenharmony_ci	setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	/* Wait exit done */
128162306a36Sopenharmony_ci	for (i = 0; i < 150; i++) {
128262306a36Sopenharmony_ci		dr = in_be32(&pci->pex_pme_mes_dr);
128362306a36Sopenharmony_ci		if (dr) {
128462306a36Sopenharmony_ci			out_be32(&pci->pex_pme_mes_dr, dr);
128562306a36Sopenharmony_ci			break;
128662306a36Sopenharmony_ci		}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci		udelay(1000);
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	setup_pci_atmu(hose);
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_cistatic void fsl_pci_syscore_resume(void)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	struct pci_controller *hose, *tmp;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
129962306a36Sopenharmony_ci		fsl_pci_syscore_do_resume(hose);
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_cistatic struct syscore_ops pci_syscore_pm_ops = {
130362306a36Sopenharmony_ci	.suspend = fsl_pci_syscore_suspend,
130462306a36Sopenharmony_ci	.resume = fsl_pci_syscore_resume,
130562306a36Sopenharmony_ci};
130662306a36Sopenharmony_ci#endif
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_civoid fsl_pcibios_fixup_phb(struct pci_controller *phb)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
131162306a36Sopenharmony_ci	fsl_pci_pme_probe(phb);
131262306a36Sopenharmony_ci#endif
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic int add_err_dev(struct platform_device *pdev)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct platform_device *errdev;
131862306a36Sopenharmony_ci	struct mpc85xx_edac_pci_plat_data pd = {
131962306a36Sopenharmony_ci		.of_node = pdev->dev.of_node
132062306a36Sopenharmony_ci	};
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	errdev = platform_device_register_resndata(&pdev->dev,
132362306a36Sopenharmony_ci						   "mpc85xx-pci-edac",
132462306a36Sopenharmony_ci						   PLATFORM_DEVID_AUTO,
132562306a36Sopenharmony_ci						   pdev->resource,
132662306a36Sopenharmony_ci						   pdev->num_resources,
132762306a36Sopenharmony_ci						   &pd, sizeof(pd));
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(errdev);
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_cistatic int fsl_pci_probe(struct platform_device *pdev)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	struct device_node *node;
133562306a36Sopenharmony_ci	int ret;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	node = pdev->dev.of_node;
133862306a36Sopenharmony_ci	ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
133962306a36Sopenharmony_ci	if (ret)
134062306a36Sopenharmony_ci		return ret;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	ret = add_err_dev(pdev);
134362306a36Sopenharmony_ci	if (ret)
134462306a36Sopenharmony_ci		dev_err(&pdev->dev, "couldn't register error device: %d\n",
134562306a36Sopenharmony_ci			ret);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	return 0;
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic struct platform_driver fsl_pci_driver = {
135162306a36Sopenharmony_ci	.driver = {
135262306a36Sopenharmony_ci		.name = "fsl-pci",
135362306a36Sopenharmony_ci		.of_match_table = pci_ids,
135462306a36Sopenharmony_ci	},
135562306a36Sopenharmony_ci	.probe = fsl_pci_probe,
135662306a36Sopenharmony_ci	.driver_managed_dma = true,
135762306a36Sopenharmony_ci};
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic int __init fsl_pci_init(void)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
136262306a36Sopenharmony_ci	register_syscore_ops(&pci_syscore_pm_ops);
136362306a36Sopenharmony_ci#endif
136462306a36Sopenharmony_ci	return platform_driver_register(&fsl_pci_driver);
136562306a36Sopenharmony_ci}
136662306a36Sopenharmony_ciarch_initcall(fsl_pci_init);
136762306a36Sopenharmony_ci#endif
1368