mirror of
https://github.com/torvalds/linux.git
synced 2024-11-19 18:41:48 +00:00
PCI: mvebu: Add PCI Express root complex capability block
Add a PCI Express root complex capability block so the PCI layer identifies the bridge as a PCI Express device. We expose this as a version 1 PCIe capability block, with slot support. We disable the clock power management capability as this depends on boards wiring the CLKREQ# signal. Tested-by: Willy Tarreau <w@1wt.eu> (Iomega iConnect Kirkwood, MiraBox Armada 370) Tested-by: Andrew Lunn <andrew@lunn.ch> (D-Link DIR664 Kirkwood) Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> (Armada XP GP) Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
This commit is contained in:
parent
d609a8d8e8
commit
dc0352ab0b
@ -30,6 +30,7 @@
|
||||
#define PCIE_DEV_REV_OFF 0x0008
|
||||
#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
|
||||
#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
|
||||
#define PCIE_CAP_PCIEXP 0x0060
|
||||
#define PCIE_HEADER_LOG_4_OFF 0x0128
|
||||
#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4))
|
||||
#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
|
||||
@ -57,14 +58,35 @@
|
||||
#define PCIE_STAT_BUS 0xff00
|
||||
#define PCIE_STAT_DEV 0x1f0000
|
||||
#define PCIE_STAT_LINK_DOWN BIT(0)
|
||||
#define PCIE_RC_RTSTA 0x1a14
|
||||
#define PCIE_DEBUG_CTRL 0x1a60
|
||||
#define PCIE_DEBUG_SOFT_RESET BIT(20)
|
||||
|
||||
enum {
|
||||
PCISWCAP = PCI_BRIDGE_CONTROL + 2,
|
||||
PCISWCAP_EXP_LIST_ID = PCISWCAP + PCI_CAP_LIST_ID,
|
||||
PCISWCAP_EXP_DEVCAP = PCISWCAP + PCI_EXP_DEVCAP,
|
||||
PCISWCAP_EXP_DEVCTL = PCISWCAP + PCI_EXP_DEVCTL,
|
||||
PCISWCAP_EXP_LNKCAP = PCISWCAP + PCI_EXP_LNKCAP,
|
||||
PCISWCAP_EXP_LNKCTL = PCISWCAP + PCI_EXP_LNKCTL,
|
||||
PCISWCAP_EXP_SLTCAP = PCISWCAP + PCI_EXP_SLTCAP,
|
||||
PCISWCAP_EXP_SLTCTL = PCISWCAP + PCI_EXP_SLTCTL,
|
||||
PCISWCAP_EXP_RTCTL = PCISWCAP + PCI_EXP_RTCTL,
|
||||
PCISWCAP_EXP_RTSTA = PCISWCAP + PCI_EXP_RTSTA,
|
||||
PCISWCAP_EXP_DEVCAP2 = PCISWCAP + PCI_EXP_DEVCAP2,
|
||||
PCISWCAP_EXP_DEVCTL2 = PCISWCAP + PCI_EXP_DEVCTL2,
|
||||
PCISWCAP_EXP_LNKCAP2 = PCISWCAP + PCI_EXP_LNKCAP2,
|
||||
PCISWCAP_EXP_LNKCTL2 = PCISWCAP + PCI_EXP_LNKCTL2,
|
||||
PCISWCAP_EXP_SLTCAP2 = PCISWCAP + PCI_EXP_SLTCAP2,
|
||||
PCISWCAP_EXP_SLTCTL2 = PCISWCAP + PCI_EXP_SLTCTL2,
|
||||
};
|
||||
|
||||
/* PCI configuration space of a PCI-to-PCI bridge */
|
||||
struct mvebu_sw_pci_bridge {
|
||||
u16 vendor;
|
||||
u16 device;
|
||||
u16 command;
|
||||
u16 status;
|
||||
u16 class;
|
||||
u8 interface;
|
||||
u8 revision;
|
||||
@ -84,13 +106,15 @@ struct mvebu_sw_pci_bridge {
|
||||
u16 memlimit;
|
||||
u16 iobaseupper;
|
||||
u16 iolimitupper;
|
||||
u8 cappointer;
|
||||
u8 reserved1;
|
||||
u16 reserved2;
|
||||
u32 romaddr;
|
||||
u8 intline;
|
||||
u8 intpin;
|
||||
u16 bridgectrl;
|
||||
|
||||
/* PCI express capability */
|
||||
u32 pcie_sltcap;
|
||||
u16 pcie_devctl;
|
||||
u16 pcie_rtctl;
|
||||
};
|
||||
|
||||
struct mvebu_pcie_port;
|
||||
@ -451,6 +475,9 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
|
||||
/* We support 32 bits I/O addressing */
|
||||
bridge->iobase = PCI_IO_RANGE_TYPE_32;
|
||||
bridge->iolimit = PCI_IO_RANGE_TYPE_32;
|
||||
|
||||
/* Add capabilities */
|
||||
bridge->status = PCI_STATUS_CAP_LIST;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -468,7 +495,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
|
||||
break;
|
||||
|
||||
case PCI_COMMAND:
|
||||
*value = bridge->command;
|
||||
*value = bridge->command | bridge->status << 16;
|
||||
break;
|
||||
|
||||
case PCI_CLASS_REVISION:
|
||||
@ -513,6 +540,10 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
|
||||
*value = (bridge->iolimitupper << 16 | bridge->iobaseupper);
|
||||
break;
|
||||
|
||||
case PCI_CAPABILITY_LIST:
|
||||
*value = PCISWCAP;
|
||||
break;
|
||||
|
||||
case PCI_ROM_ADDRESS1:
|
||||
*value = 0;
|
||||
break;
|
||||
@ -522,6 +553,59 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
|
||||
*value = 0;
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_LIST_ID:
|
||||
/* Set PCIe v2, root port, slot support */
|
||||
*value = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2 |
|
||||
PCI_EXP_FLAGS_SLOT) << 16 | PCI_CAP_ID_EXP;
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_DEVCAP:
|
||||
*value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCAP);
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_DEVCTL:
|
||||
*value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL) &
|
||||
~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
|
||||
PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
|
||||
*value |= bridge->pcie_devctl;
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_LNKCAP:
|
||||
/*
|
||||
* PCIe requires the clock power management capability to be
|
||||
* hard-wired to zero for downstream ports
|
||||
*/
|
||||
*value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCAP) &
|
||||
~PCI_EXP_LNKCAP_CLKPM;
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_LNKCTL:
|
||||
*value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_SLTCAP:
|
||||
*value = bridge->pcie_sltcap;
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_SLTCTL:
|
||||
*value = PCI_EXP_SLTSTA_PDS << 16;
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_RTCTL:
|
||||
*value = bridge->pcie_rtctl;
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_RTSTA:
|
||||
*value = mvebu_readl(port, PCIE_RC_RTSTA);
|
||||
break;
|
||||
|
||||
/* PCIe requires the v2 fields to be hard-wired to zero */
|
||||
case PCISWCAP_EXP_DEVCAP2:
|
||||
case PCISWCAP_EXP_DEVCTL2:
|
||||
case PCISWCAP_EXP_LNKCAP2:
|
||||
case PCISWCAP_EXP_LNKCTL2:
|
||||
case PCISWCAP_EXP_SLTCAP2:
|
||||
case PCISWCAP_EXP_SLTCTL2:
|
||||
default:
|
||||
/*
|
||||
* PCI defines configuration read accesses to reserved or
|
||||
@ -614,6 +698,51 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
|
||||
mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus);
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_DEVCTL:
|
||||
/*
|
||||
* Armada370 data says these bits must always
|
||||
* be zero when in root complex mode.
|
||||
*/
|
||||
value &= ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
|
||||
PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
|
||||
|
||||
/*
|
||||
* If the mask is 0xffff0000, then we only want to write
|
||||
* the device control register, rather than clearing the
|
||||
* RW1C bits in the device status register. Mask out the
|
||||
* status register bits.
|
||||
*/
|
||||
if (mask == 0xffff0000)
|
||||
value &= 0xffff;
|
||||
|
||||
mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL);
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_LNKCTL:
|
||||
/*
|
||||
* If we don't support CLKREQ, we must ensure that the
|
||||
* CLKREQ enable bit always reads zero. Since we haven't
|
||||
* had this capability, and it's dependent on board wiring,
|
||||
* disable it for the time being.
|
||||
*/
|
||||
value &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
|
||||
|
||||
/*
|
||||
* If the mask is 0xffff0000, then we only want to write
|
||||
* the link control register, rather than clearing the
|
||||
* RW1C bits in the link status register. Mask out the
|
||||
* status register bits.
|
||||
*/
|
||||
if (mask == 0xffff0000)
|
||||
value &= 0xffff;
|
||||
|
||||
mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
|
||||
break;
|
||||
|
||||
case PCISWCAP_EXP_RTSTA:
|
||||
mvebu_writel(port, value, PCIE_RC_RTSTA);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user