From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <bounce+27952+110172+7686176+12367111@groups.io>
Received: from mail02.groups.io (mail02.groups.io [66.175.222.108])
	by spool.mail.gandi.net (Postfix) with ESMTPS id 9C0559408EF
	for <rebecca@openfw.io>; Fri, 27 Oct 2023 03:24:04 +0000 (UTC)
DKIM-Signature: a=rsa-sha256; bh=cg8epHoICo1WAJezdXeMjuTILuLKDTcs5CLMK6u8Ya8=;
 c=relaxed/simple; d=groups.io;
 h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type:Content-Transfer-Encoding;
 s=20140610; t=1698377043; v=1;
 b=BUk8jCQ6F7lIWZY4yEmLQeewAVlFrKSeE3GJq3xwEuK6INfcRE8CcW9Zd2SQ8IiZLmQ4k8eZ
 CnFWshfcdeDmbwRMrzkHKzWM7/eyL0scFBD94VP5NS4CO1LaC3aZ+eX4ZdwrVcA8jOXyvZiR8Af
 AAryQPbVf2AE5pSeWaiTclTY=
X-Received: by 127.0.0.2 with SMTP id vFaiYY7687511xEcD2WDfCKl; Thu, 26 Oct 2023 20:24:03 -0700
X-Received: from ex01.ufhost.com (ex01.ufhost.com [61.152.239.75])
 by mx.groups.io with SMTP id smtpd.web11.89095.1698377041079709977
 for <devel@edk2.groups.io>;
 Thu, 26 Oct 2023 20:24:02 -0700
X-Received: from EXMBX165.cuchost.com (unknown [175.102.18.54])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(Client CN "EXMBX165", Issuer "EXMBX165" (not verified))
	by ex01.ufhost.com (Postfix) with ESMTP id 9E84524E29A;
	Fri, 27 Oct 2023 11:23:50 +0800 (CST)
X-Received: from EXMBX073.cuchost.com (172.16.6.83) by EXMBX165.cuchost.com
 (172.16.6.75) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Fri, 27 Oct
 2023 11:23:50 +0800
X-Received: from localhost.localdomain (202.188.176.82) by EXMBX073.cuchost.com
 (172.16.6.83) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Fri, 27 Oct
 2023 11:23:44 +0800
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
Message-ID: <20231027031906.1814-2-yuinyee.chew@starfivetech.com>
In-Reply-To: <20231027031906.1814-1-yuinyee.chew@starfivetech.com>
References: <20231027031906.1814-1-yuinyee.chew@starfivetech.com>
MIME-Version: 1.0
X-Originating-IP: [202.188.176.82]
X-ClientProxiedBy: EXCAS062.cuchost.com (172.16.6.22) To EXMBX073.cuchost.com
 (172.16.6.83)
