public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH v2 0/4] Patches for JH7110 SoC platform
@ 2023-10-23  7:18 John Chew
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 1/4] StarFive/JH7110Pkg: Add Pci controller driver John Chew
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: John Chew @ 2023-10-23  7:18 UTC (permalink / raw)
  To: devel; +Cc: John Chew, Sunil V L, Leif Lindholm, Michael D Kinney,
	Cc : Li Yong

v2:
  - Include all maintainer in all patches in this series [Sunil]
  - Added missing commit message to patches 1/6, 2/6, 6/6 [Sunil]
  - Remove commented code in JH7110.h [Sunil]
  - Remove BootServicesDxe/BootServicesDxe.inf, as it is not required 
    anymore because memory allocation is handle by MMC driver [Sunil]
  - Remove PlatformBootManagerLib.inf and change PlatformBootManagerLib to
    "Platform/RISC-V/PlatformPkg/.../PlatformBootManagerLib.inf" [Sunil] 
  - Added PCDs for PCIE (Please refer to patch 0001 for details) [John Chew]

v1:
  - In this patches it include all the platform specific drivers/protocol
    that is being use for JH7110 SoC platform. All the drivers includes:
      1. PCIE driver for NVME and USB (GT710 graphic in progress)
      2. QSPI Flash driver for efi variable
      3. FVB driver for efi variable
      4. Boot service memory allocation driver
      5. Platform boot manager for graphical console display

  Reference branch:
    https://github.com/johnchewyy/edkii-platforms/tree/vf2_jh7110_devel_upstream

Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Cc: Li Yong <yong.li@intel.com>

John Chew (2):
  StarFive/JH7110Pkg: Add SPI protocol and driver support
  StarFive/JH7110Pkg: Add firmware volume block protocol

mindachen1987 (2):
  StarFive/JH7110Pkg: Add Pci controller driver
  StarFive/JH7110Pkg: Add JH7110 Silicon Package

 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 +
 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/IndustryStandard/JH7110.h                      |   21 +
 Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h                                 |  163 +++
 Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h                            |   88 ++
 Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec                                          |   57 +
 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c            |  263 ++++
 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf          |   61 +
 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c |  406 ++++++
 Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c                  | 1460 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf                |   33 +
 18 files changed, 5452 insertions(+)
 create mode 100644 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c
 create mode 100644 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h
 create mode 100644 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf
 create mode 100755 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c
 create mode 100644 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h
 create mode 100644 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf
 create mode 100755 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c
 create mode 100755 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h
 create mode 100644 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf
 create mode 100644 Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
 create mode 100644 Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h
 create mode 100644 Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h
 create mode 100644 Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
 create mode 100644 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
 create mode 100644 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
 create mode 100644 Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
 create mode 100644 Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c
 create mode 100644 Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf

-- 
2.34.1



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



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

* [edk2-devel] [PATCH v2 1/4] StarFive/JH7110Pkg: Add Pci controller driver
  2023-10-23  7:18 [edk2-devel] [PATCH v2 0/4] Patches for JH7110 SoC platform John Chew
