18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
48c2ecf20Sopenharmony_ci *		      IBM Corp.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#undef DEBUG
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/pci.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/string.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/irq.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <asm/sections.h>
178c2ecf20Sopenharmony_ci#include <asm/io.h>
188c2ecf20Sopenharmony_ci#include <asm/prom.h>
198c2ecf20Sopenharmony_ci#include <asm/pci-bridge.h>
208c2ecf20Sopenharmony_ci#include <asm/machdep.h>
218c2ecf20Sopenharmony_ci#include <asm/iommu.h>
228c2ecf20Sopenharmony_ci#include <asm/ppc-pci.h>
238c2ecf20Sopenharmony_ci#include <asm/isa-bridge.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "maple.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#ifdef DEBUG
288c2ecf20Sopenharmony_ci#define DBG(x...) printk(x)
298c2ecf20Sopenharmony_ci#else
308c2ecf20Sopenharmony_ci#define DBG(x...)
318c2ecf20Sopenharmony_ci#endif
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic struct pci_controller *u3_agp, *u3_ht, *u4_pcie;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic int __init fixup_one_level_bus_range(struct device_node *node, int higher)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	for (; node != 0;node = node->sibling) {
388c2ecf20Sopenharmony_ci		const int *bus_range;
398c2ecf20Sopenharmony_ci		const unsigned int *class_code;
408c2ecf20Sopenharmony_ci		int len;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci		/* For PCI<->PCI bridges or CardBus bridges, we go down */
438c2ecf20Sopenharmony_ci		class_code = of_get_property(node, "class-code", NULL);
448c2ecf20Sopenharmony_ci		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
458c2ecf20Sopenharmony_ci			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
468c2ecf20Sopenharmony_ci			continue;
478c2ecf20Sopenharmony_ci		bus_range = of_get_property(node, "bus-range", &len);
488c2ecf20Sopenharmony_ci		if (bus_range != NULL && len > 2 * sizeof(int)) {
498c2ecf20Sopenharmony_ci			if (bus_range[1] > higher)
508c2ecf20Sopenharmony_ci				higher = bus_range[1];
518c2ecf20Sopenharmony_ci		}
528c2ecf20Sopenharmony_ci		higher = fixup_one_level_bus_range(node->child, higher);
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci	return higher;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* This routine fixes the "bus-range" property of all bridges in the
588c2ecf20Sopenharmony_ci * system since they tend to have their "last" member wrong on macs
598c2ecf20Sopenharmony_ci *
608c2ecf20Sopenharmony_ci * Note that the bus numbers manipulated here are OF bus numbers, they
618c2ecf20Sopenharmony_ci * are not Linux bus numbers.
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_cistatic void __init fixup_bus_range(struct device_node *bridge)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	int *bus_range;
668c2ecf20Sopenharmony_ci	struct property *prop;
678c2ecf20Sopenharmony_ci	int len;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* Lookup the "bus-range" property for the hose */
708c2ecf20Sopenharmony_ci	prop = of_find_property(bridge, "bus-range", &len);
718c2ecf20Sopenharmony_ci	if (prop == NULL  || prop->value == NULL || len < 2 * sizeof(int)) {
728c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Can't get bus-range for %pOF\n",
738c2ecf20Sopenharmony_ci			       bridge);
748c2ecf20Sopenharmony_ci		return;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci	bus_range = prop->value;
778c2ecf20Sopenharmony_ci	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic unsigned long u3_agp_cfa0(u8 devfn, u8 off)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	return (1 << (unsigned long)PCI_SLOT(devfn)) |
848c2ecf20Sopenharmony_ci		((unsigned long)PCI_FUNC(devfn) << 8) |
858c2ecf20Sopenharmony_ci		((unsigned long)off & 0xFCUL);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic unsigned long u3_agp_cfa1(u8 bus, u8 devfn, u8 off)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	return ((unsigned long)bus << 16) |
918c2ecf20Sopenharmony_ci		((unsigned long)devfn << 8) |
928c2ecf20Sopenharmony_ci		((unsigned long)off & 0xFCUL) |
938c2ecf20Sopenharmony_ci		1UL;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic volatile void __iomem *u3_agp_cfg_access(struct pci_controller* hose,
978c2ecf20Sopenharmony_ci				       u8 bus, u8 dev_fn, u8 offset)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	unsigned int caddr;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (bus == hose->first_busno) {
1028c2ecf20Sopenharmony_ci		if (dev_fn < (11 << 3))
1038c2ecf20Sopenharmony_ci			return NULL;
1048c2ecf20Sopenharmony_ci		caddr = u3_agp_cfa0(dev_fn, offset);
1058c2ecf20Sopenharmony_ci	} else
1068c2ecf20Sopenharmony_ci		caddr = u3_agp_cfa1(bus, dev_fn, offset);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* Uninorth will return garbage if we don't read back the value ! */
1098c2ecf20Sopenharmony_ci	do {
1108c2ecf20Sopenharmony_ci		out_le32(hose->cfg_addr, caddr);
1118c2ecf20Sopenharmony_ci	} while (in_le32(hose->cfg_addr) != caddr);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	offset &= 0x07;
1148c2ecf20Sopenharmony_ci	return hose->cfg_data + offset;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn,
1188c2ecf20Sopenharmony_ci			      int offset, int len, u32 *val)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct pci_controller *hose;
1218c2ecf20Sopenharmony_ci	volatile void __iomem *addr;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	hose = pci_bus_to_host(bus);
1248c2ecf20Sopenharmony_ci	if (hose == NULL)
1258c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	addr = u3_agp_cfg_access(hose, bus->number, devfn, offset);
1288c2ecf20Sopenharmony_ci	if (!addr)
1298c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1308c2ecf20Sopenharmony_ci	/*
1318c2ecf20Sopenharmony_ci	 * Note: the caller has already checked that offset is
1328c2ecf20Sopenharmony_ci	 * suitably aligned and that len is 1, 2 or 4.
1338c2ecf20Sopenharmony_ci	 */
1348c2ecf20Sopenharmony_ci	switch (len) {
1358c2ecf20Sopenharmony_ci	case 1:
1368c2ecf20Sopenharmony_ci		*val = in_8(addr);
1378c2ecf20Sopenharmony_ci		break;
1388c2ecf20Sopenharmony_ci	case 2:
1398c2ecf20Sopenharmony_ci		*val = in_le16(addr);
1408c2ecf20Sopenharmony_ci		break;
1418c2ecf20Sopenharmony_ci	default:
1428c2ecf20Sopenharmony_ci		*val = in_le32(addr);
1438c2ecf20Sopenharmony_ci		break;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn,
1498c2ecf20Sopenharmony_ci			       int offset, int len, u32 val)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct pci_controller *hose;
1528c2ecf20Sopenharmony_ci	volatile void __iomem *addr;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	hose = pci_bus_to_host(bus);
1558c2ecf20Sopenharmony_ci	if (hose == NULL)
1568c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	addr = u3_agp_cfg_access(hose, bus->number, devfn, offset);
1598c2ecf20Sopenharmony_ci	if (!addr)
1608c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1618c2ecf20Sopenharmony_ci	/*
1628c2ecf20Sopenharmony_ci	 * Note: the caller has already checked that offset is
1638c2ecf20Sopenharmony_ci	 * suitably aligned and that len is 1, 2 or 4.
1648c2ecf20Sopenharmony_ci	 */
1658c2ecf20Sopenharmony_ci	switch (len) {
1668c2ecf20Sopenharmony_ci	case 1:
1678c2ecf20Sopenharmony_ci		out_8(addr, val);
1688c2ecf20Sopenharmony_ci		break;
1698c2ecf20Sopenharmony_ci	case 2:
1708c2ecf20Sopenharmony_ci		out_le16(addr, val);
1718c2ecf20Sopenharmony_ci		break;
1728c2ecf20Sopenharmony_ci	default:
1738c2ecf20Sopenharmony_ci		out_le32(addr, val);
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic struct pci_ops u3_agp_pci_ops =
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	.read = u3_agp_read_config,
1828c2ecf20Sopenharmony_ci	.write = u3_agp_write_config,
1838c2ecf20Sopenharmony_ci};
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic unsigned long u3_ht_cfa0(u8 devfn, u8 off)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	return (devfn << 8) | off;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic unsigned long u3_ht_cfa1(u8 bus, u8 devfn, u8 off)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	return u3_ht_cfa0(devfn, off) + (bus << 16) + 0x01000000UL;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose,
1968c2ecf20Sopenharmony_ci				      u8 bus, u8 devfn, u8 offset)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	if (bus == hose->first_busno) {
1998c2ecf20Sopenharmony_ci		if (PCI_SLOT(devfn) == 0)
2008c2ecf20Sopenharmony_ci			return NULL;
2018c2ecf20Sopenharmony_ci		return hose->cfg_data + u3_ht_cfa0(devfn, offset);
2028c2ecf20Sopenharmony_ci	} else
2038c2ecf20Sopenharmony_ci		return hose->cfg_data + u3_ht_cfa1(bus, devfn, offset);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int u3_ht_root_read_config(struct pci_controller *hose, u8 offset,
2078c2ecf20Sopenharmony_ci				  int len, u32 *val)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	volatile void __iomem *addr;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	addr = hose->cfg_addr;
2128c2ecf20Sopenharmony_ci	addr += ((offset & ~3) << 2) + (4 - len - (offset & 3));
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	switch (len) {
2158c2ecf20Sopenharmony_ci	case 1:
2168c2ecf20Sopenharmony_ci		*val = in_8(addr);
2178c2ecf20Sopenharmony_ci		break;
2188c2ecf20Sopenharmony_ci	case 2:
2198c2ecf20Sopenharmony_ci		*val = in_be16(addr);
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci	default:
2228c2ecf20Sopenharmony_ci		*val = in_be32(addr);
2238c2ecf20Sopenharmony_ci		break;
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int u3_ht_root_write_config(struct pci_controller *hose, u8 offset,
2308c2ecf20Sopenharmony_ci				  int len, u32 val)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	volatile void __iomem *addr;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	addr = hose->cfg_addr + ((offset & ~3) << 2) + (4 - len - (offset & 3));
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (offset >= PCI_BASE_ADDRESS_0 && offset < PCI_CAPABILITY_LIST)
2378c2ecf20Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	switch (len) {
2408c2ecf20Sopenharmony_ci	case 1:
2418c2ecf20Sopenharmony_ci		out_8(addr, val);
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci	case 2:
2448c2ecf20Sopenharmony_ci		out_be16(addr, val);
2458c2ecf20Sopenharmony_ci		break;
2468c2ecf20Sopenharmony_ci	default:
2478c2ecf20Sopenharmony_ci		out_be32(addr, val);
2488c2ecf20Sopenharmony_ci		break;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
2558c2ecf20Sopenharmony_ci			     int offset, int len, u32 *val)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct pci_controller *hose;
2588c2ecf20Sopenharmony_ci	volatile void __iomem *addr;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	hose = pci_bus_to_host(bus);
2618c2ecf20Sopenharmony_ci	if (hose == NULL)
2628c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0))
2658c2ecf20Sopenharmony_ci		return u3_ht_root_read_config(hose, offset, len, val);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (offset > 0xff)
2688c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
2718c2ecf20Sopenharmony_ci	if (!addr)
2728c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/*
2758c2ecf20Sopenharmony_ci	 * Note: the caller has already checked that offset is
2768c2ecf20Sopenharmony_ci	 * suitably aligned and that len is 1, 2 or 4.
2778c2ecf20Sopenharmony_ci	 */
2788c2ecf20Sopenharmony_ci	switch (len) {
2798c2ecf20Sopenharmony_ci	case 1:
2808c2ecf20Sopenharmony_ci		*val = in_8(addr);
2818c2ecf20Sopenharmony_ci		break;
2828c2ecf20Sopenharmony_ci	case 2:
2838c2ecf20Sopenharmony_ci		*val = in_le16(addr);
2848c2ecf20Sopenharmony_ci		break;
2858c2ecf20Sopenharmony_ci	default:
2868c2ecf20Sopenharmony_ci		*val = in_le32(addr);
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
2938c2ecf20Sopenharmony_ci			      int offset, int len, u32 val)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct pci_controller *hose;
2968c2ecf20Sopenharmony_ci	volatile void __iomem *addr;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	hose = pci_bus_to_host(bus);
2998c2ecf20Sopenharmony_ci	if (hose == NULL)
3008c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0))
3038c2ecf20Sopenharmony_ci		return u3_ht_root_write_config(hose, offset, len, val);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (offset > 0xff)
3068c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
3098c2ecf20Sopenharmony_ci	if (!addr)
3108c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
3118c2ecf20Sopenharmony_ci	/*
3128c2ecf20Sopenharmony_ci	 * Note: the caller has already checked that offset is
3138c2ecf20Sopenharmony_ci	 * suitably aligned and that len is 1, 2 or 4.
3148c2ecf20Sopenharmony_ci	 */
3158c2ecf20Sopenharmony_ci	switch (len) {
3168c2ecf20Sopenharmony_ci	case 1:
3178c2ecf20Sopenharmony_ci		out_8(addr, val);
3188c2ecf20Sopenharmony_ci		break;
3198c2ecf20Sopenharmony_ci	case 2:
3208c2ecf20Sopenharmony_ci		out_le16(addr, val);
3218c2ecf20Sopenharmony_ci		break;
3228c2ecf20Sopenharmony_ci	default:
3238c2ecf20Sopenharmony_ci		out_le32(addr, val);
3248c2ecf20Sopenharmony_ci		break;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic struct pci_ops u3_ht_pci_ops =
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	.read = u3_ht_read_config,
3328c2ecf20Sopenharmony_ci	.write = u3_ht_write_config,
3338c2ecf20Sopenharmony_ci};
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	return (1 << PCI_SLOT(devfn))	|
3388c2ecf20Sopenharmony_ci	       (PCI_FUNC(devfn) << 8)	|
3398c2ecf20Sopenharmony_ci	       ((off >> 8) << 28) 	|
3408c2ecf20Sopenharmony_ci	       (off & 0xfcu);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic unsigned int u4_pcie_cfa1(unsigned int bus, unsigned int devfn,
3448c2ecf20Sopenharmony_ci				 unsigned int off)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci        return (bus << 16)		|
3478c2ecf20Sopenharmony_ci	       (devfn << 8)		|
3488c2ecf20Sopenharmony_ci	       ((off >> 8) << 28)	|
3498c2ecf20Sopenharmony_ci	       (off & 0xfcu)		| 1u;
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose,
3538c2ecf20Sopenharmony_ci                                        u8 bus, u8 dev_fn, int offset)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci        unsigned int caddr;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci        if (bus == hose->first_busno)
3588c2ecf20Sopenharmony_ci                caddr = u4_pcie_cfa0(dev_fn, offset);
3598c2ecf20Sopenharmony_ci        else
3608c2ecf20Sopenharmony_ci                caddr = u4_pcie_cfa1(bus, dev_fn, offset);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci        /* Uninorth will return garbage if we don't read back the value ! */
3638c2ecf20Sopenharmony_ci        do {
3648c2ecf20Sopenharmony_ci                out_le32(hose->cfg_addr, caddr);
3658c2ecf20Sopenharmony_ci        } while (in_le32(hose->cfg_addr) != caddr);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci        offset &= 0x03;
3688c2ecf20Sopenharmony_ci        return hose->cfg_data + offset;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
3728c2ecf20Sopenharmony_ci                               int offset, int len, u32 *val)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci        struct pci_controller *hose;
3758c2ecf20Sopenharmony_ci        volatile void __iomem *addr;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci        hose = pci_bus_to_host(bus);
3788c2ecf20Sopenharmony_ci        if (hose == NULL)
3798c2ecf20Sopenharmony_ci                return PCIBIOS_DEVICE_NOT_FOUND;
3808c2ecf20Sopenharmony_ci        if (offset >= 0x1000)
3818c2ecf20Sopenharmony_ci                return  PCIBIOS_BAD_REGISTER_NUMBER;
3828c2ecf20Sopenharmony_ci        addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
3838c2ecf20Sopenharmony_ci        if (!addr)
3848c2ecf20Sopenharmony_ci                return PCIBIOS_DEVICE_NOT_FOUND;
3858c2ecf20Sopenharmony_ci        /*
3868c2ecf20Sopenharmony_ci         * Note: the caller has already checked that offset is
3878c2ecf20Sopenharmony_ci         * suitably aligned and that len is 1, 2 or 4.
3888c2ecf20Sopenharmony_ci         */
3898c2ecf20Sopenharmony_ci        switch (len) {
3908c2ecf20Sopenharmony_ci        case 1:
3918c2ecf20Sopenharmony_ci                *val = in_8(addr);
3928c2ecf20Sopenharmony_ci                break;
3938c2ecf20Sopenharmony_ci        case 2:
3948c2ecf20Sopenharmony_ci                *val = in_le16(addr);
3958c2ecf20Sopenharmony_ci                break;
3968c2ecf20Sopenharmony_ci        default:
3978c2ecf20Sopenharmony_ci                *val = in_le32(addr);
3988c2ecf20Sopenharmony_ci                break;
3998c2ecf20Sopenharmony_ci        }
4008c2ecf20Sopenharmony_ci        return PCIBIOS_SUCCESSFUL;
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_cistatic int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
4038c2ecf20Sopenharmony_ci                                int offset, int len, u32 val)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci        struct pci_controller *hose;
4068c2ecf20Sopenharmony_ci        volatile void __iomem *addr;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci        hose = pci_bus_to_host(bus);
4098c2ecf20Sopenharmony_ci        if (hose == NULL)
4108c2ecf20Sopenharmony_ci                return PCIBIOS_DEVICE_NOT_FOUND;
4118c2ecf20Sopenharmony_ci        if (offset >= 0x1000)
4128c2ecf20Sopenharmony_ci                return  PCIBIOS_BAD_REGISTER_NUMBER;
4138c2ecf20Sopenharmony_ci        addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
4148c2ecf20Sopenharmony_ci        if (!addr)
4158c2ecf20Sopenharmony_ci                return PCIBIOS_DEVICE_NOT_FOUND;
4168c2ecf20Sopenharmony_ci        /*
4178c2ecf20Sopenharmony_ci         * Note: the caller has already checked that offset is
4188c2ecf20Sopenharmony_ci         * suitably aligned and that len is 1, 2 or 4.
4198c2ecf20Sopenharmony_ci         */
4208c2ecf20Sopenharmony_ci        switch (len) {
4218c2ecf20Sopenharmony_ci        case 1:
4228c2ecf20Sopenharmony_ci                out_8(addr, val);
4238c2ecf20Sopenharmony_ci                break;
4248c2ecf20Sopenharmony_ci        case 2:
4258c2ecf20Sopenharmony_ci                out_le16(addr, val);
4268c2ecf20Sopenharmony_ci                break;
4278c2ecf20Sopenharmony_ci        default:
4288c2ecf20Sopenharmony_ci                out_le32(addr, val);
4298c2ecf20Sopenharmony_ci                break;
4308c2ecf20Sopenharmony_ci        }
4318c2ecf20Sopenharmony_ci        return PCIBIOS_SUCCESSFUL;
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic struct pci_ops u4_pcie_pci_ops =
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	.read = u4_pcie_read_config,
4378c2ecf20Sopenharmony_ci	.write = u4_pcie_write_config,
4388c2ecf20Sopenharmony_ci};
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic void __init setup_u3_agp(struct pci_controller* hose)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	/* On G5, we move AGP up to high bus number so we don't need
4438c2ecf20Sopenharmony_ci	 * to reassign bus numbers for HT. If we ever have P2P bridges
4448c2ecf20Sopenharmony_ci	 * on AGP, we'll have to move pci_assign_all_buses to the
4458c2ecf20Sopenharmony_ci	 * pci_controller structure so we enable it for AGP and not for
4468c2ecf20Sopenharmony_ci	 * HT childs.
4478c2ecf20Sopenharmony_ci	 * We hard code the address because of the different size of
4488c2ecf20Sopenharmony_ci	 * the reg address cell, we shall fix that by killing struct
4498c2ecf20Sopenharmony_ci	 * reg_property and using some accessor functions instead
4508c2ecf20Sopenharmony_ci	 */
4518c2ecf20Sopenharmony_ci	hose->first_busno = 0xf0;
4528c2ecf20Sopenharmony_ci	hose->last_busno = 0xff;
4538c2ecf20Sopenharmony_ci	hose->ops = &u3_agp_pci_ops;
4548c2ecf20Sopenharmony_ci	hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
4558c2ecf20Sopenharmony_ci	hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	u3_agp = hose;
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic void __init setup_u4_pcie(struct pci_controller* hose)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci        /* We currently only implement the "non-atomic" config space, to
4638c2ecf20Sopenharmony_ci         * be optimised later.
4648c2ecf20Sopenharmony_ci         */
4658c2ecf20Sopenharmony_ci        hose->ops = &u4_pcie_pci_ops;
4668c2ecf20Sopenharmony_ci        hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
4678c2ecf20Sopenharmony_ci        hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci        u4_pcie = hose;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic void __init setup_u3_ht(struct pci_controller* hose)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	hose->ops = &u3_ht_pci_ops;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	/* We hard code the address because of the different size of
4778c2ecf20Sopenharmony_ci	 * the reg address cell, we shall fix that by killing struct
4788c2ecf20Sopenharmony_ci	 * reg_property and using some accessor functions instead
4798c2ecf20Sopenharmony_ci	 */
4808c2ecf20Sopenharmony_ci	hose->cfg_data = ioremap(0xf2000000, 0x02000000);
4818c2ecf20Sopenharmony_ci	hose->cfg_addr = ioremap(0xf8070000, 0x1000);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	hose->first_busno = 0;
4848c2ecf20Sopenharmony_ci	hose->last_busno = 0xef;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	u3_ht = hose;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic int __init maple_add_bridge(struct device_node *dev)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	int len;
4928c2ecf20Sopenharmony_ci	struct pci_controller *hose;
4938c2ecf20Sopenharmony_ci	char* disp_name;
4948c2ecf20Sopenharmony_ci	const int *bus_range;
4958c2ecf20Sopenharmony_ci	int primary = 1;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	DBG("Adding PCI host bridge %pOF\n", dev);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	bus_range = of_get_property(dev, "bus-range", &len);
5008c2ecf20Sopenharmony_ci	if (bus_range == NULL || len < 2 * sizeof(int)) {
5018c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Can't get bus-range for %pOF, assume bus 0\n",
5028c2ecf20Sopenharmony_ci		dev);
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	hose = pcibios_alloc_controller(dev);
5068c2ecf20Sopenharmony_ci	if (hose == NULL)
5078c2ecf20Sopenharmony_ci		return -ENOMEM;
5088c2ecf20Sopenharmony_ci	hose->first_busno = bus_range ? bus_range[0] : 0;
5098c2ecf20Sopenharmony_ci	hose->last_busno = bus_range ? bus_range[1] : 0xff;
5108c2ecf20Sopenharmony_ci	hose->controller_ops = maple_pci_controller_ops;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	disp_name = NULL;
5138c2ecf20Sopenharmony_ci	if (of_device_is_compatible(dev, "u3-agp")) {
5148c2ecf20Sopenharmony_ci		setup_u3_agp(hose);
5158c2ecf20Sopenharmony_ci		disp_name = "U3-AGP";
5168c2ecf20Sopenharmony_ci		primary = 0;
5178c2ecf20Sopenharmony_ci	} else if (of_device_is_compatible(dev, "u3-ht")) {
5188c2ecf20Sopenharmony_ci		setup_u3_ht(hose);
5198c2ecf20Sopenharmony_ci		disp_name = "U3-HT";
5208c2ecf20Sopenharmony_ci		primary = 1;
5218c2ecf20Sopenharmony_ci        } else if (of_device_is_compatible(dev, "u4-pcie")) {
5228c2ecf20Sopenharmony_ci                setup_u4_pcie(hose);
5238c2ecf20Sopenharmony_ci                disp_name = "U4-PCIE";
5248c2ecf20Sopenharmony_ci                primary = 0;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci	printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
5278c2ecf20Sopenharmony_ci		disp_name, hose->first_busno, hose->last_busno);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* Interpret the "ranges" property */
5308c2ecf20Sopenharmony_ci	/* This also maps the I/O region and sets isa_io/mem_base */
5318c2ecf20Sopenharmony_ci	pci_process_bridge_OF_ranges(hose, dev, primary);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* Fixup "bus-range" OF property */
5348c2ecf20Sopenharmony_ci	fixup_bus_range(dev);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/* Check for legacy IOs */
5378c2ecf20Sopenharmony_ci	isa_bridge_find_early(hose);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	return 0;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_civoid maple_pci_irq_fixup(struct pci_dev *dev)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	DBG(" -> maple_pci_irq_fixup\n");
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/* Fixup IRQ for PCIe host */
5488c2ecf20Sopenharmony_ci	if (u4_pcie != NULL && dev->bus->number == 0 &&
5498c2ecf20Sopenharmony_ci	    pci_bus_to_host(dev->bus) == u4_pcie) {
5508c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n");
5518c2ecf20Sopenharmony_ci		dev->irq = irq_create_mapping(NULL, 1);
5528c2ecf20Sopenharmony_ci		if (dev->irq)
5538c2ecf20Sopenharmony_ci			irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	/* Hide AMD8111 IDE interrupt when in legacy mode so
5578c2ecf20Sopenharmony_ci	 * the driver calls pci_get_legacy_ide_irq()
5588c2ecf20Sopenharmony_ci	 */
5598c2ecf20Sopenharmony_ci	if (dev->vendor == PCI_VENDOR_ID_AMD &&
5608c2ecf20Sopenharmony_ci	    dev->device == PCI_DEVICE_ID_AMD_8111_IDE &&
5618c2ecf20Sopenharmony_ci	    (dev->class & 5) != 5) {
5628c2ecf20Sopenharmony_ci		dev->irq = 0;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	DBG(" <- maple_pci_irq_fixup\n");
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic int maple_pci_root_bridge_prepare(struct pci_host_bridge *bridge)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(bridge->bus);
5718c2ecf20Sopenharmony_ci	struct device_node *np, *child;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	if (hose != u3_agp)
5748c2ecf20Sopenharmony_ci		return 0;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
5778c2ecf20Sopenharmony_ci	 * assume there is no P2P bridge on the AGP bus, which should be a
5788c2ecf20Sopenharmony_ci	 * safe assumptions hopefully.
5798c2ecf20Sopenharmony_ci	 */
5808c2ecf20Sopenharmony_ci	np = hose->dn;
5818c2ecf20Sopenharmony_ci	PCI_DN(np)->busno = 0xf0;
5828c2ecf20Sopenharmony_ci	for_each_child_of_node(np, child)
5838c2ecf20Sopenharmony_ci		PCI_DN(child)->busno = 0xf0;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	return 0;
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_civoid __init maple_pci_init(void)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	struct device_node *np, *root;
5918c2ecf20Sopenharmony_ci	struct device_node *ht = NULL;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* Probe root PCI hosts, that is on U3 the AGP host and the
5948c2ecf20Sopenharmony_ci	 * HyperTransport host. That one is actually "kept" around
5958c2ecf20Sopenharmony_ci	 * and actually added last as it's resource management relies
5968c2ecf20Sopenharmony_ci	 * on the AGP resources to have been setup first
5978c2ecf20Sopenharmony_ci	 */
5988c2ecf20Sopenharmony_ci	root = of_find_node_by_path("/");
5998c2ecf20Sopenharmony_ci	if (root == NULL) {
6008c2ecf20Sopenharmony_ci		printk(KERN_CRIT "maple_find_bridges: can't find root of device tree\n");
6018c2ecf20Sopenharmony_ci		return;
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci	for_each_child_of_node(root, np) {
6048c2ecf20Sopenharmony_ci		if (!of_node_is_type(np, "pci") && !of_node_is_type(np, "ht"))
6058c2ecf20Sopenharmony_ci			continue;
6068c2ecf20Sopenharmony_ci		if ((of_device_is_compatible(np, "u4-pcie") ||
6078c2ecf20Sopenharmony_ci		     of_device_is_compatible(np, "u3-agp")) &&
6088c2ecf20Sopenharmony_ci		    maple_add_bridge(np) == 0)
6098c2ecf20Sopenharmony_ci			of_node_get(np);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci		if (of_device_is_compatible(np, "u3-ht")) {
6128c2ecf20Sopenharmony_ci			of_node_get(np);
6138c2ecf20Sopenharmony_ci			ht = np;
6148c2ecf20Sopenharmony_ci		}
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci	of_node_put(root);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	/* Now setup the HyperTransport host if we found any
6198c2ecf20Sopenharmony_ci	 */
6208c2ecf20Sopenharmony_ci	if (ht && maple_add_bridge(ht) != 0)
6218c2ecf20Sopenharmony_ci		of_node_put(ht);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	ppc_md.pcibios_root_bridge_prepare = maple_pci_root_bridge_prepare;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	/* Tell pci.c to not change any resource allocations.  */
6268c2ecf20Sopenharmony_ci	pci_add_flags(PCI_PROBE_ONLY);
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ciint maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	struct device_node *np;
6328c2ecf20Sopenharmony_ci	unsigned int defirq = channel ? 15 : 14;
6338c2ecf20Sopenharmony_ci	unsigned int irq;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if (pdev->vendor != PCI_VENDOR_ID_AMD ||
6368c2ecf20Sopenharmony_ci	    pdev->device != PCI_DEVICE_ID_AMD_8111_IDE)
6378c2ecf20Sopenharmony_ci		return defirq;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	np = pci_device_to_OF_node(pdev);
6408c2ecf20Sopenharmony_ci	if (np == NULL) {
6418c2ecf20Sopenharmony_ci		printk("Failed to locate OF node for IDE %s\n",
6428c2ecf20Sopenharmony_ci		       pci_name(pdev));
6438c2ecf20Sopenharmony_ci		return defirq;
6448c2ecf20Sopenharmony_ci	}
6458c2ecf20Sopenharmony_ci	irq = irq_of_parse_and_map(np, channel & 0x1);
6468c2ecf20Sopenharmony_ci	if (!irq) {
6478c2ecf20Sopenharmony_ci		printk("Failed to map onboard IDE interrupt for channel %d\n",
6488c2ecf20Sopenharmony_ci		       channel);
6498c2ecf20Sopenharmony_ci		return defirq;
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci	return irq;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic void quirk_ipr_msi(struct pci_dev *dev)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	/* Something prevents MSIs from the IPR from working on Bimini,
6578c2ecf20Sopenharmony_ci	 * and the driver has no smarts to recover. So disable MSI
6588c2ecf20Sopenharmony_ci	 * on it for now. */
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	if (machine_is(maple)) {
6618c2ecf20Sopenharmony_ci		dev->no_msi = 1;
6628c2ecf20Sopenharmony_ci		dev_info(&dev->dev, "Quirk disabled MSI\n");
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
6668c2ecf20Sopenharmony_ci			quirk_ipr_msi);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistruct pci_controller_ops maple_pci_controller_ops = {
6698c2ecf20Sopenharmony_ci};
670