linux/drivers/pci/controller/dwc/pcie-tegra194-acpi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * ACPI quirks for Tegra194 PCIe host controller
   4 *
   5 * Copyright (C) 2021 NVIDIA Corporation.
   6 *
   7 * Author: Vidya Sagar <vidyas@nvidia.com>
   8 */
   9
  10#include <linux/pci.h>
  11#include <linux/pci-acpi.h>
  12#include <linux/pci-ecam.h>
  13
  14#include "pcie-designware.h"
  15
  16struct tegra194_pcie_ecam  {
  17        void __iomem *config_base;
  18        void __iomem *iatu_base;
  19        void __iomem *dbi_base;
  20};
  21
  22static int tegra194_acpi_init(struct pci_config_window *cfg)
  23{
  24        struct device *dev = cfg->parent;
  25        struct tegra194_pcie_ecam *pcie_ecam;
  26
  27        pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL);
  28        if (!pcie_ecam)
  29                return -ENOMEM;
  30
  31        pcie_ecam->config_base = cfg->win;
  32        pcie_ecam->iatu_base = cfg->win + SZ_256K;
  33        pcie_ecam->dbi_base = cfg->win + SZ_512K;
  34        cfg->priv = pcie_ecam;
  35
  36        return 0;
  37}
  38
  39static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index,
  40                          u32 val, u32 reg)
  41{
  42        u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
  43
  44        writel(val, pcie_ecam->iatu_base + offset + reg);
  45}
  46
  47static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
  48                                 int index, int type, u64 cpu_addr,
  49                                 u64 pci_addr, u64 size)
  50{
  51        atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
  52                      PCIE_ATU_LOWER_BASE);
  53        atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr),
  54                      PCIE_ATU_UPPER_BASE);
  55        atu_reg_write(pcie_ecam, index, lower_32_bits(pci_addr),
  56                      PCIE_ATU_LOWER_TARGET);
  57        atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr + size - 1),
  58                      PCIE_ATU_LIMIT);
  59        atu_reg_write(pcie_ecam, index, upper_32_bits(pci_addr),
  60                      PCIE_ATU_UPPER_TARGET);
  61        atu_reg_write(pcie_ecam, index, type, PCIE_ATU_CR1);
  62        atu_reg_write(pcie_ecam, index, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
  63}
  64
  65static void __iomem *tegra194_map_bus(struct pci_bus *bus,
  66                                      unsigned int devfn, int where)
  67{
  68        struct pci_config_window *cfg = bus->sysdata;
  69        struct tegra194_pcie_ecam *pcie_ecam = cfg->priv;
  70        u32 busdev;
  71        int type;
  72
  73        if (bus->number < cfg->busr.start || bus->number > cfg->busr.end)
  74                return NULL;
  75
  76        if (bus->number == cfg->busr.start) {
  77                if (PCI_SLOT(devfn) == 0)
  78                        return pcie_ecam->dbi_base + where;
  79                else
  80                        return NULL;
  81        }
  82
  83        busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
  84                 PCIE_ATU_FUNC(PCI_FUNC(devfn));
  85
  86        if (bus->parent->number == cfg->busr.start) {
  87                if (PCI_SLOT(devfn) == 0)
  88                        type = PCIE_ATU_TYPE_CFG0;
  89                else
  90                        return NULL;
  91        } else {
  92                type = PCIE_ATU_TYPE_CFG1;
  93        }
  94
  95        program_outbound_atu(pcie_ecam, 0, type, cfg->res.start, busdev,
  96                             SZ_256K);
  97
  98        return pcie_ecam->config_base + where;
  99}
 100
 101const struct pci_ecam_ops tegra194_pcie_ops = {
 102        .init           = tegra194_acpi_init,
 103        .pci_ops        = {
 104                .map_bus        = tegra194_map_bus,
 105                .read           = pci_generic_config_read,
 106                .write          = pci_generic_config_write,
 107        }
 108};
 109