@ 2023-10-23  7:18 ` John Chew
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 2/4] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: John Chew @ 2023-10-23  7:18 UTC (permalink / raw)
  To: devel
  Cc: mindachen1987, Sunil V L, Leif Lindholm, Michael D Kinney,
	Cc : Li Yong, John Chew

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

v2:
  - Change Bus, IO, Mem and MemAbove4G "#define" into
    PCDs [John Chew]

v1:

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

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

  - Non-prefetachable memory is not used in this configuration.

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

diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
new file mode 100644
index 000000000000..8b46f6ff58e5
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
@@ -0,0 +1,263 @@
+/** @file

+ *

+ * PCI Host Bridge Library instance for StarFive JH7110 SOC

+ *

+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ * SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#include <IndustryStandard/JH7110.h>

+#include <IndustryStandard/Pci22.h>

+#include <Library/DebugLib.h>

+#include <Library/DevicePathLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/PcdLib.h>

+#include <Library/PciHostBridgeLib.h>

+#include <PiDxe.h>

+#include <Protocol/PciRootBridgeIo.h>

+#include <Protocol/PciHostBridgeResourceAllocation.h>

+

+#pragma pack(1)

+

+typedef PACKED struct {

+  ACPI_HID_DEVICE_PATH        AcpiDevicePath;

+  EFI_DEVICE_PATH_PROTOCOL    EndDevicePath;

+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;

+

+#pragma pack ()

+

+STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH  mEfiPciRootBridgeDevicePath[] = {

+  {

+    {

+      {

+        ACPI_DEVICE_PATH,

+        ACPI_DP,

+        {

+          (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),

+          (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)

+        }

+      },

+      EISA_PNP_ID (0x0A08), // PCI Express

+      0

+    },

+

+    {

+      END_DEVICE_PATH_TYPE,

+      END_ENTIRE_DEVICE_PATH_SUBTYPE,

+      {

+        END_DEVICE_PATH_LENGTH,

+        0

+      }

+    }

+  },

+

+  {

+    {

+      {

+        ACPI_DEVICE_PATH,

+        ACPI_DP,

+        {

+          (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),

+          (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)

+        }

+      },

+      EISA_PNP_ID (0x0A08), // PCI Express

+      1

+    },

+

+    {

+      END_DEVICE_PATH_TYPE,

+      END_ENTIRE_DEVICE_PATH_SUBTYPE,

+      {

+        END_DEVICE_PATH_LENGTH,

+        0

+      }

+    }

+  },

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED

+CHAR16  *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {

+  L"Mem", L"I/O", L"Bus"

+};

+

+//

+// See description in MdeModulePkg/Include/Library/PciHostBridgeLib.h

+//

+PCI_ROOT_BRIDGE  mPciRootBridges[] = {

+  {

+    0,                                      // Segment

+    0,                                      // Supports

+    0,                                      // Attributes

+    FALSE,                                  // DmaAbove4G

+    FALSE,                                  // NoExtendedConfigSpace (true=256 byte config, false=4k)

+    FALSE,                                  // ResourceAssigned

+    EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |

+    EFI_PCI_HOST_BRIDGE_MEM64_DECODE,       // AllocationAttributes

+    {

+      // Bus

+      FixedPcdGet32 (PcdPciBusMin),

+      FixedPcdGet32 (PcdPciBusMax)

+    }, {

+      // Io

+      FixedPcdGet64 (PcdPciIoBase),

+      FixedPcdGet64 (PcdPciIoBase) + FixedPcdGet64 (PcdPciIoSize) - 1,

+      MAX_UINT64 - FixedPcdGet64 (PcdPciIoOffset) + 1

+    }, {

+      // Mem

+      FixedPcdGet32 (PcdPci0Mmio32Base),

+      FixedPcdGet32 (PcdPci0Mmio32Base) + FixedPcdGet32 (PcdPci0Mmio32Size) - 1

+    }, {

+      // MemAbove4G

+      FixedPcdGet64 (PcdPci0Mmio64Base),

+      FixedPcdGet64 (PcdPci0Mmio64Base) + FixedPcdGet64 (PcdPci0Mmio64Size) - 1

+    },

+    {

+      // Pefetchable Mem

+      MAX_UINT32,

+      0x0

+    }, {

+      // Pefetchable MemAbove4G

+      MAX_UINT64,

+      0x0

+    },

+    (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[0]

+  },

+  {

+    1,                                  // Segment

+    0,                                  // Supports

+    0,                                  // Attributes

+    FALSE,                              // DmaAbove4G

+    FALSE,                              // NoExtendedConfigSpace (true=256 byte config, false=4k)

+    FALSE,                              // ResourceAssigned

+    EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |

+    EFI_PCI_HOST_BRIDGE_MEM64_DECODE,   // AllocationAttributes

+    {

+      // Bus

+      FixedPcdGet32 (PcdPciBusMin),

+      FixedPcdGet32 (PcdPciBusMax)

+    }, {

+      // Io

+      FixedPcdGet64 (PcdPciIoBase),

+      FixedPcdGet64 (PcdPciIoBase) + FixedPcdGet64 (PcdPciIoSize) - 1,

+      MAX_UINT64 - FixedPcdGet64 (PcdPciIoOffset) + 1

+    }, {

+      // Mem

+      FixedPcdGet32 (PcdPci1Mmio32Base),

+      FixedPcdGet32 (PcdPci1Mmio32Base) + FixedPcdGet32 (PcdPci1Mmio32Size) - 1

+    }, {

+      // MemAbove4G

+      FixedPcdGet64 (PcdPci1Mmio64Base),

+      FixedPcdGet64 (PcdPci1Mmio64Base) + FixedPcdGet64 (PcdPci1Mmio64Size) - 1

+    },

+    {

+      // Pefetchable Mem

+      MAX_UINT32,

+      0x0

+    }, {

+      // Pefetchable MemAbove4G

+      MAX_UINT64,

+      0x0

+    },

+    (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[1]

+  }

+};

+

+/**

+  Return all the root bridge instances in an array.

+

+  @param Count  Return the count of root bridge instances.

+

+  @return All the root bridge instances in an array.

+          The array should be passed into PciHostBridgeFreeRootBridges()

+          when it's not used.

+**/

+PCI_ROOT_BRIDGE *

+EFIAPI

+PciHostBridgeGetRootBridges (

+  OUT UINTN  *Count

+  )

+{

+  *Count = ARRAY_SIZE (mPciRootBridges);

+  return mPciRootBridges;

+}

+

+/**

+  Free the root bridge instances array returned from PciHostBridgeGetRootBridges().

+

+  @param Bridges The root bridge instances array.

+  @param Count   The count of the array.

+**/

+VOID

+EFIAPI

+PciHostBridgeFreeRootBridges (

+  PCI_ROOT_BRIDGE  *Bridges,

+  UINTN            Count

+  )

+{

+}

+

+/**

+  Inform the platform that the resource conflict happens.

+

+  @param HostBridgeHandle Handle of the Host Bridge.

+  @param Configuration    Pointer to PCI I/O and PCI memory resource

+                          descriptors. The Configuration contains the resources

+                          for all the root bridges. The resource for each root

+                          bridge is terminated with END descriptor and an

+                          additional END is appended indicating the end of the

+                          entire resources. The resource descriptor field

+                          values follow the description in

+                          EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL

+                          .SubmitResources().

+**/

+VOID

+EFIAPI

+PciHostBridgeResourceConflict (

+  EFI_HANDLE  HostBridgeHandle,

+  VOID        *Configuration

+  )

+{

+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Descriptor;

+  UINTN                              RootBridgeIndex;

+

+  DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));

+

+  RootBridgeIndex = 0;

+  Descriptor      = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;

+  while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {

+    DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));

+    for ( ; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {

+      ASSERT (

+              Descriptor->ResType <

+              ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr)

+              );

+      DEBUG (

+             (DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",

+              mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],

+              Descriptor->AddrLen, Descriptor->AddrRangeMax

+             )

+             );

+      if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {

+        DEBUG (

+               (DEBUG_ERROR, "     Granularity/SpecificFlag = %ld / %02x%s\n",

+                Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,

+                ((Descriptor->SpecificFlag &

+                  EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE

+                  ) != 0) ? L" (Prefetchable)" : L""

+               )

+               );

+      }

+    }

+

+    //

+    // Skip the END descriptor for root bridge

+    //

+    ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);

+    Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(

+                                                       (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1

+                                                       );

+  }

+}

diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
new file mode 100644
index 000000000000..e18e8e57829f
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -0,0 +1,61 @@
+## @file

+#

+#  PCI Host Bridge Library instance for StarFive JH7110 SOC

+#  Liberally borrowed from the SynQuacer

+#

+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+#

+#  SPDX-License-Identifier: BSD-2-Clause-Patent

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010019

+  BASE_NAME                      = PciHostBridgeLib

+  FILE_GUID                      = 606d906f-eba7-d5c6-fcf0-6aeedea00193

+  MODULE_TYPE                    = DXE_DRIVER

+  VERSION_STRING                 = 1.0

+  LIBRARY_CLASS                  = PciHostBridgeLib|DXE_DRIVER

+  CONSTRUCTOR                    = JH7110PciHostBridgeLibConstructor

+

+#

+# The following information is for reference only and not required by the build

+# tools.

+#

+#  VALID_ARCHITECTURES           = ARM AARCH64 RISCV64

+#

+

+[Sources]

+  PciHostBridgeLib.c

+  PciHostBridgeLibConstructor.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec

+

+[LibraryClasses]

+  DebugLib

+  DevicePathLib

+  MemoryAllocationLib

+  PcdLib

+  UefiBootServicesTableLib

+

+[FixedPcd]

+  gJH7110TokenSpaceGuid.PcdPciRegBase

+  gJH7110TokenSpaceGuid.PcdPciBusMmioAdr

+  gJH7110TokenSpaceGuid.PcdPciBusMmioLen

+  gJH7110TokenSpaceGuid.PcdPciCpuMmioAdr

+  gJH7110TokenSpaceGuid.PcdPciBusMin

+  gJH7110TokenSpaceGuid.PcdPciBusMax

+  gJH7110TokenSpaceGuid.PcdPciIoBase

+  gJH7110TokenSpaceGuid.PcdPciIoSize

+  gJH7110TokenSpaceGuid.PcdPciIoOffset

+  gJH7110TokenSpaceGuid.PcdPci0Mmio32Base

+  gJH7110TokenSpaceGuid.PcdPci0Mmio32Size

+  gJH7110TokenSpaceGuid.PcdPci0Mmio64Base

+  gJH7110TokenSpaceGuid.PcdPci0Mmio64Size

+  gJH7110TokenSpaceGuid.PcdPci1Mmio32Base

+  gJH7110TokenSpaceGuid.PcdPci1Mmio32Size

+  gJH7110TokenSpaceGuid.PcdPci1Mmio64Base

+  gJH7110TokenSpaceGuid.PcdPci1Mmio64Size

diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
new file mode 100644
index 000000000000..cc505f2723d1
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
@@ -0,0 +1,406 @@
+/** @file

+ *

+ * PCI Host Bridge Library instance for StarFive JH7110 SOC

+ *

+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ * SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ * This module initializes the Pci as close to a standard

+ * PCI root complex as possible. The general information

+ * for this driver was sourced from.

+ *

+ *

+ **/

+

+#include <IndustryStandard/JH7110.h>

+#include <IndustryStandard/Pci22.h>

+#include <Library/DebugLib.h>

+#include <Library/IoLib.h>

+#include <Library/PcdLib.h>

+#include <Library/PciHostBridgeLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <PiDxe.h>

+#include <Protocol/PciHostBridgeResourceAllocation.h>

+#include <Library/TimerLib.h>

+

+#define RegWrite(addr, data)  MmioWrite32((addr), (data))

+#define RegRead(addr, data)   ((data) = MmioRead32 (addr))

+

+#define STG_SYSCON_BASE  0x10240000

+

+#define STG_SYSCON_K_RP_NEP_MASK    (1 << 8)

+#define STG_SYSCON_CKREF_SRC_SHIFT  18

+#define STG_SYSCON_CKREF_SRC_MASK   (0x3 << 18)

+#define STG_SYSCON_CLKREQ_MASK      (1 << 22)

+#define STG_SYSCON_BASE             0x10240000

+#define SYS_CLK_BASE                0x13020000

+#define STG_CLK_BASE                0x10230000

+#define SYS_CLK_NOC_OFFSET          0x98

+#define STG_PCIE_CLK_OFFSET         0x20

+#define STG_PCIE_CLKS               0xc

+#define STG_PCIE_RESET_OFFSET       0x74

+#define SYS_GPIO_BASE               0x13040000

+

+#define PREF_MEM_WIN_64_SUPPORT  (1 << 3)

+#define PMSG_LTR_SUPPORT         (1 << 2)

+#define PDLA_LINK_SPEED_GEN2     (1 << 12)

+#define PLDA_FUNCTION_DIS        (1 << 15)

+#define PLDA_FUNC_NUM            4

+#define PLDA_PHY_FUNC_SHIFT      9

+#define PLDA_RP_ENABLE           1

+

+#define PCIE_BASIC_STATUS  0x018

+#define PCIE_CFGNUM        0x140

+#define IMASK_LOCAL        0x180

+#define ISTATUS_LOCAL      0x184

+#define IMSI_ADDR          0x190

+#define ISTATUS_MSI        0x194

+#define CFG_SPACE          0x1000

+#define GEN_SETTINGS       0x80

+#define PCIE_PCI_IDS       0x9C

+#define PCIE_WINROM        0xFC

+#define PMSG_SUPPORT_RX    0x3F0

+#define PCI_MISC           0xB4

+

+#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK   0x7FFF00

+#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT  0x8

+#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK   0x7FFF

+#define STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT  0x0

+

+#define XR3PCI_ATR_AXI4_SLV0       0x800

+#define XR3PCI_ATR_SRC_ADDR_LOW    0x0

+#define XR3PCI_ATR_SRC_ADDR_HIGH   0x4

+#define XR3PCI_ATR_TRSL_ADDR_LOW   0x8

+#define XR3PCI_ATR_TRSL_ADDR_HIGH  0xc

+#define XR3PCI_ATR_TRSL_PARAM      0x10

+#define XR3PCI_ATR_TABLE_OFFSET    0x20

+#define XR3PCI_ATR_MAX_TABLE_NUM   8

+

+#define XR3PCI_ATR_SRC_ADDR_MASK       0xfffff000

+#define XR3PCI_ATR_TRSL_ADDR_MASK      0xfffff000

+#define XR3PCI_ATR_SRC_WIN_SIZE_SHIFT  1

+#define XR3_PCI_ECAM_SIZE              28

+

+#define IDS_PCI_TO_PCI_BRIDGE  0x060400

+#define IDS_CLASS_CODE_SHIFT   8

+#define SYS_GPIO_OUTPUT_OFF    0x40

+

+UINT32  AtrTableNum;

+UINT64  PCIE_CFG_BASE[2]      = { FixedPcdGet32 (PcdPci0Mmio64Base) + FixedPcdGet32 (PcdPci0Mmio64Size),

+                                  FixedPcdGet32 (PcdPci1Mmio64Base) + FixedPcdGet32 (PcdPci1Mmio64Size) };

+UINT64  PCI_MEMREGION_32[2]   = { FixedPcdGet32 (PcdPci0Mmio32Base), FixedPcdGet32 (PcdPci1Mmio32Base) };

+UINT64  PCI_MEMREGION_64[2]   = { FixedPcdGet32 (PcdPci0Mmio64Base), FixedPcdGet32 (PcdPci1Mmio64Base) };

+UINT64  PCI_MEMREGION_SIZE[2] = { 27, 30 };

+UINT32  STG_ARFUNC_OFFSET[2]  = { 0xc0, 0x270 };

+UINT32  STG_AWFUNC_OFFSET[2]  = { 0xc4, 0x274 };

+UINT32  STG_RP_REP_OFFSET[2]  = { 0x130, 0x2e0 };

+UINT32  PCIE_GPIO[2]          = { 26, 28 };

+

+STATIC inline UINT64

+GetPcieRegBase (

+  IN UINT32  Port

+  )

+{

+  return PCIE_REG_BASE + Port * 0x1000000;

+}

+

+VOID

+PcieRegWrite (

+  IN UINT32  Port,

+  IN UINTN   Offset,

+  IN UINT32  Value

+  )

+{

+  UINT64  Base = GetPcieRegBase (Port);

+

+  RegWrite ((UINT64)Base + Offset, Value);

+}

+

+UINT32

+PcieRegRead (

+  IN UINT32  Port,

+  IN UINTN   Offset

+  )

+{

+  UINT32  Value = 0;

+  UINT64  Base  = GetPcieRegBase (Port);

+

+  RegRead ((UINT64)Base + Offset, Value);

+  return Value;

+}

+

+STATIC VOID

+PcieUpdatebits (

+  IN UINT64  Base,

+  IN UINTN   Offset,

+  IN UINT32  Mask,

+  IN UINT32  val

+  )

+{

+  UINT32  Value = 0;

+

+  Value  = MmioRead32 ((UINT64)Base + Offset);

+  Value &= ~Mask;

+  Value |= val;

+  MmioWrite32 ((UINT64)Base + Offset, Value);

+}

+

+STATIC

+VOID

+PcieFuncSet (

+  IN UINT32  Port

+  )

+{

+  INTN    i;

+  UINT32  Value;

+  UINT64  Base = GetPcieRegBase (Port);

+

+  /* Disable physical functions except #0 */

+  for (i = 1; i < PLDA_FUNC_NUM; i++) {

+    PcieUpdatebits (

+                    STG_SYSCON_BASE,

+                    STG_ARFUNC_OFFSET[Port],

+                    STG_SYSCON_AXI4_SLVL_ARFUNC_MASK,

+                    (i << PLDA_PHY_FUNC_SHIFT) <<

+                    STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT

+                    );

+    PcieUpdatebits (

+                    STG_SYSCON_BASE,

+                    STG_AWFUNC_OFFSET[Port],

+                    STG_SYSCON_AXI4_SLVL_AWFUNC_MASK,

+                    (i << PLDA_PHY_FUNC_SHIFT) <<

+                    STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT

+                    );

+    PcieUpdatebits (

+                    Base,

+                    PCI_MISC,

+                    PLDA_FUNCTION_DIS,

+                    PLDA_FUNCTION_DIS

+                    );

+  }

+

+  PcieUpdatebits (

+                  STG_SYSCON_BASE,

+                  STG_ARFUNC_OFFSET[Port],

+                  STG_SYSCON_AXI4_SLVL_ARFUNC_MASK,

+                  0

+                  );

+  PcieUpdatebits (

+                  STG_SYSCON_BASE,

+                  STG_AWFUNC_OFFSET[Port],

+                  STG_SYSCON_AXI4_SLVL_AWFUNC_MASK,

+                  0

+                  );

+

+  /* Enable root port*/

+  PcieUpdatebits (

+                  Base,

+                  GEN_SETTINGS,

+                  PLDA_RP_ENABLE,

+                  PLDA_RP_ENABLE

+                  );

+

+  Value = (IDS_PCI_TO_PCI_BRIDGE << IDS_CLASS_CODE_SHIFT);

+  PcieRegWrite (Port, PCIE_PCI_IDS, Value);

+

+  PcieUpdatebits (

+                  Base,

+                  PMSG_SUPPORT_RX,

+                  PMSG_LTR_SUPPORT,

+                  0

+                  );

+

+  /* Prefetchable memory window 64-bit addressing support */

+  PcieUpdatebits (

+                  Base,

+                  PCIE_WINROM,

+                  PREF_MEM_WIN_64_SUPPORT,

+                  PREF_MEM_WIN_64_SUPPORT

+                  );

+}

+

+STATIC

+VOID

+PcieSTGInit (

+  IN UINT32  Port

+  )

+{

+  PcieUpdatebits (

+                  STG_SYSCON_BASE,

+                  STG_RP_REP_OFFSET[Port],

+                  STG_SYSCON_K_RP_NEP_MASK,

+                  STG_SYSCON_K_RP_NEP_MASK

+                  );

+  PcieUpdatebits (

+                  STG_SYSCON_BASE,

+                  STG_AWFUNC_OFFSET[Port],

+                  STG_SYSCON_CKREF_SRC_MASK,

+                  2 << STG_SYSCON_CKREF_SRC_SHIFT

+                  );

+  PcieUpdatebits (

+                  STG_SYSCON_BASE,

+                  STG_AWFUNC_OFFSET[Port],

+                  STG_SYSCON_CLKREQ_MASK,

+                  STG_SYSCON_CLKREQ_MASK

+                  );

+}

+

+STATIC

+VOID

+PcieClockInit (

+  IN UINT32  Port

+  )

+{

+  RegWrite (

+            STG_CLK_BASE + STG_PCIE_CLK_OFFSET

+            + Port * STG_PCIE_CLKS,

+            1 << 31

+            ); /*axi mst0*/

+  RegWrite (

+            STG_CLK_BASE + STG_PCIE_CLK_OFFSET

+            + Port * STG_PCIE_CLKS + 4,

+            1 << 31

+            ); /* apb */

+  RegWrite (

+            STG_CLK_BASE + STG_PCIE_CLK_OFFSET

+            + Port * STG_PCIE_CLKS + 8,

+            1 << 31

+            ); /* tl0 */

+}

+

+STATIC

+VOID

+PcieResetDeassert (

+  IN UINT32  Port

+  )

+{

+  UINT32  PortOffset = Port * 6 + 11;

+

+  PcieUpdatebits (

+                  STG_CLK_BASE,

+                  STG_PCIE_RESET_OFFSET,

+                  0x3f << (PortOffset),

+                  0

+                  ); /*reset all*/

+}

+

+VOID

+PcieResetAssert (

+  IN UINT32  Port

+  )

+{

+  UINT32  PortOffset = Port * 6 + 11;

+

+  PcieUpdatebits (

+                  STG_CLK_BASE,

+                  STG_PCIE_RESET_OFFSET,

+                  0x3f << (PortOffset),

+                  0x3f << (PortOffset)

+                  ); /*axi mst0*/

+}

+

+STATIC

+VOID

+PcieGpioResetSet (

+  IN UINT32  Port,

+  IN UINT32  Value

+  )

+{

+  UINT32  Remain, Mask;

+

+  Remain = PCIE_GPIO[Port] & 0x3;

+  Mask   = 0xff << (Remain * 8);

+  PcieUpdatebits (

+                  SYS_GPIO_BASE,

+                  SYS_GPIO_OUTPUT_OFF + (PCIE_GPIO[Port] & 0xfffc),

+                  Mask,

+                  Value << (Remain * 8)

+                  );

+}

+

+STATIC

+VOID

+PcieAtrInit (

+  IN UINT32  Port,

+  IN UINT64  SrcAddr,

+  IN UINT64  TrslAddr,

+  IN UINT32  WinSize,

+  IN UINT32  Config

+  )

+{

+  UINT64  Base = GetPcieRegBase (Port) + XR3PCI_ATR_AXI4_SLV0;

+  UINT32  Value;

+

+  Base +=  XR3PCI_ATR_TABLE_OFFSET * AtrTableNum;

+  AtrTableNum++;

+

+  /* X3PCI_ATR_SRC_ADDR_LOW:

+   *   - bit 0: enable entry,

+   *   - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1)

+   *   - bits 7-11: reserved

+   *   - bits 12-31: start of source address

+   */

+  Value = SrcAddr;

+

+  RegWrite (

+            Base + XR3PCI_ATR_SRC_ADDR_LOW,

+            (Value & XR3PCI_ATR_SRC_ADDR_MASK) | ((WinSize - 1) << 1) | 0x1

+            );

+  Value = SrcAddr >> 32;

+

+  RegWrite (Base + XR3PCI_ATR_SRC_ADDR_HIGH, Value);

+  Value = TrslAddr;

+  RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_LOW, Value);

+  Value = TrslAddr >> 32;

+  RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_HIGH, Value);

+  RegWrite (Base + XR3PCI_ATR_TRSL_PARAM, Config);

+}

+

+EFI_STATUS

+EFIAPI

+JH7110PciHostBridgeLibConstructor (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+  UINT32  PortIndex;

+

+  DEBUG ((DEBUG_ERROR, "PCIe RootBridge constructor\n"));

+  for (PortIndex = 0; PortIndex < 2; PortIndex++) {

+    PcieSTGInit (PortIndex);

+    RegWrite (SYS_CLK_BASE + SYS_CLK_NOC_OFFSET, 1 << 31);

+    PcieClockInit (PortIndex);

+    PcieResetDeassert (PortIndex);

+    PcieGpioResetSet (PortIndex, 0);

+    PcieFuncSet (PortIndex);

+

+    PcieAtrInit (

+                 PortIndex,

+                 PCIE_CFG_BASE[PortIndex],

+                 0,

+                 XR3_PCI_ECAM_SIZE,

+                 1

+                 );

+    PcieAtrInit (

+                 PortIndex,

+                 PCI_MEMREGION_32[PortIndex],

+                 PCI_MEMREGION_32[PortIndex],

+                 PCI_MEMREGION_SIZE[0],

+                 0

+                 );

+    PcieAtrInit (

+                 PortIndex,

+                 PCI_MEMREGION_64[PortIndex],

+                 PCI_MEMREGION_64[PortIndex],

+                 PCI_MEMREGION_SIZE[1],

+                 0

+                 );

+    PcieGpioResetSet (PortIndex, 1);

+    MicroSecondDelay (300);

+

+    DEBUG ((DEBUG_ERROR, "PCIe port %d init\n", PortIndex));

+  }

+

+  return EFI_SUCCESS;

+}

diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c
new file mode 100644
index 000000000000..43dca2a6236a
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c
@@ -0,0 +1,1460 @@
+/** @file

+ *

+ * PCI Segment Library for StarFive JH7110 SoC

+ *

+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ * SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#include <Base.h>

+#include <Uefi.h>

+#include <Library/BaseLib.h>

+#include <Library/DebugLib.h>

+#include <Library/IoLib.h>

+#include <Library/PcdLib.h>

+#include <Library/PciSegmentLib.h>

+#include <Library/UefiLib.h>

+#include <IndustryStandard/JH7110.h>

+#include <IndustryStandard/Pci30.h>

+

+typedef enum {

+  PciCfgWidthUint8 = 0,

+  PciCfgWidthUint16,

+  PciCfgWidthUint32,

+  PciCfgWidthMax

+} PCI_CFG_WIDTH;

+

+/*

+ * This PCIe config space is unusual...

+ * The root port is the first bytes of the register space (offset 0)

+ * The individual devices are then selected by computing their BDF index

+ * and writing that into the CFG_INDEX register (offset 0x9000)

+ * the "ECAM" data is then read/writeable at CFG_DATA (offset 0x8000)

+ */

+

+#define EFI_PCI_ADDR_BUS(bus)  ((bus >> 20) & 0xFF)   /* Note PCI_SEGMENT_LIB_ADDRESS */

+#define EFI_PCI_ADDR_DEV(dev)  ((dev >> 15) & 0x1F)

+#define EFI_PCI_ADDR_FUN(fun)  ((fun >> 12) & 0x07)

+

+/**

+  Assert the validity of a PCI Segment address.

+  A valid PCI Segment address should not contain 1's in bits 28..31 and 48..63

+

+  @param  A The address to validate.

+  @param  M Additional bits to assert to be zero.

+

+**/

+#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A, M) \

+  ASSERT (((A) & (0xffff0000f0000000ULL | (M))) == 0)

+

+/**

+  Given the nature of how we access PCI devices, we ensure that

+  read/write accesses are serialized through the use of a lock.

+**/

+STATIC

+EFI_LOCK  mPciSegmentReadWriteLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);

+

+// STATIC UINT64 mPciSegmentLastAccess;     /* Avoid repeat CFG_INDEX updates */

+

+/**

+  Internal worker function to obtain config space base address.

+

+  @param  Address The address that encodes the PCI Bus, Device, Function and

+                  Register.

+

+  @return The value read from the PCI configuration register.

+

+**/

+STATIC

+UINT64

+PciSegmentLibGetConfigBase (

+  IN  UINT64  Address,

+  IN  UINT16  Segment,

+  IN  UINT32  Write

+  )

+{

+  UINT64  Base;

+  UINT64  Offset;

+  UINT32  Dev;

+  UINT32  Bus;

+

+  Base     = PCIE_CONFIG_BASE;

+  Offset   = Address & 0xFFF;      /* Pick off the 4k register offset */

+  Address &= 0xFFFF000;            /* Clear the offset leave only the BDF */

+

+  /* The root port is at the base of the PCIe register space */

+  if (Address != 0) {

+    Dev = EFI_PCI_ADDR_DEV (Address);

+    Bus = EFI_PCI_ADDR_BUS (Address);

+

+    /*

+     * There can only be a single device on bus 1 (downstream of root).

+     * Subsequent busses (behind a PCIe switch) can have more.

+     */

+    if (Dev > 0) {

+      return 0xFFFFFFFF;

+    }

+

+    return Base + Segment * 0x80000000 + Address + Offset;

+  } else {

+    if (Write && ((Offset == 0x10) || (Offset == 0x14))) {

+      return 0xFFFFFFFF;

+    }

+  }

+

+  return Base + Segment * 0x80000000 + Offset;

+}

+

+/**

+  Internal worker function to read a PCI configuration register.

+

+  @param  Address The address that encodes the PCI Bus, Device, Function and

+                  Register.

+  @param  Width   The width of data to read

+

+  @return The value read from the PCI configuration register.

+

+**/

+STATIC

+UINT32

+PciSegmentLibReadWorker (

+  IN  UINT64         Address,

+  IN  PCI_CFG_WIDTH  Width

+  )

+{

+  UINT64  Base;

+  UINT32  Ret;

+  UINT16  Segment = (Address >> 32);

+

+  EfiAcquireLock (&mPciSegmentReadWriteLock);

+  Base = PciSegmentLibGetConfigBase (Address, Segment, 0);

+

+  if (Base == 0xFFFFFFFF) {

+    EfiReleaseLock (&mPciSegmentReadWriteLock);

+    return Base;

+  }

+

+  switch (Width) {

+    case PciCfgWidthUint8:

+      Ret = MmioRead8 (Base);

+      break;

+    case PciCfgWidthUint16:

+      Ret = MmioRead16 (Base);

+      break;

+    case PciCfgWidthUint32:

+      Ret = MmioRead32 (Base);

+      break;

+    default:

+      ASSERT (FALSE);

+      Ret = 0;

+  }

+

+  EfiReleaseLock (&mPciSegmentReadWriteLock);

+  // DEBUG ((DEBUG_ERROR, "PCIe seg read Address %lx %lx width %d val %x Segment %d\n", Base, Address, Width, Ret, Segment));

+  return Ret;

+}

+

+/**

+  Internal worker function to writes a PCI configuration register.

+

+  @param  Address The address that encodes the PCI Bus, Device, Function and

+                  Register.

+  @param  Width   The width of data to write

+  @param  Data    The value to write.

+

+  @return The value written to the PCI configuration register.

+

+**/

+STATIC

+UINT32

+PciSegmentLibWriteWorker (

+  IN  UINT64         Address,

+  IN  PCI_CFG_WIDTH  Width,

+  IN  UINT32         Data

+  )

+{

+  UINT64  Base;

+  UINT16  Segment = (Address >> 32);

+

+  EfiAcquireLock (&mPciSegmentReadWriteLock);

+  Base = PciSegmentLibGetConfigBase (Address, Segment, 1);

+

+  if (Base == 0xFFFFFFFF) {

+    EfiReleaseLock (&mPciSegmentReadWriteLock);

+    return Data;

+  }

+

+  switch (Width) {

+    case PciCfgWidthUint8:

+      MmioWrite8 (Base, Data);

+      break;

+    case PciCfgWidthUint16:

+      MmioWrite16 (Base, Data);

+      break;

+    case PciCfgWidthUint32:

+      MmioWrite32 (Base, Data);

+      break;

+    default:

+      ASSERT (FALSE);

+  }

+

+  EfiReleaseLock (&mPciSegmentReadWriteLock);

+  return Data;

+}

+

+/**

+  Register a PCI device so PCI configuration registers may be accessed after

+  SetVirtualAddressMap().

+

+  If any reserved bits in Address are set, then ASSERT().

+

+  @param  Address The address that encodes the PCI Bus, Device, Function and

+                  Register.

+

+  @retval RETURN_SUCCESS           The PCI device was registered for runtime access.

+  @retval RETURN_UNSUPPORTED       An attempt was made to call this function

+                                   after ExitBootServices().

+  @retval RETURN_UNSUPPORTED       The resources required to access the PCI device

+                                   at runtime could not be mapped.

+  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to

+                                   complete the registration.

+

+**/

+RETURN_STATUS

+EFIAPI

+PciSegmentRegisterForRuntimeAccess (

+  IN UINTN  Address

+  )

+{

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);

+  return RETURN_UNSUPPORTED;

+}

+

+/**

+  Reads an 8-bit PCI configuration register.

+

+  Reads and returns the 8-bit PCI configuration register specified by Address.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,

+                    and Register.

+

+  @return The 8-bit PCI configuration register specified by Address.

+

+**/

+UINT8

+EFIAPI

+PciSegmentRead8 (

+  IN UINT64  Address

+  )

+{

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);

+

+  return (UINT8)PciSegmentLibReadWorker (Address, PciCfgWidthUint8);

+}

+

+/**

+  Writes an 8-bit PCI configuration register.

+

+  Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.

+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+

+  @param  Address     The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  Value       The value to write.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentWrite8 (

+  IN UINT64  Address,

+  IN UINT8   Value

+  )

+{

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);

+

+  return (UINT8)PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, Value);

+}

+

+/**

+  Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.

+

+  Reads the 8-bit PCI configuration register specified by Address,

+  performs a bitwise OR between the read result and the value specified by OrData,

+  and writes the result to the 8-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  OrData    The value to OR with the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentOr8 (

+  IN UINT64  Address,

+  IN UINT8   OrData

+  )

+{

+  return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) | OrData));

+}

+

+/**

+  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.

+

+  Reads the 8-bit PCI configuration register specified by Address,

+  performs a bitwise AND between the read result and the value specified by AndData,

+  and writes the result to the 8-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+  If any reserved bits in Address are set, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  AndData   The value to AND with the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentAnd8 (

+  IN UINT64  Address,

+  IN UINT8   AndData

+  )

+{

+  return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) & AndData));

+}

+

+/**

+  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,

+  followed a  bitwise OR with another 8-bit value.

+

+  Reads the 8-bit PCI configuration register specified by Address,

+  performs a bitwise AND between the read result and the value specified by AndData,

+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,

+  and writes the result to the 8-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  AndData    The value to AND with the PCI configuration register.

+  @param  OrData    The value to OR with the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentAndThenOr8 (

+  IN UINT64  Address,

+  IN UINT8   AndData,

+  IN UINT8   OrData

+  )

+{

+  return PciSegmentWrite8 (Address, (UINT8)((PciSegmentRead8 (Address) & AndData) | OrData));

+}

+

+/**

+  Reads a bit field of a PCI configuration register.

+

+  Reads the bit field in an 8-bit PCI configuration register. The bit field is

+  specified by the StartBit and the EndBit. The value of the bit field is

+  returned.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If StartBit is greater than 7, then ASSERT().

+  If EndBit is greater than 7, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to read.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..7.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..7.

+

+  @return The value of the bit field read from the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentBitFieldRead8 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit

+  )

+{

+  return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit);

+}

+

+/**

+  Writes a bit field to a PCI configuration register.

+

+  Writes Value to the bit field of the PCI configuration register. The bit

+  field is specified by the StartBit and the EndBit. All other bits in the

+  destination PCI configuration register are preserved. The new value of the

+  8-bit register is returned.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If StartBit is greater than 7, then ASSERT().

+  If EndBit is greater than 7, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..7.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..7.

+  @param  Value     The new value of the bit field.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentBitFieldWrite8 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT8   Value

+  )

+{

+  return PciSegmentWrite8 (

+                           Address,

+                           BitFieldWrite8 (PciSegmentRead8 (Address), StartBit, EndBit, Value)

+                           );

+}

+

+/**

+  Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and

+  writes the result back to the bit field in the 8-bit port.

+

+  Reads the 8-bit PCI configuration register specified by Address, performs a

+  bitwise OR between the read result and the value specified by

+  OrData, and writes the result to the 8-bit PCI configuration register

+  specified by Address. The value written to the PCI configuration register is

+  returned. This function must guarantee that all PCI read and write operations

+  are serialized. Extra left bits in OrData are stripped.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If StartBit is greater than 7, then ASSERT().

+  If EndBit is greater than 7, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..7.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..7.

+  @param  OrData    The value to OR with the PCI configuration register.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentBitFieldOr8 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT8   OrData

+  )

+{

+  return PciSegmentWrite8 (

+                           Address,

+                           BitFieldOr8 (PciSegmentRead8 (Address), StartBit, EndBit, OrData)

+                           );

+}

+

+/**

+  Reads a bit field in an 8-bit PCI configuration register, performs a bitwise

+  AND, and writes the result back to the bit field in the 8-bit register.

+

+  Reads the 8-bit PCI configuration register specified by Address, performs a

+  bitwise AND between the read result and the value specified by AndData, and

+  writes the result to the 8-bit PCI configuration register specified by

+  Address. The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are

+  serialized. Extra left bits in AndData are stripped.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If StartBit is greater than 7, then ASSERT().

+  If EndBit is greater than 7, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..7.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..7.

+  @param  AndData   The value to AND with the PCI configuration register.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentBitFieldAnd8 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT8   AndData

+  )

+{

+  return PciSegmentWrite8 (

+                           Address,

+                           BitFieldAnd8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData)

+                           );

+}

+

+/**

+  Reads a bit field in an 8-bit port, performs a bitwise AND followed by a

+  bitwise OR, and writes the result back to the bit field in the

+  8-bit port.

+

+  Reads the 8-bit PCI configuration register specified by Address, performs a

+  bitwise AND followed by a bitwise OR between the read result and

+  the value specified by AndData, and writes the result to the 8-bit PCI

+  configuration register specified by Address. The value written to the PCI

+  configuration register is returned. This function must guarantee that all PCI

+  read and write operations are serialized. Extra left bits in both AndData and

+  OrData are stripped.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If StartBit is greater than 7, then ASSERT().

+  If EndBit is greater than 7, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..7.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..7.

+  @param  AndData   The value to AND with the PCI configuration register.

+  @param  OrData    The value to OR with the result of the AND operation.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT8

+EFIAPI

+PciSegmentBitFieldAndThenOr8 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT8   AndData,

+  IN UINT8   OrData

+  )

+{

+  return PciSegmentWrite8 (

+                           Address,

+                           BitFieldAndThenOr8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData, OrData)

+                           );

+}

+

+/**

+  Reads a 16-bit PCI configuration register.

+

+  Reads and returns the 16-bit PCI configuration register specified by Address.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+

+  @return The 16-bit PCI configuration register specified by Address.

+

+**/

+UINT16

+EFIAPI

+PciSegmentRead16 (

+  IN UINT64  Address

+  )

+{

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);

+

+  return (UINT16)PciSegmentLibReadWorker (Address, PciCfgWidthUint16);

+}

+

+/**

+  Writes a 16-bit PCI configuration register.

+

+  Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.

+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+

+  @param  Address     The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  Value       The value to write.

+

+  @return The parameter of Value.

+

+**/

+UINT16

+EFIAPI

+PciSegmentWrite16 (

+  IN UINT64  Address,

+  IN UINT16  Value

+  )

+{

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);

+

+  return (UINT16)PciSegmentLibWriteWorker (Address, PciCfgWidthUint16, Value);

+}

+

+/**

+  Performs a bitwise OR of a 16-bit PCI configuration register with

+  a 16-bit value.

+

+  Reads the 16-bit PCI configuration register specified by Address, performs a

+  bitwise OR between the read result and the value specified by

+  OrData, and writes the result to the 16-bit PCI configuration register

+  specified by Address. The value written to the PCI configuration register is

+  returned. This function must guarantee that all PCI read and write operations

+  are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+

+  @param  Address The address that encodes the PCI Segment, Bus, Device, Function and

+                  Register.

+  @param  OrData  The value to OR with the PCI configuration register.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT16

+EFIAPI

+PciSegmentOr16 (

+  IN UINT64  Address,

+  IN UINT16  OrData

+  )

+{

+  return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) | OrData));

+}

+

+/**

+  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.

+

+  Reads the 16-bit PCI configuration register specified by Address,

+  performs a bitwise AND between the read result and the value specified by AndData,

+  and writes the result to the 16-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  AndData   The value to AND with the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT16

+EFIAPI

+PciSegmentAnd16 (

+  IN UINT64  Address,

+  IN UINT16  AndData

+  )

+{

+  return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) & AndData));

+}

+

+/**

+  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,

+  followed a  bitwise OR with another 16-bit value.

+

+  Reads the 16-bit PCI configuration register specified by Address,

+  performs a bitwise AND between the read result and the value specified by AndData,

+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,

+  and writes the result to the 16-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  AndData   The value to AND with the PCI configuration register.

+  @param  OrData    The value to OR with the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT16

+EFIAPI

+PciSegmentAndThenOr16 (

+  IN UINT64  Address,

+  IN UINT16  AndData,

+  IN UINT16  OrData

+  )

+{

+  return PciSegmentWrite16 (Address, (UINT16)((PciSegmentRead16 (Address) & AndData) | OrData));

+}

+

+/**

+  Reads a bit field of a PCI configuration register.

+

+  Reads the bit field in a 16-bit PCI configuration register. The bit field is

+  specified by the StartBit and the EndBit. The value of the bit field is

+  returned.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+  If StartBit is greater than 15, then ASSERT().

+  If EndBit is greater than 15, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to read.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..15.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..15.

+

+  @return The value of the bit field read from the PCI configuration register.

+

+**/

+UINT16

+EFIAPI

+PciSegmentBitFieldRead16 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit

+  )

+{

+  return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit);

+}

+

+/**

+  Writes a bit field to a PCI configuration register.

+

+  Writes Value to the bit field of the PCI configuration register. The bit

+  field is specified by the StartBit and the EndBit. All other bits in the

+  destination PCI configuration register are preserved. The new value of the

+  16-bit register is returned.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+  If StartBit is greater than 15, then ASSERT().

+  If EndBit is greater than 15, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..15.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..15.

+  @param  Value     The new value of the bit field.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT16

+EFIAPI

+PciSegmentBitFieldWrite16 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT16  Value

+  )

+{

+  return PciSegmentWrite16 (

+                            Address,

+                            BitFieldWrite16 (PciSegmentRead16 (Address), StartBit, EndBit, Value)

+                            );

+}

+

+/**

+  Reads the 16-bit PCI configuration register specified by Address,

+  performs a bitwise OR between the read result and the value specified by OrData,

+  and writes the result to the 16-bit PCI configuration register specified by Address.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+  If StartBit is greater than 15, then ASSERT().

+  If EndBit is greater than 15, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..15.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..15.

+  @param  OrData    The value to OR with the PCI configuration register.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT16

+EFIAPI

+PciSegmentBitFieldOr16 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT16  OrData

+  )

+{

+  return PciSegmentWrite16 (

+                            Address,

+                            BitFieldOr16 (PciSegmentRead16 (Address), StartBit, EndBit, OrData)

+                            );

+}

+

+/**

+  Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR,

+  and writes the result back to the bit field in the 16-bit port.

+

+  Reads the 16-bit PCI configuration register specified by Address,

+  performs a bitwise OR between the read result and the value specified by OrData,

+  and writes the result to the 16-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+  Extra left bits in OrData are stripped.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 16-bit boundary, then ASSERT().

+  If StartBit is greater than 7, then ASSERT().

+  If EndBit is greater than 7, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    The ordinal of the least significant bit in a byte is bit 0.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    The ordinal of the most significant bit in a byte is bit 7.

+  @param  AndData   The value to AND with the read value from the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT16

+EFIAPI

+PciSegmentBitFieldAnd16 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT16  AndData

+  )

+{

+  return PciSegmentWrite16 (

+                            Address,

+                            BitFieldAnd16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData)

+                            );

+}

+

+/**

+  Reads a bit field in a 16-bit port, performs a bitwise AND followed by a

+  bitwise OR, and writes the result back to the bit field in the

+  16-bit port.

+

+  Reads the 16-bit PCI configuration register specified by Address, performs a

+  bitwise AND followed by a bitwise OR between the read result and

+  the value specified by AndData, and writes the result to the 16-bit PCI

+  configuration register specified by Address. The value written to the PCI

+  configuration register is returned. This function must guarantee that all PCI

+  read and write operations are serialized. Extra left bits in both AndData and

+  OrData are stripped.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If StartBit is greater than 15, then ASSERT().

+  If EndBit is greater than 15, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..15.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..15.

+  @param  AndData   The value to AND with the PCI configuration register.

+  @param  OrData    The value to OR with the result of the AND operation.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT16

+EFIAPI

+PciSegmentBitFieldAndThenOr16 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT16  AndData,

+  IN UINT16  OrData

+  )

+{

+  return PciSegmentWrite16 (

+                            Address,

+                            BitFieldAndThenOr16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData, OrData)

+                            );

+}

+

+/**

+  Reads a 32-bit PCI configuration register.

+

+  Reads and returns the 32-bit PCI configuration register specified by Address.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 32-bit boundary, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,

+                    and Register.

+

+  @return The 32-bit PCI configuration register specified by Address.

+

+**/

+UINT32

+EFIAPI

+PciSegmentRead32 (

+  IN UINT64  Address

+  )

+{

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);

+

+  return PciSegmentLibReadWorker (Address, PciCfgWidthUint32);

+}

+

+/**

+  Writes a 32-bit PCI configuration register.

+

+  Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.

+  Value is returned.  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 32-bit boundary, then ASSERT().

+

+  @param  Address     The address that encodes the PCI Segment, Bus, Device,

+                      Function, and Register.

+  @param  Value       The value to write.

+

+  @return The parameter of Value.

+

+**/

+UINT32

+EFIAPI

+PciSegmentWrite32 (

+  IN UINT64  Address,

+  IN UINT32  Value

+  )

+{

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);

+

+  return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, Value);

+}

+

+/**

+  Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.

+

+  Reads the 32-bit PCI configuration register specified by Address,

+  performs a bitwise OR between the read result and the value specified by OrData,

+  and writes the result to the 32-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 32-bit boundary, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function, and Register.

+  @param  OrData    The value to OR with the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT32

+EFIAPI

+PciSegmentOr32 (

+  IN UINT64  Address,

+  IN UINT32  OrData

+  )

+{

+  return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData);

+}

+

+/**

+  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.

+

+  Reads the 32-bit PCI configuration register specified by Address,

+  performs a bitwise AND between the read result and the value specified by AndData,

+  and writes the result to the 32-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 32-bit boundary, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,

+                    and Register.

+  @param  AndData   The value to AND with the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT32

+EFIAPI

+PciSegmentAnd32 (

+  IN UINT64  Address,

+  IN UINT32  AndData

+  )

+{

+  return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData);

+}

+

+/**

+  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,

+  followed a  bitwise OR with another 32-bit value.

+

+  Reads the 32-bit PCI configuration register specified by Address,

+  performs a bitwise AND between the read result and the value specified by AndData,

+  performs a bitwise OR between the result of the AND operation and the value specified by OrData,

+  and writes the result to the 32-bit PCI configuration register specified by Address.

+  The value written to the PCI configuration register is returned.

+  This function must guarantee that all PCI read and write operations are serialized.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 32-bit boundary, then ASSERT().

+

+  @param  Address   The address that encodes the PCI Segment, Bus, Device, Function,

+                    and Register.

+  @param  AndData   The value to AND with the PCI configuration register.

+  @param  OrData    The value to OR with the PCI configuration register.

+

+  @return The value written to the PCI configuration register.

+

+**/

+UINT32

+EFIAPI

+PciSegmentAndThenOr32 (

+  IN UINT64  Address,

+  IN UINT32  AndData,

+  IN UINT32  OrData

+  )

+{

+  return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData) | OrData);

+}

+

+/**

+  Reads a bit field of a PCI configuration register.

+

+  Reads the bit field in a 32-bit PCI configuration register. The bit field is

+  specified by the StartBit and the EndBit. The value of the bit field is

+  returned.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 32-bit boundary, then ASSERT().

+  If StartBit is greater than 31, then ASSERT().

+  If EndBit is greater than 31, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to read.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..31.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..31.

+

+  @return The value of the bit field read from the PCI configuration register.

+

+**/

+UINT32

+EFIAPI

+PciSegmentBitFieldRead32 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit

+  )

+{

+  return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit);

+}

+

+/**

+  Writes a bit field to a PCI configuration register.

+

+  Writes Value to the bit field of the PCI configuration register. The bit

+  field is specified by the StartBit and the EndBit. All other bits in the

+  destination PCI configuration register are preserved. The new value of the

+  32-bit register is returned.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 32-bit boundary, then ASSERT().

+  If StartBit is greater than 31, then ASSERT().

+  If EndBit is greater than 31, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..31.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..31.

+  @param  Value     The new value of the bit field.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT32

+EFIAPI

+PciSegmentBitFieldWrite32 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT32  Value

+  )

+{

+  return PciSegmentWrite32 (

+                            Address,

+                            BitFieldWrite32 (PciSegmentRead32 (Address), StartBit, EndBit, Value)

+                            );

+}

+

+/**

+  Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and

+  writes the result back to the bit field in the 32-bit port.

+

+  Reads the 32-bit PCI configuration register specified by Address, performs a

+  bitwise OR between the read result and the value specified by

+  OrData, and writes the result to the 32-bit PCI configuration register

+  specified by Address. The value written to the PCI configuration register is

+  returned. This function must guarantee that all PCI read and write operations

+  are serialized. Extra left bits in OrData are stripped.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If StartBit is greater than 31, then ASSERT().

+  If EndBit is greater than 31, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..31.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..31.

+  @param  OrData    The value to OR with the PCI configuration register.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT32

+EFIAPI

+PciSegmentBitFieldOr32 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT32  OrData

+  )

+{

+  return PciSegmentWrite32 (

+                            Address,

+                            BitFieldOr32 (PciSegmentRead32 (Address), StartBit, EndBit, OrData)

+                            );

+}

+

+/**

+  Reads a bit field in a 32-bit PCI configuration register, performs a bitwise

+  AND, and writes the result back to the bit field in the 32-bit register.

+

+

+  Reads the 32-bit PCI configuration register specified by Address, performs a bitwise

+  AND between the read result and the value specified by AndData, and writes the result

+  to the 32-bit PCI configuration register specified by Address. The value written to

+  the PCI configuration register is returned.  This function must guarantee that all PCI

+  read and write operations are serialized.  Extra left bits in AndData are stripped.

+  If any reserved bits in Address are set, then ASSERT().

+  If Address is not aligned on a 32-bit boundary, then ASSERT().

+  If StartBit is greater than 31, then ASSERT().

+  If EndBit is greater than 31, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..31.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..31.

+  @param  AndData   The value to AND with the PCI configuration register.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT32

+EFIAPI

+PciSegmentBitFieldAnd32 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT32  AndData

+  )

+{

+  return PciSegmentWrite32 (

+                            Address,

+                            BitFieldAnd32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData)

+                            );

+}

+

+/**

+  Reads a bit field in a 32-bit port, performs a bitwise AND followed by a

+  bitwise OR, and writes the result back to the bit field in the

+  32-bit port.

+

+  Reads the 32-bit PCI configuration register specified by Address, performs a

+  bitwise AND followed by a bitwise OR between the read result and

+  the value specified by AndData, and writes the result to the 32-bit PCI

+  configuration register specified by Address. The value written to the PCI

+  configuration register is returned. This function must guarantee that all PCI

+  read and write operations are serialized. Extra left bits in both AndData and

+  OrData are stripped.

+

+  If any reserved bits in Address are set, then ASSERT().

+  If StartBit is greater than 31, then ASSERT().

+  If EndBit is greater than 31, then ASSERT().

+  If EndBit is less than StartBit, then ASSERT().

+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().

+

+  @param  Address   The PCI configuration register to write.

+  @param  StartBit  The ordinal of the least significant bit in the bit field.

+                    Range 0..31.

+  @param  EndBit    The ordinal of the most significant bit in the bit field.

+                    Range 0..31.

+  @param  AndData   The value to AND with the PCI configuration register.

+  @param  OrData    The value to OR with the result of the AND operation.

+

+  @return The value written back to the PCI configuration register.

+

+**/

+UINT32

+EFIAPI

+PciSegmentBitFieldAndThenOr32 (

+  IN UINT64  Address,

+  IN UINTN   StartBit,

+  IN UINTN   EndBit,

+  IN UINT32  AndData,

+  IN UINT32  OrData

+  )

+{

+  return PciSegmentWrite32 (

+                            Address,

+                            BitFieldAndThenOr32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData, OrData)

+                            );

+}

+

+/**

+  Reads a range of PCI configuration registers into a caller supplied buffer.

+

+  Reads the range of PCI configuration registers specified by StartAddress and

+  Size into the buffer specified by Buffer. This function only allows the PCI

+  configuration registers from a single PCI function to be read. Size is

+  returned. When possible 32-bit PCI configuration read cycles are used to read

+  from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit

+  and 16-bit PCI configuration read cycles may be used at the beginning and the

+  end of the range.

+

+  If any reserved bits in StartAddress are set, then ASSERT().

+  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().

+  If Size > 0 and Buffer is NULL, then ASSERT().

+

+  @param  StartAddress  The starting address that encodes the PCI Segment, Bus,

+                        Device, Function and Register.

+  @param  Size          The size in bytes of the transfer.

+  @param  Buffer        The pointer to a buffer receiving the data read.

+

+  @return Size

+

+**/

+UINTN

+EFIAPI

+PciSegmentReadBuffer (

+  IN  UINT64  StartAddress,

+  IN  UINTN   Size,

+  OUT VOID    *Buffer

+  )

+{

+  UINTN  ReturnValue;

+

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);

+  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);

+

+  if (Size == 0) {

+    return Size;

+  }

+

+  ASSERT (Buffer != NULL);

+

+  //

+  // Save Size for return

+  //

+  ReturnValue = Size;

+

+  if ((StartAddress & BIT0) != 0) {

+    //

+    // Read a byte if StartAddress is byte aligned

+    //

+    *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);

+    StartAddress             += sizeof (UINT8);

+    Size                     -= sizeof (UINT8);

+    Buffer                    = (UINT8 *)Buffer + 1;

+  }

+

+  if ((Size >= sizeof (UINT16)) && ((StartAddress & BIT1) != 0)) {

+    //

+    // Read a word if StartAddress is word aligned

+    //

+    WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));

+    StartAddress += sizeof (UINT16);

+    Size         -= sizeof (UINT16);

+    Buffer        = (UINT16 *)Buffer + 1;

+  }

+

+  while (Size >= sizeof (UINT32)) {

+    //

+    // Read as many double words as possible

+    //

+    WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress));

+    StartAddress += sizeof (UINT32);

+    Size         -= sizeof (UINT32);

+    Buffer        = (UINT32 *)Buffer + 1;

+  }

+

+  if (Size >= sizeof (UINT16)) {

+    //

+    // Read the last remaining word if exist

+    //

+    WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));

+    StartAddress += sizeof (UINT16);

+    Size         -= sizeof (UINT16);

+    Buffer        = (UINT16 *)Buffer + 1;

+  }

+

+  if (Size >= sizeof (UINT8)) {

+    //

+    // Read the last remaining byte if exist

+    //

+    *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);

+  }

+

+  return ReturnValue;

+}

+

+/**

+  Copies the data in a caller supplied buffer to a specified range of PCI

+  configuration space.

+

+  Writes the range of PCI configuration registers specified by StartAddress and

+  Size from the buffer specified by Buffer. This function only allows the PCI

+  configuration registers from a single PCI function to be written. Size is

+  returned. When possible 32-bit PCI configuration write cycles are used to

+  write from StartAdress to StartAddress + Size. Due to alignment restrictions,

+  8-bit and 16-bit PCI configuration write cycles may be used at the beginning

+  and the end of the range.

+

+  If any reserved bits in StartAddress are set, then ASSERT().

+  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().

+  If Size > 0 and Buffer is NULL, then ASSERT().

+

+  @param  StartAddress  The starting address that encodes the PCI Segment, Bus,

+                        Device, Function and Register.

+  @param  Size          The size in bytes of the transfer.

+  @param  Buffer        The pointer to a buffer containing the data to write.

+

+  @return The parameter of Size.

+

+**/

+UINTN

+EFIAPI

+PciSegmentWriteBuffer (

+  IN UINT64  StartAddress,

+  IN UINTN   Size,

+  IN VOID    *Buffer

+  )

+{

+  UINTN  ReturnValue;

+

+  ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);

+  ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);

+

+  if (Size == 0) {

+    return 0;

+  }

+

+  ASSERT (Buffer != NULL);

+

+  // The Bcm/Rpi has a single cfg which can be mapped

+  // to any given device on the bus, which means we need to remap

+  // it basically everytime a new config access is done

+

+  //

+  // Save Size for return

+  //

+  ReturnValue = Size;

+

+  if ((StartAddress & BIT0) != 0) {

+    //

+    // Write a byte if StartAddress is byte aligned

+    //

+    PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);

+    StartAddress += sizeof (UINT8);

+    Size         -= sizeof (UINT8);

+    Buffer        = (UINT8 *)Buffer + 1;

+  }

+

+  if ((Size >= sizeof (UINT16)) && ((StartAddress & BIT1) != 0)) {

+    //

+    // Write a word if StartAddress is word aligned

+    //

+    PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));

+    StartAddress += sizeof (UINT16);

+    Size         -= sizeof (UINT16);

+    Buffer        = (UINT16 *)Buffer + 1;

+  }

+

+  while (Size >= sizeof (UINT32)) {

+    //

+    // Write as many double words as possible

+    //

+    PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer));

+    StartAddress += sizeof (UINT32);

+    Size         -= sizeof (UINT32);

+    Buffer        = (UINT32 *)Buffer + 1;

+  }

+

+  if (Size >= sizeof (UINT16)) {

+    //

+    // Write the last remaining word if exist

+    //

+    PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));

+    StartAddress += sizeof (UINT16);

+    Size         -= sizeof (UINT16);

+    Buffer        = (UINT16 *)Buffer + 1;

+  }

+

+  if (Size >= sizeof (UINT8)) {

+    //

+    // Write the last remaining byte if exist

+    //

+    PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);

+  }

+

+  return ReturnValue;

+}

diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf
new file mode 100644
index 000000000000..063c85ebc428
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf
@@ -0,0 +1,33 @@
+## @file

+# PCI Segment Library for StarFive JH7110 SoC

+#

+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+#

+#  SPDX-License-Identifier: BSD-2-Clause-Patent

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x0001001B

+  BASE_NAME                      = PciSegmentLib

+  FILE_GUID                      = 832163a2-41f5-c529-3f02-77fb68abbc2c

+  MODULE_TYPE                    = BASE

+  VERSION_STRING                 = 1.0

+  LIBRARY_CLASS                  = PciSegmentLib

+

+[Sources]

+  PciSegmentLib.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec

+

+[LibraryClasses]

+  BaseLib

+  DebugLib

+  IoLib

+  PcdLib

+  UefiLib

+

+[FixedPcd]

+  gJH7110TokenSpaceGuid.PcdPciConfigRegBase

-- 
2.34.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109900): https://edk2.groups.io/g/devel/message/109900
Mute This Topic: https://groups.io/mt/102130712/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] 5+ messages in thread

* [edk2-devel] [PATCH v2 2/4] StarFive/JH7110Pkg: Add SPI protocol and driver support
  2023-10-23  7:18 [edk2-devel] [PATCH v2 0/4] Patches for JH7110 SoC platform John Chew
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 1/4] StarFive/JH7110Pkg: Add Pci controller driver John Chew
@ 2023-10-23  7:18 ` John Chew
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 3/4] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 4/4] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
  3 siblings, 0 replies; 5+ messages in thread
