* [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