18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 38c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 48c2ecf20Sopenharmony_ci#include <linux/pci-ecam.h> 58c2ecf20Sopenharmony_ci#include <linux/delay.h> 68c2ecf20Sopenharmony_ci#include <linux/msi.h> 78c2ecf20Sopenharmony_ci#include <linux/of_address.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define MSI_MAX 256 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define SMP8759_MUX 0x48 128c2ecf20Sopenharmony_ci#define SMP8759_TEST_OUT 0x74 138c2ecf20Sopenharmony_ci#define SMP8759_DOORBELL 0x7c 148c2ecf20Sopenharmony_ci#define SMP8759_STATUS 0x80 158c2ecf20Sopenharmony_ci#define SMP8759_ENABLE 0xa0 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct tango_pcie { 188c2ecf20Sopenharmony_ci DECLARE_BITMAP(used_msi, MSI_MAX); 198c2ecf20Sopenharmony_ci u64 msi_doorbell; 208c2ecf20Sopenharmony_ci spinlock_t used_msi_lock; 218c2ecf20Sopenharmony_ci void __iomem *base; 228c2ecf20Sopenharmony_ci struct irq_domain *dom; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void tango_msi_isr(struct irq_desc *desc) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 288c2ecf20Sopenharmony_ci struct tango_pcie *pcie = irq_desc_get_handler_data(desc); 298c2ecf20Sopenharmony_ci unsigned long status, base, virq, idx, pos = 0; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci chained_irq_enter(chip, desc); 328c2ecf20Sopenharmony_ci spin_lock(&pcie->used_msi_lock); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci while ((pos = find_next_bit(pcie->used_msi, MSI_MAX, pos)) < MSI_MAX) { 358c2ecf20Sopenharmony_ci base = round_down(pos, 32); 368c2ecf20Sopenharmony_ci status = readl_relaxed(pcie->base + SMP8759_STATUS + base / 8); 378c2ecf20Sopenharmony_ci for_each_set_bit(idx, &status, 32) { 388c2ecf20Sopenharmony_ci virq = irq_find_mapping(pcie->dom, base + idx); 398c2ecf20Sopenharmony_ci generic_handle_irq(virq); 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci pos = base + 32; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci spin_unlock(&pcie->used_msi_lock); 458c2ecf20Sopenharmony_ci chained_irq_exit(chip, desc); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void tango_ack(struct irq_data *d) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct tango_pcie *pcie = d->chip_data; 518c2ecf20Sopenharmony_ci u32 offset = (d->hwirq / 32) * 4; 528c2ecf20Sopenharmony_ci u32 bit = BIT(d->hwirq % 32); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci writel_relaxed(bit, pcie->base + SMP8759_STATUS + offset); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void update_msi_enable(struct irq_data *d, bool unmask) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci unsigned long flags; 608c2ecf20Sopenharmony_ci struct tango_pcie *pcie = d->chip_data; 618c2ecf20Sopenharmony_ci u32 offset = (d->hwirq / 32) * 4; 628c2ecf20Sopenharmony_ci u32 bit = BIT(d->hwirq % 32); 638c2ecf20Sopenharmony_ci u32 val; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci spin_lock_irqsave(&pcie->used_msi_lock, flags); 668c2ecf20Sopenharmony_ci val = readl_relaxed(pcie->base + SMP8759_ENABLE + offset); 678c2ecf20Sopenharmony_ci val = unmask ? val | bit : val & ~bit; 688c2ecf20Sopenharmony_ci writel_relaxed(val, pcie->base + SMP8759_ENABLE + offset); 698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pcie->used_msi_lock, flags); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void tango_mask(struct irq_data *d) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci update_msi_enable(d, false); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void tango_unmask(struct irq_data *d) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci update_msi_enable(d, true); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int tango_set_affinity(struct irq_data *d, const struct cpumask *mask, 838c2ecf20Sopenharmony_ci bool force) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci return -EINVAL; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void tango_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct tango_pcie *pcie = d->chip_data; 918c2ecf20Sopenharmony_ci msg->address_lo = lower_32_bits(pcie->msi_doorbell); 928c2ecf20Sopenharmony_ci msg->address_hi = upper_32_bits(pcie->msi_doorbell); 938c2ecf20Sopenharmony_ci msg->data = d->hwirq; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic struct irq_chip tango_chip = { 978c2ecf20Sopenharmony_ci .irq_ack = tango_ack, 988c2ecf20Sopenharmony_ci .irq_mask = tango_mask, 998c2ecf20Sopenharmony_ci .irq_unmask = tango_unmask, 1008c2ecf20Sopenharmony_ci .irq_set_affinity = tango_set_affinity, 1018c2ecf20Sopenharmony_ci .irq_compose_msi_msg = tango_compose_msi_msg, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void msi_ack(struct irq_data *d) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci irq_chip_ack_parent(d); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void msi_mask(struct irq_data *d) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci pci_msi_mask_irq(d); 1128c2ecf20Sopenharmony_ci irq_chip_mask_parent(d); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void msi_unmask(struct irq_data *d) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci pci_msi_unmask_irq(d); 1188c2ecf20Sopenharmony_ci irq_chip_unmask_parent(d); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic struct irq_chip msi_chip = { 1228c2ecf20Sopenharmony_ci .name = "MSI", 1238c2ecf20Sopenharmony_ci .irq_ack = msi_ack, 1248c2ecf20Sopenharmony_ci .irq_mask = msi_mask, 1258c2ecf20Sopenharmony_ci .irq_unmask = msi_unmask, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic struct msi_domain_info msi_dom_info = { 1298c2ecf20Sopenharmony_ci .flags = MSI_FLAG_PCI_MSIX 1308c2ecf20Sopenharmony_ci | MSI_FLAG_USE_DEF_DOM_OPS 1318c2ecf20Sopenharmony_ci | MSI_FLAG_USE_DEF_CHIP_OPS, 1328c2ecf20Sopenharmony_ci .chip = &msi_chip, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int tango_irq_domain_alloc(struct irq_domain *dom, unsigned int virq, 1368c2ecf20Sopenharmony_ci unsigned int nr_irqs, void *args) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct tango_pcie *pcie = dom->host_data; 1398c2ecf20Sopenharmony_ci unsigned long flags; 1408c2ecf20Sopenharmony_ci int pos; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci spin_lock_irqsave(&pcie->used_msi_lock, flags); 1438c2ecf20Sopenharmony_ci pos = find_first_zero_bit(pcie->used_msi, MSI_MAX); 1448c2ecf20Sopenharmony_ci if (pos >= MSI_MAX) { 1458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pcie->used_msi_lock, flags); 1468c2ecf20Sopenharmony_ci return -ENOSPC; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci __set_bit(pos, pcie->used_msi); 1498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pcie->used_msi_lock, flags); 1508c2ecf20Sopenharmony_ci irq_domain_set_info(dom, virq, pos, &tango_chip, 1518c2ecf20Sopenharmony_ci pcie, handle_edge_irq, NULL, NULL); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void tango_irq_domain_free(struct irq_domain *dom, unsigned int virq, 1578c2ecf20Sopenharmony_ci unsigned int nr_irqs) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci unsigned long flags; 1608c2ecf20Sopenharmony_ci struct irq_data *d = irq_domain_get_irq_data(dom, virq); 1618c2ecf20Sopenharmony_ci struct tango_pcie *pcie = d->chip_data; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci spin_lock_irqsave(&pcie->used_msi_lock, flags); 1648c2ecf20Sopenharmony_ci __clear_bit(d->hwirq, pcie->used_msi); 1658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pcie->used_msi_lock, flags); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic const struct irq_domain_ops dom_ops = { 1698c2ecf20Sopenharmony_ci .alloc = tango_irq_domain_alloc, 1708c2ecf20Sopenharmony_ci .free = tango_irq_domain_free, 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int smp8759_config_read(struct pci_bus *bus, unsigned int devfn, 1748c2ecf20Sopenharmony_ci int where, int size, u32 *val) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct pci_config_window *cfg = bus->sysdata; 1778c2ecf20Sopenharmony_ci struct tango_pcie *pcie = dev_get_drvdata(cfg->parent); 1788c2ecf20Sopenharmony_ci int ret; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* Reads in configuration space outside devfn 0 return garbage */ 1818c2ecf20Sopenharmony_ci if (devfn != 0) 1828c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* 1858c2ecf20Sopenharmony_ci * PCI config and MMIO accesses are muxed. Linux doesn't have a 1868c2ecf20Sopenharmony_ci * mutual exclusion mechanism for config vs. MMIO accesses, so 1878c2ecf20Sopenharmony_ci * concurrent accesses may cause corruption. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci writel_relaxed(1, pcie->base + SMP8759_MUX); 1908c2ecf20Sopenharmony_ci ret = pci_generic_config_read(bus, devfn, where, size, val); 1918c2ecf20Sopenharmony_ci writel_relaxed(0, pcie->base + SMP8759_MUX); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return ret; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int smp8759_config_write(struct pci_bus *bus, unsigned int devfn, 1978c2ecf20Sopenharmony_ci int where, int size, u32 val) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct pci_config_window *cfg = bus->sysdata; 2008c2ecf20Sopenharmony_ci struct tango_pcie *pcie = dev_get_drvdata(cfg->parent); 2018c2ecf20Sopenharmony_ci int ret; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci writel_relaxed(1, pcie->base + SMP8759_MUX); 2048c2ecf20Sopenharmony_ci ret = pci_generic_config_write(bus, devfn, where, size, val); 2058c2ecf20Sopenharmony_ci writel_relaxed(0, pcie->base + SMP8759_MUX); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return ret; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic const struct pci_ecam_ops smp8759_ecam_ops = { 2118c2ecf20Sopenharmony_ci .bus_shift = 20, 2128c2ecf20Sopenharmony_ci .pci_ops = { 2138c2ecf20Sopenharmony_ci .map_bus = pci_ecam_map_bus, 2148c2ecf20Sopenharmony_ci .read = smp8759_config_read, 2158c2ecf20Sopenharmony_ci .write = smp8759_config_write, 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int tango_pcie_link_up(struct tango_pcie *pcie) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci void __iomem *test_out = pcie->base + SMP8759_TEST_OUT; 2228c2ecf20Sopenharmony_ci int i; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci writel_relaxed(16, test_out); 2258c2ecf20Sopenharmony_ci for (i = 0; i < 10; ++i) { 2268c2ecf20Sopenharmony_ci u32 ltssm_state = readl_relaxed(test_out) >> 8; 2278c2ecf20Sopenharmony_ci if ((ltssm_state & 0x1f) == 0xf) /* L0 */ 2288c2ecf20Sopenharmony_ci return 1; 2298c2ecf20Sopenharmony_ci usleep_range(3000, 4000); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int tango_pcie_probe(struct platform_device *pdev) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2388c2ecf20Sopenharmony_ci struct tango_pcie *pcie; 2398c2ecf20Sopenharmony_ci struct resource *res; 2408c2ecf20Sopenharmony_ci struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node); 2418c2ecf20Sopenharmony_ci struct irq_domain *msi_dom, *irq_dom; 2428c2ecf20Sopenharmony_ci struct of_pci_range_parser parser; 2438c2ecf20Sopenharmony_ci struct of_pci_range range; 2448c2ecf20Sopenharmony_ci int virq, offset; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci dev_warn(dev, "simultaneous PCI config and MMIO accesses may cause data corruption\n"); 2478c2ecf20Sopenharmony_ci add_taint(TAINT_CRAP, LOCKDEP_STILL_OK); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); 2508c2ecf20Sopenharmony_ci if (!pcie) 2518c2ecf20Sopenharmony_ci return -ENOMEM; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 2548c2ecf20Sopenharmony_ci pcie->base = devm_ioremap_resource(dev, res); 2558c2ecf20Sopenharmony_ci if (IS_ERR(pcie->base)) 2568c2ecf20Sopenharmony_ci return PTR_ERR(pcie->base); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pcie); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (!tango_pcie_link_up(pcie)) 2618c2ecf20Sopenharmony_ci return -ENODEV; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (of_pci_dma_range_parser_init(&parser, dev->of_node) < 0) 2648c2ecf20Sopenharmony_ci return -ENOENT; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (of_pci_range_parser_one(&parser, &range) == NULL) 2678c2ecf20Sopenharmony_ci return -ENOENT; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci range.pci_addr += range.size; 2708c2ecf20Sopenharmony_ci pcie->msi_doorbell = range.pci_addr + res->start + SMP8759_DOORBELL; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci for (offset = 0; offset < MSI_MAX / 8; offset += 4) 2738c2ecf20Sopenharmony_ci writel_relaxed(0, pcie->base + SMP8759_ENABLE + offset); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci virq = platform_get_irq(pdev, 1); 2768c2ecf20Sopenharmony_ci if (virq < 0) 2778c2ecf20Sopenharmony_ci return virq; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &dom_ops, pcie); 2808c2ecf20Sopenharmony_ci if (!irq_dom) { 2818c2ecf20Sopenharmony_ci dev_err(dev, "Failed to create IRQ domain\n"); 2828c2ecf20Sopenharmony_ci return -ENOMEM; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci msi_dom = pci_msi_create_irq_domain(fwnode, &msi_dom_info, irq_dom); 2868c2ecf20Sopenharmony_ci if (!msi_dom) { 2878c2ecf20Sopenharmony_ci dev_err(dev, "Failed to create MSI domain\n"); 2888c2ecf20Sopenharmony_ci irq_domain_remove(irq_dom); 2898c2ecf20Sopenharmony_ci return -ENOMEM; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci pcie->dom = irq_dom; 2938c2ecf20Sopenharmony_ci spin_lock_init(&pcie->used_msi_lock); 2948c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return pci_host_common_probe(pdev); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic const struct of_device_id tango_pcie_ids[] = { 3008c2ecf20Sopenharmony_ci { 3018c2ecf20Sopenharmony_ci .compatible = "sigma,smp8759-pcie", 3028c2ecf20Sopenharmony_ci .data = &smp8759_ecam_ops, 3038c2ecf20Sopenharmony_ci }, 3048c2ecf20Sopenharmony_ci { }, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic struct platform_driver tango_pcie_driver = { 3088c2ecf20Sopenharmony_ci .probe = tango_pcie_probe, 3098c2ecf20Sopenharmony_ci .driver = { 3108c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 3118c2ecf20Sopenharmony_ci .of_match_table = tango_pcie_ids, 3128c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 3138c2ecf20Sopenharmony_ci }, 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_cibuiltin_platform_driver(tango_pcie_driver); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* 3188c2ecf20Sopenharmony_ci * The root complex advertises the wrong device class. 3198c2ecf20Sopenharmony_ci * Header Type 1 is for PCI-to-PCI bridges. 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_cistatic void tango_fixup_class(struct pci_dev *dev) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci dev->class = PCI_CLASS_BRIDGE_PCI << 8; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x0024, tango_fixup_class); 3268c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x0028, tango_fixup_class); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/* 3298c2ecf20Sopenharmony_ci * The root complex exposes a "fake" BAR, which is used to filter 3308c2ecf20Sopenharmony_ci * bus-to-system accesses. Only accesses within the range defined by this 3318c2ecf20Sopenharmony_ci * BAR are forwarded to the host, others are ignored. 3328c2ecf20Sopenharmony_ci * 3338c2ecf20Sopenharmony_ci * By default, the DMA framework expects an identity mapping, and DRAM0 is 3348c2ecf20Sopenharmony_ci * mapped at 0x80000000. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_cistatic void tango_fixup_bar(struct pci_dev *dev) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci dev->non_compliant_bars = true; 3398c2ecf20Sopenharmony_ci pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x80000000); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x0024, tango_fixup_bar); 3428c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIGMA, 0x0028, tango_fixup_bar); 343