From: John Chew @ 2023-10-23  7:18 UTC (permalink / raw)
  To: devel; +Cc: John Chew, Sunil V L, Leif Lindholm, Michael D Kinney,
	Cc : Li Yong

This patch include QSPI driver and Flash driver protocol.
QSPI driver:
	1. Used indirect read/write
	2. Master mode only
	3. Require to setup qspi driver after located protocol
	4. Require to free device if no longer needed
	5. Support command read/write & data read/write
Flash driver:
	1. Require QSPI protocol as prerequisite
	2. Support for flash read/write/update/erase
	3. Require to init flash driver after allocated protocol

Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Cc: Li Yong <yong.li@intel.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 (#109897): https://edk2.groups.io/g/devel/message/109897
Mute This Topic: https://groups.io/mt/102130703/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] 5+ messages in thread

* [edk2-devel] [PATCH v2 3/4] StarFive/JH7110Pkg: Add firmware volume block protocol
  2023-10-23  7:18 [edk2-devel] [PATCH v2 0/4] Patches for JH7110 SoC platform John Chew
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 1/4] StarFive/JH7110Pkg: Add Pci controller driver John Chew
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 2/4] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
@ 2023-10-23  7:18 ` John Chew
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 4/4] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
  3 siblings, 0 replies; 5+ messages in thread
From: John Chew @ 2023-10-23  7:18 UTC (permalink / raw)
  To: devel; +Cc: John Chew, Sunil V L, Leif Lindholm, Michael D Kinney,
	Cc : Li Yong

Support for efi variable to store in QSPI flash.
This driver is responsible to initialize both QSPI and Flash driver.

Firmware Volume(FV) Initialization:
	1. Copy flash content into allocated shadow buffer (RAM)
	2. Check FV header validity
	3. If not valid, erase flash based on the region defined in PCDs
           , else skip
	4. If erased, write flash with new FV header, else skip
EFI Variable read:
	1. Read anbd return the content from the shadow buffer (RAM)
EFI Variable write:
	1. Write the data into flash
	2. Update shadow buffer (RAM)

Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Cc: Li Yong <yong.li@intel.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 (#109898): https://edk2.groups.io/g/devel/message/109898
Mute This Topic: https://groups.io/mt/102130707/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] 5+ messages in thread

* [edk2-devel] [PATCH v2 4/4] StarFive/JH7110Pkg: Add JH7110 Silicon Package
  2023-10-23  7:18 [edk2-devel] [PATCH v2 0/4] Patches for JH7110 SoC platform John Chew
                   ` (2 preceding siblings ...)
  2023-10-23  7:18 ` [edk2-devel] [PATCH v2 3/4] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
@ 2023-10-23  7:18 ` John Chew
  3 siblings, 0 replies; 5+ messages in thread
