Home | History | Annotate | Download | only in PciHostBridgeDxe
      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