X-YovoleRuleAgent: yovoleflag
Precedence: Bulk
List-Subscribe: <mailto:devel+subscribe@edk2.groups.io>
List-Help: <mailto:devel+help@edk2.groups.io>
Sender: devel@edk2.groups.io
List-Id: <devel.edk2.groups.io>
Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io
Reply-To: devel@edk2.groups.io,yuinyee.chew@starfivetech.com
List-Unsubscribe-Post: List-Unsubscribe=One-Click
List-Unsubscribe: <https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/plugh>
X-Gm-Message-State: kHsxmvQJ03kzKaCGe6CIZb1Gx7686176AA=
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable
X-GND-Status: LEGIT
Authentication-Results: spool.mail.gandi.net;
	dkim=pass header.d=groups.io header.s=20140610 header.b=BUk8jCQ6;
	dmarc=none;
	spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io

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/PciHostBridgeLibConstr=
uctor.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/PciHostBri=
dgeLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridg=
eLib.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[=
] =3D {
+  {
+    {
+      {
+        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[] =3D {
+  L"Mem", L"I/O", L"Bus"
+};
+
+//
+// See description in MdeModulePkg/Include/Library/PciHostBridgeLib.h
+//
+PCI_ROOT_BRIDGE  mPciRootBridges[] =3D {
+  {
+    0,                                      // Segment
+    0,                                      // Supports
+    0,                                      // Attributes
+    FALSE,                                  // DmaAbove4G
+    FALSE,                                  // NoExtendedConfigSpace (true=
=3D256 byte config, false=3D4k)
+    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=3D2=
56 byte config, false=3D4k)
+    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 =3D ARRAY_SIZE (mPciRootBridges);
+  return mPciRootBridges;
+}
+
+/**
+  Free the root bridge instances array returned from PciHostBridgeGetRootB=
ridges().
+
+  @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 reso=
urces
+                          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 =3D 0;
+  Descriptor      =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
+  while (Descriptor->Desc =3D=3D ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+    DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+    for ( ; Descriptor->Desc =3D=3D ACPI_ADDRESS_SPACE_DESCRIPTOR; Descrip=
tor++) {
+      ASSERT (
+              Descriptor->ResType <
+              ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr)
+              );
+      DEBUG (
+             (DEBUG_ERROR, " %s: Length/Alignment =3D 0x%lx / 0x%lx\n",
+              mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType=
],
+              Descriptor->AddrLen, Descriptor->AddrRangeMax
+             )
+             );
+      if (Descriptor->ResType =3D=3D ACPI_ADDRESS_SPACE_TYPE_MEM) {
+        DEBUG (
+               (DEBUG_ERROR, "     Granularity/SpecificFlag =3D %ld / %02x=
%s\n",
+                Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag=
,
+                ((Descriptor->SpecificFlag &
+                  EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETC=
HABLE
+                  ) !=3D 0) ? L" (Prefetchable)" : L""
+               )
+               );
+      }
+    }
+
+    //
+    // Skip the END descriptor for root bridge
+    //
+    ASSERT (Descriptor->Desc =3D=3D ACPI_END_TAG_DESCRIPTOR);
+    Descriptor =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+                                                       (EFI_ACPI_END_TAG_D=
ESCRIPTOR *)Descriptor + 1
+                                                       );
+  }
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri=
dgeLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBri=
dgeLib.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                    =3D 0x00010019
+  BASE_NAME                      =3D PciHostBridgeLib
+  FILE_GUID                      =3D 606d906f-eba7-d5c6-fcf0-6aeedea00193
+  MODULE_TYPE                    =3D DXE_DRIVER
+  VERSION_STRING                 =3D 1.0
+  LIBRARY_CLASS                  =3D PciHostBridgeLib|DXE_DRIVER
+  CONSTRUCTOR                    =3D JH7110PciHostBridgeLibConstructor
+
+#
+# The following information is for reference only and not required by the =
build
+# tools.
+#
+#  VALID_ARCHITECTURES           =3D 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/PciHostBri=
dgeLibConstructor.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/P=
ciHostBridgeLibConstructor.c
new file mode 100644
index 000000000000..cc505f2723d1
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibC=
onstructor.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) =3D 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]      =3D { FixedPcdGet32 (PcdPci0Mmio64Base) + Fi=
xedPcdGet32 (PcdPci0Mmio64Size),
+                                  FixedPcdGet32 (PcdPci1Mmio64Base) + Fixe=
dPcdGet32 (PcdPci1Mmio64Size) };
+UINT64  PCI_MEMREGION_32[2]   =3D { FixedPcdGet32 (PcdPci0Mmio32Base), Fix=
edPcdGet32 (PcdPci1Mmio32Base) };
+UINT64  PCI_MEMREGION_64[2]   =3D { FixedPcdGet32 (PcdPci0Mmio64Base), Fix=
edPcdGet32 (PcdPci1Mmio64Base) };
+UINT64  PCI_MEMREGION_SIZE[2] =3D { 27, 30 };
+UINT32  STG_ARFUNC_OFFSET[2]  =3D { 0xc0, 0x270 };
+UINT32  STG_AWFUNC_OFFSET[2]  =3D { 0xc4, 0x274 };
+UINT32  STG_RP_REP_OFFSET[2]  =3D { 0x130, 0x2e0 };
+UINT32  PCIE_GPIO[2]          =3D { 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 =3D GetPcieRegBase (Port);
+
+  RegWrite ((UINT64)Base + Offset, Value);
+}
+
+UINT32
+PcieRegRead (
+  IN UINT32  Port,
+  IN UINTN   Offset
+  )
+{
+  UINT32  Value =3D 0;
+  UINT64  Base  =3D 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 =3D 0;
+
+  Value  =3D MmioRead32 ((UINT64)Base + Offset);
+  Value &=3D ~Mask;
+  Value |=3D val;
+  MmioWrite32 ((UINT64)Base + Offset, Value);
+}
+
+STATIC
+VOID
+PcieFuncSet (
+  IN UINT32  Port
+  )
+{
+  INTN    i;
+  UINT32  Value;
+  UINT64  Base =3D GetPcieRegBase (Port);
+
+  /* Disable physical functions except #0 */
+  for (i =3D 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 =3D (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 =3D Port * 6 + 11;
+
+  PcieUpdatebits (
+                  STG_CLK_BASE,
+                  STG_PCIE_RESET_OFFSET,
+                  0x3f << (PortOffset),
+                  0
+                  ); /*reset all*/
+}
+
+VOID
+PcieResetAssert (
+  IN UINT32  Port
+  )
+{
+  UINT32  PortOffset =3D 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 =3D PCIE_GPIO[Port] & 0x3;
+  Mask   =3D 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 =3D GetPcieRegBase (Port) + XR3PCI_ATR_AXI4_SLV0;
+  UINT32  Value;
+
+  Base +=3D  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 =3D SrcAddr;
+
+  RegWrite (
+            Base + XR3PCI_ATR_SRC_ADDR_LOW,
+            (Value & XR3PCI_ATR_SRC_ADDR_MASK) | ((WinSize - 1) << 1) | 0x=
1
+            );
+  Value =3D SrcAddr >> 32;
+
+  RegWrite (Base + XR3PCI_ATR_SRC_ADDR_HIGH, Value);
+  Value =3D TrslAddr;
+  RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_LOW, Value);
+  Value =3D 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 =3D 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 =3D 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))) =3D=3D 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 =3D EFI_INITIALIZE_LOCK_VARIABLE (TPL_H=
IGH_LEVEL);
+
+// STATIC UINT64 mPciSegmentLastAccess;     /* Avoid repeat CFG_INDEX upda=
tes */
+
+/**
+  Internal worker function to obtain config space base address.
+
+  @param  Address The address that encodes the PCI Bus, Device, Function a=
nd
+                  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     =3D PCIE_CONFIG_BASE;
+  Offset   =3D Address & 0xFFF;      /* Pick off the 4k register offset */
+  Address &=3D 0xFFFF000;            /* Clear the offset leave only the BD=
F */
+
+  /* The root port is at the base of the PCIe register space */
+  if (Address !=3D 0) {
+    Dev =3D EFI_PCI_ADDR_DEV (Address);
+    Bus =3D 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 =3D=3D 0x10) || (Offset =3D=3D 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 a=
nd
+                  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 =3D (Address >> 32);
+
+  EfiAcquireLock (&mPciSegmentReadWriteLock);
+  Base =3D PciSegmentLibGetConfigBase (Address, Segment, 0);
+
+  if (Base =3D=3D 0xFFFFFFFF) {
+    EfiReleaseLock (&mPciSegmentReadWriteLock);
+    return Base;
+  }
+
+  switch (Width) {
+    case PciCfgWidthUint8:
+      Ret =3D MmioRead8 (Base);
+      break;
+    case PciCfgWidthUint16:
+      Ret =3D MmioRead16 (Base);
+      break;
+    case PciCfgWidthUint32:
+      Ret =3D MmioRead32 (Base);
+      break;
+    default:
+      ASSERT (FALSE);
+      Ret =3D 0;
+  }
+
+  EfiReleaseLock (&mPciSegmentReadWriteLock);
+  // DEBUG ((DEBUG_ERROR, "PCIe seg read Address %lx %lx width %d val %x S=
egment %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 a=
nd
+                  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 =3D (Address >> 32);
+
+  EfiAcquireLock (&mPciSegmentReadWriteLock);
+  Base =3D PciSegmentLibGetConfigBase (Address, Segment, 1);
+
+  if (Base =3D=3D 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 aft=
er
+  SetVirtualAddressMap().
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address The address that encodes the PCI Bus, Device, Function a=
nd
+                  Register.
+
+  @retval RETURN_SUCCESS           The PCI device was registered for runti=
me access.
+  @retval RETURN_UNSUPPORTED       An attempt was made to call this functi=
on
+                                   after ExitBootServices().
+  @retval RETURN_UNSUPPORTED       The resources required to access the PC=
I device
+                                   at runtime could not be mapped.
+  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources availabl=
e 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 Addr=
ess.
+  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 th=
e value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and w=
rite operations are serialized.
+
+  If any reserved bits in Address are set, then ASSERT().
+
+  @param  Address     The address that encodes the PCI Segment, Bus, Devic=
e, 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-b=
it 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) | Or=
Data));
+}
+
+/**
+  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 b=
y 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) & An=
dData));
+}
+
+/**
+  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 b=
y AndData,
+  performs a bitwise OR between the result of the AND operation and the va=
lue 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) & A=
ndData) | OrData));
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in an 8-bit PCI configuration register. The bit fiel=
d 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 fi=
eld.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    Range 0..7.
+
+  @return The value of the bit field read from the PCI configuration regis=
ter.
+
+**/
+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 t=
he
+  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 an=
d EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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), Star=
tBit, 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, perform=
s 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 registe=
r is
+  returned. This function must guarantee that all PCI read and write opera=
tions
+  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 a=
nd EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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), StartBi=
t, EndBit, OrData)
+                           );
+}
+
+/**
+  Reads a bit field in an 8-bit PCI configuration register, performs a bit=
wise
+  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, perform=
s 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 fi=
eld.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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), StartB=
it, 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, perform=
s 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 PC=
I
+  configuration register is returned. This function must guarantee that al=
l PCI
+  read and write operations are serialized. Extra left bits in both AndDat=
a 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 a=
nd EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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 Add=
ress.
+  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 t=
he value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and w=
rite 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, Devic=
e, 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, Val=
ue);
+}
+
+/**
+  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, perfor=
ms 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 registe=
r is
+  returned. This function must guarantee that all PCI read and write opera=
tions
+  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, F=
unction 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 b=
y 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 b=
y AndData,
+  performs a bitwise OR between the result of the AND operation and the va=
lue 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 fiel=
d 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 fi=
eld.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    Range 0..15.
+
+  @return The value of the bit field read from the PCI configuration regis=
ter.
+
+**/
+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 t=
he
+  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 an=
d EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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), S=
tartBit, 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 a=
nd EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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), Star=
tBit, 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 fi=
eld.
+                    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 fie=
ld.
+                    The ordinal of the most significant bit in a byte is b=
it 7.
+  @param  AndData   The value to AND with the read value from the PCI conf=
iguration 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), Sta=
rtBit, 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, perfor=
ms 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 PC=
I
+  configuration register is returned. This function must guarantee that al=
l PCI
+  read and write operations are serialized. Extra left bits in both AndDat=
a 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 a=
nd EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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 Add=
ress.
+  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 t=
he value specified by Value.
+  Value is returned.  This function must guarantee that all PCI read and w=
rite 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, Devic=
e,
+                      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-b=
it 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 b=
y 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 b=
y AndData,
+  performs a bitwise OR between the result of the AND operation and the va=
lue 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 fiel=
d 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 fi=
eld.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    Range 0..31.
+
+  @return The value of the bit field read from the PCI configuration regis=
ter.
+
+**/
+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 t=
he
+  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 an=
d EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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), S=
tartBit, 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, perfor=
ms 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 registe=
r is
+  returned. This function must guarantee that all PCI read and write opera=
tions
+  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 a=
nd EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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), Star=
tBit, EndBit, OrData)
+                            );
+}
+
+/**
+  Reads a bit field in a 32-bit PCI configuration register, performs a bit=
wise
+  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, perfor=
ms a bitwise
+  AND between the read result and the value specified by AndData, and writ=
es 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 guarante=
e that all PCI
+  read and write operations are serialized.  Extra left bits in AndData ar=
e 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 fi=
eld.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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), Sta=
rtBit, 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, perfor=
ms 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 PC=
I
+  configuration register is returned. This function must guarantee that al=
l PCI
+  read and write operations are serialized. Extra left bits in both AndDat=
a 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 a=
nd EndBit, then ASSERT().
+
+  @param  Address   The PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit fi=
eld.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit fie=
ld.
+                    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 buff=
er.
+
+  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 an=
d 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) <=3D 0x1000);
+
+  if (Size =3D=3D 0) {
+    return Size;
+  }
+
+  ASSERT (Buffer !=3D NULL);
+
+  //
+  // Save Size for return
+  //
+  ReturnValue =3D Size;
+
+  if ((StartAddress & BIT0) !=3D 0) {
+    //
+    // Read a byte if StartAddress is byte aligned
+    //
+    *(volatile UINT8 *)Buffer =3D PciSegmentRead8 (StartAddress);
+    StartAddress             +=3D sizeof (UINT8);
+    Size                     -=3D sizeof (UINT8);
+    Buffer                    =3D (UINT8 *)Buffer + 1;
+  }
+
+  if ((Size >=3D sizeof (UINT16)) && ((StartAddress & BIT1) !=3D 0)) {
+    //
+    // Read a word if StartAddress is word aligned
+    //
+    WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
+    StartAddress +=3D sizeof (UINT16);
+    Size         -=3D sizeof (UINT16);
+    Buffer        =3D (UINT16 *)Buffer + 1;
+  }
+
+  while (Size >=3D sizeof (UINT32)) {
+    //
+    // Read as many double words as possible
+    //
+    WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress));
+    StartAddress +=3D sizeof (UINT32);
+    Size         -=3D sizeof (UINT32);
+    Buffer        =3D (UINT32 *)Buffer + 1;
+  }
+
+  if (Size >=3D sizeof (UINT16)) {
+    //
+    // Read the last remaining word if exist
+    //
+    WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
+    StartAddress +=3D sizeof (UINT16);
+    Size         -=3D sizeof (UINT16);
+    Buffer        =3D (UINT16 *)Buffer + 1;
+  }
+
+  if (Size >=3D sizeof (UINT8)) {
+    //
+    // Read the last remaining byte if exist
+    //
+    *(volatile UINT8 *)Buffer =3D 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 StartAddres=
s 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 i=
s
+  returned. When possible 32-bit PCI configuration write cycles are used t=
o
+  write from StartAdress to StartAddress + Size. Due to alignment restrict=
ions,
+  8-bit and 16-bit PCI configuration write cycles may be used at the begin=
ning
+  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 wri=
te.
+
+  @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) <=3D 0x1000);
+
+  if (Size =3D=3D 0) {
+    return 0;
+  }
+
+  ASSERT (Buffer !=3D 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 =3D Size;
+
+  if ((StartAddress & BIT0) !=3D 0) {
+    //
+    // Write a byte if StartAddress is byte aligned
+    //
+    PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);
+    StartAddress +=3D sizeof (UINT8);
+    Size         -=3D sizeof (UINT8);
+    Buffer        =3D (UINT8 *)Buffer + 1;
+  }
+
+  if ((Size >=3D sizeof (UINT16)) && ((StartAddress & BIT1) !=3D 0)) {
+    //
+    // Write a word if StartAddress is word aligned
+    //
+    PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
+    StartAddress +=3D sizeof (UINT16);
+    Size         -=3D sizeof (UINT16);
+    Buffer        =3D (UINT16 *)Buffer + 1;
+  }
+
+  while (Size >=3D sizeof (UINT32)) {
+    //
+    // Write as many double words as possible
+    //
+    PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer));
+    StartAddress +=3D sizeof (UINT32);
+    Size         -=3D sizeof (UINT32);
+    Buffer        =3D (UINT32 *)Buffer + 1;
+  }
+
+  if (Size >=3D sizeof (UINT16)) {
+    //
+    // Write the last remaining word if exist
+    //
+    PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
+    StartAddress +=3D sizeof (UINT16);
+    Size         -=3D sizeof (UINT16);
+    Buffer        =3D (UINT16 *)Buffer + 1;
+  }
+
+  if (Size >=3D 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.<B=
R>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    =3D 0x0001001B
+  BASE_NAME                      =3D PciSegmentLib
+  FILE_GUID                      =3D 832163a2-41f5-c529-3f02-77fb68abbc2c
+  MODULE_TYPE                    =3D BASE
+  VERSION_STRING                 =3D 1.0
+  LIBRARY_CLASS                  =3D PciSegmentLib
+
+[Sources]
+  PciSegmentLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  IoLib
+  PcdLib
+  UefiLib
+
+[FixedPcd]
+  gJH7110TokenSpaceGuid.PcdPciConfigRegBase
--=20
2.34.1



-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-
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]
-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-