public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver
@ 2023-10-19  2:59 John Chew
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: John Chew @ 2023-10-19  2:59 UTC (permalink / raw)
  To: devel; +Cc: mindachen1987, Sunil V L, John Chew

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

Cc: Sunil V L <sunilvl@ventanamicro.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            |  249 ++++
 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf          |   48 +
 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c |  405 ++++++
 Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c                  | 1460 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf                |   33 +
 5 files changed, 2195 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..7d73cb5b4b5c
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
@@ -0,0 +1,249 @@
+/** @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"
+};
+
+// These should come from the PCD...
+#define JH7110_PCI_BUSNUM_MIN     0x00
+#define JH7110_PCI_BUSNUM_MAX     0xFF
+#define JH7110_PCI_PORTIO_MIN     0x01
+#define JH7110_PCI_PORTIO_MAX     0x00 // MIN>MAX disables PIO
+#define JH7110_PCI_PORTIO_OFFSET  0x00
+// The bridge thinks its MMIO is here (which means it can't access this area in phy ram)
+
+#define JH7110_PCI_SEG0_MMIO32_MIN  (0x30000000)
+#define JH7110_PCI_SEG0_MMIO32_MAX  (JH7110_PCI_SEG0_MMIO32_MIN + 0x7FFFFFF)
+// The CPU views it via a window here..
+// We might be able to size another region?
+#define JH7110_PCI_SEG0_MMIO64_MIN  (0x900000000)
+#define JH7110_PCI_SEG0_MMIO64_MAX  (0x940000000)
+
+#define JH7110_PCI_SEG1_MMIO32_MIN  (0x38000000)
+#define JH7110_PCI_SEG1_MMIO32_MAX  (JH7110_PCI_SEG1_MMIO32_MIN + 0x7FFFFFF)
+// The CPU views it via a window here..
+// We might be able to size another region?
+#define JH7110_PCI_SEG1_MMIO64_MIN  (0x980000000)
+#define JH7110_PCI_SEG1_MMIO64_MAX  (0x9c0000000)
+
+//
+// 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
+    { JH7110_PCI_BUSNUM_MIN,
+      JH7110_PCI_BUSNUM_MAX },        // Bus
+    { JH7110_PCI_PORTIO_MIN,
+      JH7110_PCI_PORTIO_MAX,
+      MAX_UINT64 - JH7110_PCI_PORTIO_OFFSET + 1 },   // Io
+    { JH7110_PCI_SEG0_MMIO32_MIN, JH7110_PCI_SEG0_MMIO32_MAX, 0 },  // Mem
+    { JH7110_PCI_SEG0_MMIO64_MIN,JH7110_PCI_SEG0_MMIO64_MAX,  0 },  // MemAbove4G
+    { MAX_UINT32,                0x0 },                             // Pefetchable Mem
+    { MAX_UINT64,                0x0 },                             // Pefetchable MemAbove4G
+    (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
+    { JH7110_PCI_BUSNUM_MIN,
+      JH7110_PCI_BUSNUM_MAX },        // Bus
+    { JH7110_PCI_PORTIO_MIN,
+      JH7110_PCI_PORTIO_MAX,
+      MAX_UINT64 - JH7110_PCI_PORTIO_OFFSET + 1 },   // Io
+    { JH7110_PCI_SEG1_MMIO32_MIN, JH7110_PCI_SEG1_MMIO32_MAX, 0 },  // Mem
+    { JH7110_PCI_SEG1_MMIO64_MIN, JH7110_PCI_SEG1_MMIO64_MAX,  0},  // MemAbove4G
+    { MAX_UINT32,                0x0 },                             // Pefetchable Mem
+    { MAX_UINT64,                0x0 },                             // Pefetchable MemAbove4G
+    (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..c6d498df2d62
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -0,0 +1,48 @@
+## @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.PcdJH7110PciRegBase
+  gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioAdr
+  gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioLen
+  gJH7110TokenSpaceGuid.PcdJH7110PciCpuMmioAdr
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
new file mode 100644
index 000000000000..05d10e08232c
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
@@ -0,0 +1,405 @@
+/** @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]      = { 0x940000000, 0x9c0000000 };
+UINT64  PCI_MEMREGION_32[2]   = { 0x30000000, 0x38000000 };
+UINT64  PCI_MEMREGION_64[2]   = { 0x900000000, 0x980000000 };
+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;
+  // DEBUG ((DEBUG_ERROR, "addr low %x\n", Value));
+  RegWrite (
+            Base + XR3PCI_ATR_SRC_ADDR_LOW,
+            (Value & XR3PCI_ATR_SRC_ADDR_MASK) | ((WinSize - 1) << 1) | 0x1
+            );
+  Value = SrcAddr >> 32;
+  // DEBUG ((DEBUG_ERROR, "addr high %x\n", Value));
+  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..30d9d9599564
--- /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.PcdJH7110PciConfigRegBase
-- 
2.34.1



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



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support
  2023-10-19  2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
@ 2023-10-19  2:59 ` John Chew
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 3/6] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-19  2:59 UTC (permalink / raw)
  To: devel; +Cc: John Chew, Sunil V L

Cc: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c             | 893 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h             | 188 +++++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf           |  52 ++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c   | 571 +++++++++++++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h   |  35 +
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf |  44 +
 Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h                               | 163 ++++
 Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h                          |  88 ++
 8 files changed, 2034 insertions(+)

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c
new file mode 100755
index 000000000000..c345556f8abf
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c
@@ -0,0 +1,893 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include "SpiDxe.h"
+
+SPI_MASTER  *mSpiMasterInstance;
+
+STATIC
+VOID
+SpiControllerEnable (
+  IN UINT32  RegBase
+  )
+{
+  UINT32  Reg;
+
+  Reg  = MmioRead32 (RegBase + SPI_REG_CONFIG);
+  Reg |= SPI_REG_CONFIG_ENABLE;
+  MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg);
+}
+
+STATIC
+VOID
+SpiControllerDisable (
+  IN UINT32  RegBase
+  )
+{
+  UINT32  Reg;
+
+  Reg  = MmioRead32 (RegBase + SPI_REG_CONFIG);
+  Reg &= ~SPI_REG_CONFIG_ENABLE;
+  MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg);
+}
+
+STATIC
+VOID
+SpiWriteSpeed (
+  IN SPI_DEVICE_PARAMS  *Slave,
+  IN UINT32             SclkHz,
+  IN SPI_TIMING_PARAMS  *Timing
+  )
+{
+  UINT32  Reg, Div, RefClkNs, SclkNs;
+  UINT32  Tshsl, Tchsh, Tslch, Tsd2d;
+
+  SpiControllerDisable (Slave->RegBase);
+
+  /* Configure baudrate */
+  Reg  = MmioRead32 (Slave->RegBase + SPI_REG_CONFIG);
+  Reg &= ~(SPI_REG_CONFIG_BAUD_MASK << SPI_REG_CONFIG_BAUD_LSB);
+
+  Div = DIV_ROUND_UP (Timing->RefClkHz, SclkHz * 2) - 1;
+
+  if (Div > SPI_REG_CONFIG_BAUD_MASK) {
+    Div = SPI_REG_CONFIG_BAUD_MASK;
+  }
+
+  DEBUG (
+         (DEBUG_INFO, "%a(): RefClk %dHz sclk %dHz Div 0x%x, actual %dHz\n", __func__,
+          Timing->RefClkHz, SclkHz, Div, Timing->RefClkHz / (2 * (Div + 1)))
+         );
+
+  Reg |= (Div << SPI_REG_CONFIG_BAUD_LSB);
+  MmioWrite32 (Slave->RegBase + SPI_REG_CONFIG, Reg);
+
+  /* Configure delay timing */
+  RefClkNs = DIV_ROUND_UP (1000000000, Timing->RefClkHz);
+  SclkNs = DIV_ROUND_UP (1000000000, SclkHz);
+
+  if (Timing->TshslNs >= SclkNs + RefClkNs) {
+    Timing->TshslNs -= SclkNs + RefClkNs;
+  }
+
+  if (Timing->TchshNs >= SclkNs + 3 * RefClkNs) {
+    Timing->TchshNs -= SclkNs + 3 * RefClkNs;
+  }
+
+  Tshsl = DIV_ROUND_UP (Timing->TshslNs, RefClkNs);
+  Tchsh = DIV_ROUND_UP (Timing->TchshNs, RefClkNs);
+  Tslch = DIV_ROUND_UP (Timing->TslchNs, RefClkNs);
+  Tsd2d = DIV_ROUND_UP (Timing->Tsd2dNs, RefClkNs);
+
+  Reg = ((Tshsl & SPI_REG_DELAY_TSHSL_MASK)
+         << SPI_REG_DELAY_TSHSL_LSB);
+  Reg |= ((Tchsh & SPI_REG_DELAY_TCHSH_MASK)
+          << SPI_REG_DELAY_TCHSH_LSB);
+  Reg |= ((Tslch & SPI_REG_DELAY_TSLCH_MASK)
+          << SPI_REG_DELAY_TSLCH_LSB);
+  Reg |= ((Tsd2d & SPI_REG_DELAY_TSD2D_MASK)
+          << SPI_REG_DELAY_TSD2D_LSB);
+  MmioWrite32 (Slave->RegBase + SPI_REG_DELAY, Reg);
+
+  SpiControllerEnable (Slave->RegBase);
+}
+
+STATIC
+EFI_STATUS
+SpiWaitIdle (
+  IN UINT32  RegBase
+  )
+{
+  BOOLEAN IsIdle;
+  UINT32  Count     = 0;
+  UINT32  TimeoutMs = 5000000;
+
+  do {
+    IsIdle = (BOOLEAN)((MmioRead32(RegBase + SPI_REG_CONFIG) >>
+                        SPI_REG_CONFIG_IDLE_LSB) & 0x1);
+    Count = (IsIdle) ? (Count+1) : 0;
+
+    /*
+     * Make sure the QSPI controller is in really idle
+     * for n period of time before proceed
+     */
+    if (Count >= SPI_POLL_IDLE_RETRY) {
+      return EFI_SUCCESS;
+    }
+
+    gBS->Stall (1);
+  } while (TimeoutMs);
+
+  return EFI_TIMEOUT;
+}
+
+STATIC
+EFI_STATUS
+SpiExecFlashCmd (
+  IN UINT32  RegBase,
+  IN UINT32  Reg
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      Retry = SPI_REG_RETRY;
+
+  /* Write the CMDCTRL without start execution */
+  MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg);
+  /* Start execute */
+  Reg |= SPI_REG_CMDCTRL_EXECUTE;
+  MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg);
+
+  while (Retry--) {
+    Reg = MmioRead32 (RegBase + SPI_REG_CMDCTRL);
+    if ((Reg & SPI_REG_CMDCTRL_INPROGRESS) == 0) {
+      break;
+    }
+    gBS->Stall (1);
+  }
+
+  if (!Retry) {
+    DEBUG ((DEBUG_ERROR, "%a(): flash command execution Timeout\n", __func__));
+    return EFI_TIMEOUT;
+  }
+
+  /* Polling QSPI idle status */
+  Status = SpiWaitIdle (RegBase);
+  if (EFI_ERROR (Status)) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/* For command RDID, RDSR. */
+EFI_STATUS
+SpiCommandRead (
+  IN SPI_MASTER_PROTOCOL *This,
+  IN SPI_DEVICE_PARAMS  *Slave,
+  IN OUT SPI_OP_PARAMS   *Cmds
+  )
+{
+  UINT32      Reg;
+  UINT32      ReadLen;
+  EFI_STATUS  Status;
+  SPI_MASTER *SpiMaster;
+  UINT32      RxLen  = Cmds->Data.NBytes;
+  VOID        *RxBuf = Cmds->Data.Buf.In;
+
+  SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+  if (!EfiAtRuntime ()) {
+    EfiAcquireLock (&SpiMaster->Lock);
+  }
+
+  if ((RxLen > SPI_STIG_DATA_LEN_MAX) || !RxBuf) {
+    DEBUG ((DEBUG_ERROR, "%a(): Invalid input arguments RxLen %d\n", __func__, RxLen));
+    Status = EFI_INVALID_PARAMETER;
+    goto Fail;
+  }
+
+  Reg = Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB;
+  Reg |= (0x1 << SPI_REG_CMDCTRL_RD_EN_LSB);
+
+  /* 0 means 1 byte */
+  Reg |= (((RxLen - 1) & SPI_REG_CMDCTRL_RD_BYTES_MASK)
+          << SPI_REG_CMDCTRL_RD_BYTES_LSB);
+  Status = SpiExecFlashCmd (Slave->RegBase, Reg);
+  if (EFI_ERROR (Status)) {
+    goto Fail;
+  }
+
+  Reg = MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATALOWER);
+
+  /* Put the read value into rx_buf */
+  ReadLen = (RxLen > 4) ? 4 : RxLen;
+  CopyMem (RxBuf, &Reg, ReadLen);
+  RxBuf += ReadLen;
+
+  if (RxLen > 4) {
+    Reg = MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATAUPPER);
+
+    ReadLen = RxLen - ReadLen;
+    CopyMem (RxBuf, &Reg, ReadLen);
+  }
+
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (&SpiMaster->Lock);
+  }
+  return EFI_SUCCESS;
+
+Fail:
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (&SpiMaster->Lock);
+  }
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+SpiGetReadSramLevel (
+  IN UINT32   RegBase,
+  OUT UINT16  *SramLvl
+  )
+{
+  UINT32  Reg = MmioRead32 (RegBase + SPI_REG_SDRAMLEVEL);
+  Reg >>= SPI_REG_SDRAMLEVEL_RD_LSB;
+  *SramLvl = (UINT16)(Reg & SPI_REG_SDRAMLEVEL_RD_MASK);
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SpiWaitForData (
+  IN UINT32  RegBase,
+  UINT16    *SramLvl
+  )
+{
+  UINT32  Timeout = 10000;
+
+  while (Timeout--) {
+    SpiGetReadSramLevel (RegBase, SramLvl);
+    if (SramLvl != 0) {
+      return EFI_SUCCESS;
+    }
+    gBS->Stall (1);
+  }
+
+  return EFI_TIMEOUT;
+}
+
+STATIC
+EFI_STATUS
+SpiWaitForBitLe32 (
+  IN INT32          Reg,
+  IN CONST UINT32   Mask,
+  IN CONST BOOLEAN  Set,
+  IN CONST UINT32   TimeoutMs
+  )
+{
+  UINT32  Val;
+  UINTN   Start = TimeoutMs*1000;
+
+  while(1) {
+    Val = MmioRead32 (Reg);
+
+    if (!Set) {
+      Val = ~Val;
+    }
+
+    if ((Val & Mask) == Mask) {
+      return EFI_SUCCESS;
+    }
+
+    if (Start == 0) {
+      break;
+    } else {
+      Start--;
+    }
+
+    gBS->Stall (1);
+  }
+
+  DEBUG ((DEBUG_ERROR, "Timeout (Reg=%lx Mask=%x wait_set=%d)\n", Reg, Mask, Set));
+
+  return EFI_TIMEOUT;
+}
+
+STATIC
+VOID
+SpiReadByte (
+  IN VOID  *Addr,
+  IN VOID  *Data,
+  IN UINT16 ByteLen
+  )
+{
+  UINT8  *AddrPtr;
+  UINT8  *DataPtr;
+
+  AddrPtr  = (UINT8 *)Addr;
+  DataPtr = (UINT8 *)Data;
+
+  while (ByteLen) {
+    *DataPtr = *AddrPtr;
+    DataPtr++;
+    ByteLen--;
+  }
+}
+
+STATIC
+VOID
+SpiReadLong (
+  VOID    *Addr,
+  VOID    *Data,
+  UINT16  LongLen
+  )
+{
+  UINT32  *AddrPtr;
+  UINT32  *DataPtr;
+
+  AddrPtr = (UINT32 *)Addr;
+  DataPtr = (UINT32 *)Data;
+
+  while (LongLen) {
+    *DataPtr = *AddrPtr;
+    DataPtr++;
+    LongLen--;
+  }
+}
+
+EFI_STATUS
+SpiDataRead (
+  IN SPI_MASTER_PROTOCOL *This,
+  IN SPI_DEVICE_PARAMS  *Slave,
+  IN OUT SPI_OP_PARAMS  *Cmds
+  )
+{
+  SPI_MASTER  *SpiMaster;
+  UINT8       *RxBuf      = Cmds->Data.Buf.In;
+  UINT32      Remaining   = Cmds->Data.NBytes;
+  UINT16      BytesToRead = 0;
+  EFI_STATUS  Status;
+  UINT32      Reg;
+
+  SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+  if (!EfiAtRuntime ()) {
+    EfiAcquireLock (&SpiMaster->Lock);
+  }
+
+  if (!Cmds->Addr.NBytes) {
+    Status = EFI_ABORTED;
+    goto Fail;
+  }
+
+  /* Setup the indirect trigger start address */
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDSTARTADDR, Cmds->Addr.Val);
+
+  /* Register command */
+  Reg  = Cmds->Cmd.OpCode << SPI_REG_RD_INSTR_OPCODE_LSB;
+  MmioWrite32 (Slave->RegBase + SPI_REG_RD_INSTR, Reg);
+
+  /* Set device size */
+  Reg  = MmioRead32 (Slave->RegBase + SPI_REG_SIZE);
+  Reg &= ~SPI_REG_SIZE_ADDRESS_MASK;
+  Reg |= (Cmds->Addr.NBytes - 1);
+  MmioWrite32 (Slave->RegBase + SPI_REG_SIZE, Reg);
+
+  /* Setup indirect read bytes */
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDBYTES, Remaining);
+
+  /* Start the indirect read transfer */
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_START);
+
+  while (Remaining > 0) {
+    Status = SpiWaitForData (Slave->RegBase, &BytesToRead);
+    if (EFI_ERROR(Status)) {
+      DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out\n", __func__));
+      goto Fail;
+    }
+
+    while (BytesToRead != 0) {
+      BytesToRead *= Slave->FifoWidth;
+      if (BytesToRead > Remaining) {
+        BytesToRead = Remaining;
+      }
+
+      if (((UINTN)RxBuf % 4) || (BytesToRead % 4)) {
+        SpiReadByte (Slave->AhbBase, RxBuf, BytesToRead);
+      } else {
+        SpiReadLong (Slave->AhbBase, RxBuf, BytesToRead >> 2);
+      }
+
+      RxBuf        += BytesToRead;
+      Remaining    -= BytesToRead;
+      SpiGetReadSramLevel (Slave->RegBase, &BytesToRead);
+    }
+  }
+
+  /* Check indirect done status */
+  Status = SpiWaitForBitLe32 (
+                              Slave->RegBase + SPI_REG_INDIRECTRD,
+                              SPI_REG_INDIRECTRD_DONE,
+                              1,
+                              10
+                             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Indirect read completion error\n"));
+    goto Fail;
+  }
+
+  /* Clear indirect completion status */
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_DONE);
+
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (&SpiMaster->Lock);
+  }
+  return EFI_SUCCESS;
+
+Fail:
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_CANCEL);
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (&SpiMaster->Lock);
+  }
+  return EFI_ABORTED;
+}
+
+/* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */
+EFI_STATUS
+SpiCommandWrite (
+  IN SPI_MASTER_PROTOCOL *This,
+  IN SPI_DEVICE_PARAMS  *Slave,
+  IN OUT SPI_OP_PARAMS  *Cmds
+  )
+{
+  UINT32      Reg;
+  UINT32      WriteData;
+  UINT32      WriteLen;
+  SPI_MASTER  *SpiMaster;
+  UINT32      TxLen   = Cmds->Data.NBytes;
+  CONST VOID  *TxBuf  = Cmds->Data.Buf.Out;
+  UINT32      Addr;
+  EFI_STATUS  Status;
+
+  SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+  if (!EfiAtRuntime ()) {
+    EfiAcquireLock (&SpiMaster->Lock);
+  }
+
+  /* Reorder address to SPI bus order if only transferring address */
+  if (!TxLen) {
+    Addr = SwapBytes32 (Cmds->Addr.Val);
+    if (Cmds->Addr.NBytes == 3) {
+      Addr >>= 8;
+    }
+
+    TxBuf = &Addr;
+    TxLen = Cmds->Addr.NBytes;
+  }
+
+  if (TxLen > SPI_STIG_DATA_LEN_MAX) {
+    DEBUG ((DEBUG_ERROR, "QSPI: Invalid input arguments TxLen %d\n", TxLen));
+    Status = EFI_INVALID_PARAMETER;
+    goto Fail;
+  }
+
+  Reg = Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB;
+
+  if (TxLen) {
+    Reg |= (0x1 << SPI_REG_CMDCTRL_WR_EN_LSB);
+    Reg |= ((TxLen - 1) & SPI_REG_CMDCTRL_WR_BYTES_MASK)
+           << SPI_REG_CMDCTRL_WR_BYTES_LSB;
+
+    WriteLen = TxLen > 4 ? 4 : TxLen;
+    CopyMem (&WriteData, TxBuf, WriteLen);
+    MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATALOWER, WriteData);
+
+    if (TxLen > 4) {
+      TxBuf   += WriteLen;
+      WriteLen = TxLen - WriteLen;
+      CopyMem (&WriteData, TxBuf, WriteLen);
+      MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATAUPPER, WriteData);
+    }
+  }
+
+  Status = SpiExecFlashCmd (Slave->RegBase, Reg);
+  if (EFI_ERROR (Status)) {
+    goto Fail;
+  }
+
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (&SpiMaster->Lock);
+  }
+  return EFI_SUCCESS;
+
+Fail:
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (&SpiMaster->Lock);
+  }
+  return Status;
+}
+
+STATIC
+VOID
+SpiDelayNanoSec (
+  IN UINTN  nsec
+  )
+{
+  UINT32  Timeout = DIV_ROUND_UP (nsec, 1000);
+
+  do {
+    Timeout--;
+    gBS->Stall (1);
+  } while (Timeout);
+}
+
+STATIC
+VOID
+SpiWriteLong (
+  IN VOID        *Addr,
+  IN CONST VOID  *Data,
+  IN INTN        LongLen
+  )
+{
+  UINT32  *AddrPtr;
+  UINT32  *DataPtr;
+
+  AddrPtr  = (UINT32 *)Addr;
+  DataPtr = (UINT32 *)Data;
+
+  while (LongLen) {
+    *AddrPtr = *DataPtr;
+    DataPtr++;
+    LongLen--;
+  }
+}
+
+STATIC
+VOID
+SpiWriteByte (
+  IN VOID        *Addr,
+  IN CONST VOID  *Data,
+  IN INTN        ByteLen
+  )
+{
+  UINT8  *AddrPtr;
+  UINT8  *DataPtr;
+
+  AddrPtr  = (UINT8 *)Addr;
+  DataPtr  = (UINT8 *)Data;
+
+  while (ByteLen) {
+    *AddrPtr = *DataPtr;
+    DataPtr++;
+    ByteLen--;
+  }
+}
+
+EFI_STATUS
+SpiDataWrite (
+  IN SPI_MASTER_PROTOCOL *This,
+  IN SPI_DEVICE_PARAMS   *Slave,
+  IN OUT SPI_OP_PARAMS  *Cmds
+  )
+{
+  UINT32       Reg;
+  SPI_MASTER   *SpiMaster;
+  UINT32       PageSize  = Slave->Info->PageSize;
+  UINT32       Remaining = Cmds->Data.NBytes;
+  CONST UINT8  *TxBuf = Cmds->Data.Buf.Out;
+  UINT32       WriteBytes;
+  EFI_STATUS   Status;
+
+  SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+  if (!EfiAtRuntime ()) {
+    EfiAcquireLock (&SpiMaster->Lock);
+  }
+
+  if (!Cmds->Addr.NBytes) {
+    return EFI_ABORTED;
+  }
+
+  /* Write opcode to write instruction register */
+  Reg  = Cmds->Cmd.OpCode << SPI_REG_WR_INSTR_OPCODE_LSB;
+  MmioWrite32 (Slave->RegBase + SPI_REG_WR_INSTR, Reg);
+
+  /* Set buffer address */
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWRSTARTADDR, Cmds->Addr.Val);
+
+  /* Configure device size */
+  Reg  = MmioRead32 (Slave->RegBase + SPI_REG_SIZE);
+  Reg &= ~SPI_REG_SIZE_ADDRESS_MASK;
+  Reg |= (Cmds->Addr.NBytes - 1);
+  MmioWrite32 (Slave->RegBase + SPI_REG_SIZE, Reg);
+
+  /* Configure the indirect read transfer bytes */
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWRBYTES, Remaining);
+
+  /* Start the indirect write transfer */
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_START);
+
+  /* Delay is required for QSPI module to synchronized internally */
+  SpiDelayNanoSec (Slave->WriteDelay);
+
+  while (Remaining > 0) {
+    WriteBytes = Remaining > PageSize ? PageSize : Remaining;
+    SpiWriteLong (Slave->AhbBase, TxBuf, WriteBytes >> 2);
+    if (WriteBytes % 4) {
+      SpiWriteByte (
+                    Slave->AhbBase,
+                    TxBuf + ROUND_DOWN (WriteBytes, 4),
+                    WriteBytes % 4
+                    );
+    }
+
+    Status = SpiWaitForBitLe32 (
+                                Slave->RegBase + SPI_REG_SDRAMLEVEL,
+                                SPI_REG_SDRAMLEVEL_WR_MASK <<
+                                SPI_REG_SDRAMLEVEL_WR_LSB,
+                                0,
+                                10
+                                );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out (%d)\n", __func__, Status));
+      goto FailWrite;
+    }
+
+    TxBuf  += WriteBytes;
+    Remaining -= WriteBytes;
+  }
+
+  /* Check indirect done status */
+  Status = SpiWaitForBitLe32 (
+                              Slave->RegBase + SPI_REG_INDIRECTWR,
+                              SPI_REG_INDIRECTWR_DONE,
+                              1,
+                              10
+                             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Indirect write completion error (%d)\n", Status));
+    goto FailWrite;
+  }
+
+  /* Clear indirect completion status */
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_DONE);
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (&SpiMaster->Lock);
+  }
+  return EFI_SUCCESS;
+
+FailWrite:
+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_CANCEL);
+  if (!EfiAtRuntime ()) {
+    EfiReleaseLock (&SpiMaster->Lock);
+  }
+  return Status;
+}
+
+STATIC
+VOID
+SpiConfigGetDataCapture (
+  IN UINT32  RegBase,
+  IN UINT32  ByPass,
+  IN UINT32  Delay
+  )
+{
+  UINT32  Reg;
+
+  SpiControllerDisable (RegBase);
+
+  Reg = MmioRead32 (RegBase + SPI_REG_RD_DATA_CAPTURE);
+
+  if (ByPass) {
+    Reg |= SPI_REG_RD_DATA_CAPTURE_BYPASS;
+  } else {
+    Reg &= ~SPI_REG_RD_DATA_CAPTURE_BYPASS;
+  }
+
+  Reg &= ~(SPI_REG_RD_DATA_CAPTURE_DELAY_MASK
+           << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB);
+
+  Reg |= (Delay & SPI_REG_RD_DATA_CAPTURE_DELAY_MASK)
+         << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB;
+
+  MmioWrite32 (RegBase + SPI_REG_RD_DATA_CAPTURE, Reg);
+
+  SpiControllerEnable (RegBase);
+}
+
+STATIC
+EFI_STATUS
+SpiSpeedCalibration (
+  IN SPI_MASTER_PROTOCOL *This,
+  IN SPI_DEVICE_PARAMS  *Slave,
+  IN SPI_TIMING_PARAMS  *Timing
+  )
+{
+  UINT8         IdLen = 3;
+  UINT32        IdInit = 0, IdCali = 0;
+  INTN          RangeLow = -1, RangeHigh = -1;
+  SPI_OP_PARAMS  CmdsInitialId = SPI_READID_OP ((UINT8 *)&IdInit, IdLen);
+  SPI_OP_PARAMS  CmdsCalibrateId = SPI_READID_OP ((UINT8 *)&IdCali, IdLen);
+  EFI_STATUS    Status;
+
+  /* Start calibration with slowest clock speed at 1 MHz */
+  SpiWriteSpeed (Slave, SPI_MIN_HZ, Timing);
+
+  /* Set the read data capture delay register to 0 */
+  SpiConfigGetDataCapture (Slave->RegBase, 1, 0);
+
+  /* Get flash ID value as reference */
+  Status = SpiCommandRead (This, Slave, &CmdsInitialId);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read id)\n"));
+    return EFI_ABORTED;
+  }
+
+  /* Use the input speed */
+  SpiWriteSpeed (Slave, SPI_MAX_HZ, Timing);
+
+  /* Find high and low range */
+  for (UINT8 i = 0; i < SPI_READ_CAPTURE_MAX_DELAY; i++) {
+    /* Change the read data capture delay register */
+    SpiConfigGetDataCapture (Slave->RegBase, 1, i);
+
+    /* Read flash ID for comparison later */
+    Status = SpiCommandRead (This, Slave, &CmdsCalibrateId);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read)\n"));
+      return EFI_ABORTED;
+    }
+
+    /* Verify low range */
+    if ((RangeLow == -1) && (IdCali == IdInit)) {
+      RangeLow = i;
+      continue;
+    }
+
+    /* Verify high range */
+    if ((RangeLow != -1) && (IdCali != IdInit)) {
+      RangeHigh = i - 1;
+      break;
+    }
+
+    RangeHigh = i;
+  }
+
+  if (RangeLow == -1) {
+    DEBUG ((DEBUG_ERROR, "Spi: Calibration failed\n"));
+    return EFI_ABORTED;
+  }
+
+  /*
+  * Set the final value for read data capture delay register based
+  * on the calibrated value
+  */
+  SpiConfigGetDataCapture (Slave->RegBase, 1, (RangeHigh + RangeLow) / 2);
+  DEBUG (
+         (DEBUG_INFO, "Spi: Read data capture delay calibrated to %d (%d - %d)\n",
+          (RangeHigh + RangeLow) / 2, RangeLow, RangeHigh)
+         );
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiSetupDevice (
+  IN SPI_MASTER_PROTOCOL *This,
+  OUT SPI_DEVICE_PARAMS  *Slave
+  )
+{
+  SPI_TIMING_PARAMS  *Timing;
+  EFI_STATUS  Status;
+
+  if (!Slave) {
+    Slave = AllocateZeroPool (sizeof (SPI_DEVICE_PARAMS));
+    if (Slave == NULL) {
+      DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave\n", __func__));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Fail;
+    }
+  }
+
+  if (!Slave->Info) {
+    Slave->Info = AllocateZeroPool (sizeof (NOR_FLASH_INFO));
+    if (Slave->Info == NULL) {
+      DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave->Info\n", __func__));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Fail;
+    }
+  }
+
+  Timing = AllocateZeroPool (sizeof (SPI_TIMING_PARAMS));
+  if (Timing == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Timing\n", __func__));
+    FreePool(Slave);
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Fail;
+  }
+
+  Slave->RegBase    = PcdGet32 (PcdSpiFlashRegBase);
+  Slave->AhbBase    = (VOID *)(UINTN)PcdGet64 (PcdSpiFlashAhbBase);
+  Slave->FifoWidth  = PcdGet8 (PcdSpiFlashFifoWidth);
+  Timing->RefClkHz  = PcdGet32 (PcdSpiFlashRefClkHz);
+  Timing->TshslNs   = PcdGet32 (PcdSpiFlashTshslNs);
+  Timing->Tsd2dNs   = PcdGet32 (PcdSpiFlashTsd2dNs);
+  Timing->TchshNs   = PcdGet32 (PcdSpiFlashTchshNs);
+  Timing->TslchNs   = PcdGet32 (PcdSpiFlashTslchNs);
+
+  Slave->WriteDelay = 50 * DIV_ROUND_UP (NSEC_PER_SEC, Timing->RefClkHz);
+
+  Status = SpiSpeedCalibration (This, Slave, Timing);
+  if (EFI_ERROR (Status)) {
+    goto Fail;
+  }
+
+  FreePool(Timing);
+  return EFI_SUCCESS;
+
+Fail:
+  FreePool(Slave);
+  FreePool(Timing);
+  return Status;
+}
+
+EFI_STATUS
+SpiFreeDevice (
+  IN SPI_DEVICE_PARAMS  *Slave
+  )
+{
+  FreePool (Slave);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiMasterInitProtocol (
+  IN SPI_MASTER_PROTOCOL  *SpiMasterProtocol
+  )
+{
+  SpiMasterProtocol->SetupDevice = SpiSetupDevice;
+  SpiMasterProtocol->FreeDevice  = SpiFreeDevice;
+  SpiMasterProtocol->CmdRead     = SpiCommandRead;
+  SpiMasterProtocol->DataRead    = SpiDataRead;
+  SpiMasterProtocol->CmdWrite    = SpiCommandWrite;
+  SpiMasterProtocol->DataWrite   = SpiDataWrite;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  mSpiMasterInstance = AllocateRuntimeZeroPool (sizeof (SPI_MASTER));
+  if (mSpiMasterInstance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY);
+
+  SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol);
+
+  mSpiMasterInstance->Signature = SPI_MASTER_SIGNATURE;
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                                                   &(mSpiMasterInstance->Handle),
+                                                   &gJH7110SpiMasterProtocolGuid,
+                                                   &(mSpiMasterInstance->SpiMasterProtocol),
+                                                   NULL
+                                                   );
+  if (EFI_ERROR (Status)) {
+    FreePool (mSpiMasterInstance);
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h
new file mode 100644
index 000000000000..804ee29c5ff1
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h
@@ -0,0 +1,188 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __SPI_DXE_H__
+#define __SPI_DXE_H__
+
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/Spi.h>
+
+#define SPI_MASTER_SIGNATURE                      SIGNATURE_32 ('M', 'S', 'P', 'I')
+#define SPI_MASTER_FROM_SPI_MASTER_PROTOCOL(a)  CR (a, SPI_MASTER, SpiMasterProtocol, SPI_MASTER_SIGNATURE)
+
+#ifndef BIT
+#define BIT(nr)  (1 << (nr))
+#endif
+
+#define DIV_ROUND_UP(n, d)  (((n) + (d) - 1) / (d))
+#define ROUND_DOWN(x, y)  (\
+{                         \
+  typeof(x) __x = (x);    \
+  __x - (__x % (y));      \
+}                         \
+)
+#define NSEC_PER_SEC  1000000000L
+
+/* Configs */
+#define SPI_READ_CAPTURE_MAX_DELAY  16
+#define SPI_REG_RETRY               10000
+#define SPI_POLL_IDLE_RETRY         3
+#define SPI_STIG_DATA_LEN_MAX       8
+#define SPI_MIN_HZ                  1000000
+#define SPI_MAX_HZ                  100000000
+
+/*
+* QSPI controller's config and status register (offset from QSPI_BASE)
+*/
+#define SPI_REG_CONFIG                  0x00
+#define SPI_REG_CONFIG_ENABLE           BIT(0)
+#define SPI_REG_CONFIG_CLK_POL          BIT(1)
+#define SPI_REG_CONFIG_CLK_PHA          BIT(2)
+#define SPI_REG_CONFIG_DIRECT           BIT(7)
+#define SPI_REG_CONFIG_DECODE           BIT(9)
+#define SPI_REG_CONFIG_XIP_IMM          BIT(18)
+#define SPI_REG_CONFIG_CHIPSELECT_LSB   10
+#define SPI_REG_CONFIG_BAUD_LSB         19
+#define SPI_REG_CONFIG_DTR_PROTO        BIT(24)
+#define SPI_REG_CONFIG_DUAL_OPCODE      BIT(30)
+#define SPI_REG_CONFIG_IDLE_LSB         31
+#define SPI_REG_CONFIG_CHIPSELECT_MASK  0xF
+#define SPI_REG_CONFIG_BAUD_MASK        0xF
+
+#define SPI_REG_RD_INSTR                  0x04
+#define SPI_REG_RD_INSTR_OPCODE_LSB       0
+#define SPI_REG_RD_INSTR_TYPE_INSTR_LSB   8
+#define SPI_REG_RD_INSTR_TYPE_ADDR_LSB    12
+#define SPI_REG_RD_INSTR_TYPE_DATA_LSB    16
+#define SPI_REG_RD_INSTR_MODE_EN_LSB      20
+#define SPI_REG_RD_INSTR_DUMMY_LSB        24
+#define SPI_REG_RD_INSTR_TYPE_INSTR_MASK  0x3
+#define SPI_REG_RD_INSTR_TYPE_ADDR_MASK   0x3
+#define SPI_REG_RD_INSTR_TYPE_DATA_MASK   0x3
+#define SPI_REG_RD_INSTR_DUMMY_MASK       0x1F
+
+#define SPI_REG_WR_INSTR                0x08
+#define SPI_REG_WR_INSTR_OPCODE_LSB     0
+#define SPI_REG_WR_INSTR_TYPE_ADDR_LSB  12
+#define SPI_REG_WR_INSTR_TYPE_DATA_LSB  16
+
+#define SPI_REG_DELAY             0x0C
+#define SPI_REG_DELAY_TSLCH_LSB   0
+#define SPI_REG_DELAY_TCHSH_LSB   8
+#define SPI_REG_DELAY_TSD2D_LSB   16
+#define SPI_REG_DELAY_TSHSL_LSB   24
+#define SPI_REG_DELAY_TSLCH_MASK  0xFF
+#define SPI_REG_DELAY_TCHSH_MASK  0xFF
+#define SPI_REG_DELAY_TSD2D_MASK  0xFF
+#define SPI_REG_DELAY_TSHSL_MASK  0xFF
+
+#define SPI_REG_RD_DATA_CAPTURE             0x10
+#define SPI_REG_RD_DATA_CAPTURE_BYPASS      BIT(0)
+#define SPI_REG_RD_DATA_CAPTURE_DELAY_LSB   1
+#define SPI_REG_RD_DATA_CAPTURE_DELAY_MASK  0xF
+
+#define SPI_REG_SIZE               0x14
+#define SPI_REG_SIZE_ADDRESS_LSB   0
+#define SPI_REG_SIZE_PAGE_LSB      4
+#define SPI_REG_SIZE_BLOCK_LSB     16
+#define SPI_REG_SIZE_ADDRESS_MASK  0xF
+#define SPI_REG_SIZE_PAGE_MASK     0xFFF
+#define SPI_REG_SIZE_BLOCK_MASK    0x3F
+
+#define SPI_REG_SRAMPARTITION    0x18
+#define SPI_REG_INDIRECTTRIGGER  0x1C
+
+#define SPI_REG_REMAP     0x24
+#define SPI_REG_MODE_BIT  0x28
+
+#define SPI_REG_SDRAMLEVEL          0x2C
+#define SPI_REG_SDRAMLEVEL_RD_LSB   0
+#define SPI_REG_SDRAMLEVEL_WR_LSB   16
+#define SPI_REG_SDRAMLEVEL_RD_MASK  0xFFFF
+#define SPI_REG_SDRAMLEVEL_WR_MASK  0xFFFF
+
+#define SPI_REG_WR_COMPLETION_CTRL    0x38
+#define SPI_REG_WR_DISABLE_AUTO_POLL  BIT(14)
+
+#define SPI_REG_IRQSTATUS  0x40
+#define SPI_REG_IRQMASK    0x44
+
+#define SPI_REG_INDIRECTRD             0x60
+#define SPI_REG_INDIRECTRD_START       BIT(0)
+#define SPI_REG_INDIRECTRD_CANCEL      BIT(1)
+#define SPI_REG_INDIRECTRD_INPROGRESS  BIT(2)
+#define SPI_REG_INDIRECTRD_DONE        BIT(5)
+
+#define SPI_REG_INDIRECTRDWATERMARK  0x64
+#define SPI_REG_INDIRECTRDSTARTADDR  0x68
+#define SPI_REG_INDIRECTRDBYTES      0x6C
+
+#define SPI_REG_CMDCTRL                 0x90
+#define SPI_REG_CMDCTRL_EXECUTE         BIT(0)
+#define SPI_REG_CMDCTRL_INPROGRESS      BIT(1)
+#define SPI_REG_CMDCTRL_DUMMY_LSB       7
+#define SPI_REG_CMDCTRL_WR_BYTES_LSB    12
+#define SPI_REG_CMDCTRL_WR_EN_LSB       15
+#define SPI_REG_CMDCTRL_ADD_BYTES_LSB   16
+#define SPI_REG_CMDCTRL_ADDR_EN_LSB     19
+#define SPI_REG_CMDCTRL_RD_BYTES_LSB    20
+#define SPI_REG_CMDCTRL_RD_EN_LSB       23
+#define SPI_REG_CMDCTRL_OPCODE_LSB      24
+#define SPI_REG_CMDCTRL_DUMMY_MASK      0x1F
+#define SPI_REG_CMDCTRL_WR_BYTES_MASK   0x7
+#define SPI_REG_CMDCTRL_ADD_BYTES_MASK  0x3
+#define SPI_REG_CMDCTRL_RD_BYTES_MASK   0x7
+#define SPI_REG_CMDCTRL_OPCODE_MASK     0xFF
+
+#define SPI_REG_INDIRECTWR             0x70
+#define SPI_REG_INDIRECTWR_START       BIT(0)
+#define SPI_REG_INDIRECTWR_CANCEL      BIT(1)
+#define SPI_REG_INDIRECTWR_INPROGRESS  BIT(2)
+#define SPI_REG_INDIRECTWR_DONE        BIT(5)
+
+#define SPI_REG_INDIRECTWRWATERMARK  0x74
+#define SPI_REG_INDIRECTWRSTARTADDR  0x78
+#define SPI_REG_INDIRECTWRBYTES      0x7C
+
+#define SPI_REG_CMDADDRESS         0x94
+#define SPI_REG_CMDREADDATALOWER   0xA0
+#define SPI_REG_CMDREADDATAUPPER   0xA4
+#define SPI_REG_CMDWRITEDATALOWER  0xA8
+#define SPI_REG_CMDWRITEDATAUPPER  0xAC
+
+#define SPI_REG_OP_EXT_LOWER      0xE0
+#define SPI_REG_OP_EXT_READ_LSB   24
+#define SPI_REG_OP_EXT_WRITE_LSB  16
+#define SPI_REG_OP_EXT_STIG_LSB   0
+
+typedef struct {
+  SPI_MASTER_PROTOCOL  SpiMasterProtocol;
+  UINTN                Signature;
+  EFI_HANDLE           Handle;
+  EFI_LOCK             Lock;
+} SPI_MASTER;
+
+typedef struct {
+  UINT32  RefClkHz;
+  UINT32  TshslNs;
+  UINT32  TchshNs;
+  UINT32  TslchNs;
+  UINT32  Tsd2dNs;
+}SPI_TIMING_PARAMS;
+
+#endif //__SPI_DXE_H__
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf
new file mode 100644
index 000000000000..ed3f639346b2
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf
@@ -0,0 +1,52 @@
+## @file
+#
+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SpiDxe
+  FILE_GUID                      = 2FBD9E55-9BC7-4EEF-BF93-0D5582FE647B
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SpiEntryPoint
+
+[Sources]
+  SpiDxe.c
+  SpiDxe.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+  DebugLib
+  DxeServicesTableLib
+  IoLib
+  MemoryAllocationLib
+  NorFlashInfoLib
+  TimerLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiRuntimeLib
+
+[FixedPcd]
+  gJH7110TokenSpaceGuid.PcdSpiFlashRegBase
+  gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase
+  gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth
+  gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz
+  gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs
+  gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs
+  gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs
+  gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs
+
+[Protocols]
+  gJH7110SpiMasterProtocolGuid
+
+[Depex]
+  TRUE
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c
new file mode 100755
index 000000000000..cd508e53eb06
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c
@@ -0,0 +1,571 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Library/NorFlashInfoLib.h>
+#include "SpiFlashDxe.h"
+
+SPI_MASTER_PROTOCOL  *SpiMasterProtocol;
+SPI_FLASH_INSTANCE   *mSpiFlashInstance;
+
+STATIC
+EFI_STATUS
+SpiFlashWriteEnableCmd (
+  IN  SPI_DEVICE_PARAMS  *Slave
+  )
+{
+  EFI_STATUS  Status;
+  SPI_OP_PARAMS  Op = SPI_WRITE_EN_OP();
+
+  /* Send write enable command */
+  Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op);
+
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+SpiFlashWriteDisableCmd (
+  IN  SPI_DEVICE_PARAMS  *Slave
+  )
+{
+  EFI_STATUS  Status;
+  SPI_OP_PARAMS  Op = SPI_WRITE_DIS_OP();
+
+  /* Send write disable command */
+  Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op);
+
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+SpiFlashPoll (
+  IN SPI_DEVICE_PARAMS *Slave
+)
+{
+  EFI_STATUS  Status;
+  UINT16      State;
+  UINT32      Counter     = 0xFFFFF;
+  UINT8       ReadLength  = 2;
+
+  SPI_OP_PARAMS  OpRdSts = SPI_OP (
+                                  SPI_OP_CMD (SPI_CMD_READ_STATUS),
+                                  SPI_OP_NO_ADDR,
+                                  SPI_OP_NO_DUMMY,
+                                  SPI_OP_DATA_IN (ReadLength, (VOID *)&State)
+                                  );
+
+  Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRdSts);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __func__));
+    return Status;
+  }
+
+  do {
+    Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRdSts);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __func__));
+      return Status;
+    }
+
+    Counter--;
+    if (!(State & STATUS_REG_POLL_WIP_MSK)) {
+      break;
+    }
+  } while (Counter > 0);
+
+  if (Counter == 0) {
+    DEBUG ((DEBUG_ERROR, "%a(): Timeout while writing to spi flash\n", __func__));
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashErase (
+  IN SPI_DEVICE_PARAMS  *Slave,
+  IN UINT32             Offset,
+  IN UINTN              Length
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      EraseAddr;
+  UINTN      EraseSize;
+  UINT8       EraseCmd;
+
+  if (Slave->Info->Flags & NOR_FLASH_ERASE_4K) {
+    EraseCmd  = SPI_CMD_ERASE_4K;
+    EraseSize = SIZE_4KB;
+  } else if (Slave->Info->Flags & NOR_FLASH_ERASE_32K) {
+    EraseCmd  = SPI_CMD_ERASE_32K;
+    EraseSize = SIZE_32KB;
+  } else {
+    EraseCmd  = SPI_CMD_ERASE_64K;
+    EraseSize = Slave->Info->SectorSize;
+  }
+
+  /* Verify input parameters */
+  if (Offset % EraseSize || Length % EraseSize) {
+    DEBUG (
+           (DEBUG_ERROR, "%a(): Either erase offset or length "
+                         "is not multiple of erase size\n, __func__")
+           );
+    return EFI_DEVICE_ERROR;
+  }
+
+  Status = SpiFlashWriteEnableCmd (Slave);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_enable\n", __func__));
+    return Status;
+  }
+
+  while (Length) {
+    EraseAddr = Offset;
+
+    SPI_OP_PARAMS  OpErase = SPI_OP (
+                                        SPI_OP_CMD (EraseCmd),
+                                        SPI_OP_ADDR (3, EraseAddr),
+                                        SPI_OP_NO_DUMMY,
+                                        SPI_OP_NO_DATA
+                                        );
+
+    Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpErase);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a(): Spi erase fail\n", __func__));
+      return Status;
+    }
+
+    Status = SpiFlashPoll(Slave);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Offset += EraseSize;
+    Length -= EraseSize;
+  }
+
+  Status = SpiFlashWriteDisableCmd (Slave);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_disable\n", __func__));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashRead (
+  IN SPI_DEVICE_PARAMS *Slave,
+  IN UINT32 Offset,
+  IN UINTN Length,
+  OUT VOID *Buffer
+  )
+{
+  EFI_STATUS  Status;
+  UINTN      ReadAddr, ReadLength, RemainLength;
+  UINT32      FlashSize;
+
+  FlashSize = Slave->Info->PageSize * Slave->Info->SectorSize;
+
+  /* Current handling is only limit for single flash Bank */
+  while (Length) {
+    ReadAddr = Offset;
+
+    RemainLength = (FlashSize - Offset);
+    if (Length < RemainLength) {
+      ReadLength = Length;
+    } else {
+      ReadLength = RemainLength;
+    }
+
+    /* Send read command */
+    SPI_OP_PARAMS  OpRead = SPI_OP (
+                                SPI_OP_CMD (SPI_CMD_READ_DATA),
+                                SPI_OP_ADDR (Slave->AddrSize, ReadAddr),
+                                SPI_OP_NO_DUMMY,
+                                SPI_OP_DATA_IN (ReadLength, Buffer)
+                                );
+
+    Status = SpiMasterProtocol->DataRead (SpiMasterProtocol, Slave, &OpRead);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading data\n", __func__));
+      return Status;
+    }
+
+    Offset += ReadLength;
+    Length -= ReadLength;
+    Buffer = (VOID *)((UINTN)Buffer + ReadLength);
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashWrite (
+  IN SPI_DEVICE_PARAMS *Slave,
+  IN UINT32 Offset,
+  IN UINTN Length,
+  IN VOID *Buffer
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       ByteAddr, ChunkLength, ActualIndex, PageSize;
+  UINT32      WriteAddr;
+
+  PageSize = Slave->Info->PageSize;
+
+  Status = SpiFlashWriteEnableCmd (Slave);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __func__));
+    return Status;
+  }
+
+  for (ActualIndex = 0; ActualIndex < Length; ActualIndex += ChunkLength) {
+    WriteAddr = Offset;
+
+    ByteAddr    = Offset % PageSize;
+    ChunkLength = MIN (Length - ActualIndex, (UINT64)(PageSize - ByteAddr));
+
+    SPI_OP_PARAMS  OpPgProg = SPI_OP (
+                                      SPI_OP_CMD (SPI_CMD_PAGE_PROGRAM),
+                                      SPI_OP_ADDR (3, WriteAddr),
+                                      SPI_OP_NO_DUMMY,
+                                      SPI_OP_DATA_OUT (ChunkLength, (VOID *)((UINTN)Buffer + ActualIndex))
+                                      );
+
+    Status = SpiMasterProtocol->DataWrite (SpiMasterProtocol, Slave, &OpPgProg);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a(): Error while programming write address\n", __func__));
+      return Status;
+    }
+
+    Status = SpiFlashPoll(Slave);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Offset += ChunkLength;
+  }
+
+  Status = SpiFlashWriteDisableCmd (Slave);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __func__));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SpiFlashUpdateBlock (
+  IN SPI_DEVICE_PARAMS *Slave,
+  IN UINT32 Offset,
+  IN UINTN ToUpdate,
+  IN UINT8 *Buffer,
+  IN UINT8 *TmpBuf,
+  IN UINTN EraseSize
+  )
+{
+  EFI_STATUS Status;
+
+  /* Read backup */
+  Status = SpiFlashRead (Slave, Offset, EraseSize, TmpBuf);
+    if (EFI_ERROR (Status)) {
+      DEBUG((DEBUG_ERROR, "%a(): Update: Error while reading old data\n", __func__));
+      return Status;
+    }
+
+  /* Erase entire sector */
+  Status = SpiFlashErase (Slave, Offset, EraseSize);
+  if (EFI_ERROR (Status)) {
+      DEBUG((DEBUG_ERROR, "%a(): Update: Error while erasing block\n", __func__));
+      return Status;
+    }
+
+  /* Write new data */
+  SpiFlashWrite (Slave, Offset, ToUpdate, Buffer);
+  if (EFI_ERROR (Status)) {
+      DEBUG((DEBUG_ERROR, "%a(): Update: Error while writing new data\n", __func__));
+      return Status;
+    }
+
+  /* Write backup */
+  if (ToUpdate != EraseSize) {
+    Status = SpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpdate,
+      &TmpBuf[ToUpdate]);
+    if (EFI_ERROR (Status)) {
+      DEBUG((DEBUG_ERROR, "%a(): Update: Error while writing backup\n", __func__));
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashUpdate (
+  IN SPI_DEVICE_PARAMS *Slave,
+  IN UINT32 Offset,
+  IN UINTN ByteCount,
+  IN UINT8 *Buffer
+  )
+{
+  EFI_STATUS Status;
+  UINT64 SectorSize, ToUpdate, Scale = 1;
+  UINT8 *TmpBuf, *End;
+
+  SectorSize = Slave->Info->SectorSize;
+
+  End = Buffer + ByteCount;
+
+  TmpBuf = (UINT8 *)AllocateZeroPool (SectorSize);
+  if (TmpBuf == NULL) {
+    DEBUG((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (End - Buffer >= 200)
+    Scale = (End - Buffer) / 100;
+
+  for (; Buffer < End; Buffer += ToUpdate, Offset += ToUpdate) {
+    ToUpdate = MIN((UINT64)(End - Buffer), SectorSize);
+    Print (L"   \rUpdating, %d%%", 100 - (End - Buffer) / Scale);
+    Status = SpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buffer, TmpBuf, SectorSize);
+
+    if (EFI_ERROR (Status)) {
+      DEBUG((DEBUG_ERROR, "%a(): Error while updating\n", __func__));
+      return Status;
+    }
+  }
+
+  Print(L"\n");
+  FreePool (TmpBuf);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashUpdateWithProgress (
+  IN SPI_DEVICE_PARAMS                             *Slave,
+  IN UINT32                                         Offset,
+  IN UINTN                                          ByteCount,
+  IN UINT8                                         *Buffer,
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,        OPTIONAL
+  IN UINTN                                          StartPercentage,
+  IN UINTN                                          EndPercentage
+  )
+{
+  EFI_STATUS Status;
+  UINTN SectorSize;
+  UINTN SectorNum;
+  UINTN ToUpdate;
+  UINTN Index;
+  UINT8 *TmpBuf;
+
+  SectorSize = Slave->Info->SectorSize;
+  SectorNum = (ByteCount / SectorSize) + 1;
+  ToUpdate = SectorSize;
+
+  TmpBuf = (UINT8 *)AllocateZeroPool (SectorSize);
+  if (TmpBuf == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < SectorNum; Index++) {
+    if (Progress != NULL) {
+      Progress (StartPercentage +
+                ((Index * (EndPercentage - StartPercentage)) / SectorNum));
+    }
+
+    /* In the last chunk update only an actual number of remaining bytes */
+    if (Index + 1 == SectorNum) {
+      ToUpdate = ByteCount % SectorSize;
+    }
+
+    Status = SpiFlashUpdateBlock (Slave,
+               Offset + Index * SectorSize,
+               ToUpdate,
+               Buffer + Index * SectorSize,
+               TmpBuf,
+               SectorSize);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a(): Error while updating\n", __func__));
+      return Status;
+    }
+  }
+  FreePool (TmpBuf);
+
+  if (Progress != NULL) {
+    Progress (EndPercentage);
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiFlashReadId (
+  IN SPI_DEVICE_PARAMS  *Slave,
+  IN BOOLEAN            UseInRuntime
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       IdLen = 3;
+  UINT8       Id[IdLen];
+
+  SPI_OP_PARAMS  Op = SPI_READID_OP (Id, IdLen);
+
+  Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &Op);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading id\n", __func__));
+    return Status;
+  }
+
+  Status = NorFlashGetInfo (Id, &Slave->Info, UseInRuntime);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a: Unrecognized JEDEC Id bytes: 0x%02x%02x%02x\n",
+            __func__,
+            Id[0],
+            Id[1],
+            Id[2])
+           );
+    return Status;
+  }
+
+  NorFlashPrintInfo (Slave->Info);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiFlashInit (
+  IN SPI_FLASH_PROTOCOL  *This,
+  IN SPI_DEVICE_PARAMS   *Slave
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       StatusRegister;
+
+  Slave->AddrSize = (Slave->Info->Flags & NOR_FLASH_4B_ADDR) ? 4 : 3;
+
+  Status = SpiFlashWriteEnableCmd (Slave);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __func__));
+    return Status;
+  }
+
+  if (Slave->AddrSize == 4) {
+
+    /* Enable 4byte addressing */
+    SPI_OP_PARAMS  Op4BAddEn = SPI_OP (
+                                        SPI_OP_CMD (SPI_CMD_4B_ADDR_ENABLE),
+                                        SPI_OP_NO_ADDR,
+                                        SPI_OP_NO_DUMMY,
+                                        SPI_OP_NO_DATA
+                                        );
+    Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op4BAddEn);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a(): Error while setting 4B address\n", __func__));
+      return Status;
+    }
+  }
+
+  /* Initialize flash status register */
+  StatusRegister = 0x0;
+  SPI_OP_PARAMS  OpWrSts = SPI_OP (
+                                    SPI_OP_CMD (SPI_CMD_WRITE_STATUS_REG),
+                                    SPI_OP_NO_ADDR,
+                                    SPI_OP_NO_DUMMY,
+                                    SPI_OP_DATA_OUT (1, (VOID *)&StatusRegister)
+                                    );
+
+  Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpWrSts);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Error while writing status register\n", __func__));
+    return Status;
+  }
+
+  Status = SpiFlashWriteDisableCmd (Slave);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __func__));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashInitProtocol (
+  IN SPI_FLASH_PROTOCOL  *SpiFlashProtocol
+  )
+{
+  SpiFlashProtocol->Read   = SpiFlashRead;
+  SpiFlashProtocol->Write  = SpiFlashWrite;
+  SpiFlashProtocol->Update = SpiFlashUpdate;
+  SpiFlashProtocol->UpdateWithProgress = SpiFlashUpdateWithProgress;
+  SpiFlashProtocol->Erase  = SpiFlashErase;
+  SpiFlashProtocol->ReadId = SpiFlashReadId;
+  SpiFlashProtocol->Init   = SpiFlashInit;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiFlashEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = gBS->LocateProtocol (
+                                &gJH7110SpiMasterProtocolGuid,
+                                NULL,
+                                (VOID **)&SpiMasterProtocol
+                                );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SPI Master protocol\n", __func__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  mSpiFlashInstance = AllocateRuntimeZeroPool (sizeof (SPI_FLASH_INSTANCE));
+  if (mSpiFlashInstance == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol);
+
+  mSpiFlashInstance->Signature = SPI_FLASH_SIGNATURE;
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                                                   &(mSpiFlashInstance->Handle),
+                                                   &gJH7110SpiFlashProtocolGuid,
+                                                   &(mSpiFlashInstance->SpiFlashProtocol),
+                                                   NULL
+                                                   );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot install SPI flash protocol\n", __func__));
+    goto ErrorInstallProto;
+  }
+
+  return EFI_SUCCESS;
+
+ErrorInstallProto:
+  FreePool (mSpiFlashInstance);
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h
new file mode 100755
index 000000000000..f3bb300334c0
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h
@@ -0,0 +1,35 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __SPI_FLASH_DXE_H__
+#define __SPI_FLASH_DXE_H__
+
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define SPI_FLASH_SIGNATURE      SIGNATURE_32 ('F', 'S', 'P', 'I')
+
+#define STATUS_REG_POLL_WIP_MSK  (1 << 0)
+
+typedef struct {
+  SPI_FLASH_PROTOCOL    SpiFlashProtocol;
+  UINTN                 Signature;
+  EFI_HANDLE            Handle;
+} SPI_FLASH_INSTANCE;
+
+#endif //__SPI_FLASH_DXE_H__
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf
new file mode 100644
index 000000000000..3ca429fdc2dd
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf
@@ -0,0 +1,44 @@
+## @file
+#
+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SpiFlashDxe
+  FILE_GUID                      = D3DF07BE-3810-4521-89EF-C4E22E0B2484
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SpiFlashEntryPoint
+
+[Sources]
+  SpiFlashDxe.c
+  SpiFlashDxe.h
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+  DebugLib
+  MemoryAllocationLib
+  NorFlashInfoLib
+  TimerLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiRuntimeLib
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+  gJH7110SpiFlashProtocolGuid
+  gJH7110SpiMasterProtocolGuid
+
+[Depex]
+  gJH7110SpiMasterProtocolGuid
diff --git a/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h b/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h
new file mode 100644
index 000000000000..b8db3ad4c5b0
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h
@@ -0,0 +1,163 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __SPI_MASTER_PROTOCOL_H__
+#define __SPI_MASTER_PROTOCOL_H__
+
+#include <Library/NorFlashInfoLib.h>
+
+typedef struct _SPI_MASTER_PROTOCOL SPI_MASTER_PROTOCOL;
+
+
+#define SPI_CMD_WRITE_STATUS_REG  0x01
+#define SPI_CMD_PAGE_PROGRAM      0x02
+#define SPI_CMD_READ_DATA         0x03
+#define SPI_CMD_WRITE_DISABLE     0x04
+#define SPI_CMD_READ_STATUS       0x05
+#define SPI_CMD_WRITE_ENABLE      0x06
+#define SPI_CMD_READ_ARRAY_FAST   0x0b
+#define SPI_CMD_BANKADDR_BRWR     0x17
+#define SPI_CMD_ERASE_4K          0x20
+#define SPI_CMD_ERASE_32K         0x52
+#define SPI_CMD_FLAG_STATUS       0x70
+#define SPI_CMD_READ_ID           0x9f
+#define SPI_CMD_4B_ADDR_ENABLE    0xb7
+#define SPI_CMD_BANK_WRITE        0xc5
+#define SPI_CMD_ERASE_64K         0xd8
+
+
+
+#define SPI_OP_CMD(__OpCode)  \
+  {                      \
+    .OpCode = __OpCode,  \
+    .NBytes = 1,         \
+  }
+
+#define SPI_OP_ADDR(__NBytes, __Val)  \
+  {                      \
+    .NBytes = __NBytes,  \
+    .Val = __Val,        \
+  }
+
+#define SPI_OP_NO_ADDR  { }
+
+#define SPI_OP_DUMMY(__NBytes)  \
+  {                      \
+    .NBytes = __NBytes,  \
+  }
+
+#define SPI_OP_NO_DUMMY  { }
+
+#define SPI_OP_DATA_IN(__NBytes, __Buf)  \
+  {                      \
+    .NBytes = __NBytes,  \
+    .Buf.In = __Buf,     \
+  }
+
+#define SPI_OP_DATA_OUT(__NBytes, __Buf)  \
+  {                     \
+    .NBytes = __NBytes, \
+    .Buf.Out = __Buf,   \
+  }
+
+#define SPI_OP_NO_DATA  { }
+
+#define SPI_OP(__Cmd, __Addr, __Dummy, __Data)  \
+  {                    \
+    .Cmd = __Cmd,      \
+    .Addr = __Addr,    \
+    .Dummy = __Dummy,  \
+    .Data = __Data,    \
+  }
+
+/**
+ * Standard SPI NOR flash operations
+ */
+#define SPI_WRITE_EN_OP()    \
+  SPI_OP(SPI_OP_CMD(SPI_CMD_WRITE_ENABLE),  \
+       SPI_OP_NO_ADDR,        \
+       SPI_OP_NO_DUMMY,       \
+       SPI_OP_NO_DATA)
+
+#define SPI_WRITE_DIS_OP()   \
+  SPI_OP(SPI_OP_CMD(SPI_CMD_WRITE_DISABLE),  \
+       SPI_OP_NO_ADDR,        \
+       SPI_OP_NO_DUMMY,       \
+       SPI_OP_NO_DATA)
+
+#define SPI_READID_OP(Buf, Len)  \
+  SPI_OP(SPI_OP_CMD(SPI_CMD_READ_ID),  \
+       SPI_OP_NO_ADDR,        \
+       SPI_OP_NO_DUMMY,       \
+       SPI_OP_DATA_IN(Len, Buf))
+
+typedef struct {
+  struct {
+    UINT8     NBytes;
+    UINT16    OpCode;
+  } Cmd;
+
+  struct {
+    UINT8     NBytes;
+    UINT64    Val;
+  } Addr;
+
+  struct {
+    UINT8    NBytes;
+  } Dummy;
+
+  struct {
+    UINT32          NBytes;
+    union {
+      VOID          *In;
+      CONST VOID    *Out;
+    } Buf;
+  } Data;
+} SPI_OP_PARAMS;
+
+typedef struct {
+  UINT32            AddrSize;
+  NOR_FLASH_INFO    *Info;
+  UINT32            RegBase;
+  VOID              *AhbBase;
+  UINT8             FifoWidth;
+  UINT32            WriteDelay;
+} SPI_DEVICE_PARAMS;
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_DEVICE_SETUP)(
+                      IN SPI_MASTER_PROTOCOL *This,
+                      OUT SPI_DEVICE_PARAMS *Slave
+                    );
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_DEVICE_FREE)(
+                      IN SPI_DEVICE_PARAMS  *Slave
+                    );
+
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_EXECUTE_RW)(
+                          IN SPI_MASTER_PROTOCOL *This,
+                          IN SPI_DEVICE_PARAMS  *Slave,
+                          IN OUT SPI_OP_PARAMS  *Cmds
+                        );
+
+struct _SPI_MASTER_PROTOCOL {
+  SPI_DEVICE_SETUP  SetupDevice;
+  SPI_DEVICE_FREE   FreeDevice;
+  SPI_EXECUTE_RW    CmdRead;
+  SPI_EXECUTE_RW    DataRead;
+  SPI_EXECUTE_RW    CmdWrite;
+  SPI_EXECUTE_RW    DataWrite;
+};
+
+#endif // __SPI_MASTER_PROTOCOL_H__
diff --git a/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h b/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h
new file mode 100644
index 000000000000..cdbe4d0b6b67
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h
@@ -0,0 +1,88 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __SPI_FLASH_PROTOCOL_H__
+#define __SPI_FLASH_PROTOCOL_H__
+
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/Spi.h>
+
+typedef struct _SPI_FLASH_PROTOCOL SPI_FLASH_PROTOCOL;
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_FLASH_INIT) (
+                         IN SPI_FLASH_PROTOCOL *This,
+                         IN SPI_DEVICE_PARAMS *SpiDev
+                         );
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_FLASH_READ_ID) (
+                            IN SPI_DEVICE_PARAMS *Slave,
+                            IN BOOLEAN UseInRuntime
+                            );
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_FLASH_READ) (
+                         IN SPI_DEVICE_PARAMS *Slave,
+                         IN UINT32 Offset,
+                         IN UINTN Length,
+                         OUT VOID *Buffer
+                         );
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_FLASH_WRITE) (
+                          IN SPI_DEVICE_PARAMS *Slave,
+                          IN UINT32 Offset,
+                          IN UINTN Length,
+                          IN VOID *Buffer
+                          );
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_FLASH_ERASE) (
+                          IN SPI_DEVICE_PARAMS *Slave,
+                          IN UINT32 Offset,
+                          IN UINTN Length
+                          );
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_FLASH_UPDATE) (
+                          IN SPI_DEVICE_PARAMS *Slave,
+                          IN UINT32     Address,
+                          IN UINTN      DataByteCount,
+                          IN UINT8      *Buffer
+                          );
+
+typedef
+  EFI_STATUS
+(EFIAPI *SPI_FLASH_UPDATE_WITH_PROGRESS) (
+  IN SPI_DEVICE_PARAMS                              *Slave,
+  IN UINT32                                         Offset,
+  IN UINTN                                          ByteCount,
+  IN UINT8                                         *Buffer,
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress, OPTIONAL
+  IN UINTN                                          StartPercentage,
+  IN UINTN                                          EndPercentage
+  );
+
+struct _SPI_FLASH_PROTOCOL {
+  SPI_FLASH_INIT     Init;
+  SPI_FLASH_READ_ID  ReadId;
+  SPI_FLASH_READ     Read;
+  SPI_FLASH_WRITE    Write;
+  SPI_FLASH_ERASE    Erase;
+  SPI_FLASH_UPDATE   Update;
+  SPI_FLASH_UPDATE_WITH_PROGRESS  UpdateWithProgress;
+};
+
+#endif // __SPI_FLASH_PROTOCOL_H__
-- 
2.34.1



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



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [edk2-devel] [PATCH v1 3/6] StarFive/JH7110Pkg: Add firmware volume block protocol
  2023-10-19  2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
