|
22 | 22 | #include <linux/of_irq.h>
|
23 | 23 | #include <linux/of_pci.h>
|
24 | 24 | #include <linux/pci.h>
|
| 25 | +#include <linux/pci-acpi.h> |
| 26 | +#include <linux/pci-ecam.h> |
25 | 27 | #include <linux/phy/phy.h>
|
26 | 28 | #include <linux/pinctrl/consumer.h>
|
27 | 29 | #include <linux/platform_device.h>
|
@@ -311,6 +313,104 @@ struct tegra_pcie_dw_of_data {
|
311 | 313 | enum dw_pcie_device_mode mode;
|
312 | 314 | };
|
313 | 315 |
|
| 316 | +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) |
| 317 | +struct tegra194_pcie_ecam { |
| 318 | + void __iomem *config_base; |
| 319 | + void __iomem *iatu_base; |
| 320 | + void __iomem *dbi_base; |
| 321 | +}; |
| 322 | + |
| 323 | +static int tegra194_acpi_init(struct pci_config_window *cfg) |
| 324 | +{ |
| 325 | + struct device *dev = cfg->parent; |
| 326 | + struct tegra194_pcie_ecam *pcie_ecam; |
| 327 | + |
| 328 | + pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL); |
| 329 | + if (!pcie_ecam) |
| 330 | + return -ENOMEM; |
| 331 | + |
| 332 | + pcie_ecam->config_base = cfg->win; |
| 333 | + pcie_ecam->iatu_base = cfg->win + SZ_256K; |
| 334 | + pcie_ecam->dbi_base = cfg->win + SZ_512K; |
| 335 | + cfg->priv = pcie_ecam; |
| 336 | + |
| 337 | + return 0; |
| 338 | +} |
| 339 | + |
| 340 | +static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index, |
| 341 | + u32 val, u32 reg) |
| 342 | +{ |
| 343 | + u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); |
| 344 | + |
| 345 | + writel(val, pcie_ecam->iatu_base + offset + reg); |
| 346 | +} |
| 347 | + |
| 348 | +static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam, |
| 349 | + int index, int type, u64 cpu_addr, |
| 350 | + u64 pci_addr, u64 size) |
| 351 | +{ |
| 352 | + atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr), |
| 353 | + PCIE_ATU_LOWER_BASE); |
| 354 | + atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr), |
| 355 | + PCIE_ATU_UPPER_BASE); |
| 356 | + atu_reg_write(pcie_ecam, index, lower_32_bits(pci_addr), |
| 357 | + PCIE_ATU_LOWER_TARGET); |
| 358 | + atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr + size - 1), |
| 359 | + PCIE_ATU_LIMIT); |
| 360 | + atu_reg_write(pcie_ecam, index, upper_32_bits(pci_addr), |
| 361 | + PCIE_ATU_UPPER_TARGET); |
| 362 | + atu_reg_write(pcie_ecam, index, type, PCIE_ATU_CR1); |
| 363 | + atu_reg_write(pcie_ecam, index, PCIE_ATU_ENABLE, PCIE_ATU_CR2); |
| 364 | +} |
| 365 | + |
| 366 | +static void __iomem *tegra194_map_bus(struct pci_bus *bus, |
| 367 | + unsigned int devfn, int where) |
| 368 | +{ |
| 369 | + struct pci_config_window *cfg = bus->sysdata; |
| 370 | + struct tegra194_pcie_ecam *pcie_ecam = cfg->priv; |
| 371 | + u32 busdev; |
| 372 | + int type; |
| 373 | + |
| 374 | + if (bus->number < cfg->busr.start || bus->number > cfg->busr.end) |
| 375 | + return NULL; |
| 376 | + |
| 377 | + if (bus->number == cfg->busr.start) { |
| 378 | + if (PCI_SLOT(devfn) == 0) |
| 379 | + return pcie_ecam->dbi_base + where; |
| 380 | + else |
| 381 | + return NULL; |
| 382 | + } |
| 383 | + |
| 384 | + busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | |
| 385 | + PCIE_ATU_FUNC(PCI_FUNC(devfn)); |
| 386 | + |
| 387 | + if (bus->parent->number == cfg->busr.start) { |
| 388 | + if (PCI_SLOT(devfn) == 0) |
| 389 | + type = PCIE_ATU_TYPE_CFG0; |
| 390 | + else |
| 391 | + return NULL; |
| 392 | + } else { |
| 393 | + type = PCIE_ATU_TYPE_CFG1; |
| 394 | + } |
| 395 | + |
| 396 | + program_outbound_atu(pcie_ecam, 0, type, cfg->res.start, busdev, |
| 397 | + SZ_256K); |
| 398 | + |
| 399 | + return pcie_ecam->config_base + where; |
| 400 | +} |
| 401 | + |
| 402 | +const struct pci_ecam_ops tegra194_pcie_ops = { |
| 403 | + .init = tegra194_acpi_init, |
| 404 | + .pci_ops = { |
| 405 | + .map_bus = tegra194_map_bus, |
| 406 | + .read = pci_generic_config_read, |
| 407 | + .write = pci_generic_config_write, |
| 408 | + } |
| 409 | +}; |
| 410 | +#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */ |
| 411 | + |
| 412 | +#ifdef CONFIG_PCIE_TEGRA194 |
| 413 | + |
314 | 414 | static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
|
315 | 415 | {
|
316 | 416 | return container_of(pci, struct tegra_pcie_dw, pci);
|
@@ -2311,3 +2411,5 @@ MODULE_DEVICE_TABLE(of, tegra_pcie_dw_of_match);
|
2311 | 2411 | MODULE_AUTHOR( "Vidya Sagar <[email protected]>");
|
2312 | 2412 | MODULE_DESCRIPTION("NVIDIA PCIe host controller driver");
|
2313 | 2413 | MODULE_LICENSE("GPL v2");
|
| 2414 | + |
| 2415 | +#endif /* CONFIG_PCIE_TEGRA194 */ |
0 commit comments