162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
462306a36Sopenharmony_ci *		      IBM Corp.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#undef DEBUG
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/pci.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/string.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/irq.h>
1562306a36Sopenharmony_ci#include <linux/of_irq.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <asm/sections.h>
1862306a36Sopenharmony_ci#include <asm/io.h>
1962306a36Sopenharmony_ci#include <asm/pci-bridge.h>
2062306a36Sopenharmony_ci#include <asm/machdep.h>
2162306a36Sopenharmony_ci#include <asm/iommu.h>
2262306a36Sopenharmony_ci#include <asm/ppc-pci.h>
2362306a36Sopenharmony_ci#include <asm/isa-bridge.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "maple.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#ifdef DEBUG
2862306a36Sopenharmony_ci#define DBG(x...) printk(x)
2962306a36Sopenharmony_ci#else
3062306a36Sopenharmony_ci#define DBG(x...)
3162306a36Sopenharmony_ci#endif
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic struct pci_controller *u3_agp, *u3_ht, *u4_pcie;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic int __init fixup_one_level_bus_range(struct device_node *node, int higher)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	for (; node; node = node->sibling) {
3862306a36Sopenharmony_ci		const int *bus_range;
3962306a36Sopenharmony_ci		const unsigned int *class_code;
4062306a36Sopenharmony_ci		int len;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		/* For PCI<->PCI bridges or CardBus bridges, we go down */
4362306a36Sopenharmony_ci		class_code = of_get_property(node, "class-code", NULL);
4462306a36Sopenharmony_ci		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
4562306a36Sopenharmony_ci			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
4662306a36Sopenharmony_ci			continue;
4762306a36Sopenharmony_ci		bus_range = of_get_property(node, "bus-range", &len);
4862306a36Sopenharmony_ci		if (bus_range != NULL && len > 2 * sizeof(int)) {
4962306a36Sopenharmony_ci			if (bus_range[1] > higher)
5062306a36Sopenharmony_ci				higher = bus_range[1];
5162306a36Sopenharmony_ci		}
5262306a36Sopenharmony_ci		higher = fixup_one_level_bus_range(node->child, higher);
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci	return higher;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* This routine fixes the "bus-range" property of all bridges in the
5862306a36Sopenharmony_ci * system since they tend to have their "last" member wrong on macs
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci * Note that the bus numbers manipulated here are OF bus numbers, they
6162306a36Sopenharmony_ci * are not Linux bus numbers.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistatic void __init fixup_bus_range(struct device_node *bridge)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	int *bus_range;
6662306a36Sopenharmony_ci	struct property *prop;
6762306a36Sopenharmony_ci	int len;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* Lookup the "bus-range" property for the hose */
7062306a36Sopenharmony_ci	prop = of_find_property(bridge, "bus-range", &len);
7162306a36Sopenharmony_ci	if (prop == NULL  || prop->value == NULL || len < 2 * sizeof(int)) {
7262306a36Sopenharmony_ci		printk(KERN_WARNING "Can't get bus-range for %pOF\n",
7362306a36Sopenharmony_ci			       bridge);
7462306a36Sopenharmony_ci		return;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci	bus_range = prop->value;
7762306a36Sopenharmony_ci	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic unsigned long u3_agp_cfa0(u8 devfn, u8 off)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	return (1 << (unsigned long)PCI_SLOT(devfn)) |
8462306a36Sopenharmony_ci		((unsigned long)PCI_FUNC(devfn) << 8) |
8562306a36Sopenharmony_ci		((unsigned long)off & 0xFCUL);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic unsigned long u3_agp_cfa1(u8 bus, u8 devfn, u8 off)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	return ((unsigned long)bus << 16) |
9162306a36Sopenharmony_ci		((unsigned long)devfn << 8) |
9262306a36Sopenharmony_ci		((unsigned long)off & 0xFCUL) |
9362306a36Sopenharmony_ci		1UL;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic volatile void __iomem *u3_agp_cfg_access(struct pci_controller* hose,
9762306a36Sopenharmony_ci				       u8 bus, u8 dev_fn, u8 offset)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	unsigned int caddr;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (bus == hose->first_busno) {
10262306a36Sopenharmony_ci		if (dev_fn < (11 << 3))
10362306a36Sopenharmony_ci			return NULL;
10462306a36Sopenharmony_ci		caddr = u3_agp_cfa0(dev_fn, offset);
10562306a36Sopenharmony_ci	} else
10662306a36Sopenharmony_ci		caddr = u3_agp_cfa1(bus, dev_fn, offset);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Uninorth will return garbage if we don't read back the value ! */
10962306a36Sopenharmony_ci	do {
11062306a36Sopenharmony_ci		out_le32(hose->cfg_addr, caddr);
11162306a36Sopenharmony_ci	} while (in_le32(hose->cfg_addr) != caddr);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	offset &= 0x07;
11462306a36Sopenharmony_ci	return hose->cfg_data + offset;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn,
11862306a36Sopenharmony_ci			      int offset, int len, u32 *val)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	struct pci_controller *hose;
12162306a36Sopenharmony_ci	volatile void __iomem *addr;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	hose = pci_bus_to_host(bus);
12462306a36Sopenharmony_ci	if (hose == NULL)
12562306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	addr = u3_agp_cfg_access(hose, bus->number, devfn, offset);
12862306a36Sopenharmony_ci	if (!addr)
12962306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
13062306a36Sopenharmony_ci	/*
13162306a36Sopenharmony_ci	 * Note: the caller has already checked that offset is
13262306a36Sopenharmony_ci	 * suitably aligned and that len is 1, 2 or 4.
13362306a36Sopenharmony_ci	 */
13462306a36Sopenharmony_ci	switch (len) {
13562306a36Sopenharmony_ci	case 1:
13662306a36Sopenharmony_ci		*val = in_8(addr);
13762306a36Sopenharmony_ci		break;
13862306a36Sopenharmony_ci	case 2:
13962306a36Sopenharmony_ci		*val = in_le16(addr);
14062306a36Sopenharmony_ci		break;
14162306a36Sopenharmony_ci	default:
14262306a36Sopenharmony_ci		*val = in_le32(addr);
14362306a36Sopenharmony_ci		break;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn,
14962306a36Sopenharmony_ci			       int offset, int len, u32 val)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct pci_controller *hose;
15262306a36Sopenharmony_ci	volatile void __iomem *addr;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	hose = pci_bus_to_host(bus);
15562306a36Sopenharmony_ci	if (hose == NULL)
15662306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	addr = u3_agp_cfg_access(hose, bus->number, devfn, offset);
15962306a36Sopenharmony_ci	if (!addr)
16062306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
16162306a36Sopenharmony_ci	/*
16262306a36Sopenharmony_ci	 * Note: the caller has already checked that offset is
16362306a36Sopenharmony_ci	 * suitably aligned and that len is 1, 2 or 4.
16462306a36Sopenharmony_ci	 */
16562306a36Sopenharmony_ci	switch (len) {
16662306a36Sopenharmony_ci	case 1:
16762306a36Sopenharmony_ci		out_8(addr, val);
16862306a36Sopenharmony_ci		break;
16962306a36Sopenharmony_ci	case 2:
17062306a36Sopenharmony_ci		out_le16(addr, val);
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	default:
17362306a36Sopenharmony_ci		out_le32(addr, val);
17462306a36Sopenharmony_ci		break;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic struct pci_ops u3_agp_pci_ops =
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	.read = u3_agp_read_config,
18262306a36Sopenharmony_ci	.write = u3_agp_write_config,
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic unsigned long u3_ht_cfa0(u8 devfn, u8 off)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	return (devfn << 8) | off;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic unsigned long u3_ht_cfa1(u8 bus, u8 devfn, u8 off)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	return u3_ht_cfa0(devfn, off) + (bus << 16) + 0x01000000UL;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose,
19662306a36Sopenharmony_ci				      u8 bus, u8 devfn, u8 offset)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	if (bus == hose->first_busno) {
19962306a36Sopenharmony_ci		if (PCI_SLOT(devfn) == 0)
20062306a36Sopenharmony_ci			return NULL;
20162306a36Sopenharmony_ci		return hose->cfg_data + u3_ht_cfa0(devfn, offset);
20262306a36Sopenharmony_ci	} else
20362306a36Sopenharmony_ci		return hose->cfg_data + u3_ht_cfa1(bus, devfn, offset);
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic int u3_ht_root_read_config(struct pci_controller *hose, u8 offset,
20762306a36Sopenharmony_ci				  int len, u32 *val)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	volatile void __iomem *addr;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	addr = hose->cfg_addr;
21262306a36Sopenharmony_ci	addr += ((offset & ~3) << 2) + (4 - len - (offset & 3));
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	switch (len) {
21562306a36Sopenharmony_ci	case 1:
21662306a36Sopenharmony_ci		*val = in_8(addr);
21762306a36Sopenharmony_ci		break;
21862306a36Sopenharmony_ci	case 2:
21962306a36Sopenharmony_ci		*val = in_be16(addr);
22062306a36Sopenharmony_ci		break;
22162306a36Sopenharmony_ci	default:
22262306a36Sopenharmony_ci		*val = in_be32(addr);
22362306a36Sopenharmony_ci		break;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic int u3_ht_root_write_config(struct pci_controller *hose, u8 offset,
23062306a36Sopenharmony_ci				  int len, u32 val)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	volatile void __iomem *addr;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	addr = hose->cfg_addr + ((offset & ~3) << 2) + (4 - len - (offset & 3));
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (offset >= PCI_BASE_ADDRESS_0 && offset < PCI_CAPABILITY_LIST)
23762306a36Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	switch (len) {
24062306a36Sopenharmony_ci	case 1:
24162306a36Sopenharmony_ci		out_8(addr, val);
24262306a36Sopenharmony_ci		break;
24362306a36Sopenharmony_ci	case 2:
24462306a36Sopenharmony_ci		out_be16(addr, val);
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	default:
24762306a36Sopenharmony_ci		out_be32(addr, val);
24862306a36Sopenharmony_ci		break;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
25562306a36Sopenharmony_ci			     int offset, int len, u32 *val)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct pci_controller *hose;
25862306a36Sopenharmony_ci	volatile void __iomem *addr;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	hose = pci_bus_to_host(bus);
26162306a36Sopenharmony_ci	if (hose == NULL)
26262306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0))
26562306a36Sopenharmony_ci		return u3_ht_root_read_config(hose, offset, len, val);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (offset > 0xff)
26862306a36Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
27162306a36Sopenharmony_ci	if (!addr)
27262306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/*
27562306a36Sopenharmony_ci	 * Note: the caller has already checked that offset is
27662306a36Sopenharmony_ci	 * suitably aligned and that len is 1, 2 or 4.
27762306a36Sopenharmony_ci	 */
27862306a36Sopenharmony_ci	switch (len) {
27962306a36Sopenharmony_ci	case 1:
28062306a36Sopenharmony_ci		*val = in_8(addr);
28162306a36Sopenharmony_ci		break;
28262306a36Sopenharmony_ci	case 2:
28362306a36Sopenharmony_ci		*val = in_le16(addr);
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	default:
28662306a36Sopenharmony_ci		*val = in_le32(addr);
28762306a36Sopenharmony_ci		break;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
29362306a36Sopenharmony_ci			      int offset, int len, u32 val)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct pci_controller *hose;
29662306a36Sopenharmony_ci	volatile void __iomem *addr;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	hose = pci_bus_to_host(bus);
29962306a36Sopenharmony_ci	if (hose == NULL)
30062306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0))
30362306a36Sopenharmony_ci		return u3_ht_root_write_config(hose, offset, len, val);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (offset > 0xff)
30662306a36Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
30962306a36Sopenharmony_ci	if (!addr)
31062306a36Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
31162306a36Sopenharmony_ci	/*
31262306a36Sopenharmony_ci	 * Note: the caller has already checked that offset is
31362306a36Sopenharmony_ci	 * suitably aligned and that len is 1, 2 or 4.
31462306a36Sopenharmony_ci	 */
31562306a36Sopenharmony_ci	switch (len) {
31662306a36Sopenharmony_ci	case 1:
31762306a36Sopenharmony_ci		out_8(addr, val);
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci	case 2:
32062306a36Sopenharmony_ci		out_le16(addr, val);
32162306a36Sopenharmony_ci		break;
32262306a36Sopenharmony_ci	default:
32362306a36Sopenharmony_ci		out_le32(addr, val);
32462306a36Sopenharmony_ci		break;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic struct pci_ops u3_ht_pci_ops =
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	.read = u3_ht_read_config,
33262306a36Sopenharmony_ci	.write = u3_ht_write_config,
33362306a36Sopenharmony_ci};
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	return (1 << PCI_SLOT(devfn))	|
33862306a36Sopenharmony_ci	       (PCI_FUNC(devfn) << 8)	|
33962306a36Sopenharmony_ci	       ((off >> 8) << 28) 	|
34062306a36Sopenharmony_ci	       (off & 0xfcu);
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic unsigned int u4_pcie_cfa1(unsigned int bus, unsigned int devfn,
34462306a36Sopenharmony_ci				 unsigned int off)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci        return (bus << 16)		|
34762306a36Sopenharmony_ci	       (devfn << 8)		|
34862306a36Sopenharmony_ci	       ((off >> 8) << 28)	|
34962306a36Sopenharmony_ci	       (off & 0xfcu)		| 1u;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose,
35362306a36Sopenharmony_ci                                        u8 bus, u8 dev_fn, int offset)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci        unsigned int caddr;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci        if (bus == hose->first_busno)
35862306a36Sopenharmony_ci                caddr = u4_pcie_cfa0(dev_fn, offset);
35962306a36Sopenharmony_ci        else
36062306a36Sopenharmony_ci                caddr = u4_pcie_cfa1(bus, dev_fn, offset);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci        /* Uninorth will return garbage if we don't read back the value ! */
36362306a36Sopenharmony_ci        do {
36462306a36Sopenharmony_ci                out_le32(hose->cfg_addr, caddr);
36562306a36Sopenharmony_ci        } while (in_le32(hose->cfg_addr) != caddr);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci        offset &= 0x03;
36862306a36Sopenharmony_ci        return hose->cfg_data + offset;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
37262306a36Sopenharmony_ci                               int offset, int len, u32 *val)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci        struct pci_controller *hose;
37562306a36Sopenharmony_ci        volatile void __iomem *addr;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci        hose = pci_bus_to_host(bus);
37862306a36Sopenharmony_ci        if (hose == NULL)
37962306a36Sopenharmony_ci                return PCIBIOS_DEVICE_NOT_FOUND;
38062306a36Sopenharmony_ci        if (offset >= 0x1000)
38162306a36Sopenharmony_ci                return  PCIBIOS_BAD_REGISTER_NUMBER;
38262306a36Sopenharmony_ci        addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
38362306a36Sopenharmony_ci        if (!addr)
38462306a36Sopenharmony_ci                return PCIBIOS_DEVICE_NOT_FOUND;
38562306a36Sopenharmony_ci        /*
38662306a36Sopenharmony_ci         * Note: the caller has already checked that offset is
38762306a36Sopenharmony_ci         * suitably aligned and that len is 1, 2 or 4.
38862306a36Sopenharmony_ci         */
38962306a36Sopenharmony_ci        switch (len) {
39062306a36Sopenharmony_ci        case 1:
39162306a36Sopenharmony_ci                *val = in_8(addr);
39262306a36Sopenharmony_ci                break;
39362306a36Sopenharmony_ci        case 2:
39462306a36Sopenharmony_ci                *val = in_le16(addr);
39562306a36Sopenharmony_ci                break;
39662306a36Sopenharmony_ci        default:
39762306a36Sopenharmony_ci                *val = in_le32(addr);
39862306a36Sopenharmony_ci                break;
39962306a36Sopenharmony_ci        }
40062306a36Sopenharmony_ci        return PCIBIOS_SUCCESSFUL;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_cistatic int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
40362306a36Sopenharmony_ci                                int offset, int len, u32 val)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci        struct pci_controller *hose;
40662306a36Sopenharmony_ci        volatile void __iomem *addr;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci        hose = pci_bus_to_host(bus);
40962306a36Sopenharmony_ci        if (hose == NULL)
41062306a36Sopenharmony_ci                return PCIBIOS_DEVICE_NOT_FOUND;
41162306a36Sopenharmony_ci        if (offset >= 0x1000)
41262306a36Sopenharmony_ci                return  PCIBIOS_BAD_REGISTER_NUMBER;
41362306a36Sopenharmony_ci        addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
41462306a36Sopenharmony_ci        if (!addr)
41562306a36Sopenharmony_ci                return PCIBIOS_DEVICE_NOT_FOUND;
41662306a36Sopenharmony_ci        /*
41762306a36Sopenharmony_ci         * Note: the caller has already checked that offset is
41862306a36Sopenharmony_ci         * suitably aligned and that len is 1, 2 or 4.
41962306a36Sopenharmony_ci         */
42062306a36Sopenharmony_ci        switch (len) {
42162306a36Sopenharmony_ci        case 1:
42262306a36Sopenharmony_ci                out_8(addr, val);
42362306a36Sopenharmony_ci                break;
42462306a36Sopenharmony_ci        case 2:
42562306a36Sopenharmony_ci                out_le16(addr, val);
42662306a36Sopenharmony_ci                break;
42762306a36Sopenharmony_ci        default:
42862306a36Sopenharmony_ci                out_le32(addr, val);
42962306a36Sopenharmony_ci                break;
43062306a36Sopenharmony_ci        }
43162306a36Sopenharmony_ci        return PCIBIOS_SUCCESSFUL;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic struct pci_ops u4_pcie_pci_ops =
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	.read = u4_pcie_read_config,
43762306a36Sopenharmony_ci	.write = u4_pcie_write_config,
43862306a36Sopenharmony_ci};
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic void __init setup_u3_agp(struct pci_controller* hose)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	/* On G5, we move AGP up to high bus number so we don't need
44362306a36Sopenharmony_ci	 * to reassign bus numbers for HT. If we ever have P2P bridges
44462306a36Sopenharmony_ci	 * on AGP, we'll have to move pci_assign_all_buses to the
44562306a36Sopenharmony_ci	 * pci_controller structure so we enable it for AGP and not for
44662306a36Sopenharmony_ci	 * HT childs.
44762306a36Sopenharmony_ci	 * We hard code the address because of the different size of
44862306a36Sopenharmony_ci	 * the reg address cell, we shall fix that by killing struct
44962306a36Sopenharmony_ci	 * reg_property and using some accessor functions instead
45062306a36Sopenharmony_ci	 */
45162306a36Sopenharmony_ci	hose->first_busno = 0xf0;
45262306a36Sopenharmony_ci	hose->last_busno = 0xff;
45362306a36Sopenharmony_ci	hose->ops = &u3_agp_pci_ops;
45462306a36Sopenharmony_ci	hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
45562306a36Sopenharmony_ci	hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	u3_agp = hose;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic void __init setup_u4_pcie(struct pci_controller* hose)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci        /* We currently only implement the "non-atomic" config space, to
46362306a36Sopenharmony_ci         * be optimised later.
46462306a36Sopenharmony_ci         */
46562306a36Sopenharmony_ci        hose->ops = &u4_pcie_pci_ops;
46662306a36Sopenharmony_ci        hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
46762306a36Sopenharmony_ci        hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci        u4_pcie = hose;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic void __init setup_u3_ht(struct pci_controller* hose)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	hose->ops = &u3_ht_pci_ops;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* We hard code the address because of the different size of
47762306a36Sopenharmony_ci	 * the reg address cell, we shall fix that by killing struct
47862306a36Sopenharmony_ci	 * reg_property and using some accessor functions instead
47962306a36Sopenharmony_ci	 */
48062306a36Sopenharmony_ci	hose->cfg_data = ioremap(0xf2000000, 0x02000000);
48162306a36Sopenharmony_ci	hose->cfg_addr = ioremap(0xf8070000, 0x1000);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	hose->first_busno = 0;
48462306a36Sopenharmony_ci	hose->last_busno = 0xef;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	u3_ht = hose;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic int __init maple_add_bridge(struct device_node *dev)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	int len;
49262306a36Sopenharmony_ci	struct pci_controller *hose;
49362306a36Sopenharmony_ci	char* disp_name;
49462306a36Sopenharmony_ci	const int *bus_range;
49562306a36Sopenharmony_ci	int primary = 1;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	DBG("Adding PCI host bridge %pOF\n", dev);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	bus_range = of_get_property(dev, "bus-range", &len);
50062306a36Sopenharmony_ci	if (bus_range == NULL || len < 2 * sizeof(int)) {
50162306a36Sopenharmony_ci		printk(KERN_WARNING "Can't get bus-range for %pOF, assume bus 0\n",
50262306a36Sopenharmony_ci		dev);
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	hose = pcibios_alloc_controller(dev);
50662306a36Sopenharmony_ci	if (hose == NULL)
50762306a36Sopenharmony_ci		return -ENOMEM;
50862306a36Sopenharmony_ci	hose->first_busno = bus_range ? bus_range[0] : 0;
50962306a36Sopenharmony_ci	hose->last_busno = bus_range ? bus_range[1] : 0xff;
51062306a36Sopenharmony_ci	hose->controller_ops = maple_pci_controller_ops;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	disp_name = NULL;
51362306a36Sopenharmony_ci	if (of_device_is_compatible(dev, "u3-agp")) {
51462306a36Sopenharmony_ci		setup_u3_agp(hose);
51562306a36Sopenharmony_ci		disp_name = "U3-AGP";
51662306a36Sopenharmony_ci		primary = 0;
51762306a36Sopenharmony_ci	} else if (of_device_is_compatible(dev, "u3-ht")) {
51862306a36Sopenharmony_ci		setup_u3_ht(hose);
51962306a36Sopenharmony_ci		disp_name = "U3-HT";
52062306a36Sopenharmony_ci		primary = 1;
52162306a36Sopenharmony_ci        } else if (of_device_is_compatible(dev, "u4-pcie")) {
52262306a36Sopenharmony_ci                setup_u4_pcie(hose);
52362306a36Sopenharmony_ci                disp_name = "U4-PCIE";
52462306a36Sopenharmony_ci                primary = 0;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci	printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
52762306a36Sopenharmony_ci		disp_name, hose->first_busno, hose->last_busno);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* Interpret the "ranges" property */
53062306a36Sopenharmony_ci	/* This also maps the I/O region and sets isa_io/mem_base */
53162306a36Sopenharmony_ci	pci_process_bridge_OF_ranges(hose, dev, primary);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* Fixup "bus-range" OF property */
53462306a36Sopenharmony_ci	fixup_bus_range(dev);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* Check for legacy IOs */
53762306a36Sopenharmony_ci	isa_bridge_find_early(hose);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/* create pci_dn's for DT nodes under this PHB */
54062306a36Sopenharmony_ci	pci_devs_phb_init_dynamic(hose);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	return 0;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_civoid maple_pci_irq_fixup(struct pci_dev *dev)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	DBG(" -> maple_pci_irq_fixup\n");
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	/* Fixup IRQ for PCIe host */
55162306a36Sopenharmony_ci	if (u4_pcie != NULL && dev->bus->number == 0 &&
55262306a36Sopenharmony_ci	    pci_bus_to_host(dev->bus) == u4_pcie) {
55362306a36Sopenharmony_ci		printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n");
55462306a36Sopenharmony_ci		dev->irq = irq_create_mapping(NULL, 1);
55562306a36Sopenharmony_ci		if (dev->irq)
55662306a36Sopenharmony_ci			irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* Hide AMD8111 IDE interrupt when in legacy mode so
56062306a36Sopenharmony_ci	 * the driver calls pci_get_legacy_ide_irq()
56162306a36Sopenharmony_ci	 */
56262306a36Sopenharmony_ci	if (dev->vendor == PCI_VENDOR_ID_AMD &&
56362306a36Sopenharmony_ci	    dev->device == PCI_DEVICE_ID_AMD_8111_IDE &&
56462306a36Sopenharmony_ci	    (dev->class & 5) != 5) {
56562306a36Sopenharmony_ci		dev->irq = 0;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	DBG(" <- maple_pci_irq_fixup\n");
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistatic int maple_pci_root_bridge_prepare(struct pci_host_bridge *bridge)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(bridge->bus);
57462306a36Sopenharmony_ci	struct device_node *np, *child;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (hose != u3_agp)
57762306a36Sopenharmony_ci		return 0;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
58062306a36Sopenharmony_ci	 * assume there is no P2P bridge on the AGP bus, which should be a
58162306a36Sopenharmony_ci	 * safe assumptions hopefully.
58262306a36Sopenharmony_ci	 */
58362306a36Sopenharmony_ci	np = hose->dn;
58462306a36Sopenharmony_ci	PCI_DN(np)->busno = 0xf0;
58562306a36Sopenharmony_ci	for_each_child_of_node(np, child)
58662306a36Sopenharmony_ci		PCI_DN(child)->busno = 0xf0;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	return 0;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_civoid __init maple_pci_init(void)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct device_node *np, *root;
59462306a36Sopenharmony_ci	struct device_node *ht = NULL;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/* Probe root PCI hosts, that is on U3 the AGP host and the
59762306a36Sopenharmony_ci	 * HyperTransport host. That one is actually "kept" around
59862306a36Sopenharmony_ci	 * and actually added last as it's resource management relies
59962306a36Sopenharmony_ci	 * on the AGP resources to have been setup first
60062306a36Sopenharmony_ci	 */
60162306a36Sopenharmony_ci	root = of_find_node_by_path("/");
60262306a36Sopenharmony_ci	if (root == NULL) {
60362306a36Sopenharmony_ci		printk(KERN_CRIT "maple_find_bridges: can't find root of device tree\n");
60462306a36Sopenharmony_ci		return;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci	for_each_child_of_node(root, np) {
60762306a36Sopenharmony_ci		if (!of_node_is_type(np, "pci") && !of_node_is_type(np, "ht"))
60862306a36Sopenharmony_ci			continue;
60962306a36Sopenharmony_ci		if ((of_device_is_compatible(np, "u4-pcie") ||
61062306a36Sopenharmony_ci		     of_device_is_compatible(np, "u3-agp")) &&
61162306a36Sopenharmony_ci		    maple_add_bridge(np) == 0)
61262306a36Sopenharmony_ci			of_node_get(np);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		if (of_device_is_compatible(np, "u3-ht")) {
61562306a36Sopenharmony_ci			of_node_get(np);
61662306a36Sopenharmony_ci			ht = np;
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci	of_node_put(root);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* Now setup the HyperTransport host if we found any
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci	if (ht && maple_add_bridge(ht) != 0)
62462306a36Sopenharmony_ci		of_node_put(ht);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	ppc_md.pcibios_root_bridge_prepare = maple_pci_root_bridge_prepare;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* Tell pci.c to not change any resource allocations.  */
62962306a36Sopenharmony_ci	pci_add_flags(PCI_PROBE_ONLY);
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ciint maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	struct device_node *np;
63562306a36Sopenharmony_ci	unsigned int defirq = channel ? 15 : 14;
63662306a36Sopenharmony_ci	unsigned int irq;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (pdev->vendor != PCI_VENDOR_ID_AMD ||
63962306a36Sopenharmony_ci	    pdev->device != PCI_DEVICE_ID_AMD_8111_IDE)
64062306a36Sopenharmony_ci		return defirq;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	np = pci_device_to_OF_node(pdev);
64362306a36Sopenharmony_ci	if (np == NULL) {
64462306a36Sopenharmony_ci		printk("Failed to locate OF node for IDE %s\n",
64562306a36Sopenharmony_ci		       pci_name(pdev));
64662306a36Sopenharmony_ci		return defirq;
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci	irq = irq_of_parse_and_map(np, channel & 0x1);
64962306a36Sopenharmony_ci	if (!irq) {
65062306a36Sopenharmony_ci		printk("Failed to map onboard IDE interrupt for channel %d\n",
65162306a36Sopenharmony_ci		       channel);
65262306a36Sopenharmony_ci		return defirq;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci	return irq;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic void quirk_ipr_msi(struct pci_dev *dev)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	/* Something prevents MSIs from the IPR from working on Bimini,
66062306a36Sopenharmony_ci	 * and the driver has no smarts to recover. So disable MSI
66162306a36Sopenharmony_ci	 * on it for now. */
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	if (machine_is(maple)) {
66462306a36Sopenharmony_ci		dev->no_msi = 1;
66562306a36Sopenharmony_ci		dev_info(&dev->dev, "Quirk disabled MSI\n");
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
66962306a36Sopenharmony_ci			quirk_ipr_msi);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistruct pci_controller_ops maple_pci_controller_ops = {
67262306a36Sopenharmony_ci};
673