@ 2023-10-19  2:59 ` John Chew
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library John Chew
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-19  2:59 UTC (permalink / raw)
  To: devel; +Cc: John Chew, Sunil V L

Support for efi variable to store in QSPI flash

Cc: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c   | 909 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h   | 138 +++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf |  70 ++
 3 files changed, 1117 insertions(+)

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c
new file mode 100644
index 000000000000..c30e82ed0871
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c
@@ -0,0 +1,909 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include "FvbDxe.h"
+
+STATIC FVB_DEVICE  *mFvbDevice;
+
+STATIC CONST FVB_DEVICE  mFvbFlashInstanceTemplate = {
+  {
+    0,    /* AddrSize ... NEED TO BE FILLED */
+    NULL, /* Read from NOR FLASH ... NEED TO BE FILLED */
+    0,    /* RegBase ... NEED TO BE FILLED */
+    0,    /* AbhBase ... NEED TO BE FILLED */
+    0,    /* FifoWidth ... NEED TO BE FILLED */
+    0,    /* WriteDelay ... NEED TO BE FILLED */
+  }, /* SPI_DEVICE_PARAMS */
+
+  NULL, /* SpiFlashProtocol ... NEED TO BE FILLED */
+  NULL, /* SpiMasterProtocol ... NEED TO BE FILLED */
+  NULL, /* Handle ... NEED TO BE FILLED */
+
+  FVB_FLASH_SIGNATURE, /* Signature ... NEED TO BE FILLED */
+
+  0,     /* ShadowBufBaseAddr ... NEED TO BE FILLED */
+  0,     /* ShadowBufSize ... NEED TO BE FILLED */
+  0,     /* FvbFlashVarOffset ... NEED TO BE FILLED */
+  0,     /* FvbFlashVarSize ... NEED TO BE FILLED */
+  0,     /* BlockSize ... NEED TO BE FILLED */
+  0,     /* LastBlock ... NEED TO BE FILLED */
+  0,     /* StartLba */
+
+  {
+    FvbGetAttributes,       /* GetAttributes */
+    FvbSetAttributes,       /* SetAttributes */
+    FvbGetPhysicalAddress,  /* GetPhysicalAddress */
+    FvbGetBlockSize,        /* GetBlockSize */
+    FvbRead,                /* Read */
+    FvbWrite,               /* Write */
+    FvbEraseBlocks,         /* EraseBlocks */
+    NULL,                   /* ParentHandle */
+  }, /* EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL */
+
+  {
+    {
+      {
+        HARDWARE_DEVICE_PATH,
+        HW_VENDOR_DP,
+        {
+          (UINT8)sizeof (VENDOR_DEVICE_PATH),
+          (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+        }
+      },
+      { 0xfc0cb972, 0x21df, 0x44d2, { 0x92, 0xa5, 0x78, 0x98, 0x99, 0xcb, 0xf6, 0x61 }
+      }
+    },
+    {
+      END_DEVICE_PATH_TYPE,
+      END_ENTIRE_DEVICE_PATH_SUBTYPE,
+      { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+    }
+  } /* FVB_DEVICE_PATH */
+};
+
+STATIC
+EFI_STATUS
+FvbInitFvAndVariableStoreHeaders (
+  IN FVB_DEVICE  *FlashInstance
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;
+  VARIABLE_STORE_HEADER       *VariableStoreHeader;
+  EFI_STATUS                  Status;
+  VOID                        *Headers;
+  UINTN                       HeadersLength;
+  UINTN                       BlockSize;
+
+  HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+                  sizeof (EFI_FV_BLOCK_MAP_ENTRY) +
+                  sizeof (VARIABLE_STORE_HEADER);
+  Headers = AllocateZeroPool (HeadersLength);
+
+  BlockSize = FlashInstance->BlockSize;
+
+  /* VariableBase -> FtwWOrkingBase -> FtwSpareBase are declared
+   * consecutively in contiguous memory
+   */
+  ASSERT (
+          PcdGet64 (PcdFlashNvStorageVariableBase64) +
+          PcdGet32 (PcdFlashNvStorageVariableSize) ==
+          PcdGet64 (PcdFlashNvStorageFtwWorkingBase64)
+          );
+  ASSERT (
+          PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) +
+          PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ==
+          PcdGet64 (PcdFlashNvStorageFtwSpareBase64)
+          );
+
+  /* Ensure the size of the variable area is at least one block size */
+  ASSERT (
+          (PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&
+          (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0)
+          );
+  ASSERT (
+          (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&
+          (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0)
+          );
+  ASSERT (
+          (PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&
+          (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0)
+          );
+
+  /* Ensure the Variable areas are aligned on block size boundaries */
+  ASSERT ((PcdGet64 (PcdFlashNvStorageVariableBase64) % BlockSize) == 0);
+  ASSERT ((PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % BlockSize) == 0);
+  ASSERT ((PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % BlockSize) == 0);
+
+  /* ---------------------------------------------
+   * | Firmware Volume Header |                  |
+   * --------------------------   Non-Volatile   |
+   * | Variable Store Header  | Storage Variable |
+   * --------------------------      Region      |
+   * |       Variables        |                  |
+   * ---------------------------------------------
+   */
+
+  /* Prepare Firmware Volume Header */
+  FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Headers;
+  CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
+  FirmwareVolumeHeader->FvLength   = FlashInstance->FvbFlashVarSize;
+  FirmwareVolumeHeader->Signature  = EFI_FVH_SIGNATURE;
+  FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP | /* Reads may be enabled */
+                                     EFI_FVB2_READ_STATUS |      /* Reads are currently enabled */
+                                     EFI_FVB2_STICKY_WRITE |     /* A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY */
+                                     EFI_FVB2_ERASE_POLARITY |   /* After erasure all bits take this value (i.e. '1') */
+                                     EFI_FVB2_WRITE_STATUS |     /* Writes are currently enabled */
+                                     EFI_FVB2_WRITE_ENABLED_CAP; /* Writes may be enabled */
+
+  FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+                                       sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+  FirmwareVolumeHeader->Revision              = EFI_FVH_REVISION;
+  FirmwareVolumeHeader->BlockMap[0].NumBlocks = FlashInstance->LastBlock + 1;
+  FirmwareVolumeHeader->BlockMap[0].Length    = FlashInstance->BlockSize;
+  FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
+  FirmwareVolumeHeader->BlockMap[1].Length    = 0;
+  FirmwareVolumeHeader->Checksum              = CalculateCheckSum16 (
+                                                                     (UINT16 *)FirmwareVolumeHeader,
+                                                                     FirmwareVolumeHeader->HeaderLength
+                                                                     );
+
+  /* Prepare Variable Store Header */
+  VariableStoreHeader = (VOID *)((UINTN)Headers +
+                                 FirmwareVolumeHeader->HeaderLength);
+  CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
+  VariableStoreHeader->Size = PcdGet32 (PcdFlashNvStorageVariableSize) -
+                              FirmwareVolumeHeader->HeaderLength;
+  VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
+  VariableStoreHeader->State  = VARIABLE_STORE_HEALTHY;
+
+  /* Write both header to the flash device on the base address of the
+   * declared variable base address in the flash. CAUTIONS! This will
+   * replace the existing firmware volume and variable header or possibly
+   * cause data corruption. Make sure the declared base address and size
+   * in the flash is only use for EFI Variable Storage.
+   * Offset = 0, LastBlockAdress = 0;
+   */
+  Status = FvbWrite (&FlashInstance->FvbProtocol, 0, 0, &HeadersLength, Headers);
+
+  FreePool (Headers);
+
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+FvbValidateFvHeader (
+  IN  FVB_DEVICE  *FlashInstance
+  )
+{
+  UINT16                      Checksum;
+  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;
+  VARIABLE_STORE_HEADER       *VariableStoreHeader;
+  UINTN                       VariableStoreLength;
+
+  FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->ShadowBufBaseAddr;
+
+  /* Verify the header revision, header signature, length from the flash */
+  if ((FirmwareVolumeHeader->Revision  != EFI_FVH_REVISION) ||
+      (FirmwareVolumeHeader->Signature != EFI_FVH_SIGNATURE) ||
+      (FirmwareVolumeHeader->FvLength  != FlashInstance->FvbFlashVarSize))
+  {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): No Firmware Volume header present\n",
+            __func__)
+           );
+    return EFI_NOT_FOUND;
+  }
+
+  /* Verify the Firmware Volume Guid from the flash */
+  if (!CompareGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Firmware Volume Guid non-compatible\n",
+            __func__)
+           );
+    return EFI_NOT_FOUND;
+  }
+
+  /* Verify the header checksum from the flash */
+  Checksum = CalculateSum16 ((UINT16 *)FirmwareVolumeHeader, FirmwareVolumeHeader->HeaderLength);
+  if (Checksum != 0) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): FV checksum is invalid (Checksum:0x%x)\n",
+            __func__,
+            Checksum)
+           );
+    return EFI_NOT_FOUND;
+  }
+
+  VariableStoreHeader = (VOID *)((UINTN)FirmwareVolumeHeader + FirmwareVolumeHeader->HeaderLength);
+
+  /* Verify the Variable Store Guid */
+  if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
+      !CompareGuid (
+                    &VariableStoreHeader->Signature,
+                    &gEfiAuthenticatedVariableGuid
+                    ))
+  {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Variable Store Guid non-compatible\n",
+            __func__)
+           );
+    return EFI_NOT_FOUND;
+  }
+
+  /* Verify the actual Variable Store length with declare size in header*/
+  VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -
+                        FirmwareVolumeHeader->HeaderLength;
+  if (VariableStoreHeader->Size != VariableStoreLength) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Variable Store Length does not match\n",
+            __func__)
+           );
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbGetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;
+  EFI_FVB_ATTRIBUTES_2        *FlashFvbAttributes;
+  FVB_DEVICE                  *FlashInstance;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  FirmwareVolumeHeader        = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->ShadowBufBaseAddr;
+  FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2 *)&(FirmwareVolumeHeader->Attributes);
+
+  *Attributes = *FlashFvbAttributes;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbSetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
+  )
+{
+  EFI_FVB_ATTRIBUTES_2  OldAttributes;
+  EFI_FVB_ATTRIBUTES_2  FlashFvbAttributes;
+  EFI_FVB_ATTRIBUTES_2  UnchangedAttributes;
+  FVB_DEVICE            *FlashInstance;
+  UINT32                Capabilities;
+  UINT32                OldStatus;
+  UINT32                NewStatus;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  /* Read current attribute from the Frimware Volume Header */
+  FvbGetAttributes (This, &FlashFvbAttributes);
+
+  OldAttributes = FlashFvbAttributes;
+  Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
+  OldStatus     = OldAttributes & EFI_FVB2_STATUS;
+  NewStatus     = *Attributes & EFI_FVB2_STATUS;
+
+  UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
+                        EFI_FVB2_READ_ENABLED_CAP   | \
+                        EFI_FVB2_WRITE_DISABLED_CAP | \
+                        EFI_FVB2_WRITE_ENABLED_CAP  | \
+                        EFI_FVB2_LOCK_CAP           | \
+                        EFI_FVB2_STICKY_WRITE       | \
+                        EFI_FVB2_ERASE_POLARITY     | \
+                        EFI_FVB2_READ_LOCK_CAP      | \
+                        EFI_FVB2_WRITE_LOCK_CAP     | \
+                        EFI_FVB2_ALIGNMENT;
+
+  /* Some attributes of FV is read only can *not* be set */
+  if ((OldAttributes & UnchangedAttributes) ^
+      (*Attributes & UnchangedAttributes))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  /* If firmware volume is locked, no status bit can be updated */
+  if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
+    if (OldStatus ^ NewStatus) {
+      return EFI_ACCESS_DENIED;
+    }
+  }
+
+  /*  Test read disable */
+  if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
+    if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  /* Test read enable */
+  if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
+    if (NewStatus & EFI_FVB2_READ_STATUS) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  /* Test write disable */
+  if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
+    if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  /* Test write enable */
+  if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
+    if (NewStatus & EFI_FVB2_WRITE_STATUS) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  /* Test lock */
+  if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
+    if (NewStatus & EFI_FVB2_LOCK_STATUS) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  FlashFvbAttributes = FlashFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
+  FlashFvbAttributes = FlashFvbAttributes | NewStatus;
+  *Attributes        = FlashFvbAttributes;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_PHYSICAL_ADDRESS                 *Address
+  )
+{
+  FVB_DEVICE  *FlashInstance;
+
+  ASSERT (Address != NULL);
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  /* Do not support MMIO, return the shadow buffer instead */
+  *Address = FlashInstance->ShadowBufBaseAddr;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  OUT       UINTN                                *BlockSize,
+  OUT       UINTN                                *NumberOfBlocks
+  )
+{
+  FVB_DEVICE  *FlashInstance;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  if (Lba > FlashInstance->LastBlock) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Error: Requested LBA %ld is beyond the last available LBA (%ld).\n",
+            __func__,
+            Lba,
+            FlashInstance->LastBlock)
+           );
+    return EFI_INVALID_PARAMETER;
+  } else {
+    /* Assume equal sized blocks in all flash devices */
+    *BlockSize      = (UINTN)FlashInstance->BlockSize;
+    *NumberOfBlocks = (UINTN)(FlashInstance->LastBlock - Lba + 1);
+
+    return EFI_SUCCESS;
+  }
+}
+
+EFI_STATUS
+EFIAPI
+FvbRead (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN OUT    UINT8                                *Buffer
+  )
+{
+  FVB_DEVICE  *FlashInstance;
+  UINTN       BlockSize;
+  UINTN       DataOffset;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  /* Cache the block size to avoid de-referencing pointers all the time */
+  BlockSize = FlashInstance->BlockSize;
+
+  /* Offset + byte have to be within the define block size.
+   * The read must not span block boundaries. We need to
+   * check each variable individually because adding two
+   * large values together migght cause overflows.
+   */
+  if ((Offset               >= BlockSize) ||
+      (*NumBytes            >  BlockSize) ||
+      ((Offset + *NumBytes) >  BlockSize))
+  {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Wrong buffer size: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
+            __func__,
+            Offset,
+            *NumBytes,
+            BlockSize)
+           );
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  /* No bytes to read */
+  if (*NumBytes == 0) {
+    return EFI_SUCCESS;
+  }
+
+  DataOffset = GET_DATA_OFFSET (
+                                FlashInstance->ShadowBufBaseAddr + Offset,
+                                FlashInstance->StartLba + Lba,
+                                FlashInstance->BlockSize
+                                );
+
+  /* Copy variable from the shadow buffer */
+  CopyMem (Buffer, (UINTN *)DataOffset, *NumBytes);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbWrite (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN        UINT8                                *Buffer
+  )
+{
+  EFI_STATUS  Status;
+  FVB_DEVICE  *FlashInstance;
+  UINTN       DataOffset;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  DataOffset = GET_DATA_OFFSET (
+                                FlashInstance->FvbFlashVarOffset + Offset,
+                                FlashInstance->StartLba + Lba,
+                                FlashInstance->BlockSize
+                                );
+
+  Status = FlashInstance->SpiFlashProtocol->Write (
+                                                   &FlashInstance->SpiDevice,
+                                                   DataOffset,
+                                                   *NumBytes,
+                                                   Buffer
+                                                   );
+  if (EFI_ERROR (Status)) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Failed to write to Spi device\n",
+            __func__)
+           );
+    return Status;
+  }
+
+  DataOffset = GET_DATA_OFFSET (
+                                FlashInstance->ShadowBufBaseAddr + Offset,
+                                FlashInstance->StartLba + Lba,
+                                FlashInstance->BlockSize
+                                );
+
+  /* Update shadow buffer */
+  CopyMem ((UINTN *)DataOffset, Buffer, *NumBytes);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  ...
+  )
+{
+  EFI_FVB_ATTRIBUTES_2  FlashFvbAttributes;
+  FVB_DEVICE            *FlashInstance;
+  EFI_STATUS            Status;
+  VA_LIST               Args;
+  UINTN                 BlockAddress;  /* Physical address of Lba to erase */
+  EFI_LBA               StartingLba;   /* Lba from which we start erasing */
+  UINTN                 NumOfLba;      /* Number of Lba blocks to erase */
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  Status = EFI_SUCCESS;
+
+  /* Detect WriteDisabled state */
+  FvbGetAttributes (This, &FlashFvbAttributes);
+  if ((FlashFvbAttributes & EFI_FVB2_WRITE_STATUS) == 0) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Device is in WriteDisabled state.\n",
+            __func__)
+           );
+    return EFI_ACCESS_DENIED;
+  }
+
+  /*
+   * Before erasing, check the entire list of parameters to ensure
+   * all specified blocks are valid.
+  */
+  VA_START (Args, This);
+  do {
+    /* Get the Lba from which we start erasing */
+    StartingLba = VA_ARG (Args, EFI_LBA);
+
+    /* Have we reached the end of the list? */
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+      break;
+    }
+
+    /* How many Lba blocks are we requested to erase? */
+    NumOfLba = VA_ARG (Args, UINT32);
+
+    /* All blocks must be within range */
+    if ((NumOfLba == 0) ||
+        ((FlashInstance->StartLba + StartingLba + NumOfLba - 1) >
+         FlashInstance->LastBlock))
+    {
+      DEBUG (
+             (DEBUG_ERROR,
+              "%a(): Error: Requested LBA are beyond the last available LBA (%ld).\n",
+              __func__,
+              FlashInstance->LastBlock)
+             );
+
+      VA_END (Args);
+
+      return EFI_INVALID_PARAMETER;
+    }
+  } while (TRUE);
+
+  VA_END (Args);
+
+  /* Start erasing */
+  VA_START (Args, This);
+  do {
+    /* Get the Lba from which we start erasing */
+    StartingLba = VA_ARG (Args, EFI_LBA);
+
+    /* Have we reached the end of the list? */
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+      break;
+    }
+
+    /* How many Lba blocks are we requested to erase? */
+    NumOfLba = VA_ARG (Args, UINT32);
+
+    /* Go through each requested block and erase it */
+    while (NumOfLba > 0) {
+      /* Get the offset address of Lba to erase */
+      BlockAddress = GET_DATA_OFFSET (
+                                      FlashInstance->FvbFlashVarOffset,
+                                      FlashInstance->StartLba + StartingLba,
+                                      FlashInstance->BlockSize
+                                      );
+
+      /* Erase single block */
+      Status = FlashInstance->SpiFlashProtocol->Erase (
+                                                       &FlashInstance->SpiDevice,
+                                                       BlockAddress,
+                                                       FlashInstance->BlockSize
+                                                       );
+      if (EFI_ERROR (Status)) {
+        VA_END (Args);
+        return EFI_DEVICE_ERROR;
+      }
+
+      StartingLba++;
+      NumOfLba--;
+    }
+  } while (TRUE);
+
+  VA_END (Args);
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FvbFlashProbe (
+  IN FVB_DEVICE  *FlashInstance
+  )
+{
+  SPI_FLASH_PROTOCOL  *SpiFlashProtocol;
+  EFI_STATUS          Status;
+
+  SpiFlashProtocol = FlashInstance->SpiFlashProtocol;
+
+  /* Read SPI flash ID */
+  Status = SpiFlashProtocol->ReadId (&FlashInstance->SpiDevice, TRUE);
+  if (EFI_ERROR (Status)) {
+    return EFI_NOT_FOUND;
+  }
+
+  Status = SpiFlashProtocol->Init (SpiFlashProtocol, &FlashInstance->SpiDevice);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot initialize flash device\n", __func__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FvbPrepareFvHeader (
+  IN FVB_DEVICE  *FlashInstance
+  )
+{
+  EFI_BOOT_MODE  BootMode;
+  EFI_STATUS     Status;
+
+  /* Check if it is required to use default environment */
+  BootMode = GetBootModeHob ();
+  if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+    Status = EFI_INVALID_PARAMETER;
+  } else {
+    /* Validate header at the beginning of FV region */
+    Status = FvbValidateFvHeader (FlashInstance);
+  }
+
+  /* Install the default FVB header if required */
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): The FVB Header is not valid.\n", __func__));
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Installing a correct one for this volume.\n",
+            __func__)
+           );
+
+    /* Erase entire region that is reserved for variable storage in flash */
+    Status = FlashInstance->SpiFlashProtocol->Erase (
+                                                     &FlashInstance->SpiDevice,
+                                                     FlashInstance->FvbFlashVarOffset,
+                                                     FlashInstance->FvbFlashVarSize
+                                                     );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    /* Write a new firmware volume and varaible storage headers */
+    Status = FvbInitFvAndVariableStoreHeaders (FlashInstance);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FvbConfigureFlashInstance (
+  IN OUT FVB_DEVICE  *FlashInstance
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       DataOffset;
+  UINTN       VariableSize, FtwWorkingSize, FtwSpareSize, MemorySize;
+
+  Status = gBS->LocateProtocol (
+                                &gJH7110SpiFlashProtocolGuid,
+                                NULL,
+                                (VOID **)&FlashInstance->SpiFlashProtocol
+                                );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiFlash protocol\n", __func__));
+    return Status;
+  }
+
+  Status = gBS->LocateProtocol (
+                                &gJH7110SpiMasterProtocolGuid,
+                                NULL,
+                                (VOID **)&FlashInstance->SpiMasterProtocol
+                                );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiMaster protocol\n", __func__));
+    return Status;
+  }
+
+  /* Setup and probe SPI flash */
+  FlashInstance->SpiMasterProtocol->SetupDevice (
+                                                 FlashInstance->SpiMasterProtocol,
+                                                 &FlashInstance->SpiDevice
+                                                 );
+  Status = FvbFlashProbe (FlashInstance);
+  if (EFI_ERROR (Status)) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Error while performing SPI flash probe\n",
+            __func__)
+           );
+    return Status;
+  }
+
+  /* Fill remaining flash description */
+  VariableSize   = PcdGet32 (PcdFlashNvStorageVariableSize);
+  FtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
+  FtwSpareSize   = PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+  FlashInstance->FvbFlashVarSize    = VariableSize + FtwWorkingSize + FtwSpareSize;
+  FlashInstance->FvbFlashVarOffset  = PcdGet32(PcdJH7110FlashVarOffset);
+  FlashInstance->BlockSize = FlashInstance->SpiDevice.Info->SectorSize;
+  FlashInstance->LastBlock = (FlashInstance->FvbFlashVarSize /
+                                   FlashInstance->BlockSize) - 1;
+  FlashInstance->ShadowBufSize = FlashInstance->FvbFlashVarSize;
+
+  /* Allocate memory for shadow buffer */
+  MemorySize = EFI_SIZE_TO_PAGES (FlashInstance->FvbFlashVarSize);
+
+  /* FaultTolerantWriteDxe requires memory to be aligned to FtwWorkingSize */
+  FlashInstance->ShadowBufBaseAddr = (UINTN)AllocateAlignedRuntimePages (
+                                                                          MemorySize,
+                                                                          SIZE_64KB
+                                                                          );
+  if (FlashInstance->ShadowBufBaseAddr == (UINTN)NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  /* Update PCDs value according to allocated memory */
+  Status = PcdSet64S (
+                      PcdFlashNvStorageVariableBase64,
+                      (UINT64)FlashInstance->ShadowBufBaseAddr
+                      );
+  ASSERT_EFI_ERROR (Status);
+  Status = PcdSet64S (
+                      PcdFlashNvStorageFtwWorkingBase64,
+                      (UINT64)FlashInstance->ShadowBufBaseAddr
+                      + VariableSize
+                      );
+  ASSERT_EFI_ERROR (Status);
+  Status = PcdSet64S (
+                      PcdFlashNvStorageFtwSpareBase64,
+                      (UINT64)FlashInstance->ShadowBufBaseAddr
+                      + VariableSize
+                      + FtwWorkingSize
+                      );
+  ASSERT_EFI_ERROR (Status);
+
+  /* ill the shadow buffer with data from flash */
+  DataOffset = GET_DATA_OFFSET (
+                                FlashInstance->FvbFlashVarOffset,
+                                FlashInstance->StartLba,
+                                FlashInstance->BlockSize
+                                );
+  Status = FlashInstance->SpiFlashProtocol->Read (
+                                                  &FlashInstance->SpiDevice,
+                                                  DataOffset,
+                                                  FlashInstance->FvbFlashVarSize,
+                                                  (VOID *)FlashInstance->ShadowBufBaseAddr
+                                                  );
+  if (EFI_ERROR (Status)) {
+    goto ErrorFreeAllocatedPages;
+  }
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                                                   &FlashInstance->Handle,
+                                                   &gEfiDevicePathProtocolGuid,
+                                                   &FlashInstance->DevicePath,
+                                                   &gEfiFirmwareVolumeBlockProtocolGuid,
+                                                   &FlashInstance->FvbProtocol,
+                                                   NULL
+                                                   );
+  if (EFI_ERROR (Status)) {
+    goto ErrorFreeAllocatedPages;
+  }
+
+  Status = FvbPrepareFvHeader (FlashInstance);
+  if (EFI_ERROR (Status)) {
+    goto ErrorPrepareFvbHeader;
+  }
+
+  return EFI_SUCCESS;
+
+ErrorPrepareFvbHeader:
+  gBS->UninstallMultipleProtocolInterfaces (
+                                            &FlashInstance->Handle,
+                                            &gEfiDevicePathProtocolGuid,
+                                            &gEfiFirmwareVolumeBlockProtocolGuid,
+                                            NULL
+                                            );
+
+ErrorFreeAllocatedPages:
+    FreeAlignedPages (
+                      (VOID *)FlashInstance->ShadowBufBaseAddr,
+                      MemorySize
+                      );
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FvbEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  /* Allocate memory for FVB flash device*/
+  mFvbDevice = AllocateRuntimeCopyPool (
+                                        sizeof (mFvbFlashInstanceTemplate),
+                                        &mFvbFlashInstanceTemplate
+                                        );
+  if (mFvbDevice == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  /* Detect and configure flash device */
+  Status = FvbConfigureFlashInstance (mFvbDevice);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a(): Fail to configure Fvb SPI device\n", __func__));
+    goto ErrorConfigureFlash;
+  }
+
+  /* The driver implementing the variable read service can now be dispatched;
+   * the varstore headers are in place.
+   */
+  Status = gBS->InstallProtocolInterface (
+                                          &gImageHandle,
+                                          &gEdkiiNvVarStoreFormattedGuid,
+                                          EFI_NATIVE_INTERFACE,
+                                          NULL
+                                          );
+  if (EFI_ERROR (Status)) {
+    DEBUG (
+           (DEBUG_ERROR,
+            "%a(): Failed to install gEdkiiNvVarStoreFormattedGuid\n",
+            __func__)
+           );
+    goto ErrorInstallNvVarStoreFormatted;
+  }
+
+  return Status;
+
+ErrorInstallNvVarStoreFormatted:
+  gBS->UninstallMultipleProtocolInterfaces (
+                                            &mFvbDevice->Handle,
+                                            &gEfiDevicePathProtocolGuid,
+                                            &gEfiFirmwareVolumeBlockProtocolGuid,
+                                            NULL
+                                            );
+
+ErrorConfigureFlash:
+  FreePool (mFvbDevice);
+
+  return Status;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h
new file mode 100644
index 000000000000..6b0450b17275
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h
@@ -0,0 +1,138 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __FVB_DXE_H__
+#define __FVB_DXE_H__
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Guid/NvVarStoreFormatted.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/VariableFormat.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize)  ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))
+
+#define FVB_FLASH_SIGNATURE  SIGNATURE_32('S', 'n', 'o', 'r')
+#define INSTANCE_FROM_FVB_THIS(a)  CR(a, FVB_DEVICE, FvbProtocol, FVB_FLASH_SIGNATURE)
+
+//
+// Define two helper macro to extract the Capability field or Status field in FVB
+// bit fields.
+//
+#define EFI_FVB2_CAPABILITIES  (EFI_FVB2_READ_DISABLED_CAP |\
+                               EFI_FVB2_READ_ENABLED_CAP | \
+                               EFI_FVB2_WRITE_DISABLED_CAP | \
+                               EFI_FVB2_WRITE_ENABLED_CAP | \
+                               EFI_FVB2_LOCK_CAP)
+
+#define EFI_FVB2_STATUS  (EFI_FVB2_READ_STATUS |      \
+                          EFI_FVB2_WRITE_STATUS | \
+                          EFI_FVB2_LOCK_STATUS)
+
+typedef struct {
+  VENDOR_DEVICE_PATH          Vendor;
+  EFI_DEVICE_PATH_PROTOCOL    End;
+} FVB_DEVICE_PATH;
+
+typedef struct {
+  SPI_DEVICE_PARAMS                      SpiDevice;
+
+  SPI_FLASH_PROTOCOL                     *SpiFlashProtocol;
+  SPI_MASTER_PROTOCOL                    *SpiMasterProtocol;
+
+  EFI_HANDLE                             Handle;
+
+  UINT32                                 Signature;
+
+  UINTN                                  ShadowBufBaseAddr;
+  UINTN                                  ShadowBufSize;
+  UINTN                                  FvbFlashVarOffset;
+  UINTN                                  FvbFlashVarSize;
+  UINTN                                  BlockSize;
+  UINTN                                  LastBlock;
+  EFI_LBA                                StartLba;
+
+  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL    FvbProtocol;
+
+  FVB_DEVICE_PATH                        DevicePath;
+} FVB_DEVICE;
+
+EFI_STATUS
+EFIAPI
+FvbGetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes
+  );
+
+EFI_STATUS
+EFIAPI
+FvbSetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
+  );
+
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_PHYSICAL_ADDRESS                 *Address
+  );
+
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  OUT       UINTN                                *BlockSize,
+  OUT       UINTN                                *NumberOfBlocks
+  );
+
+EFI_STATUS
+EFIAPI
+FvbRead (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN OUT    UINT8                                *Buffer
+  );
+
+EFI_STATUS
+EFIAPI
+FvbWrite (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN        UINT8                                *Buffer
+  );
+
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  ...
+  );
+
+#endif //__FVB_DXE_H__
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf
new file mode 100644
index 000000000000..715989bfcc2b
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf
@@ -0,0 +1,70 @@
+## @file
+#
+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001A
+  BASE_NAME                      = FvbDxe
+  FILE_GUID                      = DB8BFC83-6DEA-4AD1-AD3D-FDC579430233
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 0.1
+  ENTRY_POINT                    = FvbEntryPoint
+
+[Sources]
+  FvbDxe.c
+
+[Packages]
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DevicePathLib
+  DxeServicesTableLib
+  HobLib
+  IoLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiRuntimeLib
+  UefiRuntimeServicesTableLib
+
+[Guids]
+  gEdkiiNvVarStoreFormattedGuid
+  gEfiAuthenticatedVariableGuid
+  gEfiEventVirtualAddressChangeGuid
+  gEfiSystemNvDataFvGuid
+  gEfiVariableGuid
+
+[Protocols]
+  gEfiDevicePathProtocolGuid
+  gEfiFirmwareVolumeBlockProtocolGuid
+  gJH7110SpiFlashProtocolGuid
+  gJH7110SpiMasterProtocolGuid
+
+[FixedPcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+  gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
+
+[Depex]
+  gEfiCpuArchProtocolGuid AND
+  gJH7110SpiMasterProtocolGuid AND
+  gJH7110SpiFlashProtocolGuid
-- 
2.34.1



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



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library
  2023-10-19  2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 3/6] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
@ 2023-10-19  2:59 ` John Chew
  2023-10-19 12:12   ` Sunil V L
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver John Chew
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
  4 siblings, 1 reply; 12+ messages in thread
From: John Chew @ 2023-10-19  2:59 UTC (permalink / raw)
  To: devel; +Cc: JohnChew, Sunil V L, Yong Li

From: JohnChew <yuinyee.chew@starfivetech.com>

For JH7110 with graphic console

Cc: Sunil V L <sunilvl@ventanamicro.com>
Co-authored-by: Yong Li <yong.li@intel.com>
Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c               | 1014 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h               |   46 +
 Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf |   71 ++
 3 files changed, 1131 insertions(+)

diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c
new file mode 100755
index 000000000000..b58d2c7cbcd5
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c
@@ -0,0 +1,1014 @@
+/** @file
+*  Implementation for PlatformBootManagerLib library class interfaces.
+*
+*  Copyright (C) 2015-2016, Red Hat, Inc.
+*  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+*  Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+*  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <IndustryStandard/Pci22.h>
+#include <IndustryStandard/Virtio095.h>
+#include <Library/BootLogoLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PlatformBmPrintScLib.h>
+#include <Library/QemuBootOrderLib.h>
+#include <Library/TpmPlatformHierarchyLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/VirtioDevice.h>
+#include <Guid/EventGroup.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/RootBridgesConnectedEventGroup.h>
+#include <Guid/SerialPortLibVendor.h>
+#include <Guid/TtyTerm.h>
+
+#include "PlatformBm.h"
+
+#define DP_NODE_LEN(Type)  { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
+
+#define VERSION_STRING_PREFIX  L"RISC-V EDK2 firmware version "
+
+#pragma pack (1)
+typedef struct {
+  VENDOR_DEVICE_PATH            SerialDxe;
+  UART_DEVICE_PATH              Uart;
+  VENDOR_DEFINED_DEVICE_PATH    TermType;
+  EFI_DEVICE_PATH_PROTOCOL      End;
+} PLATFORM_SERIAL_CONSOLE;
+#pragma pack ()
+
+STATIC PLATFORM_SERIAL_CONSOLE  mSerialConsole = {
+  //
+  // VENDOR_DEVICE_PATH SerialDxe
+  //
+  {
+    { HARDWARE_DEVICE_PATH,  HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
+    EDKII_SERIAL_PORT_LIB_VENDOR_GUID
+  },
+
+  //
+  // UART_DEVICE_PATH Uart
+  //
+  {
+    { MESSAGING_DEVICE_PATH, MSG_UART_DP,  DP_NODE_LEN (UART_DEVICE_PATH)   },
+    0,                                      // Reserved
+    FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
+    FixedPcdGet8 (PcdUartDefaultDataBits),  // DataBits
+    FixedPcdGet8 (PcdUartDefaultParity),    // Parity
+    FixedPcdGet8 (PcdUartDefaultStopBits)   // StopBits
+  },
+
+  //
+  // VENDOR_DEFINED_DEVICE_PATH TermType
+  //
+  {
+    {
+      MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
+      DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
+    }
+    //
+    // Guid to be filled in dynamically
+    //
+  },
+
+  //
+  // EFI_DEVICE_PATH_PROTOCOL End
+  //
+  {
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+  }
+};
+
+#pragma pack (1)
+typedef struct {
+  USB_CLASS_DEVICE_PATH       Keyboard;
+  EFI_DEVICE_PATH_PROTOCOL    End;
+} PLATFORM_USB_KEYBOARD;
+#pragma pack ()
+
+STATIC PLATFORM_USB_KEYBOARD  mUsbKeyboard = {
+  //
+  // USB_CLASS_DEVICE_PATH Keyboard
+  //
+  {
+    {
+      MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
+      DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
+    },
+    0xFFFF, // VendorId: any
+    0xFFFF, // ProductId: any
+    3,      // DeviceClass: HID
+    1,      // DeviceSubClass: boot
+    1       // DeviceProtocol: keyboard
+  },
+
+  //
+  // EFI_DEVICE_PATH_PROTOCOL End
+  //
+  {
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+  }
+};
+
+/**
+  Check if the handle satisfies a particular condition.
+
+  @param[in] Handle      The handle to check.
+  @param[in] ReportText  A caller-allocated string passed in for reporting
+                         purposes. It must never be NULL.
+
+  @retval TRUE   The condition is satisfied.
+  @retval FALSE  Otherwise. This includes the case when the condition could not
+                 be fully evaluated due to an error.
+**/
+typedef
+BOOLEAN
+(EFIAPI *FILTER_FUNCTION)(
+  IN EFI_HANDLE   Handle,
+  IN CONST CHAR16 *ReportText
+  );
+
+/**
+  Process a handle.
+
+  @param[in] Handle      The handle to process.
+  @param[in] ReportText  A caller-allocated string passed in for reporting
+                         purposes. It must never be NULL.
+**/
+typedef
+VOID
+(EFIAPI *CALLBACK_FUNCTION)(
+  IN EFI_HANDLE   Handle,
+  IN CONST CHAR16 *ReportText
+  );
+
+/**
+  Locate all handles that carry the specified protocol, filter them with a
+  callback function, and pass each handle that passes the filter to another
+  callback.
+
+  @param[in] ProtocolGuid  The protocol to look for.
+
+  @param[in] Filter        The filter function to pass each handle to. If this
+                           parameter is NULL, then all handles are processed.
+
+  @param[in] Process       The callback function to pass each handle to that
+                           clears the filter.
+**/
+STATIC
+VOID
+FilterAndProcess (
+  IN EFI_GUID           *ProtocolGuid,
+  IN FILTER_FUNCTION    Filter         OPTIONAL,
+  IN CALLBACK_FUNCTION  Process
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  *Handles;
+  UINTN       NoHandles;
+  UINTN       Idx;
+
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  ProtocolGuid,
+                  NULL /* SearchKey */,
+                  &NoHandles,
+                  &Handles
+                  );
+  if (EFI_ERROR (Status)) {
+    //
+    // This is not an error, just an informative condition.
+    //
+    DEBUG ((
+      DEBUG_VERBOSE,
+      "%a: %g: %r\n",
+      __func__,
+      ProtocolGuid,
+      Status
+      ));
+    return;
+  }
+
+  ASSERT (NoHandles > 0);
+  for (Idx = 0; Idx < NoHandles; ++Idx) {
+    CHAR16         *DevicePathText;
+    STATIC CHAR16  Fallback[] = L"<device path unavailable>";
+
+    //
+    // The ConvertDevicePathToText() function handles NULL input transparently.
+    //
+    DevicePathText = ConvertDevicePathToText (
+                       DevicePathFromHandle (Handles[Idx]),
+                       FALSE, // DisplayOnly
+                       FALSE  // AllowShortcuts
+                       );
+    if (DevicePathText == NULL) {
+      DevicePathText = Fallback;
+    }
+
+    if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {
+      Process (Handles[Idx], DevicePathText);
+    }
+
+    if (DevicePathText != Fallback) {
+      FreePool (DevicePathText);
+    }
+  }
+
+  gBS->FreePool (Handles);
+}
+
+/**
+  This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+IsPciDisplay (
+  IN EFI_HANDLE    Handle,
+  IN CONST CHAR16  *ReportText
+  )
+{
+  EFI_STATUS           Status;
+  EFI_PCI_IO_PROTOCOL  *PciIo;
+  PCI_TYPE00           Pci;
+
+  Status = gBS->HandleProtocol (
+                  Handle,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **)&PciIo
+                  );
+  if (EFI_ERROR (Status)) {
+    //
+    // This is not an error worth reporting.
+    //
+    return FALSE;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        0 /* Offset */,
+                        sizeof Pci / sizeof (UINT32),
+                        &Pci
+                        );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __func__, ReportText, Status));
+    return FALSE;
+  }
+
+  return IS_PCI_DISPLAY (&Pci);
+}
+
+
+/**
+  This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
+  the EFI_PCI_IO_PROTOCOL level.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+IsVirtioPciRng (
+  IN EFI_HANDLE    Handle,
+  IN CONST CHAR16  *ReportText
+  )
+{
+  EFI_STATUS           Status;
+  EFI_PCI_IO_PROTOCOL  *PciIo;
+  UINT16               VendorId;
+  UINT16               DeviceId;
+  UINT8                RevisionId;
+  BOOLEAN              Virtio10;
+  UINT16               SubsystemId;
+
+  Status = gBS->HandleProtocol (
+                  Handle,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **)&PciIo
+                  );
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  //
+  // Read and check VendorId.
+  //
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint16,
+                        PCI_VENDOR_ID_OFFSET,
+                        1,
+                        &VendorId
+                        );
+  if (EFI_ERROR (Status)) {
+    goto PciError;
+  }
+
+  if (VendorId != VIRTIO_VENDOR_ID) {
+    return FALSE;
+  }
+
+  //
+  // Read DeviceId and RevisionId.
+  //
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint16,
+                        PCI_DEVICE_ID_OFFSET,
+                        1,
+                        &DeviceId
+                        );
+  if (EFI_ERROR (Status)) {
+    goto PciError;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        PCI_REVISION_ID_OFFSET,
+                        1,
+                        &RevisionId
+                        );
+  if (EFI_ERROR (Status)) {
+    goto PciError;
+  }
+
+  //
+  // From DeviceId and RevisionId, determine whether the device is a
+  // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
+  // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
+  // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
+  // only be sanity-checked, and SubsystemId will decide.
+  //
+  if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&
+      (RevisionId >= 0x01))
+  {
+    Virtio10 = TRUE;
+  } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {
+    Virtio10 = FALSE;
+  } else {
+    return FALSE;
+  }
+
+  //
+  // Read and check SubsystemId as dictated by Virtio10.
+  //
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint16,
+                        PCI_SUBSYSTEM_ID_OFFSET,
+                        1,
+                        &SubsystemId
+                        );
+  if (EFI_ERROR (Status)) {
+    goto PciError;
+  }
+
+  if (Virtio10 && (SubsystemId >= 0x40)) {
+    return TRUE;
+  }
+
+  if (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
+    return TRUE;
+  }
+
+  return FALSE;
+
+PciError:
+  DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __func__, ReportText, Status));
+  return FALSE;
+}
+
+/**
+  This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
+  the matching driver to produce all first-level child handles.
+**/
+STATIC
+VOID
+EFIAPI
+Connect (
+  IN EFI_HANDLE    Handle,
+  IN CONST CHAR16  *ReportText
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = gBS->ConnectController (
+                  Handle, // ControllerHandle
+                  NULL,   // DriverImageHandle
+                  NULL,   // RemainingDevicePath -- produce all children
+                  FALSE   // Recursive
+                  );
+  DEBUG ((
+    EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
+    "%a: %s: %r\n",
+    __func__,
+    ReportText,
+    Status
+    ));
+}
+
+/**
+  This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
+  handle, and adds it to ConOut and ErrOut.
+**/
+STATIC
+VOID
+EFIAPI
+AddOutput (
+  IN EFI_HANDLE    Handle,
+  IN CONST CHAR16  *ReportText
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+
+  DevicePath = DevicePathFromHandle (Handle);
+  if (DevicePath == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: %s: handle %p: device path not found\n",
+      __func__,
+      ReportText,
+      Handle
+      ));
+    return;
+  }
+
+  Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: %s: adding to ConOut: %r\n",
+      __func__,
+      ReportText,
+      Status
+      ));
+    return;
+  }
+
+  Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: %s: adding to ErrOut: %r\n",
+      __func__,
+      ReportText,
+      Status
+      ));
+    return;
+  }
+
+  DEBUG ((
+    DEBUG_VERBOSE,
+    "%a: %s: added to ConOut and ErrOut\n",
+    __func__,
+    ReportText
+    ));
+}
+
+STATIC
+VOID
+PlatformRegisterFvBootOption (
+  EFI_GUID  *FileGuid,
+  CHAR16    *Description,
+  UINT32    Attributes
+  )
+{
+  EFI_STATUS                         Status;
+  INTN                               OptionIndex;
+  EFI_BOOT_MANAGER_LOAD_OPTION       NewOption;
+  EFI_BOOT_MANAGER_LOAD_OPTION       *BootOptions;
+  UINTN                              BootOptionCount;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;
+  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;
+  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
+
+  Status = gBS->HandleProtocol (
+                  gImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **)&LoadedImage
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+  DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
+  ASSERT (DevicePath != NULL);
+  DevicePath = AppendDevicePathNode (
+                 DevicePath,
+                 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
+                 );
+  ASSERT (DevicePath != NULL);
+
+  Status = EfiBootManagerInitializeLoadOption (
+             &NewOption,
+             LoadOptionNumberUnassigned,
+             LoadOptionTypeBoot,
+             Attributes,
+             Description,
+             DevicePath,
+             NULL,
+             0
+             );
+  ASSERT_EFI_ERROR (Status);
+  FreePool (DevicePath);
+
+  BootOptions = EfiBootManagerGetLoadOptions (
+                  &BootOptionCount,
+                  LoadOptionTypeBoot
+                  );
+
+  OptionIndex = EfiBootManagerFindLoadOption (
+                  &NewOption,
+                  BootOptions,
+                  BootOptionCount
+                  );
+
+  if (OptionIndex == -1) {
+    Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  EfiBootManagerFreeLoadOption (&NewOption);
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+/**
+  Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
+  whose device paths do not resolve exactly to an FvFile in the system.
+
+  This removes any boot options that point to binaries built into the firmware
+  and have become stale due to any of the following:
+  - FvMain's base address or size changed (historical),
+  - FvMain's FvNameGuid changed,
+  - the FILE_GUID of the pointed-to binary changed,
+  - the referenced binary is no longer built into the firmware.
+
+  EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
+  avoids exact duplicates.
+**/
+STATIC
+VOID
+RemoveStaleFvFileOptions (
+  VOID
+  )
+{
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;
+  UINTN                         BootOptionCount;
+  UINTN                         Index;
+
+  BootOptions = EfiBootManagerGetLoadOptions (
+                  &BootOptionCount,
+                  LoadOptionTypeBoot
+                  );
+
+  for (Index = 0; Index < BootOptionCount; ++Index) {
+    EFI_DEVICE_PATH_PROTOCOL  *Node1, *Node2, *SearchNode;
+    EFI_STATUS                Status;
+    EFI_HANDLE                FvHandle;
+
+    //
+    // If the device path starts with neither MemoryMapped(...) nor Fv(...),
+    // then keep the boot option.
+    //
+    Node1 = BootOptions[Index].FilePath;
+    if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&
+          (DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&
+        !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
+          (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
+    {
+      continue;
+    }
+
+    //
+    // If the second device path node is not FvFile(...), then keep the boot
+    // option.
+    //
+    Node2 = NextDevicePathNode (Node1);
+    if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||
+        (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
+    {
+      continue;
+    }
+
+    //
+    // Locate the Firmware Volume2 protocol instance that is denoted by the
+    // boot option. If this lookup fails (i.e., the boot option references a
+    // firmware volume that doesn't exist), then we'll proceed to delete the
+    // boot option.
+    //
+    SearchNode = Node1;
+    Status     = gBS->LocateDevicePath (
+                        &gEfiFirmwareVolume2ProtocolGuid,
+                        &SearchNode,
+                        &FvHandle
+                        );
+
+    if (!EFI_ERROR (Status)) {
+      //
+      // The firmware volume was found; now let's see if it contains the FvFile
+      // identified by GUID.
+      //
+      EFI_FIRMWARE_VOLUME2_PROTOCOL      *FvProtocol;
+      MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  *FvFileNode;
+      UINTN                              BufferSize;
+      EFI_FV_FILETYPE                    FoundType;
+      EFI_FV_FILE_ATTRIBUTES             FileAttributes;
+      UINT32                             AuthenticationStatus;
+
+      Status = gBS->HandleProtocol (
+                      FvHandle,
+                      &gEfiFirmwareVolume2ProtocolGuid,
+                      (VOID **)&FvProtocol
+                      );
+      ASSERT_EFI_ERROR (Status);
+
+      FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
+      //
+      // Buffer==NULL means we request metadata only: BufferSize, FoundType,
+      // FileAttributes.
+      //
+      Status = FvProtocol->ReadFile (
+                             FvProtocol,
+                             &FvFileNode->FvFileName, // NameGuid
+                             NULL,                    // Buffer
+                             &BufferSize,
+                             &FoundType,
+                             &FileAttributes,
+                             &AuthenticationStatus
+                             );
+      if (!EFI_ERROR (Status)) {
+        //
+        // The FvFile was found. Keep the boot option.
+        //
+        continue;
+      }
+    }
+
+    //
+    // Delete the boot option.
+    //
+    Status = EfiBootManagerDeleteLoadOptionVariable (
+               BootOptions[Index].OptionNumber,
+               LoadOptionTypeBoot
+               );
+    DEBUG_CODE_BEGIN ();
+    CHAR16  *DevicePathString;
+
+    DevicePathString = ConvertDevicePathToText (
+                         BootOptions[Index].FilePath,
+                         FALSE,
+                         FALSE
+                         );
+    DEBUG ((
+      EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
+      "%a: removing stale Boot#%04x %s: %r\n",
+      __func__,
+      (UINT32)BootOptions[Index].OptionNumber,
+      DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
+      Status
+      ));
+    if (DevicePathString != NULL) {
+      FreePool (DevicePathString);
+    }
+
+    DEBUG_CODE_END ();
+  }
+
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+STATIC
+VOID
+PlatformRegisterOptionsAndKeys (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_INPUT_KEY                 Enter;
+  EFI_INPUT_KEY                 F2;
+  EFI_INPUT_KEY                 Esc;
+  EFI_BOOT_MANAGER_LOAD_OPTION  BootOption;
+
+  //
+  // Register ENTER as CONTINUE key
+  //
+  Enter.ScanCode    = SCAN_NULL;
+  Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+  Status            = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Map F2 and ESC to Boot Manager Menu
+  //
+  F2.ScanCode     = SCAN_F2;
+  F2.UnicodeChar  = CHAR_NULL;
+  Esc.ScanCode    = SCAN_ESC;
+  Esc.UnicodeChar = CHAR_NULL;
+  Status          = EfiBootManagerGetBootManagerMenu (&BootOption);
+  ASSERT_EFI_ERROR (Status);
+  Status = EfiBootManagerAddKeyOptionVariable (
+             NULL,
+             (UINT16)BootOption.OptionNumber,
+             0,
+             &F2,
+             NULL
+             );
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+  Status = EfiBootManagerAddKeyOptionVariable (
+             NULL,
+             (UINT16)BootOption.OptionNumber,
+             0,
+             &Esc,
+             NULL
+             );
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+}
+
+//
+// BDS Platform Functions
+//
+
+/**
+  Do the platform init, can be customized by OEM/IBV
+  Possible things that can be done in PlatformBootManagerBeforeConsole:
+  > Update console variable: 1. include hot-plug devices;
+  >                          2. Clear ConIn and add SOL for AMT
+  > Register new Driver#### or Boot####
+  > Register new Key####: e.g.: F12
+  > Signal ReadyToLock event
+  > Authentication action: 1. connect Auth devices;
+  >                        2. Identify auto logon user.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+  VOID
+  )
+{
+  UINT16         FrontPageTimeout;
+  EFI_STATUS     Status;
+
+  //
+  // Signal EndOfDxe PI Event
+  //
+  EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+
+  //
+  // Dispatch deferred images after EndOfDxe event.
+  //
+  EfiBootManagerDispatchDeferredImages ();
+
+  //
+  // Locate the PCI root bridges and make the PCI bus driver connect each,
+  // non-recursively. This will produce a number of child handles with PciIo on
+  // them.
+  //
+  FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
+
+  //
+  // Signal the ACPI platform driver that it can download QEMU ACPI tables.
+  //
+  EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
+
+  //
+  // Find all display class PCI devices (using the handles from the previous
+  // step), and connect them non-recursively. This should produce a number of
+  // child handles with GOPs on them.
+  //
+  FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
+
+  //
+  // Now add the device path of all handles with GOP on them to ConOut and
+  // ErrOut.
+  //
+  FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
+
+  //
+  // Add the hardcoded short-form USB keyboard device path to ConIn.
+  //
+  EfiBootManagerUpdateConsoleVariable (
+    ConIn,
+    (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,
+    NULL
+    );
+
+  //
+  // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
+  //
+  CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
+
+  EfiBootManagerUpdateConsoleVariable (
+    ConIn,
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
+    NULL
+    );
+  EfiBootManagerUpdateConsoleVariable (
+    ConOut,
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
+    NULL
+    );
+  EfiBootManagerUpdateConsoleVariable (
+    ErrOut,
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
+    NULL
+    );
+
+  //
+  // Reflect the PCD in the standard Timeout variable.
+  //
+  Status = gRT->SetVariable (
+                  EFI_TIME_OUT_VARIABLE_NAME,
+                  &gEfiGlobalVariableGuid,
+                  (EFI_VARIABLE_NON_VOLATILE |
+                   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                   EFI_VARIABLE_RUNTIME_ACCESS),
+                  sizeof FrontPageTimeout,
+                  &FrontPageTimeout
+                  );
+  DEBUG ((
+    EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
+    "%a: SetVariable(%s, %u): %r\n",
+    __func__,
+    EFI_TIME_OUT_VARIABLE_NAME,
+    FrontPageTimeout,
+    Status
+    ));
+
+  //
+  // Register platform-specific boot options and keyboard shortcuts.
+  //
+  PlatformRegisterOptionsAndKeys ();
+
+  //
+  // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
+  // instances on Virtio PCI RNG devices.
+  //
+  FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);
+}
+
+/**
+  Do the platform specific action after the console is ready
+  Possible things that can be done in PlatformBootManagerAfterConsole:
+  > Console post action:
+    > Dynamically switch output mode from 100x31 to 80x25 for certain scenario
+    > Signal console ready platform customized event
+  > Run diagnostics like memory testing
+  > Connect certain devices
+  > Dispatch additional option roms
+  > Special boot: e.g.: USB boot, enter UI
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+  VOID
+  )
+{
+  UINTN          FirmwareVerLength;
+
+  FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));
+  //
+  // Show the splash screen.
+  //
+  BootLogoEnableLogo ();
+
+  if (FirmwareVerLength > 0) {
+    Print (
+      VERSION_STRING_PREFIX L"%s\n",
+      PcdGetPtr (PcdFirmwareVersionString)
+      );
+  }
+
+  Print (L"Press ESCAPE within 10 seconds for boot options ");
+
+  //
+  // Enumerate all possible boot options, then filter and reorder them based on
+  // the QEMU configuration.
+  //
+  EfiBootManagerRefreshAllBootOption ();
+
+  //
+  // Register UEFI Shell
+  //
+  PlatformRegisterFvBootOption (
+    &gUefiShellFileGuid,
+    L"EFI Internal Shell",
+    LOAD_OPTION_ACTIVE
+    );
+
+  RemoveStaleFvFileOptions ();
+
+  PlatformBmPrintScRegisterHandler ();
+}
+
+/**
+  This function is called each second during the boot manager waits the
+  timeout.
+
+  @param TimeoutRemain  The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+  UINT16  TimeoutRemain
+  )
+{
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION  Black;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION  White;
+  UINT16                               TimeoutInitial;
+
+  TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);
+
+  //
+  // If PcdPlatformBootTimeOut is set to zero, then we consider
+  // that no progress update should be enacted.
+  //
+  if (TimeoutInitial == 0) {
+    return;
+  }
+
+  Black.Raw = 0x00000000;
+  White.Raw = 0x00FFFFFF;
+
+  BootLogoUpdateProgress (
+    White.Pixel,
+    Black.Pixel,
+    L"Start boot option",
+    White.Pixel,
+    (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,
+    0
+    );
+}
+
+/**
+  The function is called when no boot option could be launched,
+  including platform recovery options and options pointing to applications
+  built into firmware volumes.
+
+  If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_INPUT_KEY                 Key;
+  EFI_BOOT_MANAGER_LOAD_OPTION  BootManagerMenu;
+  UINTN                         Index;
+
+  //
+  // BootManagerMenu doesn't contain the correct information when return status
+  // is EFI_NOT_FOUND.
+  //
+  Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  //
+  // Normally BdsDxe does not print anything to the system console, but this is
+  // a last resort -- the end-user will likely not see any DEBUG messages
+  // logged in this situation.
+  //
+  // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
+  // here to see if it makes sense to request and wait for a keypress.
+  //
+  if (gST->ConIn != NULL) {
+    AsciiPrint (
+      "%a: No bootable option or device was found.\n"
+      "%a: Press any key to enter the Boot Manager Menu.\n",
+      gEfiCallerBaseName,
+      gEfiCallerBaseName
+      );
+    Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+    ASSERT_EFI_ERROR (Status);
+    ASSERT (Index == 0);
+
+    //
+    // Drain any queued keys.
+    //
+    while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
+      //
+      // just throw away Key
+      //
+    }
+  }
+
+  for ( ; ;) {
+    EfiBootManagerBoot (&BootManagerMenu);
+  }
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h
new file mode 100755
index 000000000000..067af555ad31
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h
@@ -0,0 +1,46 @@
+/** @file
+*  Head file for BDS Platform specific code
+*
+*  Copyright (C) 2015-2016, Red Hat, Inc.
+*  Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+*  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#ifndef _PLATFORM_BM_H_
+#define _PLATFORM_BM_H_
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+/**
+  Download the kernel, the initial ramdisk, and the kernel command line from
+  QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
+  image files, and load and start the kernel from it.
+
+  The kernel will be instructed via its command line to load the initrd from
+  the same Simple FileSystem.
+
+  @retval EFI_NOT_FOUND         Kernel image was not found.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
+  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.
+
+  @return                       Error codes from any of the underlying
+                                functions. On success, the function doesn't
+                                return.
+**/
+EFI_STATUS
+EFIAPI
+TryRunningQemuKernel (
+  VOID
+  );
+
+#endif // _PLATFORM_BM_H_
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
new file mode 100755
index 000000000000..d967f808cf7f
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -0,0 +1,71 @@
+## @file
+#  Implementation for PlatformBootManagerLib library class interfaces for RISC-V.
+#
+#  Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>
+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = DxeRiscV64PlatformBootManagerLib
+  FILE_GUID                      = 900C3D64-E5EA-0F56-1F51-64D593F374D2
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PlatformBootManagerLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = RISCV64
+#
+
+[Sources]
+  PlatformBm.c
+  PlatformBm.h
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+  SecurityPkg/SecurityPkg.dec
+  ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  BootLogoLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  PcdLib
+  PlatformBmPrintScLib
+  ReportStatusCodeLib
+  UefiBootManagerLib
+  UefiBootServicesTableLib
+  UefiLib
+  UefiRuntimeServicesTableLib
+
+[FixedPcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString
+
+[Guids]
+  gEfiEndOfDxeEventGroupGuid
+  gEfiGlobalVariableGuid
+  gRootBridgesConnectedEventGroupGuid
+  gUefiShellFileGuid
+  gEfiTtyTermGuid
+
+[Protocols]
+  gEfiGenericMemTestProtocolGuid  ## CONSUMES
+  gEfiGraphicsOutputProtocolGuid  ## CONSUMES
+  gEfiPciRootBridgeIoProtocolGuid
-- 
2.34.1



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



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver
  2023-10-19  2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
                   ` (2 preceding siblings ...)
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library John Chew
@ 2023-10-19  2:59 ` John Chew
  2023-10-19 12:14   ` Sunil V L
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
  4 siblings, 1 reply; 12+ messages in thread
