]> Git Repo - linux.git/blob - drivers/pci/controller/dwc/pcie-al.c
Merge tag 'for-rc-adfs' of git://git.armlinux.org.uk/~rmk/linux-arm
[linux.git] / drivers / pci / controller / dwc / pcie-al.c
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 <[email protected]>
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) */
This page took 0.041064 seconds and 4 git commands to generate.