From: John Chew @ 2023-10-23  7:18 UTC (permalink / raw)
  To: devel
  Cc: mindachen1987, Sunil V L, Leif Lindholm, Michael D Kinney,
	Cc : Li Yong, John Chew

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

v2:
  - Remove redundant commented PCDs [Sunil]
  - Remove unused PCD: PcdJH7110RegistersAddress [John Chew]
  - Added PCIE PCDs: PcdPciBusMin, PcdPciBusMax, PcdPciBusMax,
                     PcdPciIoSize, PcdPciIoOffset, PcdPci0Mmio32Base,
                     PcdPci0Mmio32Size, PcdPci0Mmio64Base,
                     PcdPci0Mmio64Size, PcdPci1Mmio32Base,
                     PcdPci1Mmio32Size, PcdPci1Mmio64Base,
                     PcdPci1Mmio64Size [John Chew]

v1:

  - Add a new JH7110 silicon package.
  - These files Contain platfrom specific Guids, PCDs and defines
    used for JH7110 SoC.

Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Cc: Li Yong <yong.li@intel.com>
Co-authored-by: John Chew <yuinyee.chew@starfivetech.com>
Signed-off-by: mindachen1987 <minda.chen@starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h | 21 ++++++++
 Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec                     | 57 ++++++++++++++++++++
 2 files changed, 78 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..142e7be10c48
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
@@ -0,0 +1,21 @@
+/** @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__

+

+/* Generic PCI addresses */

