public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "John Chew" <yuinyee.chew@starfivetech.com>
To: <devel@edk2.groups.io>
Cc: mindachen1987 <minda.chen@starfivetech.com>,
	Sunil V L <sunilvl@ventanamicro.com>,
	Leif Lindholm <quic_llindhol@quicinc.com>,
	Michael D Kinney <michael.d.kinney@intel.com>,
	Li Yong <yong.li@intel.com>,
	John Chew <yuinyee.chew@starfivetech.com>
Subject: [edk2-devel] [PATCH v3 1/5] StarFive/JH7110Pkg: Add Pci controller driver
Date: Fri, 27 Oct 2023 11:19:02 +0800	[thread overview]
Message-ID: <20231027031906.1814-2-yuinyee.chew@starfivetech.com> (raw)
In-Reply-To: <20231027031906.1814-1-yuinyee.chew@starfivetech.com>

From: mindachen1987 <minda.chen@starfivetech.com>

Implement Pci Host Bridge and Pci Segment driver:
JH7110 SoC contains two PCI segment:

- PCI Segment 0 (USB):
    32-bit Memory: 0x3000_0000 ~ 0x3FFF_FFFF
    64-bit Memory: 0x9_0000_0000 ~0x9_4000_0000
- PCI Segment 1 (NVME):
    32-bit Memory: 0x3800_0000 ~ 0x37FF_FFFF
    64-bit Memory: 0x9_8000_0000 ~0x9_C000_0000

Non-prefetachable memory is not used in this configuration.

Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Li Yong <yong.li@intel.com>
Co-authored-by: John Chew <yuinyee.chew@starfivetech.com>
Signed-off-by: mindachen1987 <minda.chen@starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c            |  263 ++++
 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf          |   61 +
 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c |  406 ++++++
 Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c                  | 1460 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf                |   33 +
 5 files changed, 2223 insertions(+)

diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
new file mode 100644
index 000000000000..8b46f6ff58e5
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
@@ -0,0 +1,263 @@
+/** @file
+ *
+ * PCI Host Bridge Library instance for StarFive JH7110 SOC
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <IndustryStandard/JH7110.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <PiDxe.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+
+#pragma pack(1)
+
+typedef PACKED struct {
+  ACPI_HID_DEVICE_PATH        AcpiDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL    EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+
+#pragma pack ()
+
+STATIC CONST 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
+      }
+    }
+  },
+
+  {
+    {
+      {
+        ACPI_DEVICE_PATH,
+        ACPI_DP,
+        {
+          (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
+          (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
+        }
+      },
+      EISA_PNP_ID (0x0A08), // PCI Express
+      1
+    },
+
+    {
+      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"
+};
+
+//
+// See description in MdeModulePkg/Include/Library/PciHostBridgeLib.h
+//
+PCI_ROOT_BRIDGE  mPciRootBridges[] = {
+  {
+    0,                                      // Segment
+    0,                                      // Supports
+    0,                                      // Attributes
+    FALSE,                                  // DmaAbove4G
+    FALSE,                                  // NoExtendedConfigSpace (true=256 byte config, false=4k)
+    FALSE,                                  // ResourceAssigned
+    EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
+    EFI_PCI_HOST_BRIDGE_MEM64_DECODE,       // AllocationAttributes
+    {
+      // Bus
+      FixedPcdGet32 (PcdPciBusMin),
+      FixedPcdGet32 (PcdPciBusMax)
+    }, {
+      // Io
+      FixedPcdGet64 (PcdPciIoBase),
+      FixedPcdGet64 (PcdPciIoBase) + FixedPcdGet64 (PcdPciIoSize) - 1,
+      MAX_UINT64 - FixedPcdGet64 (PcdPciIoOffset) + 1
+    }, {
+      // Mem
+      FixedPcdGet32 (PcdPci0Mmio32Base),
+      FixedPcdGet32 (PcdPci0Mmio32Base) + FixedPcdGet32 (PcdPci0Mmio32Size) - 1
+    }, {
+      // MemAbove4G
+      FixedPcdGet64 (PcdPci0Mmio64Base),
+      FixedPcdGet64 (PcdPci0Mmio64Base) + FixedPcdGet64 (PcdPci0Mmio64Size) - 1
+    },
+    {
+      // Pefetchable Mem
+      MAX_UINT32,
+      0x0
+    }, {
+      // Pefetchable MemAbove4G
+      MAX_UINT64,
+      0x0
+    },
+    (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[0]
+  },
+  {
+    1,                                  // Segment
+    0,                                  // Supports
+    0,                                  // Attributes
+    FALSE,                              // DmaAbove4G
+    FALSE,                              // NoExtendedConfigSpace (true=256 byte config, false=4k)
+    FALSE,                              // ResourceAssigned
+    EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
+    EFI_PCI_HOST_BRIDGE_MEM64_DECODE,   // AllocationAttributes
+    {
+      // Bus
+      FixedPcdGet32 (PcdPciBusMin),
+      FixedPcdGet32 (PcdPciBusMax)
+    }, {
+      // Io
+      FixedPcdGet64 (PcdPciIoBase),
+      FixedPcdGet64 (PcdPciIoBase) + FixedPcdGet64 (PcdPciIoSize) - 1,
+      MAX_UINT64 - FixedPcdGet64 (PcdPciIoOffset) + 1
+    }, {
+      // Mem
+      FixedPcdGet32 (PcdPci1Mmio32Base),
+      FixedPcdGet32 (PcdPci1Mmio32Base) + FixedPcdGet32 (PcdPci1Mmio32Size) - 1
+    }, {
+      // MemAbove4G
+      FixedPcdGet64 (PcdPci1Mmio64Base),
+      FixedPcdGet64 (PcdPci1Mmio64Base) + FixedPcdGet64 (PcdPci1Mmio64Size) - 1
+    },
+    {
+      // Pefetchable Mem
+      MAX_UINT32,
+      0x0
+    }, {
+      // Pefetchable MemAbove4G
+      MAX_UINT64,
+      0x0
+    },
+    (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[1]
+  }
+};
+
+/**
+  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 (
+  OUT UINTN  *Count
+  )
+{
+  *Count = ARRAY_SIZE (mPciRootBridges);
+  return mPciRootBridges;
+}
+
+/**
+  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
+  )
+{
+}
+
+/**
+  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;
+  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) {
+        DEBUG (
+               (DEBUG_ERROR, "     Granularity/SpecificFlag = %ld / %02x%s\n",
+                Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+                ((Descriptor->SpecificFlag &
+                  EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+                  ) != 0) ? L" (Prefetchable)" : L""
+               )
+               );
+      }
+    }
+
+    //
+    // 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/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
new file mode 100644
index 000000000000..e18e8e57829f
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -0,0 +1,61 @@
+## @file
+#
+#  PCI Host Bridge Library instance for StarFive JH7110 SOC
+#  Liberally borrowed from the SynQuacer
+#
+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = PciHostBridgeLib
+  FILE_GUID                      = 606d906f-eba7-d5c6-fcf0-6aeedea00193
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PciHostBridgeLib|DXE_DRIVER
+  CONSTRUCTOR                    = JH7110PciHostBridgeLibConstructor
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+#  VALID_ARCHITECTURES           = ARM AARCH64 RISCV64
+#
+
+[Sources]
+  PciHostBridgeLib.c
+  PciHostBridgeLibConstructor.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  PcdLib
+  UefiBootServicesTableLib
+
+[FixedPcd]
+  gJH7110TokenSpaceGuid.PcdPciRegBase
+  gJH7110TokenSpaceGuid.PcdPciBusMmioAdr
+  gJH7110TokenSpaceGuid.PcdPciBusMmioLen
+  gJH7110TokenSpaceGuid.PcdPciCpuMmioAdr
+  gJH7110TokenSpaceGuid.PcdPciBusMin
+  gJH7110TokenSpaceGuid.PcdPciBusMax
+  gJH7110TokenSpaceGuid.PcdPciIoBase
+  gJH7110TokenSpaceGuid.PcdPciIoSize
+  gJH7110TokenSpaceGuid.PcdPciIoOffset
+  gJH7110TokenSpaceGuid.PcdPci0Mmio32Base
+  gJH7110TokenSpaceGuid.PcdPci0Mmio32Size
+  gJH7110TokenSpaceGuid.PcdPci0Mmio64Base
+  gJH7110TokenSpaceGuid.PcdPci0Mmio64Size
+  gJH7110TokenSpaceGuid.PcdPci1Mmio32Base
+  gJH7110TokenSpaceGuid.PcdPci1Mmio32Size
+  gJH7110TokenSpaceGuid.PcdPci1Mmio64Base
+  gJH7110TokenSpaceGuid.PcdPci1Mmio64Size
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
new file mode 100644
index 000000000000..cc505f2723d1
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
@@ -0,0 +1,406 @@
+/** @file
+ *
+ * PCI Host Bridge Library instance for StarFive JH7110 SOC
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ * This module initializes the Pci as close to a standard
+ * PCI root complex as possible. The general information
+ * for this driver was sourced from.
+ *
+ *
+ **/
+
+#include <IndustryStandard/JH7110.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <PiDxe.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Library/TimerLib.h>
+
+#define RegWrite(addr, data)  MmioWrite32((addr), (data))
+#define RegRead(addr, data)   ((data) = MmioRead32 (addr))
+
+#define STG_SYSCON_BASE  0x10240000
+
+#define STG_SYSCON_K_RP_NEP_MASK    (1 << 8)
+#define STG_SYSCON_CKREF_SRC_SHIFT  18
+#define STG_SYSCON_CKREF_SRC_MASK   (0x3 << 18)
+#define STG_SYSCON_CLKREQ_MASK      (1 << 22)
+#define STG_SYSCON_BASE             0x10240000
+#define SYS_CLK_BASE                0x13020000
+#define STG_CLK_BASE                0x10230000
+#define SYS_CLK_NOC_OFFSET          0x98
+#define STG_PCIE_CLK_OFFSET         0x20
+#define STG_PCIE_CLKS               0xc
+#define STG_PCIE_RESET_OFFSET       0x74
+#define SYS_GPIO_BASE               0x13040000
+
+#define PREF_MEM_WIN_64_SUPPORT  (1 << 3)
+#define PMSG_LTR_SUPPORT         (1 << 2)
+#define PDLA_LINK_SPEED_GEN2     (1 << 12)
+#define PLDA_FUNCTION_DIS        (1 << 15)
+#define PLDA_FUNC_NUM            4
+#define PLDA_PHY_FUNC_SHIFT      9
+#define PLDA_RP_ENABLE           1
+
+#define PCIE_BASIC_STATUS  0x018
+#define PCIE_CFGNUM        0x140
+#define IMASK_LOCAL        0x180
+#define ISTATUS_LOCAL      0x184
+#define IMSI_ADDR          0x190
+#define ISTATUS_MSI        0x194
+#define CFG_SPACE          0x1000
+#define GEN_SETTINGS       0x80
+#define PCIE_PCI_IDS       0x9C
+#define PCIE_WINROM        0xFC
+#define PMSG_SUPPORT_RX    0x3F0
+#define PCI_MISC           0xB4
+
+#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK   0x7FFF00
+#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT  0x8
+#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK   0x7FFF
+#define STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT  0x0
+
+#define XR3PCI_ATR_AXI4_SLV0       0x800
+#define XR3PCI_ATR_SRC_ADDR_LOW    0x0
+#define XR3PCI_ATR_SRC_ADDR_HIGH   0x4
+#define XR3PCI_ATR_TRSL_ADDR_LOW   0x8
+#define XR3PCI_ATR_TRSL_ADDR_HIGH  0xc
+#define XR3PCI_ATR_TRSL_PARAM      0x10
+#define XR3PCI_ATR_TABLE_OFFSET    0x20
+#define XR3PCI_ATR_MAX_TABLE_NUM   8
+
+#define XR3PCI_ATR_SRC_ADDR_MASK       0xfffff000
+#define XR3PCI_ATR_TRSL_ADDR_MASK      0xfffff000
+#define XR3PCI_ATR_SRC_WIN_SIZE_SHIFT  1
+#define XR3_PCI_ECAM_SIZE              28
+
+#define IDS_PCI_TO_PCI_BRIDGE  0x060400
+#define IDS_CLASS_CODE_SHIFT   8
+#define SYS_GPIO_OUTPUT_OFF    0x40
+
+UINT32  AtrTableNum;
+UINT64  PCIE_CFG_BASE[2]      = { FixedPcdGet32 (PcdPci0Mmio64Base) + FixedPcdGet32 (PcdPci0Mmio64Size),
+                                  FixedPcdGet32 (PcdPci1Mmio64Base) + FixedPcdGet32 (PcdPci1Mmio64Size) };
+UINT64  PCI_MEMREGION_32[2]   = { FixedPcdGet32 (PcdPci0Mmio32Base), FixedPcdGet32 (PcdPci1Mmio32Base) };
+UINT64  PCI_MEMREGION_64[2]   = { FixedPcdGet32 (PcdPci0Mmio64Base), FixedPcdGet32 (PcdPci1Mmio64Base) };
+UINT64  PCI_MEMREGION_SIZE[2] = { 27, 30 };
+UINT32  STG_ARFUNC_OFFSET[2]  = { 0xc0, 0x270 };
+UINT32  STG_AWFUNC_OFFSET[2]  = { 0xc4, 0x274 };
+UINT32  STG_RP_REP_OFFSET[2]  = { 0x130, 0x2e0 };
+UINT32  PCIE_GPIO[2]          = { 26, 28 };
+
+STATIC inline UINT64
+GetPcieRegBase (
+  IN UINT32  Port
+  )
+{
+  return PCIE_REG_BASE + Port * 0x1000000;
+}
+
+VOID
+PcieRegWrite (
+  IN UINT32  Port,
+  IN UINTN   Offset,
+  IN UINT32  Value
+  )
+{
+  UINT64  Base = GetPcieRegBase (Port);
+
+  RegWrite ((UINT64)Base + Offset, Value);
+}
+
+UINT32
+PcieRegRead (
+  IN UINT32  Port,
+  IN UINTN   Offset
+  )
+{
+  UINT32  Value = 0;
+  UINT64  Base  = GetPcieRegBase (Port);
+
+  RegRead ((UINT64)Base + Offset, Value);
+  return Value;
+}
+
+STATIC VOID
+PcieUpdatebits (
+  IN UINT64  Base,
+  IN UINTN   Offset,
+  IN UINT32  Mask,
+  IN UINT32  val
+  )
+{
+  UINT32  Value = 0;
+
+  Value  = MmioRead32 ((UINT64)Base + Offset);
+  Value &= ~Mask;
+  Value |= val;
+  MmioWrite32 ((UINT64)Base + Offset, Value);
+}
+
+STATIC
+VOID
+PcieFuncSet (
+  IN UINT32  Port
+  )
+{
+  INTN    i;
+  UINT32  Value;
+  UINT64  Base = GetPcieRegBase (Port);
+
+  /* Disable physical functions except #0 */
+  for (i = 1; i < PLDA_FUNC_NUM; i++) {
+    PcieUpdatebits (
+                    STG_SYSCON_BASE,
+                    STG_ARFUNC_OFFSET[Port],
+                    STG_SYSCON_AXI4_SLVL_ARFUNC_MASK,
+                    (i << PLDA_PHY_FUNC_SHIFT) <<
+                    STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT
+                    );
+    PcieUpdatebits (
+                    STG_SYSCON_BASE,
+                    STG_AWFUNC_OFFSET[Port],
+                    STG_SYSCON_AXI4_SLVL_AWFUNC_MASK,
+                    (i << PLDA_PHY_FUNC_SHIFT) <<
+                    STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT
+                    );
+    PcieUpdatebits (
+                    Base,
+                    PCI_MISC,
+                    PLDA_FUNCTION_DIS,
+                    PLDA_FUNCTION_DIS
+                    );
+  }
+
+  PcieUpdatebits (
+                  STG_SYSCON_BASE,
+                  STG_ARFUNC_OFFSET[Port],
+                  STG_SYSCON_AXI4_SLVL_ARFUNC_MASK,
+                  0
+                  );
+  PcieUpdatebits (
+                  STG_SYSCON_BASE,
+                  STG_AWFUNC_OFFSET[Port],
+                  STG_SYSCON_AXI4_SLVL_AWFUNC_MASK,
+                  0
+                  );
+
+  /* Enable root port*/
+  PcieUpdatebits (
+                  Base,
+                  GEN_SETTINGS,
+                  PLDA_RP_ENABLE,
+                  PLDA_RP_ENABLE
+                  );
+
+  Value = (IDS_PCI_TO_PCI_BRIDGE << IDS_CLASS_CODE_SHIFT);
+  PcieRegWrite (Port, PCIE_PCI_IDS, Value);
+
+  PcieUpdatebits (
+                  Base,
+                  PMSG_SUPPORT_RX,
+                  PMSG_LTR_SUPPORT,
+                  0
+                  );
+
+  /* Prefetchable memory window 64-bit addressing support */
+  PcieUpdatebits (
+                  Base,
+                  PCIE_WINROM,
+                  PREF_MEM_WIN_64_SUPPORT,
+                  PREF_MEM_WIN_64_SUPPORT
+                  );
+}
+
+STATIC
+VOID
+PcieSTGInit (
+  IN UINT32  Port
+  )
+{
+  PcieUpdatebits (
+                  STG_SYSCON_BASE,
+                  STG_RP_REP_OFFSET[Port],
+                  STG_SYSCON_K_RP_NEP_MASK,
+                  STG_SYSCON_K_RP_NEP_MASK
+                  );
+  PcieUpdatebits (
+                  STG_SYSCON_BASE,
+                  STG_AWFUNC_OFFSET[Port],
+                  STG_SYSCON_CKREF_SRC_MASK,
+                  2 << STG_SYSCON_CKREF_SRC_SHIFT
+                  );
+  PcieUpdatebits (
+                  STG_SYSCON_BASE,
+                  STG_AWFUNC_OFFSET[Port],
+                  STG_SYSCON_CLKREQ_MASK,
+                  STG_SYSCON_CLKREQ_MASK
+                  );
+}
+
+STATIC
+VOID
+PcieClockInit (
+  IN UINT32  Port
+  )
+{
+  RegWrite (
+            STG_CLK_BASE + STG_PCIE_CLK_OFFSET
+            + Port * STG_PCIE_CLKS,
+            1 << 31
+            ); /*axi mst0*/
+  RegWrite (
+            STG_CLK_BASE + STG_PCIE_CLK_OFFSET
+            + Port * STG_PCIE_CLKS + 4,
+            1 << 31
+            ); /* apb */
+  RegWrite (
+            STG_CLK_BASE + STG_PCIE_CLK_OFFSET
+            + Port * STG_PCIE_CLKS + 8,
+            1 << 31
+            ); /* tl0 */
+}
+
+STATIC
+VOID
+PcieResetDeassert (
+  IN UINT32  Port
+  )
+{
+  UINT32  PortOffset = Port * 6 + 11;
+
+  PcieUpdatebits (
+                  STG_CLK_BASE,
+                  STG_PCIE_RESET_OFFSET,
+                  0x3f << (PortOffset),
+                  0
+                  ); /*reset all*/
+}
+
+VOID
+PcieResetAssert (
+  IN UINT32  Port
+  )
+{
+  UINT32  PortOffset = Port * 6 + 11;
+
+  PcieUpdatebits (
+                  STG_CLK_BASE,
+                  STG_PCIE_RESET_OFFSET,
+                  0x3f << (PortOffset),
+                  0x3f << (PortOffset)
+                  ); /*axi mst0*/
+}
+
+STATIC
+VOID
+PcieGpioResetSet (
+  IN UINT32  Port,
+  IN UINT32  Value
+  )
+{
+  UINT32  Remain, Mask;
+
+  Remain = PCIE_GPIO[Port] & 0x3;
+  Mask   = 0xff << (Remain * 8);
+  PcieUpdatebits (
+                  SYS_GPIO_BASE,
+                  SYS_GPIO_OUTPUT_OFF + (PCIE_GPIO[Port] & 0xfffc),
+                  Mask,
+                  Value << (Remain * 8)
+                  );
+}
+
+STATIC
+VOID
+PcieAtrInit (
+  IN UINT32  Port,
+  IN UINT64  SrcAddr,
+  IN UINT64  TrslAddr,
+  IN UINT32  WinSize,
+  IN UINT32  Config
+  )
+{
+  UINT64  Base = GetPcieRegBase (Port) + XR3PCI_ATR_AXI4_SLV0;
+  UINT32  Value;
+
+  Base +=  XR3PCI_ATR_TABLE_OFFSET * AtrTableNum;
+  AtrTableNum++;
+
+  /* X3PCI_ATR_SRC_ADDR_LOW:
+   *   - bit 0: enable entry,
+   *   - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1)
+   *   - bits 7-11: reserved
+   *   - bits 12-31: start of source address
+   */
+  Value = SrcAddr;
+
+  RegWrite (
+            Base + XR3PCI_ATR_SRC_ADDR_LOW,
+            (Value & XR3PCI_ATR_SRC_ADDR_MASK) | ((WinSize - 1) << 1) | 0x1
+            );
+  Value = SrcAddr >> 32;
+
+  RegWrite (Base + XR3PCI_ATR_SRC_ADDR_HIGH, Value);
+  Value = TrslAddr;
+  RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_LOW, Value);
+  Value = TrslAddr >> 32;
+  RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_HIGH, Value);
+  RegWrite (Base + XR3PCI_ATR_TRSL_PARAM, Config);
+}
+
+EFI_STATUS
+EFIAPI
+JH7110PciHostBridgeLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  UINT32  PortIndex;
+
+  DEBUG ((DEBUG_ERROR, "PCIe RootBridge constructor\n"));
+  for (PortIndex = 0; PortIndex < 2; PortIndex++) {
+    PcieSTGInit (PortIndex);
+    RegWrite (SYS_CLK_BASE + SYS_CLK_NOC_OFFSET, 1 << 31);
+    PcieClockInit (PortIndex);
+    PcieResetDeassert (PortIndex);
+    PcieGpioResetSet (PortIndex, 0);
+    PcieFuncSet (PortIndex);
+
+    PcieAtrInit (
+                 PortIndex,
+                 PCIE_CFG_BASE[PortIndex],
+                 0,
+                 XR3_PCI_ECAM_SIZE,
+                 1
+                 );
+    PcieAtrInit (
+                 PortIndex,
+                 PCI_MEMREGION_32[PortIndex],
+                 PCI_MEMREGION_32[PortIndex],
+                 PCI_MEMREGION_SIZE[0],
+                 0
+                 );
+    PcieAtrInit (
+                 PortIndex,
+                 PCI_MEMREGION_64[PortIndex],
+                 PCI_MEMREGION_64[PortIndex],
+                 PCI_MEMREGION_SIZE[1],
+                 0
+                 );
+    PcieGpioResetSet (PortIndex, 1);
+    MicroSecondDelay (300);
+
+    DEBUG ((DEBUG_ERROR, "PCIe port %d init\n", PortIndex));
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c
new file mode 100644
index 000000000000..43dca2a6236a
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c
@@ -0,0 +1,1460 @@
+/** @file
+ *
+ * PCI Segment Library for StarFive JH7110 SoC
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/UefiLib.h>
+#include <IndustryStandard/JH7110.h>
+#include <IndustryStandard/Pci30.h>
+
+typedef enum {
+  PciCfgWidthUint8 = 0,
+  PciCfgWidthUint16,
+  PciCfgWidthUint32,
+  PciCfgWidthMax
+} PCI_CFG_WIDTH;
+
+/*
+ * This PCIe config space is unusual...
+ * The root port is the first bytes of the register space (offset 0)
+ * The individual devices are then selected by computing their BDF index
+ * and writing that into the CFG_INDEX register (offset 0x9000)
+ * the "ECAM" data is then read/writeable at CFG_DATA (offset 0x8000)
+ */
+
+#define EFI_PCI_ADDR_BUS(bus)  ((bus >> 20) & 0xFF)   /* Note PCI_SEGMENT_LIB_ADDRESS */
+#define EFI_PCI_ADDR_DEV(dev)  ((dev >> 15) & 0x1F)
+#define EFI_PCI_ADDR_FUN(fun)  ((fun >> 12) & 0x07)
+
+/**
+  Assert the validity of a PCI Segment address.
+  A valid PCI Segment address should not contain 1's in bits 28..31 and 48..63
+
+  @param  A The address to validate.
+  @param  M Additional bits to assert to be zero.
+
+**/
+#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A, M) \
+  ASSERT (((A) & (0xffff0000f0000000ULL | (M))) == 0)
+
+/**
+  Given the nature of how we access PCI devices, we ensure that
+  read/write accesses are serialized through the use of a lock.
+**/
+STATIC
+EFI_LOCK  mPciSegmentReadWriteLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+// STATIC UINT64 mPciSegmentLastAccess;     /* Avoid repeat CFG_INDEX updates */
+
+/**
+  Internal worker function to obtain config space base address.
+
+  @param  Address The address that encodes the PCI Bus, Device, Function and
+                  Register.
+
+  @return The value read from the PCI configuration register.
+
+**/
+STATIC
+UINT64
+PciSegmentLibGetConfigBase (
+  IN  UINT64  Address,
+  IN  UINT16  Segment,
+  IN  UINT32  Write
+  )
+{
+  UINT64  Base;
+  UINT64  Offset;
+  UINT32  Dev;
+  UINT32  Bus;
+
+  Base     = PCIE_CONFIG_BASE;
+  Offset   = Address & 0xFFF;      /* Pick off the 4k register offset */
+  Address &= 0xFFFF000;            /* Clear the offset leave only the BDF */
+
+  /* The root port is at the base of the PCIe register space */
+  if (Address != 0) {
+    Dev = EFI_PCI_ADDR_DEV (Address);
+    Bus = EFI_PCI_ADDR_BUS (Address);
+
+    /*
+     * There can only be a single device on bus 1 (downstream of root).
+     * Subsequent busses (behind a PCIe switch) can have more.
+     */
+    if (Dev > 0) {
+      return 0xFFFFFFFF;
+    }
+
+    return Base + Segment * 0x80000000 + Address + Offset;
+  } else {
+    if (Write && ((Offset == 0x10) || (Offset == 0x14))) {
+      return 0xFFFFFFFF;
+    }
+  }
+
+  return Base + Segment * 0x80000000 + Offset;
+}
+
+/**
+  Internal worker function to read a PCI configuration register.
+
+  @param  Address The address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  Width   The width of data to read
+
+  @return The value read from the PCI configuration register.
+
+**/
+STATIC
+UINT32
+PciSegmentLibReadWorker (
+  IN  UINT64         Address,
+  IN  PCI_CFG_WIDTH  Width
+  )
+{
+  UINT64  Base;
+  UINT32  Ret;
+  UINT16  Segment = (Address >> 32);
+
+  EfiAcquireLock (&mPciSegmentReadWriteLock);
+  Base = PciSegmentLibGetConfigBase (Address, Segment, 0);
+
+  if (Base == 0xFFFFFFFF) {
+    EfiReleaseLock (&mPciSegmentReadWriteLock);
+    return Base;
+  }
+
+  switch (Width) {
+    case PciCfgWidthUint8:
+      Ret = MmioRead8 (Base);
+      break;
+    case PciCfgWidthUint16:
+      Ret = MmioRead16 (Base);
+      break;
+    case PciCfgWidthUint32:
+      Ret = MmioRead32 (Base);
+      break;
+    default:
+      ASSERT (FALSE);
+      Ret = 0;
+  }
+
+  EfiReleaseLock (&mPciSegmentReadWriteLock);
+  // DEBUG ((DEBUG_ERROR, "PCIe seg read Address %lx %lx width %d val %x Segment %d\n", Base, Address, Width, Ret, Segment));
+  return Ret;
+}
+
+/**
+  Internal worker function to writes a PCI configuration register.
+
+  @param  Address The address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  Width   The width of data to write
+  @param  Data    The value to write.
+
+  @return The value written to the PCI configuration register.
+
+**/
+STATIC
+UINT32
+PciSegmentLibWriteWorker (
+  IN  UINT64         Address,
+  IN  PCI_CFG_WIDTH  Width,
+  IN  UINT32         Data
+  )
+{
+  UINT64  Base;
+  UINT16  Segment = (Address >> 32);
+
+  EfiAcquireLock (&mPciSegmentReadWriteLock);
+  Base = PciSegmentLibGetConfigBase (Address, Segment, 1);
+
+  if (Base == 0xFFFFFFFF) {
+    EfiReleaseLock (&mPciSegmentReadWriteLock);
+    return Data;
+  }
+
+  switch (Width) {
+    case PciCfgWidthUint8:
+      MmioWrite8 (Base, Data);
+      break;
+    case PciCfgWidthUint16:
+      MmioWrite16 (Base, Data);
+      break;
+    case PciCfgWidthUint32:
+      MmioWrite32 (Base, Data);
+      break;
+    default:
+      ASSERT (FALSE);
+  }
+
+  EfiReleaseLock (&mPciSegmentReadWriteLock);
+  return Data;
+}
+
+/**
+  Register a PCI device so PCI configuration registers may be accessed after
+  SetVirtualAddressMap().
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address The address that encodes the PCI Bus, Device, Function and
+                  Register.
+
+  @retval RETURN_SUCCESS           The PCI device was registered for runtime access.
+  @retval RETURN_UNSUPPORTED       An attempt was made to call this function
+                                   after ExitBootServices().
+  @retval RETURN_UNSUPPORTED       The resources required to access the PCI device
+                                   at runtime could not be mapped.
+  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to
+                                   complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciSegmentRegisterForRuntimeAccess (
+  IN UINTN  Address
+  )
+{
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+  return RETURN_UNSUPPORTED;
+}
+
+/**
+  Reads an 8-bit PCI configuration register.
+
+  Reads and returns the 8-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,
+                    and Register.
+
+  @return The 8-bit PCI configuration register specified by Address.
+
+**/
+UINT8
+EFIAPI
+PciSegmentRead8 (
+  IN UINT64  Address
+  )
+{
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+
+  return (UINT8)PciSegmentLibReadWorker (Address, PciCfgWidthUint8);
+}
+
+/**
+  Writes an 8-bit PCI configuration register.
+
+  Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address     The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  Value       The value to write.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentWrite8 (
+  IN UINT64  Address,
+  IN UINT8   Value
+  )
+{
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+
+  return (UINT8)PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, Value);
+}
+
+/**
+  Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.
+
+  Reads the 8-bit PCI configuration register specified by Address,
+  performs a bitwise OR between the read result and the value specified by OrData,
+  and writes the result to the 8-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentOr8 (
+  IN UINT64  Address,
+  IN UINT8   OrData
+  )
+{
+  return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) | OrData));
+}
+
+/**
+  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.
+
+  Reads the 8-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  and writes the result to the 8-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAnd8 (
+  IN UINT64  Address,
+  IN UINT8   AndData
+  )
+{
+  return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) & AndData));
+}
+
+/**
+  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,
+  followed a  bitwise OR with another 8-bit value.
+
+  Reads the 8-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+  and writes the result to the 8-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData    The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAndThenOr8 (
+  IN UINT64  Address,
+  IN UINT8   AndData,
+  IN UINT8   OrData
+  )
+{
+  return PciSegmentWrite8 (Address, (UINT8)((PciSegmentRead8 (Address) & AndData) | OrData));
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in an 8-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldRead8 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit
+  )
+{
+  return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit);
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  8-bit register is returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  Value     The new value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldWrite8 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT8   Value
+  )
+{
+  return PciSegmentWrite8 (
+                           Address,
+                           BitFieldWrite8 (PciSegmentRead8 (Address), StartBit, EndBit, Value)
+                           );
+}
+
+/**
+  Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
+  writes the result back to the bit field in the 8-bit port.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 8-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized. Extra left bits in OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldOr8 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT8   OrData
+  )
+{
+  return PciSegmentWrite8 (
+                           Address,
+                           BitFieldOr8 (PciSegmentRead8 (Address), StartBit, EndBit, OrData)
+                           );
+}
+
+/**
+  Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
+  AND, and writes the result back to the bit field in the 8-bit register.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 8-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized. Extra left bits in AndData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAnd8 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT8   AndData
+  )
+{
+  return PciSegmentWrite8 (
+                           Address,
+                           BitFieldAnd8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData)
+                           );
+}
+
+/**
+  Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  8-bit port.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 8-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAndThenOr8 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT8   AndData,
+  IN UINT8   OrData
+  )
+{
+  return PciSegmentWrite8 (
+                           Address,
+                           BitFieldAndThenOr8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData, OrData)
+                           );
+}
+
+/**
+  Reads a 16-bit PCI configuration register.
+
+  Reads and returns the 16-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+  @return The 16-bit PCI configuration register specified by Address.
+
+**/
+UINT16
+EFIAPI
+PciSegmentRead16 (
+  IN UINT64  Address
+  )
+{
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
+
+  return (UINT16)PciSegmentLibReadWorker (Address, PciCfgWidthUint16);
+}
+
+/**
+  Writes a 16-bit PCI configuration register.
+
+  Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address     The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  Value       The value to write.
+
+  @return The parameter of Value.
+
+**/
+UINT16
+EFIAPI
+PciSegmentWrite16 (
+  IN UINT64  Address,
+  IN UINT16  Value
+  )
+{
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
+
+  return (UINT16)PciSegmentLibWriteWorker (Address, PciCfgWidthUint16, Value);
+}
+
+/**
+  Performs a bitwise OR of a 16-bit PCI configuration register with
+  a 16-bit value.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 16-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address The address that encodes the PCI Segment, Bus, Device, Function and
+                  Register.
+  @param  OrData  The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentOr16 (
+  IN UINT64  Address,
+  IN UINT16  OrData
+  )
+{
+  return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) | OrData));
+}
+
+/**
+  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.
+
+  Reads the 16-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  and writes the result to the 16-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAnd16 (
+  IN UINT64  Address,
+  IN UINT16  AndData
+  )
+{
+  return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) & AndData));
+}
+
+/**
+  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,
+  followed a  bitwise OR with another 16-bit value.
+
+  Reads the 16-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+  and writes the result to the 16-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAndThenOr16 (
+  IN UINT64  Address,
+  IN UINT16  AndData,
+  IN UINT16  OrData
+  )
+{
+  return PciSegmentWrite16 (Address, (UINT16)((PciSegmentRead16 (Address) & AndData) | OrData));
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in a 16-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldRead16 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit
+  )
+{
+  return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit);
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  16-bit register is returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  Value     The new value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldWrite16 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT16  Value
+  )
+{
+  return PciSegmentWrite16 (
+                            Address,
+                            BitFieldWrite16 (PciSegmentRead16 (Address), StartBit, EndBit, Value)
+                            );
+}
+
+/**
+  Reads the 16-bit PCI configuration register specified by Address,
+  performs a bitwise OR between the read result and the value specified by OrData,
+  and writes the result to the 16-bit PCI configuration register specified by Address.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldOr16 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT16  OrData
+  )
+{
+  return PciSegmentWrite16 (
+                            Address,
+                            BitFieldOr16 (PciSegmentRead16 (Address), StartBit, EndBit, OrData)
+                            );
+}
+
+/**
+  Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR,
+  and writes the result back to the bit field in the 16-bit port.
+
+  Reads the 16-bit PCI configuration register specified by Address,
+  performs a bitwise OR between the read result and the value specified by OrData,
+  and writes the result to the 16-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+  Extra left bits in OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    The ordinal of the least significant bit in a byte is bit 0.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    The ordinal of the most significant bit in a byte is bit 7.
+  @param  AndData   The value to AND with the read value from the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAnd16 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT16  AndData
+  )
+{
+  return PciSegmentWrite16 (
+                            Address,
+                            BitFieldAnd16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData)
+                            );
+}
+
+/**
+  Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  16-bit port.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 16-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAndThenOr16 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT16  AndData,
+  IN UINT16  OrData
+  )
+{
+  return PciSegmentWrite16 (
+                            Address,
+                            BitFieldAndThenOr16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData, OrData)
+                            );
+}
+
+/**
+  Reads a 32-bit PCI configuration register.
+
+  Reads and returns the 32-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,
+                    and Register.
+
+  @return The 32-bit PCI configuration register specified by Address.
+
+**/
+UINT32
+EFIAPI
+PciSegmentRead32 (
+  IN UINT64  Address
+  )
+{
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
+
+  return PciSegmentLibReadWorker (Address, PciCfgWidthUint32);
+}
+
+/**
+  Writes a 32-bit PCI configuration register.
+
+  Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address     The address that encodes the PCI Segment, Bus, Device,
+                      Function, and Register.
+  @param  Value       The value to write.
+
+  @return The parameter of Value.
+
+**/
+UINT32
+EFIAPI
+PciSegmentWrite32 (
+  IN UINT64  Address,
+  IN UINT32  Value
+  )
+{
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
+
+  return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, Value);
+}
+
+/**
+  Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.
+
+  Reads the 32-bit PCI configuration register specified by Address,
+  performs a bitwise OR between the read result and the value specified by OrData,
+  and writes the result to the 32-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentOr32 (
+  IN UINT64  Address,
+  IN UINT32  OrData
+  )
+{
+  return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData);
+}
+
+/**
+  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.
+
+  Reads the 32-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  and writes the result to the 32-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,
+                    and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAnd32 (
+  IN UINT64  Address,
+  IN UINT32  AndData
+  )
+{
+  return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData);
+}
+
+/**
+  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,
+  followed a  bitwise OR with another 32-bit value.
+
+  Reads the 32-bit PCI configuration register specified by Address,
+  performs a bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+  and writes the result to the 32-bit PCI configuration register specified by Address.
+  The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,
+                    and Register.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAndThenOr32 (
+  IN UINT64  Address,
+  IN UINT32  AndData,
+  IN UINT32  OrData
+  )
+{
+  return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData) | OrData);
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in a 32-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldRead32 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit
+  )
+{
+  return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit);
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  32-bit register is returned.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  Value     The new value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldWrite32 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT32  Value
+  )
+{
+  return PciSegmentWrite32 (
+                            Address,
+                            BitFieldWrite32 (PciSegmentRead32 (Address), StartBit, EndBit, Value)
+                            );
+}
+
+/**
+  Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
+  writes the result back to the bit field in the 32-bit port.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 32-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized. Extra left bits in OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldOr32 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT32  OrData
+  )
+{
+  return PciSegmentWrite32 (
+                            Address,
+                            BitFieldOr32 (PciSegmentRead32 (Address), StartBit, EndBit, OrData)
+                            );
+}
+
+/**
+  Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
+  AND, and writes the result back to the bit field in the 32-bit register.
+
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a bitwise
+  AND between the read result and the value specified by AndData, and writes the result
+  to the 32-bit PCI configuration register specified by Address. The value written to
+  the PCI configuration register is returned.  This function must guarantee that all PCI
+  read and write operations are serialized.  Extra left bits in AndData are stripped.
+  If any reserved bits in Address are set, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAnd32 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT32  AndData
+  )
+{
+  return PciSegmentWrite32 (
+                            Address,
+                            BitFieldAnd32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData)
+                            );
+}
+
+/**
+  Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  32-bit port.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 32-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If any reserved bits in Address are set, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAndThenOr32 (
+  IN UINT64  Address,
+  IN UINTN   StartBit,
+  IN UINTN   EndBit,
+  IN UINT32  AndData,
+  IN UINT32  OrData
+  )
+{
+  return PciSegmentWrite32 (
+                            Address,
+                            BitFieldAndThenOr32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData, OrData)
+                            );
+}
+
+/**
+  Reads a range of PCI configuration registers into a caller supplied buffer.
+
+  Reads the range of PCI configuration registers specified by StartAddress and
+  Size into the buffer specified by Buffer. This function only allows the PCI
+  configuration registers from a single PCI function to be read. Size is
+  returned. When possible 32-bit PCI configuration read cycles are used to read
+  from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
+  and 16-bit PCI configuration read cycles may be used at the beginning and the
+  end of the range.
+
+  If any reserved bits in StartAddress are set, then ASSERT().
+  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+  If Size > 0 and Buffer is NULL, then ASSERT().
+
+  @param  StartAddress  The starting address that encodes the PCI Segment, Bus,
+                        Device, Function and Register.
+  @param  Size          The size in bytes of the transfer.
+  @param  Buffer        The pointer to a buffer receiving the data read.
+
+  @return Size
+
+**/
+UINTN
+EFIAPI
+PciSegmentReadBuffer (
+  IN  UINT64  StartAddress,
+  IN  UINTN   Size,
+  OUT VOID    *Buffer
+  )
+{
+  UINTN  ReturnValue;
+
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
+  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+  if (Size == 0) {
+    return Size;
+  }
+
+  ASSERT (Buffer != NULL);
+
+  //
+  // Save Size for return
+  //
+  ReturnValue = Size;
+
+  if ((StartAddress & BIT0) != 0) {
+    //
+    // Read a byte if StartAddress is byte aligned
+    //
+    *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);
+    StartAddress             += sizeof (UINT8);
+    Size                     -= sizeof (UINT8);
+    Buffer                    = (UINT8 *)Buffer + 1;
+  }
+
+  if ((Size >= sizeof (UINT16)) && ((StartAddress & BIT1) != 0)) {
+    //
+    // Read a word if StartAddress is word aligned
+    //
+    WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
+    StartAddress += sizeof (UINT16);
+    Size         -= sizeof (UINT16);
+    Buffer        = (UINT16 *)Buffer + 1;
+  }
+
+  while (Size >= sizeof (UINT32)) {
+    //
+    // Read as many double words as possible
+    //
+    WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress));
+    StartAddress += sizeof (UINT32);
+    Size         -= sizeof (UINT32);
+    Buffer        = (UINT32 *)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT16)) {
+    //
+    // Read the last remaining word if exist
+    //
+    WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
+    StartAddress += sizeof (UINT16);
+    Size         -= sizeof (UINT16);
+    Buffer        = (UINT16 *)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT8)) {
+    //
+    // Read the last remaining byte if exist
+    //
+    *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);
+  }
+
+  return ReturnValue;
+}
+
+/**
+  Copies the data in a caller supplied buffer to a specified range of PCI
+  configuration space.
+
+  Writes the range of PCI configuration registers specified by StartAddress and
+  Size from the buffer specified by Buffer. This function only allows the PCI
+  configuration registers from a single PCI function to be written. Size is
+  returned. When possible 32-bit PCI configuration write cycles are used to
+  write from StartAdress to StartAddress + Size. Due to alignment restrictions,
+  8-bit and 16-bit PCI configuration write cycles may be used at the beginning
+  and the end of the range.
+
+  If any reserved bits in StartAddress are set, then ASSERT().
+  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+  If Size > 0 and Buffer is NULL, then ASSERT().
+
+  @param  StartAddress  The starting address that encodes the PCI Segment, Bus,
+                        Device, Function and Register.
+  @param  Size          The size in bytes of the transfer.
+  @param  Buffer        The pointer to a buffer containing the data to write.
+
+  @return The parameter of Size.
+
+**/
+UINTN
+EFIAPI
+PciSegmentWriteBuffer (
+  IN UINT64  StartAddress,
+  IN UINTN   Size,
+  IN VOID    *Buffer
+  )
+{
+  UINTN  ReturnValue;
+
+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
+  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+  if (Size == 0) {
+    return 0;
+  }
+
+  ASSERT (Buffer != NULL);
+
+  // The Bcm/Rpi has a single cfg which can be mapped
+  // to any given device on the bus, which means we need to remap
+  // it basically everytime a new config access is done
+
+  //
+  // Save Size for return
+  //
+  ReturnValue = Size;
+
+  if ((StartAddress & BIT0) != 0) {
+    //
+    // Write a byte if StartAddress is byte aligned
+    //
+    PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);
+    StartAddress += sizeof (UINT8);
+    Size         -= sizeof (UINT8);
+    Buffer        = (UINT8 *)Buffer + 1;
+  }
+
+  if ((Size >= sizeof (UINT16)) && ((StartAddress & BIT1) != 0)) {
+    //
+    // Write a word if StartAddress is word aligned
+    //
+    PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
+    StartAddress += sizeof (UINT16);
+    Size         -= sizeof (UINT16);
+    Buffer        = (UINT16 *)Buffer + 1;
+  }
+
+  while (Size >= sizeof (UINT32)) {
+    //
+    // Write as many double words as possible
+    //
+    PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer));
+    StartAddress += sizeof (UINT32);
+    Size         -= sizeof (UINT32);
+    Buffer        = (UINT32 *)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT16)) {
+    //
+    // Write the last remaining word if exist
+    //
+    PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
+    StartAddress += sizeof (UINT16);
+    Size         -= sizeof (UINT16);
+    Buffer        = (UINT16 *)Buffer + 1;
+  }
+
+  if (Size >= sizeof (UINT8)) {
+    //
+    // Write the last remaining byte if exist
+    //
+    PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);
+  }
+
+  return ReturnValue;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf
new file mode 100644
index 000000000000..063c85ebc428
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf
@@ -0,0 +1,33 @@
+## @file
+# PCI Segment Library for StarFive JH7110 SoC
+#
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = PciSegmentLib
+  FILE_GUID                      = 832163a2-41f5-c529-3f02-77fb68abbc2c
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PciSegmentLib
+
+[Sources]
+  PciSegmentLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  IoLib
+  PcdLib
+  UefiLib
+
+[FixedPcd]
+  gJH7110TokenSpaceGuid.PcdPciConfigRegBase
-- 
2.34.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110172): https://edk2.groups.io/g/devel/message/110172
Mute This Topic: https://groups.io/mt/102214518/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  reply	other threads:[~2023-10-27  3:24 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-27  3:19 [edk2-devel] [PATCH v3 0/5] StarFive/VisionFive2: Add VisionFive 2 platform John Chew
2023-10-27  3:19 ` John Chew [this message]
2023-10-27  3:19 ` [edk2-devel] [PATCH v3 2/5] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
2023-10-27  3:19 ` [edk2-devel] [PATCH v3 3/5] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
2023-10-27  3:19 ` [edk2-devel] [PATCH v3 4/5] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
2023-10-27  3:19 ` [edk2-devel] [PATCH v3 5/5] StarFive/VisionFive2: Add VisionFive 2 platform John Chew
2023-10-31  9:26 ` [edk2-devel] [PATCH v3 0/5] " Sunil V L
2023-11-01  1:17   ` John Chew
2023-11-02  4:00     ` Sunil V L

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231027031906.1814-2-yuinyee.chew@starfivetech.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox