18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015, 2016 Cavium, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/init.h>
88c2ecf20Sopenharmony_ci#include <linux/ioport.h>
98c2ecf20Sopenharmony_ci#include <linux/of_pci.h>
108c2ecf20Sopenharmony_ci#include <linux/of.h>
118c2ecf20Sopenharmony_ci#include <linux/pci-ecam.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#if defined(CONFIG_PCI_HOST_THUNDER_ECAM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic void set_val(u32 v, int where, int size, u32 *val)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	int shift = (where & 3) * 8;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	pr_debug("set_val %04x: %08x\n", (unsigned)(where & ~3), v);
218c2ecf20Sopenharmony_ci	v >>= shift;
228c2ecf20Sopenharmony_ci	if (size == 1)
238c2ecf20Sopenharmony_ci		v &= 0xff;
248c2ecf20Sopenharmony_ci	else if (size == 2)
258c2ecf20Sopenharmony_ci		v &= 0xffff;
268c2ecf20Sopenharmony_ci	*val = v;
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus,
308c2ecf20Sopenharmony_ci			 unsigned int devfn, int where, int size, u32 *val)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	void __iomem *addr;
338c2ecf20Sopenharmony_ci	u32 v;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* Entries are 16-byte aligned; bits[2,3] select word in entry */
368c2ecf20Sopenharmony_ci	int where_a = where & 0xc;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	if (where_a == 0) {
398c2ecf20Sopenharmony_ci		set_val(e0, where, size, val);
408c2ecf20Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
418c2ecf20Sopenharmony_ci	}
428c2ecf20Sopenharmony_ci	if (where_a == 0x4) {
438c2ecf20Sopenharmony_ci		addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
448c2ecf20Sopenharmony_ci		if (!addr) {
458c2ecf20Sopenharmony_ci			*val = ~0;
468c2ecf20Sopenharmony_ci			return PCIBIOS_DEVICE_NOT_FOUND;
478c2ecf20Sopenharmony_ci		}
488c2ecf20Sopenharmony_ci		v = readl(addr);
498c2ecf20Sopenharmony_ci		v &= ~0xf;
508c2ecf20Sopenharmony_ci		v |= 2; /* EA entry-1. Base-L */
518c2ecf20Sopenharmony_ci		set_val(v, where, size, val);
528c2ecf20Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci	if (where_a == 0x8) {
558c2ecf20Sopenharmony_ci		u32 barl_orig;
568c2ecf20Sopenharmony_ci		u32 barl_rb;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
598c2ecf20Sopenharmony_ci		if (!addr) {
608c2ecf20Sopenharmony_ci			*val = ~0;
618c2ecf20Sopenharmony_ci			return PCIBIOS_DEVICE_NOT_FOUND;
628c2ecf20Sopenharmony_ci		}
638c2ecf20Sopenharmony_ci		barl_orig = readl(addr + 0);
648c2ecf20Sopenharmony_ci		writel(0xffffffff, addr + 0);
658c2ecf20Sopenharmony_ci		barl_rb = readl(addr + 0);
668c2ecf20Sopenharmony_ci		writel(barl_orig, addr + 0);
678c2ecf20Sopenharmony_ci		/* zeros in unsettable bits */
688c2ecf20Sopenharmony_ci		v = ~barl_rb & ~3;
698c2ecf20Sopenharmony_ci		v |= 0xc; /* EA entry-2. Offset-L */
708c2ecf20Sopenharmony_ci		set_val(v, where, size, val);
718c2ecf20Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci	if (where_a == 0xc) {
748c2ecf20Sopenharmony_ci		addr = bus->ops->map_bus(bus, devfn, bar + 4); /* BAR 1 */
758c2ecf20Sopenharmony_ci		if (!addr) {
768c2ecf20Sopenharmony_ci			*val = ~0;
778c2ecf20Sopenharmony_ci			return PCIBIOS_DEVICE_NOT_FOUND;
788c2ecf20Sopenharmony_ci		}
798c2ecf20Sopenharmony_ci		v = readl(addr); /* EA entry-3. Base-H */
808c2ecf20Sopenharmony_ci		set_val(v, where, size, val);
818c2ecf20Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci	return PCIBIOS_DEVICE_NOT_FOUND;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int thunder_ecam_p2_config_read(struct pci_bus *bus, unsigned int devfn,
878c2ecf20Sopenharmony_ci				       int where, int size, u32 *val)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct pci_config_window *cfg = bus->sysdata;
908c2ecf20Sopenharmony_ci	int where_a = where & ~3;
918c2ecf20Sopenharmony_ci	void __iomem *addr;
928c2ecf20Sopenharmony_ci	u32 node_bits;
938c2ecf20Sopenharmony_ci	u32 v;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* EA Base[63:32] may be missing some bits ... */
968c2ecf20Sopenharmony_ci	switch (where_a) {
978c2ecf20Sopenharmony_ci	case 0xa8:
988c2ecf20Sopenharmony_ci	case 0xbc:
998c2ecf20Sopenharmony_ci	case 0xd0:
1008c2ecf20Sopenharmony_ci	case 0xe4:
1018c2ecf20Sopenharmony_ci		break;
1028c2ecf20Sopenharmony_ci	default:
1038c2ecf20Sopenharmony_ci		return pci_generic_config_read(bus, devfn, where, size, val);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	addr = bus->ops->map_bus(bus, devfn, where_a);
1078c2ecf20Sopenharmony_ci	if (!addr) {
1088c2ecf20Sopenharmony_ci		*val = ~0;
1098c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	v = readl(addr);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/*
1158c2ecf20Sopenharmony_ci	 * Bit 44 of the 64-bit Base must match the same bit in
1168c2ecf20Sopenharmony_ci	 * the config space access window.  Since we are working with
1178c2ecf20Sopenharmony_ci	 * the high-order 32 bits, shift everything down by 32 bits.
1188c2ecf20Sopenharmony_ci	 */
1198c2ecf20Sopenharmony_ci	node_bits = upper_32_bits(cfg->res.start) & (1 << 12);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	v |= node_bits;
1228c2ecf20Sopenharmony_ci	set_val(v, where, size, val);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,
1288c2ecf20Sopenharmony_ci				    int where, int size, u32 *val)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	u32 v;
1318c2ecf20Sopenharmony_ci	u32 vendor_device;
1328c2ecf20Sopenharmony_ci	u32 class_rev;
1338c2ecf20Sopenharmony_ci	void __iomem *addr;
1348c2ecf20Sopenharmony_ci	int cfg_type;
1358c2ecf20Sopenharmony_ci	int where_a = where & ~3;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	addr = bus->ops->map_bus(bus, devfn, 0xc);
1388c2ecf20Sopenharmony_ci	if (!addr) {
1398c2ecf20Sopenharmony_ci		*val = ~0;
1408c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	v = readl(addr);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	/* Check for non type-00 header */
1468c2ecf20Sopenharmony_ci	cfg_type = (v >> 16) & 0x7f;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	addr = bus->ops->map_bus(bus, devfn, 8);
1498c2ecf20Sopenharmony_ci	if (!addr) {
1508c2ecf20Sopenharmony_ci		*val = ~0;
1518c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	class_rev = readl(addr);
1558c2ecf20Sopenharmony_ci	if (class_rev == 0xffffffff)
1568c2ecf20Sopenharmony_ci		goto no_emulation;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if ((class_rev & 0xff) >= 8) {
1598c2ecf20Sopenharmony_ci		/* Pass-2 handling */
1608c2ecf20Sopenharmony_ci		if (cfg_type)
1618c2ecf20Sopenharmony_ci			goto no_emulation;
1628c2ecf20Sopenharmony_ci		return thunder_ecam_p2_config_read(bus, devfn, where,
1638c2ecf20Sopenharmony_ci						   size, val);
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/*
1678c2ecf20Sopenharmony_ci	 * All BARs have fixed addresses specified by the EA
1688c2ecf20Sopenharmony_ci	 * capability; they must return zero on read.
1698c2ecf20Sopenharmony_ci	 */
1708c2ecf20Sopenharmony_ci	if (cfg_type == 0 &&
1718c2ecf20Sopenharmony_ci	    ((where >= 0x10 && where < 0x2c) ||
1728c2ecf20Sopenharmony_ci	     (where >= 0x1a4 && where < 0x1bc))) {
1738c2ecf20Sopenharmony_ci		/* BAR or SR-IOV BAR */
1748c2ecf20Sopenharmony_ci		*val = 0;
1758c2ecf20Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	addr = bus->ops->map_bus(bus, devfn, 0);
1798c2ecf20Sopenharmony_ci	if (!addr) {
1808c2ecf20Sopenharmony_ci		*val = ~0;
1818c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	vendor_device = readl(addr);
1858c2ecf20Sopenharmony_ci	if (vendor_device == 0xffffffff)
1868c2ecf20Sopenharmony_ci		goto no_emulation;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	pr_debug("%04x:%04x - Fix pass#: %08x, where: %03x, devfn: %03x\n",
1898c2ecf20Sopenharmony_ci		 vendor_device & 0xffff, vendor_device >> 16, class_rev,
1908c2ecf20Sopenharmony_ci		 (unsigned) where, devfn);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* Check for non type-00 header */
1938c2ecf20Sopenharmony_ci	if (cfg_type == 0) {
1948c2ecf20Sopenharmony_ci		bool has_msix;
1958c2ecf20Sopenharmony_ci		bool is_nic = (vendor_device == 0xa01e177d);
1968c2ecf20Sopenharmony_ci		bool is_tns = (vendor_device == 0xa01f177d);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		addr = bus->ops->map_bus(bus, devfn, 0x70);
1998c2ecf20Sopenharmony_ci		if (!addr) {
2008c2ecf20Sopenharmony_ci			*val = ~0;
2018c2ecf20Sopenharmony_ci			return PCIBIOS_DEVICE_NOT_FOUND;
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci		/* E_CAP */
2048c2ecf20Sopenharmony_ci		v = readl(addr);
2058c2ecf20Sopenharmony_ci		has_msix = (v & 0xff00) != 0;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		if (!has_msix && where_a == 0x70) {
2088c2ecf20Sopenharmony_ci			v |= 0xbc00; /* next capability is EA at 0xbc */
2098c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
2108c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
2118c2ecf20Sopenharmony_ci		}
2128c2ecf20Sopenharmony_ci		if (where_a == 0xb0) {
2138c2ecf20Sopenharmony_ci			addr = bus->ops->map_bus(bus, devfn, where_a);
2148c2ecf20Sopenharmony_ci			if (!addr) {
2158c2ecf20Sopenharmony_ci				*val = ~0;
2168c2ecf20Sopenharmony_ci				return PCIBIOS_DEVICE_NOT_FOUND;
2178c2ecf20Sopenharmony_ci			}
2188c2ecf20Sopenharmony_ci			v = readl(addr);
2198c2ecf20Sopenharmony_ci			if (v & 0xff00)
2208c2ecf20Sopenharmony_ci				pr_err("Bad MSIX cap header: %08x\n", v);
2218c2ecf20Sopenharmony_ci			v |= 0xbc00; /* next capability is EA at 0xbc */
2228c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
2238c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
2248c2ecf20Sopenharmony_ci		}
2258c2ecf20Sopenharmony_ci		if (where_a == 0xbc) {
2268c2ecf20Sopenharmony_ci			if (is_nic)
2278c2ecf20Sopenharmony_ci				v = 0x40014; /* EA last in chain, 4 entries */
2288c2ecf20Sopenharmony_ci			else if (is_tns)
2298c2ecf20Sopenharmony_ci				v = 0x30014; /* EA last in chain, 3 entries */
2308c2ecf20Sopenharmony_ci			else if (has_msix)
2318c2ecf20Sopenharmony_ci				v = 0x20014; /* EA last in chain, 2 entries */
2328c2ecf20Sopenharmony_ci			else
2338c2ecf20Sopenharmony_ci				v = 0x10014; /* EA last in chain, 1 entry */
2348c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
2358c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
2368c2ecf20Sopenharmony_ci		}
2378c2ecf20Sopenharmony_ci		if (where_a >= 0xc0 && where_a < 0xd0)
2388c2ecf20Sopenharmony_ci			/* EA entry-0. PP=0, BAR0 Size:3 */
2398c2ecf20Sopenharmony_ci			return handle_ea_bar(0x80ff0003,
2408c2ecf20Sopenharmony_ci					     0x10, bus, devfn, where,
2418c2ecf20Sopenharmony_ci					     size, val);
2428c2ecf20Sopenharmony_ci		if (where_a >= 0xd0 && where_a < 0xe0 && has_msix)
2438c2ecf20Sopenharmony_ci			 /* EA entry-1. PP=0, BAR4 Size:3 */
2448c2ecf20Sopenharmony_ci			return handle_ea_bar(0x80ff0043,
2458c2ecf20Sopenharmony_ci					     0x20, bus, devfn, where,
2468c2ecf20Sopenharmony_ci					     size, val);
2478c2ecf20Sopenharmony_ci		if (where_a >= 0xe0 && where_a < 0xf0 && is_tns)
2488c2ecf20Sopenharmony_ci			/* EA entry-2. PP=0, BAR2, Size:3 */
2498c2ecf20Sopenharmony_ci			return handle_ea_bar(0x80ff0023,
2508c2ecf20Sopenharmony_ci					     0x18, bus, devfn, where,
2518c2ecf20Sopenharmony_ci					     size, val);
2528c2ecf20Sopenharmony_ci		if (where_a >= 0xe0 && where_a < 0xf0 && is_nic)
2538c2ecf20Sopenharmony_ci			/* EA entry-2. PP=4, VF_BAR0 (9), Size:3 */
2548c2ecf20Sopenharmony_ci			return handle_ea_bar(0x80ff0493,
2558c2ecf20Sopenharmony_ci					     0x1a4, bus, devfn, where,
2568c2ecf20Sopenharmony_ci					     size, val);
2578c2ecf20Sopenharmony_ci		if (where_a >= 0xf0 && where_a < 0x100 && is_nic)
2588c2ecf20Sopenharmony_ci			/* EA entry-3. PP=4, VF_BAR4 (d), Size:3 */
2598c2ecf20Sopenharmony_ci			return handle_ea_bar(0x80ff04d3,
2608c2ecf20Sopenharmony_ci					     0x1b4, bus, devfn, where,
2618c2ecf20Sopenharmony_ci					     size, val);
2628c2ecf20Sopenharmony_ci	} else if (cfg_type == 1) {
2638c2ecf20Sopenharmony_ci		bool is_rsl_bridge = devfn == 0x08;
2648c2ecf20Sopenharmony_ci		bool is_rad_bridge = devfn == 0xa0;
2658c2ecf20Sopenharmony_ci		bool is_zip_bridge = devfn == 0xa8;
2668c2ecf20Sopenharmony_ci		bool is_dfa_bridge = devfn == 0xb0;
2678c2ecf20Sopenharmony_ci		bool is_nic_bridge = devfn == 0x10;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		if (where_a == 0x70) {
2708c2ecf20Sopenharmony_ci			addr = bus->ops->map_bus(bus, devfn, where_a);
2718c2ecf20Sopenharmony_ci			if (!addr) {
2728c2ecf20Sopenharmony_ci				*val = ~0;
2738c2ecf20Sopenharmony_ci				return PCIBIOS_DEVICE_NOT_FOUND;
2748c2ecf20Sopenharmony_ci			}
2758c2ecf20Sopenharmony_ci			v = readl(addr);
2768c2ecf20Sopenharmony_ci			if (v & 0xff00)
2778c2ecf20Sopenharmony_ci				pr_err("Bad PCIe cap header: %08x\n", v);
2788c2ecf20Sopenharmony_ci			v |= 0xbc00; /* next capability is EA at 0xbc */
2798c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
2808c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
2818c2ecf20Sopenharmony_ci		}
2828c2ecf20Sopenharmony_ci		if (where_a == 0xbc) {
2838c2ecf20Sopenharmony_ci			if (is_nic_bridge)
2848c2ecf20Sopenharmony_ci				v = 0x10014; /* EA last in chain, 1 entry */
2858c2ecf20Sopenharmony_ci			else
2868c2ecf20Sopenharmony_ci				v = 0x00014; /* EA last in chain, no entries */
2878c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
2888c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
2898c2ecf20Sopenharmony_ci		}
2908c2ecf20Sopenharmony_ci		if (where_a == 0xc0) {
2918c2ecf20Sopenharmony_ci			if (is_rsl_bridge || is_nic_bridge)
2928c2ecf20Sopenharmony_ci				v = 0x0101; /* subordinate:secondary = 1:1 */
2938c2ecf20Sopenharmony_ci			else if (is_rad_bridge)
2948c2ecf20Sopenharmony_ci				v = 0x0202; /* subordinate:secondary = 2:2 */
2958c2ecf20Sopenharmony_ci			else if (is_zip_bridge)
2968c2ecf20Sopenharmony_ci				v = 0x0303; /* subordinate:secondary = 3:3 */
2978c2ecf20Sopenharmony_ci			else if (is_dfa_bridge)
2988c2ecf20Sopenharmony_ci				v = 0x0404; /* subordinate:secondary = 4:4 */
2998c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
3008c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
3018c2ecf20Sopenharmony_ci		}
3028c2ecf20Sopenharmony_ci		if (where_a == 0xc4 && is_nic_bridge) {
3038c2ecf20Sopenharmony_ci			/* Enabled, not-Write, SP=ff, PP=05, BEI=6, ES=4 */
3048c2ecf20Sopenharmony_ci			v = 0x80ff0564;
3058c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
3068c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
3078c2ecf20Sopenharmony_ci		}
3088c2ecf20Sopenharmony_ci		if (where_a == 0xc8 && is_nic_bridge) {
3098c2ecf20Sopenharmony_ci			v = 0x00000002; /* Base-L 64-bit */
3108c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
3118c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
3128c2ecf20Sopenharmony_ci		}
3138c2ecf20Sopenharmony_ci		if (where_a == 0xcc && is_nic_bridge) {
3148c2ecf20Sopenharmony_ci			v = 0xfffffffe; /* MaxOffset-L 64-bit */
3158c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
3168c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
3178c2ecf20Sopenharmony_ci		}
3188c2ecf20Sopenharmony_ci		if (where_a == 0xd0 && is_nic_bridge) {
3198c2ecf20Sopenharmony_ci			v = 0x00008430; /* NIC Base-H */
3208c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
3218c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
3228c2ecf20Sopenharmony_ci		}
3238c2ecf20Sopenharmony_ci		if (where_a == 0xd4 && is_nic_bridge) {
3248c2ecf20Sopenharmony_ci			v = 0x0000000f; /* MaxOffset-H */
3258c2ecf20Sopenharmony_ci			set_val(v, where, size, val);
3268c2ecf20Sopenharmony_ci			return PCIBIOS_SUCCESSFUL;
3278c2ecf20Sopenharmony_ci		}
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_cino_emulation:
3308c2ecf20Sopenharmony_ci	return pci_generic_config_read(bus, devfn, where, size, val);
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
3348c2ecf20Sopenharmony_ci				     int where, int size, u32 val)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	/*
3378c2ecf20Sopenharmony_ci	 * All BARs have fixed addresses; ignore BAR writes so they
3388c2ecf20Sopenharmony_ci	 * don't get corrupted.
3398c2ecf20Sopenharmony_ci	 */
3408c2ecf20Sopenharmony_ci	if ((where >= 0x10 && where < 0x2c) ||
3418c2ecf20Sopenharmony_ci	    (where >= 0x1a4 && where < 0x1bc))
3428c2ecf20Sopenharmony_ci		/* BAR or SR-IOV BAR */
3438c2ecf20Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	return pci_generic_config_write(bus, devfn, where, size, val);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ciconst struct pci_ecam_ops pci_thunder_ecam_ops = {
3498c2ecf20Sopenharmony_ci	.bus_shift	= 20,
3508c2ecf20Sopenharmony_ci	.pci_ops	= {
3518c2ecf20Sopenharmony_ci		.map_bus        = pci_ecam_map_bus,
3528c2ecf20Sopenharmony_ci		.read           = thunder_ecam_config_read,
3538c2ecf20Sopenharmony_ci		.write          = thunder_ecam_config_write,
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci};
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_HOST_THUNDER_ECAM
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic const struct of_device_id thunder_ecam_of_match[] = {
3608c2ecf20Sopenharmony_ci	{
3618c2ecf20Sopenharmony_ci		.compatible = "cavium,pci-host-thunder-ecam",
3628c2ecf20Sopenharmony_ci		.data = &pci_thunder_ecam_ops,
3638c2ecf20Sopenharmony_ci	},
3648c2ecf20Sopenharmony_ci	{ },
3658c2ecf20Sopenharmony_ci};
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic struct platform_driver thunder_ecam_driver = {
3688c2ecf20Sopenharmony_ci	.driver = {
3698c2ecf20Sopenharmony_ci		.name = KBUILD_MODNAME,
3708c2ecf20Sopenharmony_ci		.of_match_table = thunder_ecam_of_match,
3718c2ecf20Sopenharmony_ci		.suppress_bind_attrs = true,
3728c2ecf20Sopenharmony_ci	},
3738c2ecf20Sopenharmony_ci	.probe = pci_host_common_probe,
3748c2ecf20Sopenharmony_ci};
3758c2ecf20Sopenharmony_cibuiltin_platform_driver(thunder_ecam_driver);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci#endif
3788c2ecf20Sopenharmony_ci#endif
379