1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * PCIe host controller driver for Amazon's Annapurna Labs IP (used in chips 4 * such as Graviton and Alpine) 5 * 6 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 7 * 8 * Author: Jonathan Chocron <jonnyc@amazon.com> 9 */ 10 11 #include <linux/pci.h> 12 #include <linux/pci-ecam.h> 13 #include <linux/pci-acpi.h> 14 #include "../../pci.h" 15 16 #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) 17 18 struct al_pcie_acpi { 19 void __iomem *dbi_base; 20 }; 21 22 static void __iomem *al_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, 23 int where) 24 { 25 struct pci_config_window *cfg = bus->sysdata; 26 struct al_pcie_acpi *pcie = cfg->priv; 27 void __iomem *dbi_base = pcie->dbi_base; 28 29 if (bus->number == cfg->busr.start) { 30 /* 31 * The DW PCIe core doesn't filter out transactions to other 32 * devices/functions on the root bus num, so we do this here. 33 */ 34 if (PCI_SLOT(devfn) > 0) 35 return NULL; 36 else 37 return dbi_base + where; 38 } 39 40 return pci_ecam_map_bus(bus, devfn, where); 41 } 42 43 static int al_pcie_init(struct pci_config_window *cfg) 44 { 45 struct device *dev = cfg->parent; 46 struct acpi_device *adev = to_acpi_device(dev); 47 struct acpi_pci_root *root = acpi_driver_data(adev); 48 struct al_pcie_acpi *al_pcie; 49 struct resource *res; 50 int ret; 51 52 al_pcie = devm_kzalloc(dev, sizeof(*al_pcie), GFP_KERNEL); 53 if (!al_pcie) 54 return -ENOMEM; 55 56 res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL); 57 if (!res) 58 return -ENOMEM; 59 60 ret = acpi_get_rc_resources(dev, "AMZN0001", root->segment, res); 61 if (ret) { 62 dev_err(dev, "can't get rc dbi base address for SEG %d\n", 63 root->segment); 64 return ret; 65 } 66 67 dev_dbg(dev, "Root port dbi res: %pR\n", res); 68 69 al_pcie->dbi_base = devm_pci_remap_cfg_resource(dev, res); 70 if (IS_ERR(al_pcie->dbi_base)) { 71 long err = PTR_ERR(al_pcie->dbi_base); 72 73 dev_err(dev, "couldn't remap dbi base %pR (err:%ld)\n", 74 res, err); 75 return err; 76 } 77 78 cfg->priv = al_pcie; 79 80 return 0; 81 } 82 83 struct pci_ecam_ops al_pcie_ops = { 84 .bus_shift = 20, 85 .init = al_pcie_init, 86 .pci_ops = { 87 .map_bus = al_pcie_map_bus, 88 .read = pci_generic_config_read, 89 .write = pci_generic_config_write, 90 } 91 }; 92 93 #endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */ 94