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