1 /** @file 2 * Initialize the XPress-RICH3 PCIe Root complex 3 * 4 * Copyright (c) 2011-2015, ARM Ltd. All rights reserved. 5 * 6 * This program and the accompanying materials 7 * are licensed and made available under the terms and conditions of the BSD License 8 * which accompanies this distribution. The full text of the license may be found at 9 * http://opensource.org/licenses/bsd-license.php 10 * 11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 * 14 **/ 15 16 #include "PciHostBridge.h" 17 18 #include <Protocol/Cpu.h> 19 20 #include "ArmPlatform.h" 21 22 EFI_CPU_ARCH_PROTOCOL *mCpu; 23 24 #define PCI_BRIDGE_REVISION_ID 1 25 #define CLASS_CODE_REGISTER(Class, SubClass, ProgIf) ((Class << 16) | (SubClass << 8) | ProgIf) 26 #define PLDA_BRIDGE_CCR CLASS_CODE_REGISTER(PCI_CLASS_BRIDGE, \ 27 PCI_CLASS_BRIDGE_P2P, \ 28 PCI_IF_BRIDGE_P2P) 29 30 STATIC 31 VOID 32 SetTranslationAddressEntry ( 33 IN EFI_CPU_IO2_PROTOCOL *CpuIo, 34 IN UINTN Entry, 35 IN UINT64 SourceAddress, 36 IN UINT64 TranslatedAddress, 37 IN UINT64 TranslationSize, 38 IN UINT64 TranslationParameter 39 ) 40 { 41 UINTN Log2Size = HighBitSet64 (TranslationSize); 42 43 // Ensure the size is a power of two. Restriction form the AXI Translation logic 44 // Othwerwise we increase the translation size 45 if (TranslationSize != (1ULL << Log2Size)) { 46 DEBUG ((EFI_D_WARN, "PCI: The size 0x%lX of the region 0x%lx has been increased to " 47 "be a power of two for the AXI translation table.\n", 48 TranslationSize, SourceAddress)); 49 Log2Size++; 50 } 51 52 PCIE_ROOTPORT_WRITE32 (Entry + PCI_ATR_SRC_ADDR_LOW_SIZE, 53 (UINT32)SourceAddress | ((Log2Size - 1) << 1) | 0x1); 54 PCIE_ROOTPORT_WRITE32 (Entry + PCI_ATR_SRC_ADDR_HI, SourceAddress >> 32); 55 56 PCIE_ROOTPORT_WRITE32 (Entry + PCI_ATR_TRSL_ADDR_LOW, (UINT32)TranslatedAddress); 57 PCIE_ROOTPORT_WRITE32 (Entry + PCI_ATR_TRSL_ADDR_HI, TranslatedAddress >> 32); 58 59 PCIE_ROOTPORT_WRITE32 (Entry + PCI_ATR_TRSL_PARAM, TranslationParameter); 60 } 61 62 EFI_STATUS 63 HWPciRbInit ( 64 IN EFI_CPU_IO2_PROTOCOL *CpuIo 65 ) 66 { 67 UINT32 Value; 68 UINT32 Index; 69 UINTN TranslationTable; 70 71 PCI_TRACE ("VExpressPciRbInit()"); 72 73 PCI_TRACE ("PCIe Setting up Address Translation"); 74 75 // The Juno PIO window is 8M, so we need full 32-bit PIO decoding. 76 PCIE_ROOTPORT_WRITE32 (PCIE_BAR_WIN, PCIE_BAR_WIN_SUPPORT_IO | PCIE_BAR_WIN_SUPPORT_IO32 | 77 PCIE_BAR_WIN_SUPPORT_MEM | PCIE_BAR_WIN_SUPPORT_MEM64); 78 79 // Setup the PCI Configuration Registers 80 // Offset 0a: SubClass 04 PCI-PCI Bridge 81 // Offset 0b: BaseClass 06 Bridge Device 82 // The Class Code register is a 24 bit and can be configured by setting up the PCIE_PCI_IDS 83 // Refer [1] Chapter 13 84 PCIE_ROOTPORT_WRITE32 (PCIE_PCI_IDS + PCIE_PCI_IDS_CLASSCODE_OFFSET, ((PLDA_BRIDGE_CCR << 8) | PCI_BRIDGE_REVISION_ID)); 85 86 // 87 // PCIE Window 0 -> AXI4 Master 0 Address Translations 88 // 89 TranslationTable = VEXPRESS_ATR_PCIE_WIN0; 90 91 // MSI Support 92 SetTranslationAddressEntry (CpuIo, TranslationTable, ARM_JUNO_GIV2M_MSI_BASE, ARM_JUNO_GIV2M_MSI_BASE, 93 ARM_JUNO_GIV2M_MSI_SZ, PCI_ATR_TRSLID_AXIDEVICE); 94 TranslationTable += PCI_ATR_ENTRY_SIZE; 95 96 // System Memory Support 97 SetTranslationAddressEntry (CpuIo, TranslationTable, PcdGet64 (PcdSystemMemoryBase), PcdGet64 (PcdSystemMemoryBase), 98 PcdGet64 (PcdSystemMemorySize), PCI_ATR_TRSLID_AXIMEMORY); 99 TranslationTable += PCI_ATR_ENTRY_SIZE; 100 SetTranslationAddressEntry (CpuIo, TranslationTable, ARM_JUNO_EXTRA_SYSTEM_MEMORY_BASE, ARM_JUNO_EXTRA_SYSTEM_MEMORY_BASE, 101 ARM_JUNO_EXTRA_SYSTEM_MEMORY_SZ, PCI_ATR_TRSLID_AXIMEMORY); 102 103 // 104 // AXI4 Slave 1 -> PCIE Window 0 Address Translations 105 // 106 TranslationTable = VEXPRESS_ATR_AXI4_SLV1; 107 108 // PCI ECAM Support 109 SetTranslationAddressEntry (CpuIo, TranslationTable, PCI_ECAM_BASE, PCI_ECAM_BASE, PCI_ECAM_SIZE, PCI_ATR_TRSLID_PCIE_CONF); 110 TranslationTable += PCI_ATR_ENTRY_SIZE; 111 112 // PCI IO Support, the PIO space is translated from the arm MMIO PCI_IO_BASE address to the PIO base address of 0 113 // AKA, PIO addresses used by endpoints are generally in the range of 0-64K. 114 SetTranslationAddressEntry (CpuIo, TranslationTable, PCI_IO_BASE, 0, PCI_IO_SIZE, PCI_ATR_TRSLID_PCIE_IO); 115 TranslationTable += PCI_ATR_ENTRY_SIZE; 116 117 // PCI MEM32 Support 118 SetTranslationAddressEntry (CpuIo, TranslationTable, PCI_MEM32_BASE, PCI_MEM32_BASE, PCI_MEM32_SIZE, PCI_ATR_TRSLID_PCIE_MEMORY); 119 TranslationTable += PCI_ATR_ENTRY_SIZE; 120 121 // PCI MEM64 Support 122 SetTranslationAddressEntry (CpuIo, TranslationTable, PCI_MEM64_BASE, PCI_MEM64_BASE, PCI_MEM64_SIZE, PCI_ATR_TRSLID_PCIE_MEMORY); 123 124 // Add credits 125 PCIE_ROOTPORT_WRITE32 (PCIE_VC_CRED, 0x00f0b818); 126 PCIE_ROOTPORT_WRITE32 (PCIE_VC_CRED + 4, 0x1); 127 128 // Allow ECRC 129 PCIE_ROOTPORT_WRITE32 (PCIE_PEX_SPC2, 0x6006); 130 131 // Reset controller 132 PCIE_CONTROL_WRITE32 (PCIE_CONTROL_RST_CTL, PCIE_CONTROL_RST_CTL_RCPHY_REL); 133 134 // Wait for reset 135 for (Index = 0; Index < 1000; Index++) { 136 gBS->Stall (1000); 137 PCIE_CONTROL_READ32 (PCIE_CONTROL_RST_STS, Value); 138 if ((Value & PCIE_CONTROL_RST_STS_RCPHYPLL_OUT) == PCIE_CONTROL_RST_STS_RCPHYPLL_OUT) { 139 break; 140 } 141 } 142 143 // Check for reset 144 if (!(Value & PCIE_CONTROL_RST_STS_RCPHYPLL_OUT)) { 145 DEBUG ((EFI_D_ERROR, "PCIe failed to come out of reset: %x.\n", Value)); 146 return EFI_NOT_READY; 147 } 148 149 gBS->Stall (1000); 150 PCI_TRACE ("Checking link Status..."); 151 152 // Wait for Link Up 153 for (Index = 0; Index < 1000; Index++) { 154 gBS->Stall (1000); 155 PCIE_ROOTPORT_READ32 (VEXPRESS_BASIC_STATUS, Value); 156 if (Value & LINK_UP) { 157 break; 158 } 159 } 160 161 // Check for link up 162 if (!(Value & LINK_UP)) { 163 DEBUG ((EFI_D_ERROR, "PCIe link not up: %x.\n", Value)); 164 return EFI_NOT_READY; 165 } 166 167 PCIE_ROOTPORT_WRITE32 (PCIE_IMASK_LOCAL, PCIE_INT_MSI | PCIE_INT_INTx); 168 169 return EFI_SUCCESS; 170 } 171