+#define PCIE_TOP_OF_MEM_WIN   (FixedPcdGet64 (PcdPciBusMmioAdr))

+#define PCIE_CPU_MMIO_WINDOW  (FixedPcdGet64 (PcdPciCpuMmioAdr))

+#define PCIE_BRIDGE_MMIO_LEN  (FixedPcdGet32 (PcdPciBusMmioLen))

+

+/* PCI root bridge control registers location */

+#define PCIE_REG_BASE     (FixedPcdGet64 (PcdPciRegBase))

+#define PCIE_CONFIG_BASE  (FixedPcdGet64 (PcdPciConfigRegBase))

+

+#endif /* JH7110_H__ */

diff --git a/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
new file mode 100644
index 000000000000..f9dc5ab3781d
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
@@ -0,0 +1,57 @@
+## @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.PcdPciRegBase|0x2b000000|UINT64|0x00000002

+  gJH7110TokenSpaceGuid.PcdPciBusMmioAdr|0x0|UINT64|0x00000003

+  gJH7110TokenSpaceGuid.PcdPciBusMmioLen|0x0|UINT32|0x00000004

+  gJH7110TokenSpaceGuid.PcdPciCpuMmioAdr|0x0|UINT64|0x00000005

+  gJH7110TokenSpaceGuid.PcdPciConfigRegBase|0x940000000|UINT64|0x00000006

+  gJH7110TokenSpaceGuid.PcdPciBusMin|0x0|UINT32|0x10000007

+  gJH7110TokenSpaceGuid.PcdPciBusMax|0x0|UINT32|0x10000008

+  gJH7110TokenSpaceGuid.PcdPciIoBase|0x0|UINT64|0x10000009

+  gJH7110TokenSpaceGuid.PcdPciIoSize|0x0|UINT64|0x1000000A

+  gJH7110TokenSpaceGuid.PcdPciIoOffset|0x0|UINT64|0x1000000B

+  gJH7110TokenSpaceGuid.PcdPci0Mmio32Base|0x0|UINT32|0x1000000C

+  gJH7110TokenSpaceGuid.PcdPci0Mmio32Size|0x0|UINT32|0x1000000D

+  gJH7110TokenSpaceGuid.PcdPci0Mmio64Base|0x0|UINT64|0x1000000E

+  gJH7110TokenSpaceGuid.PcdPci0Mmio64Size|0x0|UINT64|0x1000000F

+  gJH7110TokenSpaceGuid.PcdPci1Mmio32Base|0x0|UINT32|0x10000010

+  gJH7110TokenSpaceGuid.PcdPci1Mmio32Size|0x0|UINT32|0x1000011

+  gJH7110TokenSpaceGuid.PcdPci1Mmio64Base|0x0|UINT64|0x1000012

+  gJH7110TokenSpaceGuid.PcdPci1Mmio64Size|0x0|UINT64|0x1000013

+

+# SPI

+  gJH7110TokenSpaceGuid.PcdSpiFlashRegBase|0|UINT32|0x1000014

+  gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase|0|UINT64|0x1000015

+  gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth|0|UINT8|0x10000016

+  gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz|0|UINT32|0x10000017

+  gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs|0|UINT32|0x10000018

+  gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs|0|UINT32|0x1000019

+  gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs|0|UINT32|0x100001A

+  gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs|0|UINT32|0x100001B

+

+[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 (#109899): https://edk2.groups.io/g/devel/message/109899
Mute This Topic: https://groups.io/mt/102130708/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] 5+ messages in thread

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

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-23  7:18 [edk2-devel] [PATCH v2 0/4] Patches for JH7110 SoC platform John Chew
2023-10-23  7:18 ` [edk2-devel] [PATCH v2 1/4] StarFive/JH7110Pkg: Add Pci controller driver John Chew
2023-10-23  7:18 ` [edk2-devel] [PATCH v2 2/4] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
2023-10-23  7:18 ` [edk2-devel] [PATCH v2 3/4] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
2023-10-23  7:18 ` [edk2-devel] [PATCH v2 4/4] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew

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