Contents
- PCIe Core
- Configuration Initialization
- Registers
- Reading and writing PCIe Configuration Space or PCIe Registers
- PCIe Configuration Space Registers
- PCIe Registers
- MDIO Access
- PCIe Attach (int state)
- PCIe Workaround PCI Setup
- PCIe Polarity Workaround
- PCIe SERDES Workaround
- PCIe ASPM Clock Request Workaround
- PCIe Clock Request Update (int state)
- u8 PCIe Clock Request (u32 mask, u32 val)
- PCI Setup Workaround
- PCIe No PLL Down Workaround
- PCIe Extend L1 Timer (bool long)
- PCIe Miscellaneous Configuration Fixup
PCIe Core
The Backplane always contains one core responsible for interacting with the computer. In the newer PCI-E cards, it is connected via the PCI-E Core. This core has a Core ID of 0x820.
Configuration Initialization
Besides the normal PCIe initialization done by the kernel routines, the code should also clear bits 0x0000FF00 of configuration register 0x40. This action prevents PCI Tx retries from interfering with the C3 state of the CPU.
Registers
Offset |
Size |
Meaning |
0x000C |
4 |
BIST Status |
0x0028 |
4 |
Backplane to PCIe Mailbox |
0x0100 |
4 |
Backplane to PCIe Translation 0 (sbtopcie0) |
0x0104 |
4 |
Backplane to PCIe Translation 1 (sbtopcie1) |
0x0108 |
4 |
Backplane to PCIe Translation 2 (sbtopcie2) |
0x0120 |
4 |
PCIe Configuration Space: Address |
0x0124 |
4 |
PCIe Configuration Space: Data |
0x0128 |
4 |
MDIO Access: Control |
0x012C |
4 |
MDIO Access: Data |
0x0130 |
4 |
PCIe PHY/DLLP/TLP Register Access: Address |
0x0134 |
4 |
PCIe PHY/DLLP/TLP Register Access: Data |
Reading and writing PCIe Configuration Space or PCIe Registers
First, write the register offset to the control register (0x120 for PCIe Configuration Registers or 0x130 for PCIe Registers), then either read or write the the associated data register.
PCIe Configuration Space Registers
PCIe Registers
Offset |
Size |
Usage |
TLP Diagnostic Registers |
||
0x0000 |
4 |
Configuration Register |
0x0004 |
4 |
TLP Workarounds Register |
0x0010 |
4 |
Write DMA Upper Address |
0x0014 |
4 |
Write DMA Lower Address |
0x0018 |
4 |
Write DMA Request Length / Byte Encoding |
0x001C |
4 |
Read DMA Upper Address |
0x0020 |
4 |
Read DMA Lower Address |
0x0024 |
4 |
Read DMA Request Length |
0x0028 |
4 |
MSI DMA Upper Address |
0x002C |
4 |
MSI DMA Lower Address |
0x0030 |
4 |
MSI DMA Request Length |
0x0034 |
4 |
Slave Request Length |
0x0038 |
4 |
Flow Control Inputs |
0x003C |
4 |
TX State Machine and Gated Request |
0x0040 |
4 |
Address ACK, Transfer Count and ARB Length |
0x0044 |
4 |
DMA Completion Header 0 |
0x0048 |
4 |
DMA Completion Header 1 |
0x004C |
4 |
DMA Completion Header 2 |
0x0050 |
4 |
DMA Completion Misc 0 |
0x0054 |
4 |
DMA Completion Misc 1 |
0x0058 |
4 |
DMA Completion Misc 2 |
0x005C |
4 |
Split Controller Request Length |
0x0060 |
4 |
Splig Controller Misc 0 |
0x0064 |
4 |
Splig Controller Misc 1 |
0x0068 |
4 |
Bus / Device Function |
0x006C |
4 |
Reset Counter |
0x0070 |
4 |
Retry Buffer Value |
0x0074 |
4 |
Target Debug Register 1 |
0x0078 |
4 |
Target Debug Register 2 |
0x007C |
4 |
Target Debug Register 3 |
0x0080 |
4 |
Target Debug Register 4 |
DLLP Diagnostic Registers |
||
0x0100 |
4 |
Link Control Register |
0x0104 |
4 |
Link Status |
0x0108 |
4 |
Link Attention |
0x010C |
4 |
Link Attention Mask |
0x0110 |
4 |
Next TX Sequence Number |
0x0114 |
4 |
ACK'd TX Sequence Number |
0x0118 |
4 |
Purged TX Sequence Number |
0x011C |
4 |
RX Sequence Number |
0x0120 |
4 |
Link Replay |
0x0124 |
4 |
Link ACK Timeout |
0x0128 |
4 |
Power Management Threshold |
0x012C |
4 |
Retry Buffer Write Pointer |
0x0130 |
4 |
Retry Buffer Read Pointer |
0x0134 |
4 |
Retry Buffer Purged Pointer |
0x0138 |
4 |
Retry Buffer Read / Write |
0x013C |
4 |
Error Count Threshold |
0x0140 |
4 |
TLP Error Counter |
0x0144 |
4 |
Error Counter |
0x0148 |
4 |
NAK Received Counter |
0x014C |
4 |
Test Register |
0x0150 |
4 |
Packet BIST |
PHY Diagnostic Registers |
||
0x0200 |
4 |
Mode |
0x0204 |
4 |
Status |
0x0208 |
4 |
LTSSM Control |
0x020C |
4 |
Link Training Link Number |
0x0210 |
4 |
Link Training Lane Number |
0x0214 |
4 |
Link Training N FTS |
0x0218 |
4 |
Attention |
0x021C |
4 |
Attention Mask |
0x0220 |
4 |
RX Error Counter |
0x0224 |
4 |
RX Framing Error Counter |
0x0228 |
4 |
RX Error Threshold |
0x022C |
4 |
Test Control Register |
0x0230 |
4 |
SERDES Control Override |
0x0234 |
4 |
Timing Parameters Override |
0x0238 |
4 |
RX/TX State Machine Diag |
0x023C |
4 |
LTSSM State Machine Diag |
MDIO Access
MDIO Control Register Usage
Bitmask |
Usage |
0x007F |
MDIO Clock Divsor |
0x0080 |
Enable/Disable Preamble Sequence |
0x0100 |
MDIO Transaction Complete |
MDIO SERDES Devices
Address |
Device |
0x1D |
SERDES PLL Device |
0x1F |
SERDES RX Device |
SERDES RX Device Registers
Offset |
Usage |
1 |
RX Control |
2 |
RX Timer |
6 |
CDR |
7 |
CDR BW |
int PCIe MDIO Set Block (u32 blk)
(updated for 5.10.56.46)
Initialize mdiodata (u32) with Start of Transaction bit set, the Write Transaction bit set and the Turnaround bit set (0x50020000), then Set the SERDES Rx device code (0x1F) in the address field, and OR with blk<<4.
- Write mdiodata to the MDIO Data Register
- Delay 10 usec
- Spin wait for bit 0x100 to be set in the MDIO Control register. Delay 1000 usec between tries and try for 200 times.
- If above loop times out
- Return 0
- Return 1
int Read/Write MDIO Slaves (u32 phys, u32 addr, u32 *val)
(updated for 5.10.56.46)
- Write 0x82 (Enable Preamble Sequence bitwise OR'd with a divisor value of 2) to the MDIO Control Register
If PCIe core revision >= 10
- Call PCIe MDIO Set Block with phys as argument
- If the returned value is 0
- Return 1
Set mdiodata as addr << 18
- Set spinwait loop counter to 200
- Otherwise
Set mdiodata to phys << 22 | addr << 18
- Set spinwait loop counter to 10
- OR mdiodata with the Start of Transaction bit, and the Turnaround bit.
- If reading
- Set the Read Transaction bit in mdiodata
- Otherwise
- Set the Write Transaction bit in mdiodata and OR with *val.
- Write mdiodata to the MDIO Data Register
- Delay 10 usec
- Spinwait for bit 0x100 of the MDIO Control Register to be set. Delay 1000 usec between trials and use the spinwait loop counter to determine the number of tries
- If the spinwait loop was not satisfied
- Write 0 to the MDIO Control Register
- Return 1
- If this is a read operation
- Delay 10 usec
- Read MDIO Data Register, mask with 0xFFFF, and store in *val
- Write 0 to MDIO Control Register
- Return 0
MDIO Data Word Format
Mask |
Function |
0x40000000 |
Start of Transaction |
0x20000000 |
Read Transaction |
0x10000000 |
Write Transaction |
0x0FC00000 |
Device Address |
0x003C0000 |
Register |
0x00020000 |
Turnaround |
0x0000FFFF |
Data |
PCIe Attach (int state)
If (the board vendor is Apple AND the SPROM Rev is 4 AND the boad revision < 0x72) OR bit 0x20 is set in board flags 2
Set pcie_war_aspm_ovr true
- Otherwise
Set pcie_war_aspm_ovr false
Set pcie_polarity to 0
- Call PCIe Polarity Workaround
- Call PCIe SERDES Workaround
- Call PCIe ASPM Clock Request Workaround
- Call PCIe Clock Request Update with state as argument
PCIe Workaround PCI Setup
- If PCI core rev is 0 or 1
- Set bit 0x8 in PCI Register 4
- If PCI core rev is 1
- Set bit 0x40 in PCI Register 0x100
- If PCI core rev is 0
- Write 0x8128 to serdes RX timer
- Write 0x0100 to serdes RX CDR
- Write 0x1466 to serdes RX CDR BW
- Else if PCIE and PCI core rev is 3, 4, or 5
- Read PCI Register 0x128
- Mask result with 0x00FF
OR result with 0x72 << 8
- Write result to PCI register 0x128
- Call PCIe SERDES Workaround
- Call PCIe ASPM Clock Request Workaround
- Else if PCI core rev is 7
- Call PCIe No PLL Down Workaround
If PCI core rev >= 6
- Call PCIe Miscellaneous Configuration Fixup
PCIe Polarity Workaround
If pcie_polarity is not zero
- Return
- If the PCIe PHY Status Register (0x204) anded with 0x10 is zero
Set pcie_polarity to 0x80
- Otherwise
Set pcie_polarity to 0xC0
PCIe SERDES Workaround
If pcie_polarity is not zero
- Write that value to the SERDES RX Control
- Clear bit 0x4000 in the SERDES PLL Control
PCIe ASPM Clock Request Workaround
- If the core revision is not 3, 4 or 5
- Exit
If pcie_war_aspm_ovr is false
- Get the address at sprom[4] (Note: the u16 sprom array is mapped to the shadow sprom location)
- Set bits 0x18 in that address
- Otherwise
- Clear bits 0x18 in that address
- Get an MMIO address from sprom[14]
If pcie_war_aspm_ovr is false
- Set bit 0x0800 in that address
Set pcie_pr42767 to 1
- Otherwise
- Clear bit 0x0800 in that address
Set pcie_pr42767 to 0
PCIe Clock Request Update (int state)
- If state is 1
- If the core revision is 3, 4, or 5
- Call PCIe Clock Request with 1, 0 as arguments
- If the core revision is 3, 4, or 5
- Else if state is 2
- Else if core revision is 6
- Clear the Chip Control Address Register (0x650)
- Mask the Chip Control Data (0x654) with mask 0x40
Else if pcie_pr42767 is true
- Call PCIe Clock Request with 1, 1 as arguments
- Else if core revision is 6
- Else if state is 3
- If core revision is 6
- Clear the Chip Control Address Register (0x650)
- Write 0x40 to the Chip Control Data (0x654)
- Else if core revision is 5
- Call PCIe Clock Request with 1, 0 as arguments
- If core revision is 6
u8 PCIe Clock Request (u32 mask, u32 val)
Set offset to pciecap_lcreg_offset
- If offset is zero
- Return
- If maks is not zero
- If val is zero
- Set bit 0x100 at the PCI Configuration register at offset
- Otherwise
- Clear bit 0x100 at the PCI Configuration register at offset
- If val is zero
- Read the PCI Configuration register at offset
- If bit 0x100 is set in the result
- Return 1
- Return 0
PCI Setup Workaround
- If the Core Revision is 0 or 1
- Set bit 8 in the TLP Workaround register
- If the core revision is 1
- Set bit 0x40 in the DLLP Link Control register
- If the core revision is 0
- Write 0x8128 to the SERDES RX Timer
- Write 0x0100 to the SERDES RX CDR
- Write 0x1466 to the SERDES RX CDR BW
- Else if the core revision 3, 4 or 5 and this is a PCIe bus
- Maskset the DLLP Power Management Threshold with mask 0x00FF and set with 0x7200
- Do the PCI-E SERDES Workaround
- Do the PCI-E ASPM Clock Request Workaround
- Else if the core revision is 7
- Do the PCIe No PLL Down Workaround
If the core revision >= 6
- Do the PCIe Miscellaneous Config Fixup
PCIe No PLL Down Workaround
- If the core revision is not 7
- Return
- Set bit 0x800000 in the Chip Control Register (0x28)
- Get the address at sprom[6]
- Write 0 to that address
PCIe Extend L1 Timer (bool long)
- If not a PCI-E core
- Exit
- If the core revision is not 7 and not 8
- Exit
- If long is TRUE
- Set bit 0x01000000 in the PCI-E DLP Power Management Threshold Register
- Otherwise
- Clear bit 0x01000000 in the PCI-E DLP Power Management Threshold Register
- Do dummy read of the PCI-E DLP Power Management Threshold Register
PCIe Miscellaneous Configuration Fixup
- Read sprom[5] to get a register offset
- Set bit 0x8000 in that address (for BCM4312, the address is 0x280A)