mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02: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
					
				
					 1 changed files with 133 additions and 4 deletions
				
			
		| 
						 | 
					@ -30,6 +30,7 @@
 | 
				
			||||||
#define PCIE_DEV_REV_OFF	0x0008
 | 
					#define PCIE_DEV_REV_OFF	0x0008
 | 
				
			||||||
#define PCIE_BAR_LO_OFF(n)	(0x0010 + ((n) << 3))
 | 
					#define PCIE_BAR_LO_OFF(n)	(0x0010 + ((n) << 3))
 | 
				
			||||||
#define PCIE_BAR_HI_OFF(n)	(0x0014 + ((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_HEADER_LOG_4_OFF	0x0128
 | 
				
			||||||
#define PCIE_BAR_CTRL_OFF(n)	(0x1804 + (((n) - 1) * 4))
 | 
					#define PCIE_BAR_CTRL_OFF(n)	(0x1804 + (((n) - 1) * 4))
 | 
				
			||||||
#define PCIE_WIN04_CTRL_OFF(n)	(0x1820 + ((n) << 4))
 | 
					#define PCIE_WIN04_CTRL_OFF(n)	(0x1820 + ((n) << 4))
 | 
				
			||||||
| 
						 | 
					@ -57,14 +58,35 @@
 | 
				
			||||||
#define  PCIE_STAT_BUS                  0xff00
 | 
					#define  PCIE_STAT_BUS                  0xff00
 | 
				
			||||||
#define  PCIE_STAT_DEV                  0x1f0000
 | 
					#define  PCIE_STAT_DEV                  0x1f0000
 | 
				
			||||||
#define  PCIE_STAT_LINK_DOWN		BIT(0)
 | 
					#define  PCIE_STAT_LINK_DOWN		BIT(0)
 | 
				
			||||||
 | 
					#define PCIE_RC_RTSTA		0x1a14
 | 
				
			||||||
#define PCIE_DEBUG_CTRL         0x1a60
 | 
					#define PCIE_DEBUG_CTRL         0x1a60
 | 
				
			||||||
#define  PCIE_DEBUG_SOFT_RESET		BIT(20)
 | 
					#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 */
 | 
					/* PCI configuration space of a PCI-to-PCI bridge */
 | 
				
			||||||
struct mvebu_sw_pci_bridge {
 | 
					struct mvebu_sw_pci_bridge {
 | 
				
			||||||
	u16 vendor;
 | 
						u16 vendor;
 | 
				
			||||||
	u16 device;
 | 
						u16 device;
 | 
				
			||||||
	u16 command;
 | 
						u16 command;
 | 
				
			||||||
 | 
						u16 status;
 | 
				
			||||||
	u16 class;
 | 
						u16 class;
 | 
				
			||||||
	u8 interface;
 | 
						u8 interface;
 | 
				
			||||||
	u8 revision;
 | 
						u8 revision;
 | 
				
			||||||
| 
						 | 
					@ -84,13 +106,15 @@ struct mvebu_sw_pci_bridge {
 | 
				
			||||||
	u16 memlimit;
 | 
						u16 memlimit;
 | 
				
			||||||
	u16 iobaseupper;
 | 
						u16 iobaseupper;
 | 
				
			||||||
	u16 iolimitupper;
 | 
						u16 iolimitupper;
 | 
				
			||||||
	u8 cappointer;
 | 
					 | 
				
			||||||
	u8 reserved1;
 | 
					 | 
				
			||||||
	u16 reserved2;
 | 
					 | 
				
			||||||
	u32 romaddr;
 | 
						u32 romaddr;
 | 
				
			||||||
	u8 intline;
 | 
						u8 intline;
 | 
				
			||||||
	u8 intpin;
 | 
						u8 intpin;
 | 
				
			||||||
	u16 bridgectrl;
 | 
						u16 bridgectrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* PCI express capability */
 | 
				
			||||||
 | 
						u32 pcie_sltcap;
 | 
				
			||||||
 | 
						u16 pcie_devctl;
 | 
				
			||||||
 | 
						u16 pcie_rtctl;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mvebu_pcie_port;
 | 
					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 */
 | 
						/* We support 32 bits I/O addressing */
 | 
				
			||||||
	bridge->iobase = PCI_IO_RANGE_TYPE_32;
 | 
						bridge->iobase = PCI_IO_RANGE_TYPE_32;
 | 
				
			||||||
	bridge->iolimit = 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;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PCI_COMMAND:
 | 
						case PCI_COMMAND:
 | 
				
			||||||
		*value = bridge->command;
 | 
							*value = bridge->command | bridge->status << 16;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PCI_CLASS_REVISION:
 | 
						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);
 | 
							*value = (bridge->iolimitupper << 16 | bridge->iobaseupper);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case PCI_CAPABILITY_LIST:
 | 
				
			||||||
 | 
							*value = PCISWCAP;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PCI_ROM_ADDRESS1:
 | 
						case PCI_ROM_ADDRESS1:
 | 
				
			||||||
		*value = 0;
 | 
							*value = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -522,6 +553,59 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
 | 
				
			||||||
		*value = 0;
 | 
							*value = 0;
 | 
				
			||||||
		break;
 | 
							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:
 | 
						default:
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * PCI defines configuration read accesses to reserved or
 | 
							 * 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);
 | 
							mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus);
 | 
				
			||||||
		break;
 | 
							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:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue