aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/controller/pci-aardvark.c
diff options
context:
space:
mode:
authorZachary Zhang <zhangzg@marvell.com>2018-10-18 11:37:19 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2018-10-18 12:51:41 -0400
commit8a3ebd8de328301aacbe328650a59253be2ac82c (patch)
tree9314810dc2257d2b2ef560fd88f31f4b93162ff4 /drivers/pci/controller/pci-aardvark.c
parent1f08673eef1236f7d02d93fcf596bb8531ef0d12 (diff)
PCI: aardvark: Implement emulated root PCI bridge config space
The PCI controller in the Marvell Armada 3720 does not implement a software-accessible root port PCI bridge configuration space. This causes a number of problems when using PCIe switches or when the Max Payload size needs to be aligned between the root complex and the endpoint. Implementing an emulated root PCI bridge, like is already done in the pci-mvebu driver for older Marvell platforms allows to solve those issues, and also to support features such as ASR, PME, VC, HP. Signed-off-by: Zachary Zhang <zhangzg@marvell.com> [Thomas: convert to the common emulated PCI bridge logic.] Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Diffstat (limited to 'drivers/pci/controller/pci-aardvark.c')
-rw-r--r--drivers/pci/controller/pci-aardvark.c129
1 files changed, 126 insertions, 3 deletions
diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
index 6b4555ff2548..750081c1cb48 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -20,12 +20,16 @@
20#include <linux/of_pci.h> 20#include <linux/of_pci.h>
21 21
22#include "../pci.h" 22#include "../pci.h"
23#include "../pci-bridge-emul.h"
23 24
24/* PCIe core registers */ 25/* PCIe core registers */
26#define PCIE_CORE_DEV_ID_REG 0x0
25#define PCIE_CORE_CMD_STATUS_REG 0x4 27#define PCIE_CORE_CMD_STATUS_REG 0x4
26#define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0) 28#define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0)
27#define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1) 29#define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1)
28#define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) 30#define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2)
31#define PCIE_CORE_DEV_REV_REG 0x8
32#define PCIE_CORE_PCIEXP_CAP 0xc0
29#define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8 33#define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8
30#define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4) 34#define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4)
31#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5 35#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5
@@ -41,7 +45,10 @@
41#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6) 45#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6)
42#define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK BIT(7) 46#define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK BIT(7)
43#define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV BIT(8) 47#define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV BIT(8)
44 48#define PCIE_CORE_INT_A_ASSERT_ENABLE 1
49#define PCIE_CORE_INT_B_ASSERT_ENABLE 2
50#define PCIE_CORE_INT_C_ASSERT_ENABLE 3
51#define PCIE_CORE_INT_D_ASSERT_ENABLE 4
45/* PIO registers base address and register offsets */ 52/* PIO registers base address and register offsets */
46#define PIO_BASE_ADDR 0x4000 53#define PIO_BASE_ADDR 0x4000
47#define PIO_CTRL (PIO_BASE_ADDR + 0x0) 54#define PIO_CTRL (PIO_BASE_ADDR + 0x0)
@@ -93,7 +100,9 @@
93#define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5) 100#define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5)
94#define PCIE_CORE_CTRL2_OB_WIN_ENABLE BIT(6) 101#define PCIE_CORE_CTRL2_OB_WIN_ENABLE BIT(6)
95#define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10) 102#define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10)
103#define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30)
96#define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40) 104#define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40)
105#define PCIE_MSG_PM_PME_MASK BIT(7)
97#define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44) 106#define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44)
98#define PCIE_ISR0_MSI_INT_PENDING BIT(24) 107#define PCIE_ISR0_MSI_INT_PENDING BIT(24)
99#define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val)) 108#define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val))
@@ -189,6 +198,7 @@ struct advk_pcie {
189 struct mutex msi_used_lock; 198 struct mutex msi_used_lock;
190 u16 msi_msg; 199 u16 msi_msg;
191 int root_bus_nr; 200 int root_bus_nr;
201 struct pci_bridge_emul bridge;
192}; 202};
193 203
194static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg) 204static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg)
@@ -390,6 +400,109 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
390 return -ETIMEDOUT; 400 return -ETIMEDOUT;
391} 401}
392 402
403
404static pci_bridge_emul_read_status_t
405advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
406 int reg, u32 *value)
407{
408 struct advk_pcie *pcie = bridge->data;
409
410
411 switch (reg) {
412 case PCI_EXP_SLTCTL:
413 *value = PCI_EXP_SLTSTA_PDS << 16;
414 return PCI_BRIDGE_EMUL_HANDLED;
415
416 case PCI_EXP_RTCTL: {
417 u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
418 *value = (val & PCIE_MSG_PM_PME_MASK) ? PCI_EXP_RTCTL_PMEIE : 0;
419 return PCI_BRIDGE_EMUL_HANDLED;
420 }
421
422 case PCI_EXP_RTSTA: {
423 u32 isr0 = advk_readl(pcie, PCIE_ISR0_REG);
424 u32 msglog = advk_readl(pcie, PCIE_MSG_LOG_REG);
425 *value = (isr0 & PCIE_MSG_PM_PME_MASK) << 16 | (msglog >> 16);
426 return PCI_BRIDGE_EMUL_HANDLED;
427 }
428
429 case PCI_CAP_LIST_ID:
430 case PCI_EXP_DEVCAP:
431 case PCI_EXP_DEVCTL:
432 case PCI_EXP_LNKCAP:
433 case PCI_EXP_LNKCTL:
434 *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
435 return PCI_BRIDGE_EMUL_HANDLED;
436 default:
437 return PCI_BRIDGE_EMUL_NOT_HANDLED;
438 }
439
440}
441
442static void
443advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
444 int reg, u32 old, u32 new, u32 mask)
445{
446 struct advk_pcie *pcie = bridge->data;
447
448 switch (reg) {
449 case PCI_EXP_DEVCTL:
450 case PCI_EXP_LNKCTL:
451 advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
452 break;
453
454 case PCI_EXP_RTCTL:
455 new = (new & PCI_EXP_RTCTL_PMEIE) << 3;
456 advk_writel(pcie, new, PCIE_ISR0_MASK_REG);
457 break;
458
459 case PCI_EXP_RTSTA:
460 new = (new & PCI_EXP_RTSTA_PME) >> 9;
461 advk_writel(pcie, new, PCIE_ISR0_REG);
462 break;
463
464 default:
465 break;
466 }
467}
468
469struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {
470 .read_pcie = advk_pci_bridge_emul_pcie_conf_read,
471 .write_pcie = advk_pci_bridge_emul_pcie_conf_write,
472};
473
474/*
475 * Initialize the configuration space of the PCI-to-PCI bridge
476 * associated with the given PCIe interface.
477 */
478static void advk_sw_pci_bridge_init(struct advk_pcie *pcie)
479{
480 struct pci_bridge_emul *bridge = &pcie->bridge;
481
482 bridge->conf.vendor = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff;
483 bridge->conf.device = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) >> 16;
484 bridge->conf.class_revision =
485 advk_readl(pcie, PCIE_CORE_DEV_REV_REG) & 0xff;
486
487 /* Support 32 bits I/O addressing */
488 bridge->conf.iobase = PCI_IO_RANGE_TYPE_32;
489 bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32;
490
491 /* Support 64 bits memory pref */
492 bridge->conf.pref_mem_base = PCI_PREF_RANGE_TYPE_64;
493 bridge->conf.pref_mem_limit = PCI_PREF_RANGE_TYPE_64;
494
495 /* Support interrupt A for MSI feature */
496 bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE;
497
498 bridge->has_pcie = true;
499 bridge->data = pcie;
500 bridge->ops = &advk_pci_bridge_emul_ops;
501
502 pci_bridge_emul_init(bridge);
503
504}
505
393static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus, 506static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
394 int devfn) 507 int devfn)
395{ 508{
@@ -411,6 +524,10 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
411 return PCIBIOS_DEVICE_NOT_FOUND; 524 return PCIBIOS_DEVICE_NOT_FOUND;
412 } 525 }
413 526
527 if (bus->number == pcie->root_bus_nr)
528 return pci_bridge_emul_conf_read(&pcie->bridge, where,
529 size, val);
530
414 /* Start PIO */ 531 /* Start PIO */
415 advk_writel(pcie, 0, PIO_START); 532 advk_writel(pcie, 0, PIO_START);
416 advk_writel(pcie, 1, PIO_ISR); 533 advk_writel(pcie, 1, PIO_ISR);
@@ -418,7 +535,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
418 /* Program the control register */ 535 /* Program the control register */
419 reg = advk_readl(pcie, PIO_CTRL); 536 reg = advk_readl(pcie, PIO_CTRL);
420 reg &= ~PIO_CTRL_TYPE_MASK; 537 reg &= ~PIO_CTRL_TYPE_MASK;
421 if (bus->number == pcie->root_bus_nr) 538 if (bus->primary == pcie->root_bus_nr)
422 reg |= PCIE_CONFIG_RD_TYPE0; 539 reg |= PCIE_CONFIG_RD_TYPE0;
423 else 540 else
424 reg |= PCIE_CONFIG_RD_TYPE1; 541 reg |= PCIE_CONFIG_RD_TYPE1;
@@ -463,6 +580,10 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
463 if (!advk_pcie_valid_device(pcie, bus, devfn)) 580 if (!advk_pcie_valid_device(pcie, bus, devfn))
464 return PCIBIOS_DEVICE_NOT_FOUND; 581 return PCIBIOS_DEVICE_NOT_FOUND;
465 582
583 if (bus->number == pcie->root_bus_nr)
584 return pci_bridge_emul_conf_write(&pcie->bridge, where,
585 size, val);
586
466 if (where % size) 587 if (where % size)
467 return PCIBIOS_SET_FAILED; 588 return PCIBIOS_SET_FAILED;
468 589
@@ -473,7 +594,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
473 /* Program the control register */ 594 /* Program the control register */
474 reg = advk_readl(pcie, PIO_CTRL); 595 reg = advk_readl(pcie, PIO_CTRL);
475 reg &= ~PIO_CTRL_TYPE_MASK; 596 reg &= ~PIO_CTRL_TYPE_MASK;
476 if (bus->number == pcie->root_bus_nr) 597 if (bus->primary == pcie->root_bus_nr)
477 reg |= PCIE_CONFIG_WR_TYPE0; 598 reg |= PCIE_CONFIG_WR_TYPE0;
478 else 599 else
479 reg |= PCIE_CONFIG_WR_TYPE1; 600 reg |= PCIE_CONFIG_WR_TYPE1;
@@ -875,6 +996,8 @@ static int advk_pcie_probe(struct platform_device *pdev)
875 996
876 advk_pcie_setup_hw(pcie); 997 advk_pcie_setup_hw(pcie);
877 998
999 advk_sw_pci_bridge_init(pcie);
1000
878 ret = advk_pcie_init_irq_domain(pcie); 1001 ret = advk_pcie_init_irq_domain(pcie);
879 if (ret) { 1002 if (ret) {
880 dev_err(dev, "Failed to initialize irq\n"); 1003 dev_err(dev, "Failed to initialize irq\n");