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_ATU_UNROLL_BASE(PCIE_ATU_REGION_DIR_OB, index) +
43		     PCIE_ATU_VIEWPORT_BASE;
44
45	writel(val, pcie_ecam->iatu_base + offset + reg);
46}
47
48static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
49				 int index, int type, u64 cpu_addr,
50				 u64 pci_addr, u64 size)
51{
52	atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
53		      PCIE_ATU_LOWER_BASE);
54	atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr),
55		      PCIE_ATU_UPPER_BASE);
56	atu_reg_write(pcie_ecam, index, lower_32_bits(pci_addr),
57		      PCIE_ATU_LOWER_TARGET);
58	atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr + size - 1),
59		      PCIE_ATU_LIMIT);
60	atu_reg_write(pcie_ecam, index, upper_32_bits(pci_addr),
61		      PCIE_ATU_UPPER_TARGET);
62	atu_reg_write(pcie_ecam, index, type, PCIE_ATU_REGION_CTRL1);
63	atu_reg_write(pcie_ecam, index, PCIE_ATU_ENABLE, PCIE_ATU_REGION_CTRL2);
64}
65
66static void __iomem *tegra194_map_bus(struct pci_bus *bus,
67				      unsigned int devfn, int where)
68{
69	struct pci_config_window *cfg = bus->sysdata;
70	struct tegra194_pcie_ecam *pcie_ecam = cfg->priv;
71	u32 busdev;
72	int type;
73
74	if (bus->number < cfg->busr.start || bus->number > cfg->busr.end)
75		return NULL;
76
77	if (bus->number == cfg->busr.start) {
78		if (PCI_SLOT(devfn) == 0)
79			return pcie_ecam->dbi_base + where;
80		else
81			return NULL;
82	}
83
84	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
85		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
86
87	if (bus->parent->number == cfg->busr.start) {
88		if (PCI_SLOT(devfn) == 0)
89			type = PCIE_ATU_TYPE_CFG0;
90		else
91			return NULL;
92	} else {
93		type = PCIE_ATU_TYPE_CFG1;
94	}
95
96	program_outbound_atu(pcie_ecam, 0, type, cfg->res.start, busdev,
97			     SZ_256K);
98
99	return pcie_ecam->config_base + where;
100}
101
102const struct pci_ecam_ops tegra194_pcie_ops = {
103	.init		= tegra194_acpi_init,
104	.pci_ops	= {
105		.map_bus	= tegra194_map_bus,
106		.read		= pci_generic_config_read,
107		.write		= pci_generic_config_write,
108	}
109};
110