[edk2-devel] [edk2-platforms: PATCH v2 07/14] Marvell/Armada7k8k: Implement PciHostBridgeLib

Marcin Wojtas mw at semihalf.com
Mon May 20 15:27:20 UTC 2019


Add an implementation of the PciHostBridgeLib glue library that
describes the PCIe RC on this SoC so that the generic PCI host bridge
driver can attach to it.

This includes a constructor which performs the SoC specific init and
training sequences.

This patch is based on work of Ard Biesheuvel <ard.biesheuvel at linaro.org>
and Jing Hua <jinghua at marvell.com>/

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Marcin Wojtas <mw at semihalf.com>
---
 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf          |  52 +++
 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h |  95 ++++++
 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c            | 265 +++++++++++++++
 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c | 345 ++++++++++++++++++++
 4 files changed, 757 insertions(+)
 create mode 100644 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf
 create mode 100644 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h
 create mode 100644 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c
 create mode 100644 Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c

diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf
new file mode 100644
index 0000000..e46f71d
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.inf
@@ -0,0 +1,52 @@
+## @file
+#  PCI Host Bridge Library instance for Marvell Armada 7k/8k SOC
+#
+#  Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+#  Copyright (c) 2019 Marvell International Ltd. All rights reserved.<BR>
+#
+#  This program and the accompanying materials are licensed and made available
+#  under the terms and conditions of the BSD License which accompanies this
+#  distribution. The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
+#  IMPLIED.
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = Armada7k8kPciHostBridgeLib
+  FILE_GUID                      = 7f989c9d-02a0-4348-8aeb-ab2e1566fb18
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PciHostBridgeLib|DXE_DRIVER
+  CONSTRUCTOR                    = Armada7k8kPciHostBridgeLibConstructor
+
+[Sources]
+  PciHostBridgeLib.c
+  PciHostBridgeLibConstructor.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+  ArmLib
+  ArmadaSoCDescLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  MvGpioLib
+  UefiBootServicesTableLib
+
+[Protocols]
+  gEmbeddedGpioProtocolGuid
+  gMarvellBoardDescProtocolGuid
+
+[Depex]
+  gMarvellPlatformInitCompleteProtocolGuid
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h
new file mode 100644
index 0000000..8188001
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.h
@@ -0,0 +1,95 @@
+/** @file
+  PCI Host Bridge Library instance for Marvell 70x0/80x0
+
+  Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+  Copyright (c) 2019 Marvell International Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php.
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __PCI_HOST_BRIDGE_LIB_CONSTRUCTOR_H__
+#define __PCI_HOST_BRIDGE_LIB_CONSTRUCTOR_H__
+
+#define IATU_VIEWPORT_OFF                                   0x900
+#define IATU_VIEWPORT_INBOUND                               BIT31
+#define IATU_VIEWPORT_OUTBOUND                              0
+#define IATU_VIEWPORT_REGION_INDEX(Idx)                     ((Idx) & 7)
+
+#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0                   0x904
+#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM          0x0
+#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO           0x2
+#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0         0x4
+#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1         0x5
+
+#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0                   0x908
+#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN         BIT31
+#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE    BIT28
+
+#define IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0                   0x90C
+#define IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0                 0x910
+#define IATU_LIMIT_ADDR_OFF_OUTBOUND_0                      0x914
+#define IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0                 0x918
+#define IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0               0x91C
+
+#define PORT_LINK_CTRL_OFF                                  0x710
+#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x1                  (0x01 << 16)
+#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x2                  (0x03 << 16)
+#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x4                  (0x07 << 16)
+#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x8                  (0x0f << 16)
+#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_x16                 (0x1f << 16)
+#define PORT_LINK_CTRL_OFF_LINK_CAPABLE_MASK                (0x3f << 16)
+
+#define GEN2_CTRL_OFF                                       0x80c
+#define GEN2_CTRL_OFF_NUM_OF_LANES(n)                       (((n) & 0x1f) << 8)
+#define GEN2_CTRL_OFF_NUM_OF_LANES_MASK                     (0x1f << 8)
+#define GEN2_CTRL_OFF_DIRECT_SPEED_CHANGE                   BIT17
+
+#define PCIE_GLOBAL_CTRL_OFFSET                             0x8000
+#define PCIE_GLOBAL_APP_LTSSM_EN                            BIT2
+#define PCIE_GLOBAL_CTRL_DEVICE_TYPE_RC                     (0x4 << 4)
+#define PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK                   (0xF << 4)
+
+#define PCIE_GLOBAL_STATUS_REG                              0x8008
+#define PCIE_GLOBAL_STATUS_RDLH_LINK_UP                     BIT1
+#define PCIE_GLOBAL_STATUS_PHY_LINK_UP                      BIT9
+
+#define PCIE_PM_STATUS                                      0x8014
+#define PCIE_PM_LTSSM_STAT_MASK                             (0x3f << 3)
+
+#define PCIE_GLOBAL_INT_MASK1_REG                           0x8020
+#define PCIE_INT_A_ASSERT_MASK                              BIT9
+#define PCIE_INT_B_ASSERT_MASK                              BIT10
+#define PCIE_INT_C_ASSERT_MASK                              BIT11
+#define PCIE_INT_D_ASSERT_MASK                              BIT12
+
+#define PCIE_ARCACHE_TRC_REG                                0x8050
+#define PCIE_AWCACHE_TRC_REG                                0x8054
+#define PCIE_ARUSER_REG                                     0x805C
+#define PCIE_AWUSER_REG                                     0x8060
+
+#define ARCACHE_DEFAULT_VALUE                               0x3511
+#define AWCACHE_DEFAULT_VALUE                               0x5311
+
+#define AX_USER_DOMAIN_INNER_SHAREABLE                      (0x1 << 4)
+#define AX_USER_DOMAIN_OUTER_SHAREABLE                      (0x2 << 4)
+#define AX_USER_DOMAIN_MASK                                 (0x3 << 4)
+
+#define PCIE_LINK_CAPABILITY                                0x7C
+#define PCIE_LINK_CTL_2                                     0xA0
+#define TARGET_LINK_SPEED_MASK                              0xF
+#define LINK_SPEED_GEN_1                                    0x1
+#define LINK_SPEED_GEN_2                                    0x2
+#define LINK_SPEED_GEN_3                                    0x3
+
+#define PCIE_GEN3_EQU_CTRL                                  0x8A8
+#define GEN3_EQU_EVAL_2MS_DISABLE                           BIT5
+
+#define PCIE_LINK_UP_TIMEOUT_US                             40000
+
+#endif
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c
new file mode 100644
index 0000000..58cdf83
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLib.c
@@ -0,0 +1,265 @@
+/** @file
+  PCI Host Bridge Library instance for Marvell Armada 70x0/80x0
+
+  Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+  Copyright (c) 2019 Marvell International Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php.
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <PiDxe.h>
+
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/BoardDesc.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+#pragma pack(1)
+typedef struct {
+  ACPI_HID_DEVICE_PATH     AcpiDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+#pragma pack ()
+
+STATIC EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath = {
+  {
+    {
+      ACPI_DEVICE_PATH,
+      ACPI_DP,
+      {
+        (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
+        (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)
+      }
+    },
+    EISA_PNP_ID (0x0A08), // PCI Express
+    0
+  },
+
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      END_DEVICE_PATH_LENGTH,
+      0
+    }
+  }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+  L"Mem", L"I/O", L"Bus"
+};
+
+/**
+  Return all the root bridge instances in an array.
+
+  @param Count  Return the count of root bridge instances.
+
+  @return All the root bridge instances in an array.
+          The array should be passed into PciHostBridgeFreeRootBridges()
+          when it's not used.
+
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+  UINTN *Count
+  )
+{
+  MV_BOARD_PCIE_DESCRIPTION CONST *BoardPcieDescription;
+  MARVELL_BOARD_DESC_PROTOCOL     *BoardDescriptionProtocol;
+  MV_PCIE_CONTROLLER CONST        *PcieController;
+  PCI_ROOT_BRIDGE                 *PciRootBridges;
+  PCI_ROOT_BRIDGE                 *RootBridge;
+  EFI_STATUS                       Status;
+  UINTN                            Index;
+
+  *Count = 0;
+
+  /* Obtain list of available controllers */
+  Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid,
+                  NULL,
+                  (VOID **)&BoardDescriptionProtocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Cannot locate BoardDesc protocol\n",
+      __FUNCTION__));
+    return NULL;
+  }
+
+  Status = BoardDescriptionProtocol->PcieDescriptionGet (
+                                       BoardDescriptionProtocol,
+                                       &BoardPcieDescription);
+  if (Status == EFI_NOT_FOUND) {
+    /* No controllers used on the platform, exit silently */
+    return NULL;
+  } else if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Cannot get Pcie board desc from BoardDesc protocol\n",
+      __FUNCTION__));
+    return NULL;
+  }
+
+  /* Assign return values */
+  PciRootBridges = AllocateZeroPool (BoardPcieDescription->PcieControllerCount *
+                                     sizeof (PCI_ROOT_BRIDGE));
+  if (PciRootBridges == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to allocate resources\n", __FUNCTION__));
+    return NULL;
+  }
+
+  *Count = BoardPcieDescription->PcieControllerCount;
+  RootBridge = PciRootBridges;
+
+  /* Fill information of all root bridge instances */
+  for (Index = 0; Index < *Count; Index++, RootBridge++) {
+
+    PcieController = &(BoardPcieDescription->PcieControllers[Index]);
+
+    RootBridge->Segment   = 0;
+    RootBridge->Supports  = 0;
+    RootBridge->Attributes  = RootBridge->Supports;
+
+    RootBridge->DmaAbove4G  = FALSE;
+
+#ifndef MDE_CPU_ARM
+    RootBridge->AllocationAttributes  = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
+                                        EFI_PCI_HOST_BRIDGE_MEM64_DECODE;
+#else
+    RootBridge->AllocationAttributes  = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;
+#endif
+
+    RootBridge->Bus.Base = PcieController->PcieBusMin;
+    RootBridge->Bus.Limit = PcieController->PcieBusMax;
+    RootBridge->Io.Base = PcieController->PcieIoWinBase;
+    RootBridge->Io.Limit = PcieController->PcieIoWinBase +
+                           PcieController->PcieIoWinSize - 1;
+    RootBridge->Io.Translation = MAX_UINT64 -
+                                 PcieController->PcieIoTranslation + 1;
+    RootBridge->Mem.Base = PcieController->PcieMmio32WinBase;
+    RootBridge->Mem.Limit = PcieController->PcieMmio32WinBase +
+                            PcieController->PcieMmio32WinSize - 1;
+    RootBridge->Mem.Translation = MAX_UINT64 -
+                                  PcieController->PcieMmio32Translation + 1;
+#ifndef MDE_CPU_ARM
+    RootBridge->MemAbove4G.Base = PcieController->PcieMmio64WinBase;
+    RootBridge->MemAbove4G.Limit = PcieController->PcieMmio64WinBase +
+                                   PcieController->PcieMmio64WinSize - 1;
+    RootBridge->MemAbove4G.Translation = MAX_UINT64 -
+                                      PcieController->PcieMmio64Translation + 1;
+#else
+    RootBridge->MemAbove4G.Base = MAX_UINT64;
+    RootBridge->MemAbove4G.Limit = 0;
+    RootBridge->MemAbove4G.Translation = 0;
+#endif
+
+    /* No separate ranges for prefetchable and non-prefetchable BARs */
+    RootBridge->PMem.Base           = MAX_UINT64;
+    RootBridge->PMem.Limit          = 0;
+    RootBridge->PMemAbove4G.Base    = MAX_UINT64;
+    RootBridge->PMemAbove4G.Limit   = 0;
+
+
+    RootBridge->NoExtendedConfigSpace = FALSE;
+
+    RootBridge->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath;
+  }
+
+  return PciRootBridges;
+}
+
+/**
+  Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+  @param Bridges The root bridge instances array.
+  @param Count   The count of the array.
+
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+  PCI_ROOT_BRIDGE *Bridges,
+  UINTN           Count
+  )
+{
+  FreePool (Bridges);
+}
+
+/**
+  Inform the platform that the resource conflict happens.
+
+  @param HostBridgeHandle Handle of the Host Bridge.
+  @param Configuration    Pointer to PCI I/O and PCI memory resource
+                          descriptors. The Configuration contains the resources
+                          for all the root bridges. The resource for each root
+                          bridge is terminated with END descriptor and an
+                          additional END is appended indicating the end of the
+                          entire resources. The resource descriptor field
+                          values follow the description in
+                          EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+                          .SubmitResources().
+
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+  EFI_HANDLE                        HostBridgeHandle,
+  VOID                              *Configuration
+  )
+{
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+  CHAR16 *MemoryTypeDescription[] = { L"(Prefetchable)", L"" };
+  CHAR16 *MemoryType;
+  UINTN                              RootBridgeIndex;
+
+  DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+  RootBridgeIndex = 0;
+  Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
+
+  while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+
+    DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+
+    for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+      ASSERT (Descriptor->ResType <
+              ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr));
+
+      DEBUG ((DEBUG_ERROR,
+        " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+        mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+        Descriptor->AddrLen, Descriptor->AddrRangeMax));
+
+      if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+        if (Descriptor->SpecificFlag &
+            EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {
+          MemoryType = MemoryTypeDescription[0];
+        } else {
+          MemoryType = MemoryTypeDescription[1];
+        }
+
+        DEBUG ((DEBUG_ERROR,
+          "     Granularity/SpecificFlag = %ld / %02x%s\n",
+          Descriptor->AddrSpaceGranularity,
+          Descriptor->SpecificFlag,
+          MemoryType));
+      }
+    }
+    /* Skip the END descriptor for root bridge */
+    ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+    Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+                  (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1);
+  }
+}
diff --git a/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c
new file mode 100644
index 0000000..8376756
--- /dev/null
+++ b/Silicon/Marvell/Armada7k8k/Library/Armada7k8kPciHostBridgeLib/PciHostBridgeLibConstructor.c
@@ -0,0 +1,345 @@
+/** @file
+  PCI Host Bridge Library instance for Marvell 70x0/80x0
+
+  Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+  Copyright (c) 2019 Marvell International Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php.
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Pci22.h>
+
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MvGpioLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/BoardDesc.h>
+
+#include "PciHostBridgeLibConstructor.h"
+
+/**
+  This function configures PCIE controllers IATU windows.
+
+  @param [in] PcieDbiAddress  PCIE controller base address.
+  @param [in] Index           IATU window index.
+  @param [in] CpuBase         Address from the CPU perspective.
+  @param [in] PciBase         Target PCIE address.
+  @param [in] Size            IATU window size.
+  @param [in] Type            IATU window type.
+  @param [in] EnableFlags     Extra configuration flags.
+
+  @retval none
+
+**/
+STATIC
+VOID
+ConfigureWindow (
+  IN EFI_PHYSICAL_ADDRESS PcieDbiAddress,
+  IN UINTN                Index,
+  IN UINT64               CpuBase,
+  IN UINT64               PciBase,
+  IN UINT64               Size,
+  IN UINTN                Type,
+  IN UINTN                EnableFlags
+  )
+{
+  ArmDataMemoryBarrier ();
+
+  MmioWrite32 (PcieDbiAddress + IATU_VIEWPORT_OFF,
+    IATU_VIEWPORT_OUTBOUND | IATU_VIEWPORT_REGION_INDEX (Index));
+
+  ArmDataMemoryBarrier ();
+
+  MmioWrite32 (PcieDbiAddress + IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0,
+    (UINT32)(CpuBase & MAX_UINT32));
+  MmioWrite32 (PcieDbiAddress + IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0,
+    (UINT32)(CpuBase >> 32));
+  MmioWrite32 (PcieDbiAddress + IATU_LIMIT_ADDR_OFF_OUTBOUND_0,
+    (UINT32)(CpuBase + Size - 1));
+  MmioWrite32 (PcieDbiAddress + IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0,
+    (UINT32)(PciBase & MAX_UINT32));
+  MmioWrite32 (PcieDbiAddress + IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0,
+    (UINT32)(PciBase >> 32));
+  MmioWrite32 (PcieDbiAddress + IATU_REGION_CTRL_1_OFF_OUTBOUND_0,
+    Type);
+  MmioWrite32 (PcieDbiAddress + IATU_REGION_CTRL_2_OFF_OUTBOUND_0,
+    IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN | EnableFlags);
+}
+
+/**
+  Perform PCIE slot reset using external GPIO pin.
+
+  @param [in] PcieDbiAddress  PCIE controller base address.
+
+  @retval none
+
+**/
+STATIC
+VOID
+WaitForLink (
+  IN EFI_PHYSICAL_ADDRESS PcieDbiAddress
+  )
+{
+  UINT32 Mask;
+  UINT32 Status;
+  UINT32 Timeout;
+
+  if (!(MmioRead32 (PcieDbiAddress + PCIE_PM_STATUS) & PCIE_PM_LTSSM_STAT_MASK)) {
+    DEBUG ((DEBUG_INIT, "%a: no PCIE device detected\n", __FUNCTION__));
+    return;
+  }
+
+  /* Wait for the link to establish itself. */
+  DEBUG ((DEBUG_INIT, "%a: waiting for PCIE link\n", __FUNCTION__));
+
+  Mask = PCIE_GLOBAL_STATUS_RDLH_LINK_UP | PCIE_GLOBAL_STATUS_PHY_LINK_UP;
+  Timeout = PCIE_LINK_UP_TIMEOUT_US / 10;
+  do {
+    Status = MmioRead32 (PcieDbiAddress + PCIE_GLOBAL_STATUS_REG);
+    if ((Status & Mask) == Mask) {
+      DEBUG ((DEBUG_ERROR, "pcie at 0x%x link UP\n", PcieDbiAddress));
+      break;
+    }
+    /* Wait 10us between each link status check. */
+    gBS->Stall (10);
+  } while (Timeout--);
+}
+
+/**
+  Perform PCIE slot reset using external GPIO pin.
+
+  @param [in] *PcieResetGpio  GPIO pin description.
+
+  @retval EFI_SUCEESS         PCIE slot reset succeeded.
+  @retval Other               Return error status.
+
+**/
+STATIC
+EFI_STATUS
+ResetPcieSlot (
+  IN MV_GPIO_PIN CONST *PcieResetGpio
+  )
+{
+  EMBEDDED_GPIO_MODE   Mode;
+  EMBEDDED_GPIO_PIN    GpioPin;
+  EMBEDDED_GPIO       *GpioProtocol;
+  EFI_STATUS           Status;
+
+  /* Get GPIO protocol. */
+  Status = MvGpioGetProtocol (PcieResetGpio->ControllerType, &GpioProtocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Unable to find GPIO protocol\n", __FUNCTION__));
+    return Status;
+  }
+
+  GpioPin = GPIO (PcieResetGpio->ControllerId, PcieResetGpio->PinNumber),
+
+  /* Activate reset. */
+  Mode = PcieResetGpio->ActiveHigh ? GPIO_MODE_OUTPUT_1 : GPIO_MODE_OUTPUT_0;
+  Status = GpioProtocol->Set (GpioProtocol, GpioPin, Mode);
+
+  /*
+   * According to the PCIE specification, the reset signal must be active
+   * for minimum 100ms. To be on a safe side, use 150ms delay.
+   */
+  MemoryFence ();
+  gBS->Stall (150 * 1000);
+
+  /* Dectivate reset. */
+  Mode = PcieResetGpio->ActiveHigh ? GPIO_MODE_OUTPUT_0 : GPIO_MODE_OUTPUT_1;
+  Status = GpioProtocol->Set (GpioProtocol, GpioPin, Mode);
+
+  /*
+   * The controller cannot be configured (e.g. the clocks have to establish)
+   * during 20ms period after the reset is deactivated.
+   */
+  MemoryFence ();
+  gBS->Stall (20 * 1000);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Obtain resources and perform a low-level PCIE controllers
+  configuration.
+
+  @param [in]  ImageHandle  The image handle.
+  @param [in] *SystemTable  The system table.
+
+  @retval EFI_SUCEESS       PCIE configuration successful.
+  @retval Other             Return error status.
+
+**/
+EFI_STATUS
+EFIAPI
+Armada7k8kPciHostBridgeLibConstructor (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  MV_BOARD_PCIE_DESCRIPTION CONST *BoardPcieDescription;
+  MARVELL_BOARD_DESC_PROTOCOL     *BoardDescriptionProtocol;
+  MV_PCIE_CONTROLLER CONST        *PcieController;
+  EFI_PHYSICAL_ADDRESS             PcieDbiAddress;
+  EFI_STATUS                       Status;
+  UINTN                            Index;
+
+  /* Obtain list of available controllers */
+  Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid,
+                  NULL,
+                  (VOID **)&BoardDescriptionProtocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Cannot locate BoardDesc protocol\n",
+      __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Status = BoardDescriptionProtocol->PcieDescriptionGet (
+                                       BoardDescriptionProtocol,
+                                       &BoardPcieDescription);
+  if (Status == EFI_NOT_FOUND) {
+    /* No controllers used on the platform, exit silently */
+    return EFI_SUCCESS;
+  } else if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Cannot get Pcie board desc from BoardDesc protocol\n",
+      __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  for (Index = 0; Index < BoardPcieDescription->PcieControllerCount; Index++) {
+
+    PcieController = &(BoardPcieDescription->PcieControllers[Index]);
+
+    ASSERT (PcieController->PcieBusMin == 0);
+    ASSERT (PcieController->ConfigSpaceAddress % SIZE_256MB == 0);
+
+    if (PcieController->HaveResetGpio == TRUE) {
+      /* Reset PCIE slot */
+      Status = ResetPcieSlot (&PcieController->PcieResetGpio);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR,
+          "%a: Cannot reset Pcie Slot\n",
+          __FUNCTION__));
+        return EFI_DEVICE_ERROR;
+      }
+    }
+
+    /* Low level PCIE controller configuration */
+    PcieDbiAddress = PcieController->PcieDbiAddress;
+
+    MmioAndThenOr32 (PcieDbiAddress + PORT_LINK_CTRL_OFF,
+      ~PORT_LINK_CTRL_OFF_LINK_CAPABLE_MASK,
+      PORT_LINK_CTRL_OFF_LINK_CAPABLE_x4);
+
+    MmioAndThenOr32 (PcieDbiAddress + GEN2_CTRL_OFF,
+      ~GEN2_CTRL_OFF_NUM_OF_LANES_MASK,
+      GEN2_CTRL_OFF_NUM_OF_LANES(4) | GEN2_CTRL_OFF_DIRECT_SPEED_CHANGE);
+
+    MmioAndThenOr32 (PcieDbiAddress + PCIE_GLOBAL_CTRL_OFFSET,
+      ~(PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK | PCIE_GLOBAL_APP_LTSSM_EN),
+      PCIE_GLOBAL_CTRL_DEVICE_TYPE_RC);
+
+    MmioWrite32 (PcieDbiAddress + PCIE_ARCACHE_TRC_REG,
+      ARCACHE_DEFAULT_VALUE);
+
+    MmioWrite32 (PcieDbiAddress + PCIE_AWCACHE_TRC_REG,
+      AWCACHE_DEFAULT_VALUE);
+
+    MmioAndThenOr32 (PcieDbiAddress + PCIE_ARUSER_REG,
+      ~AX_USER_DOMAIN_MASK,
+      AX_USER_DOMAIN_OUTER_SHAREABLE);
+
+    MmioAndThenOr32 (PcieDbiAddress + PCIE_AWUSER_REG,
+      ~AX_USER_DOMAIN_MASK,
+      AX_USER_DOMAIN_OUTER_SHAREABLE);
+
+    MmioAndThenOr32 (PcieDbiAddress + PCIE_LINK_CTL_2,
+      ~TARGET_LINK_SPEED_MASK,
+      LINK_SPEED_GEN_3);
+
+    MmioAndThenOr32 (PcieDbiAddress + PCIE_LINK_CAPABILITY,
+      ~TARGET_LINK_SPEED_MASK,
+      LINK_SPEED_GEN_3);
+
+    MmioOr32 (PcieDbiAddress + PCIE_GEN3_EQU_CTRL,
+      GEN3_EQU_EVAL_2MS_DISABLE);
+
+    MmioOr32 (PcieDbiAddress + PCIE_GLOBAL_CTRL_OFFSET,
+      PCIE_GLOBAL_APP_LTSSM_EN);
+
+    /* Region 0: MMIO32 range */
+    ConfigureWindow (PcieDbiAddress,
+      PcieController->PcieMmio32WinBase - PcieController->PcieMmio32Translation,
+      PcieController->PcieMmio32WinBase,
+      PcieController->PcieMmio32WinBase,
+      PcieController->PcieMmio32WinSize,
+      IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM,
+      0);
+
+    /* Region 1: Type 0 config space */
+    ConfigureWindow (PcieDbiAddress,
+      1,
+      PcieController->ConfigSpaceAddress,
+      0x0,
+      SIZE_64KB,
+      IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0,
+      IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE);
+
+    /* Region 2: Type 1 config space */
+    ConfigureWindow (PcieDbiAddress,
+      2,
+      PcieController->ConfigSpaceAddress + SIZE_64KB,
+      0x0,
+      PcieController->PcieBusMax * SIZE_1MB,
+      IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1,
+      IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE);
+
+    /* Region 3: port I/O range */
+    ConfigureWindow (PcieDbiAddress,
+      3,
+      PcieController->PcieIoTranslation,
+      PcieController->PcieIoWinBase,
+      PcieController->PcieIoWinSize,
+      IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO,
+      0);
+
+    /* Region 4: MMIO64 range */
+    ConfigureWindow (PcieDbiAddress,
+      4,
+      PcieController->PcieMmio64WinBase,
+      PcieController->PcieMmio64WinBase,
+      PcieController->PcieMmio64WinSize,
+      IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM,
+      0);
+
+    MmioOr32 (PcieDbiAddress + PCIE_GLOBAL_INT_MASK1_REG,
+      PCIE_INT_A_ASSERT_MASK |
+      PCIE_INT_B_ASSERT_MASK |
+      PCIE_INT_C_ASSERT_MASK |
+      PCIE_INT_D_ASSERT_MASK);
+
+    WaitForLink (PcieDbiAddress);
+
+    /* Enable the RC */
+    MmioOr32 (PcieDbiAddress + PCI_COMMAND_OFFSET,
+      EFI_PCI_COMMAND_IO_SPACE |
+      EFI_PCI_COMMAND_MEMORY_SPACE |
+      EFI_PCI_COMMAND_BUS_MASTER);
+  }
+
+  return EFI_SUCCESS;
+}
-- 
2.7.4


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#41074): https://edk2.groups.io/g/devel/message/41074
Mute This Topic: https://groups.io/mt/31686573/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list