From: John Chew @ 2023-10-19  2:59 UTC (permalink / raw)
  To: devel; +Cc: John Chew, Sunil V L

Some DXE drivers such as MMC's DMA can only work with 32-bit addressing.
So, EfiBootServicesData need to set within 32-bit range only.

This is achieved by setting all EfiConventionalMemory to
EfiBootServicesData before any memory allocations in the early stage of
DXE.

Cc: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.c   | 108 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.inf |  34 ++++++
 2 files changed, 142 insertions(+)

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.c
new file mode 100644
index 000000000000..a26a77661d4e
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.c
@@ -0,0 +1,108 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+EFI_STATUS
+EFIAPI
+BootServicesInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS             Status;
+  UINTN                  MemoryMapSize;
+  EFI_MEMORY_DESCRIPTOR  *MemoryMap, *Desc;
+  UINTN                  MapKey;
+  UINTN                  DescriptorSize;
+  UINT32                 DescriptorVersion;
+  EFI_PHYSICAL_ADDRESS   Addr;
+  UINTN                  Idx;
+  UINTN                  Pages;
+
+  MemoryMap     = NULL;
+  MemoryMapSize = 0;
+  Pages         = 0;
+
+  Status = gBS->GetMemoryMap (
+                              &MemoryMapSize,
+                              MemoryMap,
+                              &MapKey,
+                              &DescriptorSize,
+                              &DescriptorVersion
+                              );
+
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    Pages     = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
+    MemoryMap = AllocatePages (Pages);
+
+    //
+    // Get System MemoryMap
+    //
+    Status = gBS->GetMemoryMap (
+                                &MemoryMapSize,
+                                MemoryMap,
+                                &MapKey,
+                                &DescriptorSize,
+                                &DescriptorVersion
+                                );
+  }
+
+  if (EFI_ERROR (Status) || (MemoryMap == NULL)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to get memory map\n", __func__));
+    if (MemoryMap) {
+      FreePages ((VOID *)MemoryMap, Pages);
+    }
+
+    return EFI_SUCCESS;
+  }
+
+  Desc = MemoryMap;
+
+  //
+  // Change 64-bit EfiConventionalMemory with EfiBootServicesData
+  // So that DXE driver only allocate EfiBootServicesData in 32-bit addresses
+  //
+  for (Idx = 0; Idx < (MemoryMapSize / DescriptorSize); Idx++) {
+    if ((Desc->Type == EfiConventionalMemory) &&
+        ((Desc->PhysicalStart > MAX_UINT32) || ((Desc->PhysicalStart + Desc->NumberOfPages * EFI_PAGE_SIZE) > MAX_UINT32)))
+    {
+      if (Desc->PhysicalStart > MAX_UINT32) {
+        Addr   = Desc->PhysicalStart;
+        Status = gBS->AllocatePages (
+                                     AllocateAddress,
+                                     EfiBootServicesData,
+                                     Desc->NumberOfPages,
+                                     &Addr
+                                     );
+      } else {
+        Addr   = 0x100000000ULL;
+        Status = gBS->AllocatePages (
+                                     AllocateAddress,
+                                     EfiBootServicesData,
+                                     Desc->NumberOfPages - EFI_SIZE_TO_PAGES (0x100000000 - Desc->PhysicalStart),
+                                     &Addr
+                                     );
+      }
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Failed to allocate boot service data at %llX\n", __func__, Addr));
+      }
+    }
+
+    Desc = (EFI_MEMORY_DESCRIPTOR *)((UINT64)Desc + DescriptorSize);
+  }
+
+  FreePages ((VOID *)MemoryMap, Pages);
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.inf
new file mode 100644
index 000000000000..33a777ae5a24
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.inf
@@ -0,0 +1,34 @@
+## @file
+# DXE Boot Service driver 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                    = 0x00010019
+  BASE_NAME                      = BootServicesDxe
+  FILE_GUID                      = E7B2A7CF-4A9B-4F63-9B9E-12B34C5D6E78
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = BootServicesInitialize
+
+[Sources]
+  BootServicesDxe.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  MemoryAllocationLib
+
+[Guids]
+  gEfiEventReadyToBootGuid
+
+[Depex]
+  TRUE
-- 
2.34.1



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



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package
  2023-10-19  2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
                   ` (3 preceding siblings ...)
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver John Chew
@ 2023-10-19  2:59 ` John Chew
  2023-10-19 12:34   ` Sunil V L
  4 siblings, 1 reply; 12+ messages in thread
From: John Chew @ 2023-10-19  2:59 UTC (permalink / raw)
  To: devel; +Cc: mindachen1987, Sunil V L, John Chew

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

Cc: Sunil V L <sunilvl@ventanamicro.com>
Co-authored-by: John Chew <yuinyee.chew@starfivetech.com>
Signed-off-by: mindachen1987 <minda.chen@starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h | 24 +++++++++++
 Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec                     | 45 ++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
new file mode 100644
index 000000000000..b6875f6aa82b
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
@@ -0,0 +1,24 @@
+/** @file
+ *
+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef JH7110_H__
+#define JH7110_H__
+
+// #define JH7110_SOC_REGISTERS               (FixedPcdGet64 (PcdJH7110RegistersAddress))
+// #define JH7110_SOC_REGISTER_LENGTH         0x02000000
+
+/* Generic PCI addresses */
+#define PCIE_TOP_OF_MEM_WIN   (FixedPcdGet64 (PcdJH7110PciBusMmioAdr))
+#define PCIE_CPU_MMIO_WINDOW  (FixedPcdGet64 (PcdJH7110PciCpuMmioAdr))
+#define PCIE_BRIDGE_MMIO_LEN  (FixedPcdGet32 (PcdJH7110PciBusMmioLen))
+
+/* PCI root bridge control registers location */
+#define PCIE_REG_BASE     (FixedPcdGet64 (PcdJH7110PciRegBase))
+#define PCIE_CONFIG_BASE  (FixedPcdGet64 (PcdJH7110PciConfigRegBase))
+
+#endif /* JH7110_H__ */
diff --git a/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
new file mode 100644
index 000000000000..438557a15500
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
@@ -0,0 +1,45 @@
+## @file
+#
+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  DEC_SPECIFICATION              = 0x0001001A
+  PACKAGE_NAME                   = JH7110Pkg
+  PACKAGE_GUID                   = D4B585C5-EBCA-4779-B974-05A3CF2F10C4
+  PACKAGE_VERSION                = 1.0
+
+[Includes]
+  Include
+
+[Guids]
+  gJH7110TokenSpaceGuid = {0x44045e56, 0x7056, 0x4be6, {0x88, 0xc0, 0x49, 0x0c, 0x67, 0x90, 0x2f, 0xba}}
+
+[PcdsFixedAtBuild.common]
+# Memory map
+  gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset|0x0|UINT32|0x00000001
+
+# PCIe
+  gJH7110TokenSpaceGuid.PcdJH7110RegistersAddress|0|UINT32|0x00000002
+  gJH7110TokenSpaceGuid.PcdJH7110PciRegBase|0x2b000000|UINT64|0x00000003
+  gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioAdr|0x0|UINT64|0x00000004
+  gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioLen|0x0|UINT32|0x00000005
+  gJH7110TokenSpaceGuid.PcdJH7110PciCpuMmioAdr|0x0|UINT64|0x00000006
+  gJH7110TokenSpaceGuid.PcdJH7110PciConfigRegBase|0x940000000|UINT64|0x00000007
+
+# SPI
+  gJH7110TokenSpaceGuid.PcdSpiFlashRegBase|0|UINT32|0x10000008
+  gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase|0|UINT64|0x10000009
+  gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth|0|UINT8|0x10000010
+  gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz|0|UINT32|0x10000011
+  gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs|0|UINT32|0x10000012
+  gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs|0|UINT32|0x1000013
+  gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs|0|UINT32|0x1000014
+  gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs|0|UINT32|0x1000015
+
+[Protocols]
+  gJH7110SpiMasterProtocolGuid = { 0xA33C46E0, 0x4FB6, 0x4AA3, { 0x8E, 0x66, 0x00, 0x06, 0x9F, 0x3A, 0x11, 0x81 }}
+  gJH7110SpiFlashProtocolGuid  = { 0x5ECECDF6, 0x81DA, 0x4E10, { 0x9D, 0x4B, 0x26, 0x65, 0x8C, 0x03, 0xAB, 0xBC }}
-- 
2.34.1



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



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library John Chew
@ 2023-10-19 12:12   ` Sunil V L
  2023-10-20  9:34     ` John Chew
  0 siblings, 1 reply; 12+ messages in thread
From: Sunil V L @ 2023-10-19 12:12 UTC (permalink / raw)
  To: John Chew; +Cc: devel, Yong Li

Hi John,

On Thu, Oct 19, 2023 at 10:59:19AM +0800, John Chew wrote:
> From: JohnChew <yuinyee.chew@starfivetech.com>
> 
> For JH7110 with graphic console
>
This commit message needs to be improved. From the code, I can't find
why this library needs to be copied for your platform. Why not migrate
and use the library in ArmPkg to MdePkg?

> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Co-authored-by: Yong Li <yong.li@intel.com>
> Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
> ---
>  Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c               | 1014 ++++++++++++++++++++
>  Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h               |   46 +
>  Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf |   71 ++
>  3 files changed, 1131 insertions(+)
> 
> diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c
> new file mode 100755
> index 000000000000..b58d2c7cbcd5
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c
> @@ -0,0 +1,1014 @@
> +/** @file
> +*  Implementation for PlatformBootManagerLib library class interfaces.
> +*
> +*  Copyright (C) 2015-2016, Red Hat, Inc.
> +*  Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
> +*  Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
> +*  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> +*
> +*  SPDX-License-Identifier: BSD-2-Clause-Patent
> +*
> +**/
> +
> +#include <IndustryStandard/Pci22.h>
> +#include <IndustryStandard/Virtio095.h>
> +#include <Library/BootLogoLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PlatformBmPrintScLib.h>
> +#include <Library/QemuBootOrderLib.h>
> +#include <Library/TpmPlatformHierarchyLib.h>
> +#include <Library/UefiBootManagerLib.h>
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/FirmwareVolume2.h>
> +#include <Protocol/GraphicsOutput.h>
> +#include <Protocol/LoadedImage.h>
> +#include <Protocol/PciIo.h>
> +#include <Protocol/PciRootBridgeIo.h>
> +#include <Protocol/VirtioDevice.h>
> +#include <Guid/EventGroup.h>
> +#include <Guid/GlobalVariable.h>
> +#include <Guid/RootBridgesConnectedEventGroup.h>
> +#include <Guid/SerialPortLibVendor.h>
> +#include <Guid/TtyTerm.h>
> +
> +#include "PlatformBm.h"
> +
> +#define DP_NODE_LEN(Type)  { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
> +
> +#define VERSION_STRING_PREFIX  L"RISC-V EDK2 firmware version "
> +
> +#pragma pack (1)
> +typedef struct {
> +  VENDOR_DEVICE_PATH            SerialDxe;
> +  UART_DEVICE_PATH              Uart;
> +  VENDOR_DEFINED_DEVICE_PATH    TermType;
> +  EFI_DEVICE_PATH_PROTOCOL      End;
> +} PLATFORM_SERIAL_CONSOLE;
> +#pragma pack ()
> +
> +STATIC PLATFORM_SERIAL_CONSOLE  mSerialConsole = {
> +  //
> +  // VENDOR_DEVICE_PATH SerialDxe
> +  //
> +  {
> +    { HARDWARE_DEVICE_PATH,  HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
> +    EDKII_SERIAL_PORT_LIB_VENDOR_GUID
> +  },
> +
> +  //
> +  // UART_DEVICE_PATH Uart
> +  //
> +  {
> +    { MESSAGING_DEVICE_PATH, MSG_UART_DP,  DP_NODE_LEN (UART_DEVICE_PATH)   },
> +    0,                                      // Reserved
> +    FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
> +    FixedPcdGet8 (PcdUartDefaultDataBits),  // DataBits
> +    FixedPcdGet8 (PcdUartDefaultParity),    // Parity
> +    FixedPcdGet8 (PcdUartDefaultStopBits)   // StopBits
> +  },
> +
> +  //
> +  // VENDOR_DEFINED_DEVICE_PATH TermType
> +  //
> +  {
> +    {
> +      MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
> +      DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
> +    }
> +    //
> +    // Guid to be filled in dynamically
> +    //
> +  },
> +
> +  //
> +  // EFI_DEVICE_PATH_PROTOCOL End
> +  //
> +  {
> +    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
> +  }
> +};
> +
> +#pragma pack (1)
> +typedef struct {
> +  USB_CLASS_DEVICE_PATH       Keyboard;
> +  EFI_DEVICE_PATH_PROTOCOL    End;
> +} PLATFORM_USB_KEYBOARD;
> +#pragma pack ()
> +
> +STATIC PLATFORM_USB_KEYBOARD  mUsbKeyboard = {
> +  //
> +  // USB_CLASS_DEVICE_PATH Keyboard
> +  //
> +  {
> +    {
> +      MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
> +      DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
> +    },
> +    0xFFFF, // VendorId: any
> +    0xFFFF, // ProductId: any
> +    3,      // DeviceClass: HID
> +    1,      // DeviceSubClass: boot
> +    1       // DeviceProtocol: keyboard
> +  },
> +
> +  //
> +  // EFI_DEVICE_PATH_PROTOCOL End
> +  //
> +  {
> +    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
> +  }
> +};
> +
> +/**
> +  Check if the handle satisfies a particular condition.
> +
> +  @param[in] Handle      The handle to check.
> +  @param[in] ReportText  A caller-allocated string passed in for reporting
> +                         purposes. It must never be NULL.
> +
> +  @retval TRUE   The condition is satisfied.
> +  @retval FALSE  Otherwise. This includes the case when the condition could not
> +                 be fully evaluated due to an error.
> +**/
> +typedef
> +BOOLEAN
> +(EFIAPI *FILTER_FUNCTION)(
> +  IN EFI_HANDLE   Handle,
> +  IN CONST CHAR16 *ReportText
> +  );
> +
> +/**
> +  Process a handle.
> +
> +  @param[in] Handle      The handle to process.
> +  @param[in] ReportText  A caller-allocated string passed in for reporting
> +                         purposes. It must never be NULL.
> +**/
> +typedef
> +VOID
> +(EFIAPI *CALLBACK_FUNCTION)(
> +  IN EFI_HANDLE   Handle,
> +  IN CONST CHAR16 *ReportText
> +  );
> +
> +/**
> +  Locate all handles that carry the specified protocol, filter them with a
> +  callback function, and pass each handle that passes the filter to another
> +  callback.
> +
> +  @param[in] ProtocolGuid  The protocol to look for.
> +
> +  @param[in] Filter        The filter function to pass each handle to. If this
> +                           parameter is NULL, then all handles are processed.
> +
> +  @param[in] Process       The callback function to pass each handle to that
> +                           clears the filter.
> +**/
> +STATIC
> +VOID
> +FilterAndProcess (
> +  IN EFI_GUID           *ProtocolGuid,
> +  IN FILTER_FUNCTION    Filter         OPTIONAL,
> +  IN CALLBACK_FUNCTION  Process
> +  )
> +{
> +  EFI_STATUS  Status;
> +  EFI_HANDLE  *Handles;
> +  UINTN       NoHandles;
> +  UINTN       Idx;
> +
> +  Status = gBS->LocateHandleBuffer (
> +                  ByProtocol,
> +                  ProtocolGuid,
> +                  NULL /* SearchKey */,
> +                  &NoHandles,
> +                  &Handles
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    //
> +    // This is not an error, just an informative condition.
> +    //
> +    DEBUG ((
> +      DEBUG_VERBOSE,
> +      "%a: %g: %r\n",
> +      __func__,
> +      ProtocolGuid,
> +      Status
> +      ));
> +    return;
> +  }
> +
> +  ASSERT (NoHandles > 0);
> +  for (Idx = 0; Idx < NoHandles; ++Idx) {
> +    CHAR16         *DevicePathText;
> +    STATIC CHAR16  Fallback[] = L"<device path unavailable>";
> +
> +    //
> +    // The ConvertDevicePathToText() function handles NULL input transparently.
> +    //
> +    DevicePathText = ConvertDevicePathToText (
> +                       DevicePathFromHandle (Handles[Idx]),
> +                       FALSE, // DisplayOnly
> +                       FALSE  // AllowShortcuts
> +                       );
> +    if (DevicePathText == NULL) {
> +      DevicePathText = Fallback;
> +    }
> +
> +    if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {
> +      Process (Handles[Idx], DevicePathText);
> +    }
> +
> +    if (DevicePathText != Fallback) {
> +      FreePool (DevicePathText);
> +    }
> +  }
> +
> +  gBS->FreePool (Handles);
> +}
> +
> +/**
> +  This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
> +**/
> +STATIC
> +BOOLEAN
> +EFIAPI
> +IsPciDisplay (
> +  IN EFI_HANDLE    Handle,
> +  IN CONST CHAR16  *ReportText
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EFI_PCI_IO_PROTOCOL  *PciIo;
> +  PCI_TYPE00           Pci;
> +
> +  Status = gBS->HandleProtocol (
> +                  Handle,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **)&PciIo
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    //
> +    // This is not an error worth reporting.
> +    //
> +    return FALSE;
> +  }
> +
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint32,
> +                        0 /* Offset */,
> +                        sizeof Pci / sizeof (UINT32),
> +                        &Pci
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __func__, ReportText, Status));
> +    return FALSE;
> +  }
> +
> +  return IS_PCI_DISPLAY (&Pci);
> +}
> +
> +
> +/**
> +  This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
> +  the EFI_PCI_IO_PROTOCOL level.
> +**/
> +STATIC
> +BOOLEAN
> +EFIAPI
> +IsVirtioPciRng (

Is this required?

Thanks,
Sunil
> +  IN EFI_HANDLE    Handle,
> +  IN CONST CHAR16  *ReportText
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EFI_PCI_IO_PROTOCOL  *PciIo;
> +  UINT16               VendorId;
> +  UINT16               DeviceId;
> +  UINT8                RevisionId;
> +  BOOLEAN              Virtio10;
> +  UINT16               SubsystemId;
> +
> +  Status = gBS->HandleProtocol (
> +                  Handle,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **)&PciIo
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Read and check VendorId.
> +  //
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint16,
> +                        PCI_VENDOR_ID_OFFSET,
> +                        1,
> +                        &VendorId
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    goto PciError;
> +  }
> +
> +  if (VendorId != VIRTIO_VENDOR_ID) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Read DeviceId and RevisionId.
> +  //
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint16,
> +                        PCI_DEVICE_ID_OFFSET,
> +                        1,
> +                        &DeviceId
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    goto PciError;
> +  }
> +
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint8,
> +                        PCI_REVISION_ID_OFFSET,
> +                        1,
> +                        &RevisionId
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    goto PciError;
> +  }
> +
> +  //
> +  // From DeviceId and RevisionId, determine whether the device is a
> +  // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
> +  // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
> +  // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
> +  // only be sanity-checked, and SubsystemId will decide.
> +  //
> +  if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&
> +      (RevisionId >= 0x01))
> +  {
> +    Virtio10 = TRUE;
> +  } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {
> +    Virtio10 = FALSE;
> +  } else {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Read and check SubsystemId as dictated by Virtio10.
> +  //
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint16,
> +                        PCI_SUBSYSTEM_ID_OFFSET,
> +                        1,
> +                        &SubsystemId
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    goto PciError;
> +  }
> +
> +  if (Virtio10 && (SubsystemId >= 0x40)) {
> +    return TRUE;
> +  }
> +
> +  if (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +
> +PciError:
> +  DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __func__, ReportText, Status));
> +  return FALSE;
> +}
> +
> +/**
> +  This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
> +  the matching driver to produce all first-level child handles.
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +Connect (
> +  IN EFI_HANDLE    Handle,
> +  IN CONST CHAR16  *ReportText
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  Status = gBS->ConnectController (
> +                  Handle, // ControllerHandle
> +                  NULL,   // DriverImageHandle
> +                  NULL,   // RemainingDevicePath -- produce all children
> +                  FALSE   // Recursive
> +                  );
> +  DEBUG ((
> +    EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
> +    "%a: %s: %r\n",
> +    __func__,
> +    ReportText,
> +    Status
> +    ));
> +}
> +
> +/**
> +  This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
> +  handle, and adds it to ConOut and ErrOut.
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +AddOutput (
> +  IN EFI_HANDLE    Handle,
> +  IN CONST CHAR16  *ReportText
> +  )
> +{
> +  EFI_STATUS                Status;
> +  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
> +
> +  DevicePath = DevicePathFromHandle (Handle);
> +  if (DevicePath == NULL) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "%a: %s: handle %p: device path not found\n",
> +      __func__,
> +      ReportText,
> +      Handle
> +      ));
> +    return;
> +  }
> +
> +  Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "%a: %s: adding to ConOut: %r\n",
> +      __func__,
> +      ReportText,
> +      Status
> +      ));
> +    return;
> +  }
> +
> +  Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "%a: %s: adding to ErrOut: %r\n",
> +      __func__,
> +      ReportText,
> +      Status
> +      ));
> +    return;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_VERBOSE,
> +    "%a: %s: added to ConOut and ErrOut\n",
> +    __func__,
> +    ReportText
> +    ));
> +}
> +
> +STATIC
> +VOID
> +PlatformRegisterFvBootOption (
> +  EFI_GUID  *FileGuid,
> +  CHAR16    *Description,
> +  UINT32    Attributes
> +  )
> +{
> +  EFI_STATUS                         Status;
> +  INTN                               OptionIndex;
> +  EFI_BOOT_MANAGER_LOAD_OPTION       NewOption;
> +  EFI_BOOT_MANAGER_LOAD_OPTION       *BootOptions;
> +  UINTN                              BootOptionCount;
> +  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;
> +  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;
> +  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
> +
> +  Status = gBS->HandleProtocol (
> +                  gImageHandle,
> +                  &gEfiLoadedImageProtocolGuid,
> +                  (VOID **)&LoadedImage
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
> +  DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
> +  ASSERT (DevicePath != NULL);
> +  DevicePath = AppendDevicePathNode (
> +                 DevicePath,
> +                 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
> +                 );
> +  ASSERT (DevicePath != NULL);
> +
> +  Status = EfiBootManagerInitializeLoadOption (
> +             &NewOption,
> +             LoadOptionNumberUnassigned,
> +             LoadOptionTypeBoot,
> +             Attributes,
> +             Description,
> +             DevicePath,
> +             NULL,
> +             0
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +  FreePool (DevicePath);
> +
> +  BootOptions = EfiBootManagerGetLoadOptions (
> +                  &BootOptionCount,
> +                  LoadOptionTypeBoot
> +                  );
> +
> +  OptionIndex = EfiBootManagerFindLoadOption (
> +                  &NewOption,
> +                  BootOptions,
> +                  BootOptionCount
> +                  );
> +
> +  if (OptionIndex == -1) {
> +    Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  EfiBootManagerFreeLoadOption (&NewOption);
> +  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
> +}
> +
> +/**
> +  Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
> +  whose device paths do not resolve exactly to an FvFile in the system.
> +
> +  This removes any boot options that point to binaries built into the firmware
> +  and have become stale due to any of the following:
> +  - FvMain's base address or size changed (historical),
> +  - FvMain's FvNameGuid changed,
> +  - the FILE_GUID of the pointed-to binary changed,
> +  - the referenced binary is no longer built into the firmware.
> +
> +  EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
> +  avoids exact duplicates.
> +**/
> +STATIC
> +VOID
> +RemoveStaleFvFileOptions (
> +  VOID
> +  )
> +{
> +  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;
> +  UINTN                         BootOptionCount;
> +  UINTN                         Index;
> +
> +  BootOptions = EfiBootManagerGetLoadOptions (
> +                  &BootOptionCount,
> +                  LoadOptionTypeBoot
> +                  );
> +
> +  for (Index = 0; Index < BootOptionCount; ++Index) {
> +    EFI_DEVICE_PATH_PROTOCOL  *Node1, *Node2, *SearchNode;
> +    EFI_STATUS                Status;
> +    EFI_HANDLE                FvHandle;
> +
> +    //
> +    // If the device path starts with neither MemoryMapped(...) nor Fv(...),
> +    // then keep the boot option.
> +    //
> +    Node1 = BootOptions[Index].FilePath;
> +    if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&
> +          (DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&
> +        !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
> +          (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
> +    {
> +      continue;
> +    }
> +
> +    //
> +    // If the second device path node is not FvFile(...), then keep the boot
> +    // option.
> +    //
> +    Node2 = NextDevicePathNode (Node1);
> +    if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||
> +        (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
> +    {
> +      continue;
> +    }
> +
> +    //
> +    // Locate the Firmware Volume2 protocol instance that is denoted by the
> +    // boot option. If this lookup fails (i.e., the boot option references a
> +    // firmware volume that doesn't exist), then we'll proceed to delete the
> +    // boot option.
> +    //
> +    SearchNode = Node1;
> +    Status     = gBS->LocateDevicePath (
> +                        &gEfiFirmwareVolume2ProtocolGuid,
> +                        &SearchNode,
> +                        &FvHandle
> +                        );
> +
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // The firmware volume was found; now let's see if it contains the FvFile
> +      // identified by GUID.
> +      //
> +      EFI_FIRMWARE_VOLUME2_PROTOCOL      *FvProtocol;
> +      MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  *FvFileNode;
> +      UINTN                              BufferSize;
> +      EFI_FV_FILETYPE                    FoundType;
> +      EFI_FV_FILE_ATTRIBUTES             FileAttributes;
> +      UINT32                             AuthenticationStatus;
> +
> +      Status = gBS->HandleProtocol (
> +                      FvHandle,
> +                      &gEfiFirmwareVolume2ProtocolGuid,
> +                      (VOID **)&FvProtocol
> +                      );
> +      ASSERT_EFI_ERROR (Status);
> +
> +      FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
> +      //
> +      // Buffer==NULL means we request metadata only: BufferSize, FoundType,
> +      // FileAttributes.
> +      //
> +      Status = FvProtocol->ReadFile (
> +                             FvProtocol,
> +                             &FvFileNode->FvFileName, // NameGuid
> +                             NULL,                    // Buffer
> +                             &BufferSize,
> +                             &FoundType,
> +                             &FileAttributes,
> +                             &AuthenticationStatus
> +                             );
> +      if (!EFI_ERROR (Status)) {
> +        //
> +        // The FvFile was found. Keep the boot option.
> +        //
> +        continue;
> +      }
> +    }
> +
> +    //
> +    // Delete the boot option.
> +    //
> +    Status = EfiBootManagerDeleteLoadOptionVariable (
> +               BootOptions[Index].OptionNumber,
> +               LoadOptionTypeBoot
> +               );
> +    DEBUG_CODE_BEGIN ();
> +    CHAR16  *DevicePathString;
> +
> +    DevicePathString = ConvertDevicePathToText (
> +                         BootOptions[Index].FilePath,
> +                         FALSE,
> +                         FALSE
> +                         );
> +    DEBUG ((
> +      EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
> +      "%a: removing stale Boot#%04x %s: %r\n",
> +      __func__,
> +      (UINT32)BootOptions[Index].OptionNumber,
> +      DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
> +      Status
> +      ));
> +    if (DevicePathString != NULL) {
> +      FreePool (DevicePathString);
> +    }
> +
> +    DEBUG_CODE_END ();
> +  }
> +
> +  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
> +}
> +
> +STATIC
> +VOID
> +PlatformRegisterOptionsAndKeys (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  EFI_INPUT_KEY                 Enter;
> +  EFI_INPUT_KEY                 F2;
> +  EFI_INPUT_KEY                 Esc;
> +  EFI_BOOT_MANAGER_LOAD_OPTION  BootOption;
> +
> +  //
> +  // Register ENTER as CONTINUE key
> +  //
> +  Enter.ScanCode    = SCAN_NULL;
> +  Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
> +  Status            = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Map F2 and ESC to Boot Manager Menu
> +  //
> +  F2.ScanCode     = SCAN_F2;
> +  F2.UnicodeChar  = CHAR_NULL;
> +  Esc.ScanCode    = SCAN_ESC;
> +  Esc.UnicodeChar = CHAR_NULL;
> +  Status          = EfiBootManagerGetBootManagerMenu (&BootOption);
> +  ASSERT_EFI_ERROR (Status);
> +  Status = EfiBootManagerAddKeyOptionVariable (
> +             NULL,
> +             (UINT16)BootOption.OptionNumber,
> +             0,
> +             &F2,
> +             NULL
> +             );
> +  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
> +  Status = EfiBootManagerAddKeyOptionVariable (
> +             NULL,
> +             (UINT16)BootOption.OptionNumber,
> +             0,
> +             &Esc,
> +             NULL
> +             );
> +  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
> +}
> +
> +//
> +// BDS Platform Functions
> +//
> +
> +/**
> +  Do the platform init, can be customized by OEM/IBV
> +  Possible things that can be done in PlatformBootManagerBeforeConsole:
> +  > Update console variable: 1. include hot-plug devices;
> +  >                          2. Clear ConIn and add SOL for AMT
> +  > Register new Driver#### or Boot####
> +  > Register new Key####: e.g.: F12
> +  > Signal ReadyToLock event
> +  > Authentication action: 1. connect Auth devices;
> +  >                        2. Identify auto logon user.
> +**/
> +VOID
> +EFIAPI
> +PlatformBootManagerBeforeConsole (
> +  VOID
> +  )
> +{
> +  UINT16         FrontPageTimeout;
> +  EFI_STATUS     Status;
> +
> +  //
> +  // Signal EndOfDxe PI Event
> +  //
> +  EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
> +
> +  //
> +  // Dispatch deferred images after EndOfDxe event.
> +  //
> +  EfiBootManagerDispatchDeferredImages ();
> +
> +  //
> +  // Locate the PCI root bridges and make the PCI bus driver connect each,
> +  // non-recursively. This will produce a number of child handles with PciIo on
> +  // them.
> +  //
> +  FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
> +
> +  //
> +  // Signal the ACPI platform driver that it can download QEMU ACPI tables.
> +  //
> +  EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
> +
> +  //
> +  // Find all display class PCI devices (using the handles from the previous
> +  // step), and connect them non-recursively. This should produce a number of
> +  // child handles with GOPs on them.
> +  //
> +  FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
> +
> +  //
> +  // Now add the device path of all handles with GOP on them to ConOut and
> +  // ErrOut.
> +  //
> +  FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
> +
> +  //
> +  // Add the hardcoded short-form USB keyboard device path to ConIn.
> +  //
> +  EfiBootManagerUpdateConsoleVariable (
> +    ConIn,
> +    (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,
> +    NULL
> +    );
> +
> +  //
> +  // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
> +  //
> +  CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
> +
> +  EfiBootManagerUpdateConsoleVariable (
> +    ConIn,
> +    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
> +    NULL
> +    );
> +  EfiBootManagerUpdateConsoleVariable (
> +    ConOut,
> +    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
> +    NULL
> +    );
> +  EfiBootManagerUpdateConsoleVariable (
> +    ErrOut,
> +    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
> +    NULL
> +    );
> +
> +  //
> +  // Reflect the PCD in the standard Timeout variable.
> +  //
> +  Status = gRT->SetVariable (
> +                  EFI_TIME_OUT_VARIABLE_NAME,
> +                  &gEfiGlobalVariableGuid,
> +                  (EFI_VARIABLE_NON_VOLATILE |
> +                   EFI_VARIABLE_BOOTSERVICE_ACCESS |
> +                   EFI_VARIABLE_RUNTIME_ACCESS),
> +                  sizeof FrontPageTimeout,
> +                  &FrontPageTimeout
> +                  );
> +  DEBUG ((
> +    EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
> +    "%a: SetVariable(%s, %u): %r\n",
> +    __func__,
> +    EFI_TIME_OUT_VARIABLE_NAME,
> +    FrontPageTimeout,
> +    Status
> +    ));
> +
> +  //
> +  // Register platform-specific boot options and keyboard shortcuts.
> +  //
> +  PlatformRegisterOptionsAndKeys ();
> +
> +  //
> +  // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
> +  // instances on Virtio PCI RNG devices.
> +  //
> +  FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);
> +}
> +
> +/**
> +  Do the platform specific action after the console is ready
> +  Possible things that can be done in PlatformBootManagerAfterConsole:
> +  > Console post action:
> +    > Dynamically switch output mode from 100x31 to 80x25 for certain scenario
> +    > Signal console ready platform customized event
> +  > Run diagnostics like memory testing
> +  > Connect certain devices
> +  > Dispatch additional option roms
> +  > Special boot: e.g.: USB boot, enter UI
> +**/
> +VOID
> +EFIAPI
> +PlatformBootManagerAfterConsole (
> +  VOID
> +  )
> +{
> +  UINTN          FirmwareVerLength;
> +
> +  FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));
> +  //
> +  // Show the splash screen.
> +  //
> +  BootLogoEnableLogo ();
> +
> +  if (FirmwareVerLength > 0) {
> +    Print (
> +      VERSION_STRING_PREFIX L"%s\n",
> +      PcdGetPtr (PcdFirmwareVersionString)
> +      );
> +  }
> +
> +  Print (L"Press ESCAPE within 10 seconds for boot options ");
> +
> +  //
> +  // Enumerate all possible boot options, then filter and reorder them based on
> +  // the QEMU configuration.
> +  //
> +  EfiBootManagerRefreshAllBootOption ();
> +
> +  //
> +  // Register UEFI Shell
> +  //
> +  PlatformRegisterFvBootOption (
> +    &gUefiShellFileGuid,
> +    L"EFI Internal Shell",
> +    LOAD_OPTION_ACTIVE
> +    );
> +
> +  RemoveStaleFvFileOptions ();
> +
> +  PlatformBmPrintScRegisterHandler ();
> +}
> +
> +/**
> +  This function is called each second during the boot manager waits the
> +  timeout.
> +
> +  @param TimeoutRemain  The remaining timeout.
> +**/
> +VOID
> +EFIAPI
> +PlatformBootManagerWaitCallback (
> +  UINT16  TimeoutRemain
> +  )
> +{
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION  Black;
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION  White;
> +  UINT16                               TimeoutInitial;
> +
> +  TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);
> +
> +  //
> +  // If PcdPlatformBootTimeOut is set to zero, then we consider
> +  // that no progress update should be enacted.
> +  //
> +  if (TimeoutInitial == 0) {
> +    return;
> +  }
> +
> +  Black.Raw = 0x00000000;
> +  White.Raw = 0x00FFFFFF;
> +
> +  BootLogoUpdateProgress (
> +    White.Pixel,
> +    Black.Pixel,
> +    L"Start boot option",
> +    White.Pixel,
> +    (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,
> +    0
> +    );
> +}
> +
> +/**
> +  The function is called when no boot option could be launched,
> +  including platform recovery options and options pointing to applications
> +  built into firmware volumes.
> +
> +  If this function returns, BDS attempts to enter an infinite loop.
> +**/
> +VOID
> +EFIAPI
> +PlatformBootManagerUnableToBoot (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  EFI_INPUT_KEY                 Key;
> +  EFI_BOOT_MANAGER_LOAD_OPTION  BootManagerMenu;
> +  UINTN                         Index;
> +
> +  //
> +  // BootManagerMenu doesn't contain the correct information when return status
> +  // is EFI_NOT_FOUND.
> +  //
> +  Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
> +  if (EFI_ERROR (Status)) {
> +    return;
> +  }
> +
> +  //
> +  // Normally BdsDxe does not print anything to the system console, but this is
> +  // a last resort -- the end-user will likely not see any DEBUG messages
> +  // logged in this situation.
> +  //
> +  // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
> +  // here to see if it makes sense to request and wait for a keypress.
> +  //
> +  if (gST->ConIn != NULL) {
> +    AsciiPrint (
> +      "%a: No bootable option or device was found.\n"
> +      "%a: Press any key to enter the Boot Manager Menu.\n",
> +      gEfiCallerBaseName,
> +      gEfiCallerBaseName
> +      );
> +    Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
> +    ASSERT_EFI_ERROR (Status);
> +    ASSERT (Index == 0);
> +
> +    //
> +    // Drain any queued keys.
> +    //
> +    while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
> +      //
> +      // just throw away Key
> +      //
> +    }
> +  }
> +
> +  for ( ; ;) {
> +    EfiBootManagerBoot (&BootManagerMenu);
> +  }
> +}
> diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h
> new file mode 100755
> index 000000000000..067af555ad31
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h
> @@ -0,0 +1,46 @@
> +/** @file
> +*  Head file for BDS Platform specific code
> +*
> +*  Copyright (C) 2015-2016, Red Hat, Inc.
> +*  Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
> +*  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> +*
> +*  SPDX-License-Identifier: BSD-2-Clause-Patent
> +*
> +**/
> +
> +#ifndef _PLATFORM_BM_H_
> +#define _PLATFORM_BM_H_
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +
> +/**
> +  Download the kernel, the initial ramdisk, and the kernel command line from
> +  QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
> +  image files, and load and start the kernel from it.
> +
> +  The kernel will be instructed via its command line to load the initrd from
> +  the same Simple FileSystem.
> +
> +  @retval EFI_NOT_FOUND         Kernel image was not found.
> +  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
> +  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.
> +
> +  @return                       Error codes from any of the underlying
> +                                functions. On success, the function doesn't
> +                                return.
> +**/
> +EFI_STATUS
> +EFIAPI
> +TryRunningQemuKernel (
> +  VOID
> +  );
> +
> +#endif // _PLATFORM_BM_H_
> diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> new file mode 100755
> index 000000000000..d967f808cf7f
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> @@ -0,0 +1,71 @@
> +## @file
> +#  Implementation for PlatformBootManagerLib library class interfaces for RISC-V.
> +#
> +#  Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>
> +#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = DxeRiscV64PlatformBootManagerLib
> +  FILE_GUID                      = 900C3D64-E5EA-0F56-1F51-64D593F374D2
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = PlatformBootManagerLib|DXE_DRIVER
> +
> +#
> +# The following information is for reference only and not required by the build tools.
> +#
> +#  VALID_ARCHITECTURES           = RISCV64
> +#
> +
> +[Sources]
> +  PlatformBm.c
> +  PlatformBm.h
> +
> +[Packages]
> +  MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
> +  OvmfPkg/OvmfPkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +  ShellPkg/ShellPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  BootLogoLib
> +  DebugLib
> +  DevicePathLib
> +  MemoryAllocationLib
> +  PcdLib
> +  PlatformBmPrintScLib
> +  ReportStatusCodeLib
> +  UefiBootManagerLib
> +  UefiBootServicesTableLib
> +  UefiLib
> +  UefiRuntimeServicesTableLib
> +
> +[FixedPcd]
> +  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
> +  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
> +  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
> +  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
> +
> +[Pcd]
> +  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString
> +
> +[Guids]
> +  gEfiEndOfDxeEventGroupGuid
> +  gEfiGlobalVariableGuid
> +  gRootBridgesConnectedEventGroupGuid
> +  gUefiShellFileGuid
> +  gEfiTtyTermGuid
> +
> +[Protocols]
> +  gEfiGenericMemTestProtocolGuid  ## CONSUMES
> +  gEfiGraphicsOutputProtocolGuid  ## CONSUMES
> +  gEfiPciRootBridgeIoProtocolGuid
> -- 
> 2.34.1
> 


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



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver John Chew
@ 2023-10-19 12:14   ` Sunil V L
  2023-10-20  8:45     ` John Chew
  0 siblings, 1 reply; 12+ messages in thread
From: Sunil V L @ 2023-10-19 12:14 UTC (permalink / raw)
  To: John Chew; +Cc: devel

On Thu, Oct 19, 2023 at 10:59:20AM +0800, John Chew wrote:
> Some DXE drivers such as MMC's DMA can only work with 32-bit addressing.
> So, EfiBootServicesData need to set within 32-bit range only.
> 
> This is achieved by setting all EfiConventionalMemory to
> EfiBootServicesData before any memory allocations in the early stage of
> DXE.
> 
Hi John,

I think this is a fragile workaround. Why not MMC driver allocate 32-bit
memory using EFI API?

Thanks,
Sunil


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



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package
  2023-10-19  2:59 ` [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
@ 2023-10-19 12:34   ` Sunil V L
  2023-10-20  8:58     ` John Chew
  0 siblings, 1 reply; 12+ messages in thread
From: Sunil V L @ 2023-10-19 12:34 UTC (permalink / raw)
  To: John Chew; +Cc: devel, mindachen1987

Hi John,
On Thu, Oct 19, 2023 at 10:59:21AM +0800, John Chew wrote:
> From: mindachen1987 <minda.chen@starfivetech.com>
> 
The patch should have commit message more than one liner. Same comment
for PATCH 1/6 and 2/6.

Also, there should be a patch in the series to add maintainer entry for
your platform.

> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Co-authored-by: John Chew <yuinyee.chew@starfivetech.com>
> Signed-off-by: mindachen1987 <minda.chen@starfivetech.com>
> ---
>  Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h | 24 +++++++++++
>  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec                     | 45 ++++++++++++++++++++
>  2 files changed, 69 insertions(+)
> 
> diff --git a/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
> new file mode 100644
> index 000000000000..b6875f6aa82b
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
> @@ -0,0 +1,24 @@
> +/** @file
> + *
> + *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> + *
> + *  SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> + **/
> +
> +#ifndef JH7110_H__
> +#define JH7110_H__
> +
> +// #define JH7110_SOC_REGISTERS               (FixedPcdGet64 (PcdJH7110RegistersAddress))
> +// #define JH7110_SOC_REGISTER_LENGTH         0x02000000
> +
Could you remove these commented code?

Thanks,
Sunil

> +/* Generic PCI addresses */
> +#define PCIE_TOP_OF_MEM_WIN   (FixedPcdGet64 (PcdJH7110PciBusMmioAdr))
> +#define PCIE_CPU_MMIO_WINDOW  (FixedPcdGet64 (PcdJH7110PciCpuMmioAdr))
> +#define PCIE_BRIDGE_MMIO_LEN  (FixedPcdGet32 (PcdJH7110PciBusMmioLen))
> +
> +/* PCI root bridge control registers location */
> +#define PCIE_REG_BASE     (FixedPcdGet64 (PcdJH7110PciRegBase))
> +#define PCIE_CONFIG_BASE  (FixedPcdGet64 (PcdJH7110PciConfigRegBase))
> +
> +#endif /* JH7110_H__ */
> diff --git a/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
> new file mode 100644
> index 000000000000..438557a15500
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
> @@ -0,0 +1,45 @@
> +## @file
> +#
> +#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  DEC_SPECIFICATION              = 0x0001001A
> +  PACKAGE_NAME                   = JH7110Pkg
> +  PACKAGE_GUID                   = D4B585C5-EBCA-4779-B974-05A3CF2F10C4
> +  PACKAGE_VERSION                = 1.0
> +
> +[Includes]
> +  Include
> +
> +[Guids]
> +  gJH7110TokenSpaceGuid = {0x44045e56, 0x7056, 0x4be6, {0x88, 0xc0, 0x49, 0x0c, 0x67, 0x90, 0x2f, 0xba}}
> +
> +[PcdsFixedAtBuild.common]
> +# Memory map
> +  gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset|0x0|UINT32|0x00000001
> +
> +# PCIe
> +  gJH7110TokenSpaceGuid.PcdJH7110RegistersAddress|0|UINT32|0x00000002
> +  gJH7110TokenSpaceGuid.PcdJH7110PciRegBase|0x2b000000|UINT64|0x00000003
> +  gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioAdr|0x0|UINT64|0x00000004
> +  gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioLen|0x0|UINT32|0x00000005
> +  gJH7110TokenSpaceGuid.PcdJH7110PciCpuMmioAdr|0x0|UINT64|0x00000006
> +  gJH7110TokenSpaceGuid.PcdJH7110PciConfigRegBase|0x940000000|UINT64|0x00000007
> +
> +# SPI
> +  gJH7110TokenSpaceGuid.PcdSpiFlashRegBase|0|UINT32|0x10000008
> +  gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase|0|UINT64|0x10000009
> +  gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth|0|UINT8|0x10000010
> +  gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz|0|UINT32|0x10000011
> +  gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs|0|UINT32|0x10000012
> +  gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs|0|UINT32|0x1000013
> +  gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs|0|UINT32|0x1000014
> +  gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs|0|UINT32|0x1000015
> +
> +[Protocols]
> +  gJH7110SpiMasterProtocolGuid = { 0xA33C46E0, 0x4FB6, 0x4AA3, { 0x8E, 0x66, 0x00, 0x06, 0x9F, 0x3A, 0x11, 0x81 }}
> +  gJH7110SpiFlashProtocolGuid  = { 0x5ECECDF6, 0x81DA, 0x4E10, { 0x9D, 0x4B, 0x26, 0x65, 0x8C, 0x03, 0xAB, 0xBC }}
> -- 
> 2.34.1
> 


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



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver
  2023-10-19 12:14   ` Sunil V L
@ 2023-10-20  8:45     ` John Chew
  0 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-20  8:45 UTC (permalink / raw)
  To: Sunil V L, devel

[-- Attachment #1: Type: text/plain, Size: 970 bytes --]

Hi Sunil,

You're right.

The MMC DMA destination buffer (64-bit) actually allocated in EDK2 code and passed into the EDK2-platform MMC driver.

Now that you mention it, I think I can allocate another buffer (force to use 32-bit) in the MMC driver and use that buffer for tx/rx.

Then, copy the content from the buffer (32-bit) to the MMC destination buffer (64-bit). In this case, there is no need to change any code

in EDK2 and this "boot service memory allocation" driver is no longer needed.

I will remove this driver and add the handling in DwEmmcDxe.c in Patch V2.

Thank you!! =)


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



[-- Attachment #2: Type: text/html, Size: 1496 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package
  2023-10-19 12:34   ` Sunil V L
@ 2023-10-20  8:58     ` John Chew
  0 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-20  8:58 UTC (permalink / raw)
  To: Sunil V L, devel

[-- Attachment #1: Type: text/plain, Size: 683 bytes --]

On Thu, Oct 19, 2023 at 08:34 PM, Sunil V L wrote:

> 
> The patch should have commit message more than one liner. Same comment
> for PATCH 1/6 and 2/6

Hi Sunil,

Okay sure. I will remove the commented code.

Let me improve the commit message and include all maintainers in patch V2.

Thanks =)

John


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



[-- Attachment #2: Type: text/html, Size: 1175 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library
  2023-10-19 12:12   ` Sunil V L
@ 2023-10-20  9:34     ` John Chew
  0 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-20  9:34 UTC (permalink / raw)
  To: Sunil V L, devel

[-- Attachment #1: Type: text/plain, Size: 683 bytes --]

Hi Sunil,

Actually, we can use:

Platform/RISC-V/PlatformPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf

I think there is no need for us to have our own PlatformBootManager library.

This library is here for debugging and development.

I will update this in patch v2.

Thanks! =)

John


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



[-- Attachment #2: Type: text/html, Size: 1188 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2023-10-20  9:34 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-19  2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
2023-10-19  2:59 ` [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
2023-10-19  2:59 ` [edk2-devel] [PATCH v1 3/6] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
2023-10-19  2:59 ` [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library John Chew
2023-10-19 12:12   ` Sunil V L
2023-10-20  9:34     ` John Chew
2023-10-19  2:59 ` [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver John Chew
2023-10-19 12:14   ` Sunil V L
2023-10-20  8:45     ` John Chew
2023-10-19  2:59 ` [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
2023-10-19 12:34   ` Sunil V L
2023-10-20  8:58     ` John Chew

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox