* [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver
@ 2023-10-19 2:59 John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: John Chew @ 2023-10-19 2:59 UTC (permalink / raw)
To: devel; +Cc: mindachen1987, Sunil V L, John Chew
From: mindachen1987 <minda.chen@starfivetech.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Co-authored-by: John Chew <yuinyee.chew@starfivetech.com>
Signed-off-by: mindachen1987 <minda.chen@starfivetech.com>
---
Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c | 249 ++++
Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf | 48 +
Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c | 405 ++++++
Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c | 1460 ++++++++++++++++++++
Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf | 33 +
5 files changed, 2195 insertions(+)
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
new file mode 100644
index 000000000000..7d73cb5b4b5c
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
@@ -0,0 +1,249 @@
+/** @file
+ *
+ * PCI Host Bridge Library instance for StarFive JH7110 SOC
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <IndustryStandard/JH7110.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <PiDxe.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+
+#pragma pack(1)
+
+typedef PACKED struct {
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+
+#pragma pack ()
+
+STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[] = {
+ {
+ {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_DP,
+ {
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
+ }
+ },
+ EISA_PNP_ID (0x0A08), // PCI Express
+ 0
+ },
+
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+ },
+
+ {
+ {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_DP,
+ {
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8)
+ }
+ },
+ EISA_PNP_ID (0x0A08), // PCI Express
+ 1
+ },
+
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+ },
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+
+// These should come from the PCD...
+#define JH7110_PCI_BUSNUM_MIN 0x00
+#define JH7110_PCI_BUSNUM_MAX 0xFF
+#define JH7110_PCI_PORTIO_MIN 0x01
+#define JH7110_PCI_PORTIO_MAX 0x00 // MIN>MAX disables PIO
+#define JH7110_PCI_PORTIO_OFFSET 0x00
+// The bridge thinks its MMIO is here (which means it can't access this area in phy ram)
+
+#define JH7110_PCI_SEG0_MMIO32_MIN (0x30000000)
+#define JH7110_PCI_SEG0_MMIO32_MAX (JH7110_PCI_SEG0_MMIO32_MIN + 0x7FFFFFF)
+// The CPU views it via a window here..
+// We might be able to size another region?
+#define JH7110_PCI_SEG0_MMIO64_MIN (0x900000000)
+#define JH7110_PCI_SEG0_MMIO64_MAX (0x940000000)
+
+#define JH7110_PCI_SEG1_MMIO32_MIN (0x38000000)
+#define JH7110_PCI_SEG1_MMIO32_MAX (JH7110_PCI_SEG1_MMIO32_MIN + 0x7FFFFFF)
+// The CPU views it via a window here..
+// We might be able to size another region?
+#define JH7110_PCI_SEG1_MMIO64_MIN (0x980000000)
+#define JH7110_PCI_SEG1_MMIO64_MAX (0x9c0000000)
+
+//
+// See description in MdeModulePkg/Include/Library/PciHostBridgeLib.h
+//
+PCI_ROOT_BRIDGE mPciRootBridges[] = {
+ {
+ 0, // Segment
+ 0, // Supports
+ 0, // Attributes
+ FALSE, // DmaAbove4G
+ FALSE, // NoExtendedConfigSpace (true=256 byte config, false=4k)
+ FALSE, // ResourceAssigned
+ EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
+ EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes
+ { JH7110_PCI_BUSNUM_MIN,
+ JH7110_PCI_BUSNUM_MAX }, // Bus
+ { JH7110_PCI_PORTIO_MIN,
+ JH7110_PCI_PORTIO_MAX,
+ MAX_UINT64 - JH7110_PCI_PORTIO_OFFSET + 1 }, // Io
+ { JH7110_PCI_SEG0_MMIO32_MIN, JH7110_PCI_SEG0_MMIO32_MAX, 0 }, // Mem
+ { JH7110_PCI_SEG0_MMIO64_MIN,JH7110_PCI_SEG0_MMIO64_MAX, 0 }, // MemAbove4G
+ { MAX_UINT32, 0x0 }, // Pefetchable Mem
+ { MAX_UINT64, 0x0 }, // Pefetchable MemAbove4G
+ (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[0]
+ },
+ {
+ 1, // Segment
+ 0, // Supports
+ 0, // Attributes
+ FALSE, // DmaAbove4G
+ FALSE, // NoExtendedConfigSpace (true=256 byte config, false=4k)
+ FALSE, // ResourceAssigned
+ EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
+ EFI_PCI_HOST_BRIDGE_MEM64_DECODE, // AllocationAttributes
+ { JH7110_PCI_BUSNUM_MIN,
+ JH7110_PCI_BUSNUM_MAX }, // Bus
+ { JH7110_PCI_PORTIO_MIN,
+ JH7110_PCI_PORTIO_MAX,
+ MAX_UINT64 - JH7110_PCI_PORTIO_OFFSET + 1 }, // Io
+ { JH7110_PCI_SEG1_MMIO32_MIN, JH7110_PCI_SEG1_MMIO32_MAX, 0 }, // Mem
+ { JH7110_PCI_SEG1_MMIO64_MIN, JH7110_PCI_SEG1_MMIO64_MAX, 0}, // MemAbove4G
+ { MAX_UINT32, 0x0 }, // Pefetchable Mem
+ { MAX_UINT64, 0x0 }, // Pefetchable MemAbove4G
+ (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[1]
+ }
+};
+
+/**
+ Return all the root bridge instances in an array.
+
+ @param Count Return the count of root bridge instances.
+
+ @return All the root bridge instances in an array.
+ The array should be passed into PciHostBridgeFreeRootBridges()
+ when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+ OUT UINTN *Count
+ )
+{
+ *Count = ARRAY_SIZE (mPciRootBridges);
+ return mPciRootBridges;
+}
+
+/**
+ Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+ @param Bridges The root bridge instances array.
+ @param Count The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+ PCI_ROOT_BRIDGE *Bridges,
+ UINTN Count
+ )
+{
+}
+
+/**
+ Inform the platform that the resource conflict happens.
+
+ @param HostBridgeHandle Handle of the Host Bridge.
+ @param Configuration Pointer to PCI I/O and PCI memory resource
+ descriptors. The Configuration contains the resources
+ for all the root bridges. The resource for each root
+ bridge is terminated with END descriptor and an
+ additional END is appended indicating the end of the
+ entire resources. The resource descriptor field
+ values follow the description in
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ .SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+ EFI_HANDLE HostBridgeHandle,
+ VOID *Configuration
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ UINTN RootBridgeIndex;
+
+ DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+ RootBridgeIndex = 0;
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
+ while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+ for ( ; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ ASSERT (
+ Descriptor->ResType <
+ ARRAY_SIZE (mPciHostBridgeLibAcpiAddressSpaceTypeStr)
+ );
+ DEBUG (
+ (DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+ mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+ Descriptor->AddrLen, Descriptor->AddrRangeMax
+ )
+ );
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ DEBUG (
+ (DEBUG_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
+ Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+ ((Descriptor->SpecificFlag &
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+ ) != 0) ? L" (Prefetchable)" : L""
+ )
+ );
+ }
+ }
+
+ //
+ // Skip the END descriptor for root bridge
+ //
+ ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+ (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
+ );
+ }
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
new file mode 100644
index 000000000000..c6d498df2d62
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -0,0 +1,48 @@
+## @file
+#
+# PCI Host Bridge Library instance for StarFive JH7110 SOC
+# Liberally borrowed from the SynQuacer
+#
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = PciHostBridgeLib
+ FILE_GUID = 606d906f-eba7-d5c6-fcf0-6aeedea00193
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciHostBridgeLib|DXE_DRIVER
+ CONSTRUCTOR = JH7110PciHostBridgeLibConstructor
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = ARM AARCH64 RISCV64
+#
+
+[Sources]
+ PciHostBridgeLib.c
+ PciHostBridgeLibConstructor.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ PcdLib
+ UefiBootServicesTableLib
+
+[FixedPcd]
+ gJH7110TokenSpaceGuid.PcdJH7110PciRegBase
+ gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioAdr
+ gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioLen
+ gJH7110TokenSpaceGuid.PcdJH7110PciCpuMmioAdr
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
new file mode 100644
index 000000000000..05d10e08232c
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciHostBridgeLib/PciHostBridgeLibConstructor.c
@@ -0,0 +1,405 @@
+/** @file
+ *
+ * PCI Host Bridge Library instance for StarFive JH7110 SOC
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ * This module initializes the Pci as close to a standard
+ * PCI root complex as possible. The general information
+ * for this driver was sourced from.
+ *
+ *
+ **/
+
+#include <IndustryStandard/JH7110.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <PiDxe.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Library/TimerLib.h>
+
+#define RegWrite(addr, data) MmioWrite32((addr), (data))
+#define RegRead(addr, data) ((data) = MmioRead32 (addr))
+
+#define STG_SYSCON_BASE 0x10240000
+
+#define STG_SYSCON_K_RP_NEP_MASK (1 << 8)
+#define STG_SYSCON_CKREF_SRC_SHIFT 18
+#define STG_SYSCON_CKREF_SRC_MASK (0x3 << 18)
+#define STG_SYSCON_CLKREQ_MASK (1 << 22)
+#define STG_SYSCON_BASE 0x10240000
+#define SYS_CLK_BASE 0x13020000
+#define STG_CLK_BASE 0x10230000
+#define SYS_CLK_NOC_OFFSET 0x98
+#define STG_PCIE_CLK_OFFSET 0x20
+#define STG_PCIE_CLKS 0xc
+#define STG_PCIE_RESET_OFFSET 0x74
+#define SYS_GPIO_BASE 0x13040000
+
+#define PREF_MEM_WIN_64_SUPPORT (1 << 3)
+#define PMSG_LTR_SUPPORT (1 << 2)
+#define PDLA_LINK_SPEED_GEN2 (1 << 12)
+#define PLDA_FUNCTION_DIS (1 << 15)
+#define PLDA_FUNC_NUM 4
+#define PLDA_PHY_FUNC_SHIFT 9
+#define PLDA_RP_ENABLE 1
+
+#define PCIE_BASIC_STATUS 0x018
+#define PCIE_CFGNUM 0x140
+#define IMASK_LOCAL 0x180
+#define ISTATUS_LOCAL 0x184
+#define IMSI_ADDR 0x190
+#define ISTATUS_MSI 0x194
+#define CFG_SPACE 0x1000
+#define GEN_SETTINGS 0x80
+#define PCIE_PCI_IDS 0x9C
+#define PCIE_WINROM 0xFC
+#define PMSG_SUPPORT_RX 0x3F0
+#define PCI_MISC 0xB4
+
+#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK 0x7FFF00
+#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT 0x8
+#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK 0x7FFF
+#define STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT 0x0
+
+#define XR3PCI_ATR_AXI4_SLV0 0x800
+#define XR3PCI_ATR_SRC_ADDR_LOW 0x0
+#define XR3PCI_ATR_SRC_ADDR_HIGH 0x4
+#define XR3PCI_ATR_TRSL_ADDR_LOW 0x8
+#define XR3PCI_ATR_TRSL_ADDR_HIGH 0xc
+#define XR3PCI_ATR_TRSL_PARAM 0x10
+#define XR3PCI_ATR_TABLE_OFFSET 0x20
+#define XR3PCI_ATR_MAX_TABLE_NUM 8
+
+#define XR3PCI_ATR_SRC_ADDR_MASK 0xfffff000
+#define XR3PCI_ATR_TRSL_ADDR_MASK 0xfffff000
+#define XR3PCI_ATR_SRC_WIN_SIZE_SHIFT 1
+#define XR3_PCI_ECAM_SIZE 28
+
+#define IDS_PCI_TO_PCI_BRIDGE 0x060400
+#define IDS_CLASS_CODE_SHIFT 8
+#define SYS_GPIO_OUTPUT_OFF 0x40
+
+UINT32 AtrTableNum;
+UINT64 PCIE_CFG_BASE[2] = { 0x940000000, 0x9c0000000 };
+UINT64 PCI_MEMREGION_32[2] = { 0x30000000, 0x38000000 };
+UINT64 PCI_MEMREGION_64[2] = { 0x900000000, 0x980000000 };
+UINT64 PCI_MEMREGION_SIZE[2] = { 27, 30 };
+UINT32 STG_ARFUNC_OFFSET[2] = { 0xc0, 0x270 };
+UINT32 STG_AWFUNC_OFFSET[2] = { 0xc4, 0x274 };
+UINT32 STG_RP_REP_OFFSET[2] = { 0x130, 0x2e0 };
+UINT32 PCIE_GPIO[2] = { 26, 28 };
+
+STATIC inline UINT64
+GetPcieRegBase (
+ IN UINT32 Port
+ )
+{
+ return PCIE_REG_BASE + Port * 0x1000000;
+}
+
+VOID
+PcieRegWrite (
+ IN UINT32 Port,
+ IN UINTN Offset,
+ IN UINT32 Value
+ )
+{
+ UINT64 Base = GetPcieRegBase (Port);
+
+ RegWrite ((UINT64)Base + Offset, Value);
+}
+
+UINT32
+PcieRegRead (
+ IN UINT32 Port,
+ IN UINTN Offset
+ )
+{
+ UINT32 Value = 0;
+ UINT64 Base = GetPcieRegBase (Port);
+
+ RegRead ((UINT64)Base + Offset, Value);
+ return Value;
+}
+
+STATIC VOID
+PcieUpdatebits (
+ IN UINT64 Base,
+ IN UINTN Offset,
+ IN UINT32 Mask,
+ IN UINT32 val
+ )
+{
+ UINT32 Value = 0;
+
+ Value = MmioRead32 ((UINT64)Base + Offset);
+ Value &= ~Mask;
+ Value |= val;
+ MmioWrite32 ((UINT64)Base + Offset, Value);
+}
+
+STATIC
+VOID
+PcieFuncSet (
+ IN UINT32 Port
+ )
+{
+ INTN i;
+ UINT32 Value;
+ UINT64 Base = GetPcieRegBase (Port);
+
+ /* Disable physical functions except #0 */
+ for (i = 1; i < PLDA_FUNC_NUM; i++) {
+ PcieUpdatebits (
+ STG_SYSCON_BASE,
+ STG_ARFUNC_OFFSET[Port],
+ STG_SYSCON_AXI4_SLVL_ARFUNC_MASK,
+ (i << PLDA_PHY_FUNC_SHIFT) <<
+ STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT
+ );
+ PcieUpdatebits (
+ STG_SYSCON_BASE,
+ STG_AWFUNC_OFFSET[Port],
+ STG_SYSCON_AXI4_SLVL_AWFUNC_MASK,
+ (i << PLDA_PHY_FUNC_SHIFT) <<
+ STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT
+ );
+ PcieUpdatebits (
+ Base,
+ PCI_MISC,
+ PLDA_FUNCTION_DIS,
+ PLDA_FUNCTION_DIS
+ );
+ }
+
+ PcieUpdatebits (
+ STG_SYSCON_BASE,
+ STG_ARFUNC_OFFSET[Port],
+ STG_SYSCON_AXI4_SLVL_ARFUNC_MASK,
+ 0
+ );
+ PcieUpdatebits (
+ STG_SYSCON_BASE,
+ STG_AWFUNC_OFFSET[Port],
+ STG_SYSCON_AXI4_SLVL_AWFUNC_MASK,
+ 0
+ );
+
+ /* Enable root port*/
+ PcieUpdatebits (
+ Base,
+ GEN_SETTINGS,
+ PLDA_RP_ENABLE,
+ PLDA_RP_ENABLE
+ );
+
+ Value = (IDS_PCI_TO_PCI_BRIDGE << IDS_CLASS_CODE_SHIFT);
+ PcieRegWrite (Port, PCIE_PCI_IDS, Value);
+
+ PcieUpdatebits (
+ Base,
+ PMSG_SUPPORT_RX,
+ PMSG_LTR_SUPPORT,
+ 0
+ );
+
+ /* Prefetchable memory window 64-bit addressing support */
+ PcieUpdatebits (
+ Base,
+ PCIE_WINROM,
+ PREF_MEM_WIN_64_SUPPORT,
+ PREF_MEM_WIN_64_SUPPORT
+ );
+}
+
+STATIC
+VOID
+PcieSTGInit (
+ IN UINT32 Port
+ )
+{
+ PcieUpdatebits (
+ STG_SYSCON_BASE,
+ STG_RP_REP_OFFSET[Port],
+ STG_SYSCON_K_RP_NEP_MASK,
+ STG_SYSCON_K_RP_NEP_MASK
+ );
+ PcieUpdatebits (
+ STG_SYSCON_BASE,
+ STG_AWFUNC_OFFSET[Port],
+ STG_SYSCON_CKREF_SRC_MASK,
+ 2 << STG_SYSCON_CKREF_SRC_SHIFT
+ );
+ PcieUpdatebits (
+ STG_SYSCON_BASE,
+ STG_AWFUNC_OFFSET[Port],
+ STG_SYSCON_CLKREQ_MASK,
+ STG_SYSCON_CLKREQ_MASK
+ );
+}
+
+STATIC
+VOID
+PcieClockInit (
+ IN UINT32 Port
+ )
+{
+ RegWrite (
+ STG_CLK_BASE + STG_PCIE_CLK_OFFSET
+ + Port * STG_PCIE_CLKS,
+ 1 << 31
+ ); /*axi mst0*/
+ RegWrite (
+ STG_CLK_BASE + STG_PCIE_CLK_OFFSET
+ + Port * STG_PCIE_CLKS + 4,
+ 1 << 31
+ ); /* apb */
+ RegWrite (
+ STG_CLK_BASE + STG_PCIE_CLK_OFFSET
+ + Port * STG_PCIE_CLKS + 8,
+ 1 << 31
+ ); /* tl0 */
+}
+
+STATIC
+VOID
+PcieResetDeassert (
+ IN UINT32 Port
+ )
+{
+ UINT32 PortOffset = Port * 6 + 11;
+
+ PcieUpdatebits (
+ STG_CLK_BASE,
+ STG_PCIE_RESET_OFFSET,
+ 0x3f << (PortOffset),
+ 0
+ ); /*reset all*/
+}
+
+VOID
+PcieResetAssert (
+ IN UINT32 Port
+ )
+{
+ UINT32 PortOffset = Port * 6 + 11;
+
+ PcieUpdatebits (
+ STG_CLK_BASE,
+ STG_PCIE_RESET_OFFSET,
+ 0x3f << (PortOffset),
+ 0x3f << (PortOffset)
+ ); /*axi mst0*/
+}
+
+STATIC
+VOID
+PcieGpioResetSet (
+ IN UINT32 Port,
+ IN UINT32 Value
+ )
+{
+ UINT32 Remain, Mask;
+
+ Remain = PCIE_GPIO[Port] & 0x3;
+ Mask = 0xff << (Remain * 8);
+ PcieUpdatebits (
+ SYS_GPIO_BASE,
+ SYS_GPIO_OUTPUT_OFF + (PCIE_GPIO[Port] & 0xfffc),
+ Mask,
+ Value << (Remain * 8)
+ );
+}
+
+STATIC
+VOID
+PcieAtrInit (
+ IN UINT32 Port,
+ IN UINT64 SrcAddr,
+ IN UINT64 TrslAddr,
+ IN UINT32 WinSize,
+ IN UINT32 Config
+ )
+{
+ UINT64 Base = GetPcieRegBase (Port) + XR3PCI_ATR_AXI4_SLV0;
+ UINT32 Value;
+
+ Base += XR3PCI_ATR_TABLE_OFFSET * AtrTableNum;
+ AtrTableNum++;
+
+ /* X3PCI_ATR_SRC_ADDR_LOW:
+ * - bit 0: enable entry,
+ * - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1)
+ * - bits 7-11: reserved
+ * - bits 12-31: start of source address
+ */
+ Value = SrcAddr;
+ // DEBUG ((DEBUG_ERROR, "addr low %x\n", Value));
+ RegWrite (
+ Base + XR3PCI_ATR_SRC_ADDR_LOW,
+ (Value & XR3PCI_ATR_SRC_ADDR_MASK) | ((WinSize - 1) << 1) | 0x1
+ );
+ Value = SrcAddr >> 32;
+ // DEBUG ((DEBUG_ERROR, "addr high %x\n", Value));
+ RegWrite (Base + XR3PCI_ATR_SRC_ADDR_HIGH, Value);
+ Value = TrslAddr;
+ RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_LOW, Value);
+ Value = TrslAddr >> 32;
+ RegWrite (Base + XR3PCI_ATR_TRSL_ADDR_HIGH, Value);
+ RegWrite (Base + XR3PCI_ATR_TRSL_PARAM, Config);
+}
+
+EFI_STATUS
+EFIAPI
+JH7110PciHostBridgeLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINT32 PortIndex;
+
+ DEBUG ((DEBUG_ERROR, "PCIe RootBridge constructor\n"));
+ for (PortIndex = 0; PortIndex < 2; PortIndex++) {
+ PcieSTGInit (PortIndex);
+ RegWrite (SYS_CLK_BASE + SYS_CLK_NOC_OFFSET, 1 << 31);
+ PcieClockInit (PortIndex);
+ PcieResetDeassert (PortIndex);
+ PcieGpioResetSet (PortIndex, 0);
+ PcieFuncSet (PortIndex);
+
+ PcieAtrInit (
+ PortIndex,
+ PCIE_CFG_BASE[PortIndex],
+ 0,
+ XR3_PCI_ECAM_SIZE,
+ 1
+ );
+ PcieAtrInit (
+ PortIndex,
+ PCI_MEMREGION_32[PortIndex],
+ PCI_MEMREGION_32[PortIndex],
+ PCI_MEMREGION_SIZE[0],
+ 0
+ );
+ PcieAtrInit (
+ PortIndex,
+ PCI_MEMREGION_64[PortIndex],
+ PCI_MEMREGION_64[PortIndex],
+ PCI_MEMREGION_SIZE[1],
+ 0
+ );
+ PcieGpioResetSet (PortIndex, 1);
+ MicroSecondDelay (300);
+
+ DEBUG ((DEBUG_ERROR, "PCIe port %d init\n", PortIndex));
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c
new file mode 100644
index 000000000000..43dca2a6236a
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.c
@@ -0,0 +1,1460 @@
+/** @file
+ *
+ * PCI Segment Library for StarFive JH7110 SoC
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/UefiLib.h>
+#include <IndustryStandard/JH7110.h>
+#include <IndustryStandard/Pci30.h>
+
+typedef enum {
+ PciCfgWidthUint8 = 0,
+ PciCfgWidthUint16,
+ PciCfgWidthUint32,
+ PciCfgWidthMax
+} PCI_CFG_WIDTH;
+
+/*
+ * This PCIe config space is unusual...
+ * The root port is the first bytes of the register space (offset 0)
+ * The individual devices are then selected by computing their BDF index
+ * and writing that into the CFG_INDEX register (offset 0x9000)
+ * the "ECAM" data is then read/writeable at CFG_DATA (offset 0x8000)
+ */
+
+#define EFI_PCI_ADDR_BUS(bus) ((bus >> 20) & 0xFF) /* Note PCI_SEGMENT_LIB_ADDRESS */
+#define EFI_PCI_ADDR_DEV(dev) ((dev >> 15) & 0x1F)
+#define EFI_PCI_ADDR_FUN(fun) ((fun >> 12) & 0x07)
+
+/**
+ Assert the validity of a PCI Segment address.
+ A valid PCI Segment address should not contain 1's in bits 28..31 and 48..63
+
+ @param A The address to validate.
+ @param M Additional bits to assert to be zero.
+
+**/
+#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A, M) \
+ ASSERT (((A) & (0xffff0000f0000000ULL | (M))) == 0)
+
+/**
+ Given the nature of how we access PCI devices, we ensure that
+ read/write accesses are serialized through the use of a lock.
+**/
+STATIC
+EFI_LOCK mPciSegmentReadWriteLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
+
+// STATIC UINT64 mPciSegmentLastAccess; /* Avoid repeat CFG_INDEX updates */
+
+/**
+ Internal worker function to obtain config space base address.
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @return The value read from the PCI configuration register.
+
+**/
+STATIC
+UINT64
+PciSegmentLibGetConfigBase (
+ IN UINT64 Address,
+ IN UINT16 Segment,
+ IN UINT32 Write
+ )
+{
+ UINT64 Base;
+ UINT64 Offset;
+ UINT32 Dev;
+ UINT32 Bus;
+
+ Base = PCIE_CONFIG_BASE;
+ Offset = Address & 0xFFF; /* Pick off the 4k register offset */
+ Address &= 0xFFFF000; /* Clear the offset leave only the BDF */
+
+ /* The root port is at the base of the PCIe register space */
+ if (Address != 0) {
+ Dev = EFI_PCI_ADDR_DEV (Address);
+ Bus = EFI_PCI_ADDR_BUS (Address);
+
+ /*
+ * There can only be a single device on bus 1 (downstream of root).
+ * Subsequent busses (behind a PCIe switch) can have more.
+ */
+ if (Dev > 0) {
+ return 0xFFFFFFFF;
+ }
+
+ return Base + Segment * 0x80000000 + Address + Offset;
+ } else {
+ if (Write && ((Offset == 0x10) || (Offset == 0x14))) {
+ return 0xFFFFFFFF;
+ }
+ }
+
+ return Base + Segment * 0x80000000 + Offset;
+}
+
+/**
+ Internal worker function to read a PCI configuration register.
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param Width The width of data to read
+
+ @return The value read from the PCI configuration register.
+
+**/
+STATIC
+UINT32
+PciSegmentLibReadWorker (
+ IN UINT64 Address,
+ IN PCI_CFG_WIDTH Width
+ )
+{
+ UINT64 Base;
+ UINT32 Ret;
+ UINT16 Segment = (Address >> 32);
+
+ EfiAcquireLock (&mPciSegmentReadWriteLock);
+ Base = PciSegmentLibGetConfigBase (Address, Segment, 0);
+
+ if (Base == 0xFFFFFFFF) {
+ EfiReleaseLock (&mPciSegmentReadWriteLock);
+ return Base;
+ }
+
+ switch (Width) {
+ case PciCfgWidthUint8:
+ Ret = MmioRead8 (Base);
+ break;
+ case PciCfgWidthUint16:
+ Ret = MmioRead16 (Base);
+ break;
+ case PciCfgWidthUint32:
+ Ret = MmioRead32 (Base);
+ break;
+ default:
+ ASSERT (FALSE);
+ Ret = 0;
+ }
+
+ EfiReleaseLock (&mPciSegmentReadWriteLock);
+ // DEBUG ((DEBUG_ERROR, "PCIe seg read Address %lx %lx width %d val %x Segment %d\n", Base, Address, Width, Ret, Segment));
+ return Ret;
+}
+
+/**
+ Internal worker function to writes a PCI configuration register.
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param Width The width of data to write
+ @param Data The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+STATIC
+UINT32
+PciSegmentLibWriteWorker (
+ IN UINT64 Address,
+ IN PCI_CFG_WIDTH Width,
+ IN UINT32 Data
+ )
+{
+ UINT64 Base;
+ UINT16 Segment = (Address >> 32);
+
+ EfiAcquireLock (&mPciSegmentReadWriteLock);
+ Base = PciSegmentLibGetConfigBase (Address, Segment, 1);
+
+ if (Base == 0xFFFFFFFF) {
+ EfiReleaseLock (&mPciSegmentReadWriteLock);
+ return Data;
+ }
+
+ switch (Width) {
+ case PciCfgWidthUint8:
+ MmioWrite8 (Base, Data);
+ break;
+ case PciCfgWidthUint16:
+ MmioWrite16 (Base, Data);
+ break;
+ case PciCfgWidthUint32:
+ MmioWrite32 (Base, Data);
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ EfiReleaseLock (&mPciSegmentReadWriteLock);
+ return Data;
+}
+
+/**
+ Register a PCI device so PCI configuration registers may be accessed after
+ SetVirtualAddressMap().
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @retval RETURN_SUCCESS The PCI device was registered for runtime access.
+ @retval RETURN_UNSUPPORTED An attempt was made to call this function
+ after ExitBootServices().
+ @retval RETURN_UNSUPPORTED The resources required to access the PCI device
+ at runtime could not be mapped.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
+ complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciSegmentRegisterForRuntimeAccess (
+ IN UINTN Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Reads an 8-bit PCI configuration register.
+
+ Reads and returns the 8-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function,
+ and Register.
+
+ @return The 8-bit PCI configuration register specified by Address.
+
+**/
+UINT8
+EFIAPI
+PciSegmentRead8 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+
+ return (UINT8)PciSegmentLibReadWorker (Address, PciCfgWidthUint8);
+}
+
+/**
+ Writes an 8-bit PCI configuration register.
+
+ Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentWrite8 (
+ IN UINT64 Address,
+ IN UINT8 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0);
+
+ return (UINT8)PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, Value);
+}
+
+/**
+ Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentOr8 (
+ IN UINT64 Address,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) | OrData));
+}
+
+/**
+ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAnd8 (
+ IN UINT64 Address,
+ IN UINT8 AndData
+ )
+{
+ return PciSegmentWrite8 (Address, (UINT8)(PciSegmentRead8 (Address) & AndData));
+}
+
+/**
+ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,
+ followed a bitwise OR with another 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAndThenOr8 (
+ IN UINT64 Address,
+ IN UINT8 AndData,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (Address, (UINT8)((PciSegmentRead8 (Address) & AndData) | OrData));
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in an 8-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address The PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldRead8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 8-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param Value The new value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldWrite8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 Value
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldWrite8 (PciSegmentRead8 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
+ writes the result back to the bit field in the 8-bit port.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 8-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldOr8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldOr8 (PciSegmentRead8 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
+ AND, and writes the result back to the bit field in the 8-bit register.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise AND between the read result and the value specified by AndData, and
+ writes the result to the 8-bit PCI configuration register specified by
+ Address. The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are
+ serialized. Extra left bits in AndData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAnd8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 AndData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldAnd8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 8-bit port.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 8-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAndThenOr8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 AndData,
+ IN UINT8 OrData
+ )
+{
+ return PciSegmentWrite8 (
+ Address,
+ BitFieldAndThenOr8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a 16-bit PCI configuration register.
+
+ Reads and returns the 16-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+ @return The 16-bit PCI configuration register specified by Address.
+
+**/
+UINT16
+EFIAPI
+PciSegmentRead16 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
+
+ return (UINT16)PciSegmentLibReadWorker (Address, PciCfgWidthUint16);
+}
+
+/**
+ Writes a 16-bit PCI configuration register.
+
+ Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The parameter of Value.
+
+**/
+UINT16
+EFIAPI
+PciSegmentWrite16 (
+ IN UINT64 Address,
+ IN UINT16 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1);
+
+ return (UINT16)PciSegmentLibWriteWorker (Address, PciCfgWidthUint16, Value);
+}
+
+/**
+ Performs a bitwise OR of a 16-bit PCI configuration register with
+ a 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 16-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function and
+ Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentOr16 (
+ IN UINT64 Address,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) | OrData));
+}
+
+/**
+ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAnd16 (
+ IN UINT64 Address,
+ IN UINT16 AndData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16)(PciSegmentRead16 (Address) & AndData));
+}
+
+/**
+ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,
+ followed a bitwise OR with another 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAndThenOr16 (
+ IN UINT64 Address,
+ IN UINT16 AndData,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (Address, (UINT16)((PciSegmentRead16 (Address) & AndData) | OrData));
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in a 16-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address The PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldRead16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 16-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param Value The new value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldWrite16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 Value
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldWrite16 (PciSegmentRead16 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldOr16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldOr16 (PciSegmentRead16 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR,
+ and writes the result back to the bit field in the 16-bit port.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+ Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ The ordinal of the least significant bit in a byte is bit 0.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ The ordinal of the most significant bit in a byte is bit 7.
+ @param AndData The value to AND with the read value from the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAnd16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 AndData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldAnd16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 16-bit port.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 16-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAndThenOr16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 AndData,
+ IN UINT16 OrData
+ )
+{
+ return PciSegmentWrite16 (
+ Address,
+ BitFieldAndThenOr16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a 32-bit PCI configuration register.
+
+ Reads and returns the 32-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function,
+ and Register.
+
+ @return The 32-bit PCI configuration register specified by Address.
+
+**/
+UINT32
+EFIAPI
+PciSegmentRead32 (
+ IN UINT64 Address
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
+
+ return PciSegmentLibReadWorker (Address, PciCfgWidthUint32);
+}
+
+/**
+ Writes a 32-bit PCI configuration register.
+
+ Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device,
+ Function, and Register.
+ @param Value The value to write.
+
+ @return The parameter of Value.
+
+**/
+UINT32
+EFIAPI
+PciSegmentWrite32 (
+ IN UINT64 Address,
+ IN UINT32 Value
+ )
+{
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3);
+
+ return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, Value);
+}
+
+/**
+ Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentOr32 (
+ IN UINT64 Address,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData);
+}
+
+/**
+ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function,
+ and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAnd32 (
+ IN UINT64 Address,
+ IN UINT32 AndData
+ )
+{
+ return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData);
+}
+
+/**
+ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,
+ followed a bitwise OR with another 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address The address that encodes the PCI Segment, Bus, Device, Function,
+ and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAndThenOr32 (
+ IN UINT64 Address,
+ IN UINT32 AndData,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData) | OrData);
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in a 32-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address The PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldRead32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 32-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param Value The new value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldWrite32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 Value
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldWrite32 (PciSegmentRead32 (Address), StartBit, EndBit, Value)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
+ writes the result back to the bit field in the 32-bit port.
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 32-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldOr32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldOr32 (PciSegmentRead32 (Address), StartBit, EndBit, OrData)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
+ AND, and writes the result back to the bit field in the 32-bit register.
+
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a bitwise
+ AND between the read result and the value specified by AndData, and writes the result
+ to the 32-bit PCI configuration register specified by Address. The value written to
+ the PCI configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in AndData are stripped.
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAnd32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 AndData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldAnd32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData)
+ );
+}
+
+/**
+ Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 32-bit port.
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 32-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address The PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAndThenOr32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 AndData,
+ IN UINT32 OrData
+ )
+{
+ return PciSegmentWrite32 (
+ Address,
+ BitFieldAndThenOr32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData, OrData)
+ );
+}
+
+/**
+ Reads a range of PCI configuration registers into a caller supplied buffer.
+
+ Reads the range of PCI configuration registers specified by StartAddress and
+ Size into the buffer specified by Buffer. This function only allows the PCI
+ configuration registers from a single PCI function to be read. Size is
+ returned. When possible 32-bit PCI configuration read cycles are used to read
+ from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
+ and 16-bit PCI configuration read cycles may be used at the beginning and the
+ end of the range.
+
+ If any reserved bits in StartAddress are set, then ASSERT().
+ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+ If Size > 0 and Buffer is NULL, then ASSERT().
+
+ @param StartAddress The starting address that encodes the PCI Segment, Bus,
+ Device, Function and Register.
+ @param Size The size in bytes of the transfer.
+ @param Buffer The pointer to a buffer receiving the data read.
+
+ @return Size
+
+**/
+UINTN
+EFIAPI
+PciSegmentReadBuffer (
+ IN UINT64 StartAddress,
+ IN UINTN Size,
+ OUT VOID *Buffer
+ )
+{
+ UINTN ReturnValue;
+
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
+ ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+ if (Size == 0) {
+ return Size;
+ }
+
+ ASSERT (Buffer != NULL);
+
+ //
+ // Save Size for return
+ //
+ ReturnValue = Size;
+
+ if ((StartAddress & BIT0) != 0) {
+ //
+ // Read a byte if StartAddress is byte aligned
+ //
+ *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);
+ StartAddress += sizeof (UINT8);
+ Size -= sizeof (UINT8);
+ Buffer = (UINT8 *)Buffer + 1;
+ }
+
+ if ((Size >= sizeof (UINT16)) && ((StartAddress & BIT1) != 0)) {
+ //
+ // Read a word if StartAddress is word aligned
+ //
+ WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
+ StartAddress += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16 *)Buffer + 1;
+ }
+
+ while (Size >= sizeof (UINT32)) {
+ //
+ // Read as many double words as possible
+ //
+ WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress));
+ StartAddress += sizeof (UINT32);
+ Size -= sizeof (UINT32);
+ Buffer = (UINT32 *)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT16)) {
+ //
+ // Read the last remaining word if exist
+ //
+ WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress));
+ StartAddress += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16 *)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT8)) {
+ //
+ // Read the last remaining byte if exist
+ //
+ *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress);
+ }
+
+ return ReturnValue;
+}
+
+/**
+ Copies the data in a caller supplied buffer to a specified range of PCI
+ configuration space.
+
+ Writes the range of PCI configuration registers specified by StartAddress and
+ Size from the buffer specified by Buffer. This function only allows the PCI
+ configuration registers from a single PCI function to be written. Size is
+ returned. When possible 32-bit PCI configuration write cycles are used to
+ write from StartAdress to StartAddress + Size. Due to alignment restrictions,
+ 8-bit and 16-bit PCI configuration write cycles may be used at the beginning
+ and the end of the range.
+
+ If any reserved bits in StartAddress are set, then ASSERT().
+ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+ If Size > 0 and Buffer is NULL, then ASSERT().
+
+ @param StartAddress The starting address that encodes the PCI Segment, Bus,
+ Device, Function and Register.
+ @param Size The size in bytes of the transfer.
+ @param Buffer The pointer to a buffer containing the data to write.
+
+ @return The parameter of Size.
+
+**/
+UINTN
+EFIAPI
+PciSegmentWriteBuffer (
+ IN UINT64 StartAddress,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ UINTN ReturnValue;
+
+ ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0);
+ ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+ if (Size == 0) {
+ return 0;
+ }
+
+ ASSERT (Buffer != NULL);
+
+ // The Bcm/Rpi has a single cfg which can be mapped
+ // to any given device on the bus, which means we need to remap
+ // it basically everytime a new config access is done
+
+ //
+ // Save Size for return
+ //
+ ReturnValue = Size;
+
+ if ((StartAddress & BIT0) != 0) {
+ //
+ // Write a byte if StartAddress is byte aligned
+ //
+ PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);
+ StartAddress += sizeof (UINT8);
+ Size -= sizeof (UINT8);
+ Buffer = (UINT8 *)Buffer + 1;
+ }
+
+ if ((Size >= sizeof (UINT16)) && ((StartAddress & BIT1) != 0)) {
+ //
+ // Write a word if StartAddress is word aligned
+ //
+ PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
+ StartAddress += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16 *)Buffer + 1;
+ }
+
+ while (Size >= sizeof (UINT32)) {
+ //
+ // Write as many double words as possible
+ //
+ PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer));
+ StartAddress += sizeof (UINT32);
+ Size -= sizeof (UINT32);
+ Buffer = (UINT32 *)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT16)) {
+ //
+ // Write the last remaining word if exist
+ //
+ PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer));
+ StartAddress += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16 *)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT8)) {
+ //
+ // Write the last remaining byte if exist
+ //
+ PciSegmentWrite8 (StartAddress, *(UINT8 *)Buffer);
+ }
+
+ return ReturnValue;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf
new file mode 100644
index 000000000000..30d9d9599564
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PciSegmentLib/PciSegmentLib.inf
@@ -0,0 +1,33 @@
+## @file
+# PCI Segment Library for StarFive JH7110 SoC
+#
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = PciSegmentLib
+ FILE_GUID = 832163a2-41f5-c529-3f02-77fb68abbc2c
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciSegmentLib
+
+[Sources]
+ PciSegmentLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ IoLib
+ PcdLib
+ UefiLib
+
+[FixedPcd]
+ gJH7110TokenSpaceGuid.PcdJH7110PciConfigRegBase
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109779): https://edk2.groups.io/g/devel/message/109779
Mute This Topic: https://groups.io/mt/102053680/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support
2023-10-19 2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
@ 2023-10-19 2:59 ` John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 3/6] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
` (3 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-19 2:59 UTC (permalink / raw)
To: devel; +Cc: John Chew, Sunil V L
Cc: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
---
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c | 893 ++++++++++++++++++++
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h | 188 +++++
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf | 52 ++
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c | 571 +++++++++++++
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h | 35 +
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf | 44 +
Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h | 163 ++++
Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h | 88 ++
8 files changed, 2034 insertions(+)
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c
new file mode 100755
index 000000000000..c345556f8abf
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c
@@ -0,0 +1,893 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include "SpiDxe.h"
+
+SPI_MASTER *mSpiMasterInstance;
+
+STATIC
+VOID
+SpiControllerEnable (
+ IN UINT32 RegBase
+ )
+{
+ UINT32 Reg;
+
+ Reg = MmioRead32 (RegBase + SPI_REG_CONFIG);
+ Reg |= SPI_REG_CONFIG_ENABLE;
+ MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg);
+}
+
+STATIC
+VOID
+SpiControllerDisable (
+ IN UINT32 RegBase
+ )
+{
+ UINT32 Reg;
+
+ Reg = MmioRead32 (RegBase + SPI_REG_CONFIG);
+ Reg &= ~SPI_REG_CONFIG_ENABLE;
+ MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg);
+}
+
+STATIC
+VOID
+SpiWriteSpeed (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 SclkHz,
+ IN SPI_TIMING_PARAMS *Timing
+ )
+{
+ UINT32 Reg, Div, RefClkNs, SclkNs;
+ UINT32 Tshsl, Tchsh, Tslch, Tsd2d;
+
+ SpiControllerDisable (Slave->RegBase);
+
+ /* Configure baudrate */
+ Reg = MmioRead32 (Slave->RegBase + SPI_REG_CONFIG);
+ Reg &= ~(SPI_REG_CONFIG_BAUD_MASK << SPI_REG_CONFIG_BAUD_LSB);
+
+ Div = DIV_ROUND_UP (Timing->RefClkHz, SclkHz * 2) - 1;
+
+ if (Div > SPI_REG_CONFIG_BAUD_MASK) {
+ Div = SPI_REG_CONFIG_BAUD_MASK;
+ }
+
+ DEBUG (
+ (DEBUG_INFO, "%a(): RefClk %dHz sclk %dHz Div 0x%x, actual %dHz\n", __func__,
+ Timing->RefClkHz, SclkHz, Div, Timing->RefClkHz / (2 * (Div + 1)))
+ );
+
+ Reg |= (Div << SPI_REG_CONFIG_BAUD_LSB);
+ MmioWrite32 (Slave->RegBase + SPI_REG_CONFIG, Reg);
+
+ /* Configure delay timing */
+ RefClkNs = DIV_ROUND_UP (1000000000, Timing->RefClkHz);
+ SclkNs = DIV_ROUND_UP (1000000000, SclkHz);
+
+ if (Timing->TshslNs >= SclkNs + RefClkNs) {
+ Timing->TshslNs -= SclkNs + RefClkNs;
+ }
+
+ if (Timing->TchshNs >= SclkNs + 3 * RefClkNs) {
+ Timing->TchshNs -= SclkNs + 3 * RefClkNs;
+ }
+
+ Tshsl = DIV_ROUND_UP (Timing->TshslNs, RefClkNs);
+ Tchsh = DIV_ROUND_UP (Timing->TchshNs, RefClkNs);
+ Tslch = DIV_ROUND_UP (Timing->TslchNs, RefClkNs);
+ Tsd2d = DIV_ROUND_UP (Timing->Tsd2dNs, RefClkNs);
+
+ Reg = ((Tshsl & SPI_REG_DELAY_TSHSL_MASK)
+ << SPI_REG_DELAY_TSHSL_LSB);
+ Reg |= ((Tchsh & SPI_REG_DELAY_TCHSH_MASK)
+ << SPI_REG_DELAY_TCHSH_LSB);
+ Reg |= ((Tslch & SPI_REG_DELAY_TSLCH_MASK)
+ << SPI_REG_DELAY_TSLCH_LSB);
+ Reg |= ((Tsd2d & SPI_REG_DELAY_TSD2D_MASK)
+ << SPI_REG_DELAY_TSD2D_LSB);
+ MmioWrite32 (Slave->RegBase + SPI_REG_DELAY, Reg);
+
+ SpiControllerEnable (Slave->RegBase);
+}
+
+STATIC
+EFI_STATUS
+SpiWaitIdle (
+ IN UINT32 RegBase
+ )
+{
+ BOOLEAN IsIdle;
+ UINT32 Count = 0;
+ UINT32 TimeoutMs = 5000000;
+
+ do {
+ IsIdle = (BOOLEAN)((MmioRead32(RegBase + SPI_REG_CONFIG) >>
+ SPI_REG_CONFIG_IDLE_LSB) & 0x1);
+ Count = (IsIdle) ? (Count+1) : 0;
+
+ /*
+ * Make sure the QSPI controller is in really idle
+ * for n period of time before proceed
+ */
+ if (Count >= SPI_POLL_IDLE_RETRY) {
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (1);
+ } while (TimeoutMs);
+
+ return EFI_TIMEOUT;
+}
+
+STATIC
+EFI_STATUS
+SpiExecFlashCmd (
+ IN UINT32 RegBase,
+ IN UINT32 Reg
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Retry = SPI_REG_RETRY;
+
+ /* Write the CMDCTRL without start execution */
+ MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg);
+ /* Start execute */
+ Reg |= SPI_REG_CMDCTRL_EXECUTE;
+ MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg);
+
+ while (Retry--) {
+ Reg = MmioRead32 (RegBase + SPI_REG_CMDCTRL);
+ if ((Reg & SPI_REG_CMDCTRL_INPROGRESS) == 0) {
+ break;
+ }
+ gBS->Stall (1);
+ }
+
+ if (!Retry) {
+ DEBUG ((DEBUG_ERROR, "%a(): flash command execution Timeout\n", __func__));
+ return EFI_TIMEOUT;
+ }
+
+ /* Polling QSPI idle status */
+ Status = SpiWaitIdle (RegBase);
+ if (EFI_ERROR (Status)) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* For command RDID, RDSR. */
+EFI_STATUS
+SpiCommandRead (
+ IN SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN OUT SPI_OP_PARAMS *Cmds
+ )
+{
+ UINT32 Reg;
+ UINT32 ReadLen;
+ EFI_STATUS Status;
+ SPI_MASTER *SpiMaster;
+ UINT32 RxLen = Cmds->Data.NBytes;
+ VOID *RxBuf = Cmds->Data.Buf.In;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (&SpiMaster->Lock);
+ }
+
+ if ((RxLen > SPI_STIG_DATA_LEN_MAX) || !RxBuf) {
+ DEBUG ((DEBUG_ERROR, "%a(): Invalid input arguments RxLen %d\n", __func__, RxLen));
+ Status = EFI_INVALID_PARAMETER;
+ goto Fail;
+ }
+
+ Reg = Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB;
+ Reg |= (0x1 << SPI_REG_CMDCTRL_RD_EN_LSB);
+
+ /* 0 means 1 byte */
+ Reg |= (((RxLen - 1) & SPI_REG_CMDCTRL_RD_BYTES_MASK)
+ << SPI_REG_CMDCTRL_RD_BYTES_LSB);
+ Status = SpiExecFlashCmd (Slave->RegBase, Reg);
+ if (EFI_ERROR (Status)) {
+ goto Fail;
+ }
+
+ Reg = MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATALOWER);
+
+ /* Put the read value into rx_buf */
+ ReadLen = (RxLen > 4) ? 4 : RxLen;
+ CopyMem (RxBuf, &Reg, ReadLen);
+ RxBuf += ReadLen;
+
+ if (RxLen > 4) {
+ Reg = MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATAUPPER);
+
+ ReadLen = RxLen - ReadLen;
+ CopyMem (RxBuf, &Reg, ReadLen);
+ }
+
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+ return EFI_SUCCESS;
+
+Fail:
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+SpiGetReadSramLevel (
+ IN UINT32 RegBase,
+ OUT UINT16 *SramLvl
+ )
+{
+ UINT32 Reg = MmioRead32 (RegBase + SPI_REG_SDRAMLEVEL);
+ Reg >>= SPI_REG_SDRAMLEVEL_RD_LSB;
+ *SramLvl = (UINT16)(Reg & SPI_REG_SDRAMLEVEL_RD_MASK);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SpiWaitForData (
+ IN UINT32 RegBase,
+ UINT16 *SramLvl
+ )
+{
+ UINT32 Timeout = 10000;
+
+ while (Timeout--) {
+ SpiGetReadSramLevel (RegBase, SramLvl);
+ if (SramLvl != 0) {
+ return EFI_SUCCESS;
+ }
+ gBS->Stall (1);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+STATIC
+EFI_STATUS
+SpiWaitForBitLe32 (
+ IN INT32 Reg,
+ IN CONST UINT32 Mask,
+ IN CONST BOOLEAN Set,
+ IN CONST UINT32 TimeoutMs
+ )
+{
+ UINT32 Val;
+ UINTN Start = TimeoutMs*1000;
+
+ while(1) {
+ Val = MmioRead32 (Reg);
+
+ if (!Set) {
+ Val = ~Val;
+ }
+
+ if ((Val & Mask) == Mask) {
+ return EFI_SUCCESS;
+ }
+
+ if (Start == 0) {
+ break;
+ } else {
+ Start--;
+ }
+
+ gBS->Stall (1);
+ }
+
+ DEBUG ((DEBUG_ERROR, "Timeout (Reg=%lx Mask=%x wait_set=%d)\n", Reg, Mask, Set));
+
+ return EFI_TIMEOUT;
+}
+
+STATIC
+VOID
+SpiReadByte (
+ IN VOID *Addr,
+ IN VOID *Data,
+ IN UINT16 ByteLen
+ )
+{
+ UINT8 *AddrPtr;
+ UINT8 *DataPtr;
+
+ AddrPtr = (UINT8 *)Addr;
+ DataPtr = (UINT8 *)Data;
+
+ while (ByteLen) {
+ *DataPtr = *AddrPtr;
+ DataPtr++;
+ ByteLen--;
+ }
+}
+
+STATIC
+VOID
+SpiReadLong (
+ VOID *Addr,
+ VOID *Data,
+ UINT16 LongLen
+ )
+{
+ UINT32 *AddrPtr;
+ UINT32 *DataPtr;
+
+ AddrPtr = (UINT32 *)Addr;
+ DataPtr = (UINT32 *)Data;
+
+ while (LongLen) {
+ *DataPtr = *AddrPtr;
+ DataPtr++;
+ LongLen--;
+ }
+}
+
+EFI_STATUS
+SpiDataRead (
+ IN SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN OUT SPI_OP_PARAMS *Cmds
+ )
+{
+ SPI_MASTER *SpiMaster;
+ UINT8 *RxBuf = Cmds->Data.Buf.In;
+ UINT32 Remaining = Cmds->Data.NBytes;
+ UINT16 BytesToRead = 0;
+ EFI_STATUS Status;
+ UINT32 Reg;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (&SpiMaster->Lock);
+ }
+
+ if (!Cmds->Addr.NBytes) {
+ Status = EFI_ABORTED;
+ goto Fail;
+ }
+
+ /* Setup the indirect trigger start address */
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDSTARTADDR, Cmds->Addr.Val);
+
+ /* Register command */
+ Reg = Cmds->Cmd.OpCode << SPI_REG_RD_INSTR_OPCODE_LSB;
+ MmioWrite32 (Slave->RegBase + SPI_REG_RD_INSTR, Reg);
+
+ /* Set device size */
+ Reg = MmioRead32 (Slave->RegBase + SPI_REG_SIZE);
+ Reg &= ~SPI_REG_SIZE_ADDRESS_MASK;
+ Reg |= (Cmds->Addr.NBytes - 1);
+ MmioWrite32 (Slave->RegBase + SPI_REG_SIZE, Reg);
+
+ /* Setup indirect read bytes */
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDBYTES, Remaining);
+
+ /* Start the indirect read transfer */
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_START);
+
+ while (Remaining > 0) {
+ Status = SpiWaitForData (Slave->RegBase, &BytesToRead);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out\n", __func__));
+ goto Fail;
+ }
+
+ while (BytesToRead != 0) {
+ BytesToRead *= Slave->FifoWidth;
+ if (BytesToRead > Remaining) {
+ BytesToRead = Remaining;
+ }
+
+ if (((UINTN)RxBuf % 4) || (BytesToRead % 4)) {
+ SpiReadByte (Slave->AhbBase, RxBuf, BytesToRead);
+ } else {
+ SpiReadLong (Slave->AhbBase, RxBuf, BytesToRead >> 2);
+ }
+
+ RxBuf += BytesToRead;
+ Remaining -= BytesToRead;
+ SpiGetReadSramLevel (Slave->RegBase, &BytesToRead);
+ }
+ }
+
+ /* Check indirect done status */
+ Status = SpiWaitForBitLe32 (
+ Slave->RegBase + SPI_REG_INDIRECTRD,
+ SPI_REG_INDIRECTRD_DONE,
+ 1,
+ 10
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Indirect read completion error\n"));
+ goto Fail;
+ }
+
+ /* Clear indirect completion status */
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_DONE);
+
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+ return EFI_SUCCESS;
+
+Fail:
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_CANCEL);
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+ return EFI_ABORTED;
+}
+
+/* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */
+EFI_STATUS
+SpiCommandWrite (
+ IN SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN OUT SPI_OP_PARAMS *Cmds
+ )
+{
+ UINT32 Reg;
+ UINT32 WriteData;
+ UINT32 WriteLen;
+ SPI_MASTER *SpiMaster;
+ UINT32 TxLen = Cmds->Data.NBytes;
+ CONST VOID *TxBuf = Cmds->Data.Buf.Out;
+ UINT32 Addr;
+ EFI_STATUS Status;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (&SpiMaster->Lock);
+ }
+
+ /* Reorder address to SPI bus order if only transferring address */
+ if (!TxLen) {
+ Addr = SwapBytes32 (Cmds->Addr.Val);
+ if (Cmds->Addr.NBytes == 3) {
+ Addr >>= 8;
+ }
+
+ TxBuf = &Addr;
+ TxLen = Cmds->Addr.NBytes;
+ }
+
+ if (TxLen > SPI_STIG_DATA_LEN_MAX) {
+ DEBUG ((DEBUG_ERROR, "QSPI: Invalid input arguments TxLen %d\n", TxLen));
+ Status = EFI_INVALID_PARAMETER;
+ goto Fail;
+ }
+
+ Reg = Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB;
+
+ if (TxLen) {
+ Reg |= (0x1 << SPI_REG_CMDCTRL_WR_EN_LSB);
+ Reg |= ((TxLen - 1) & SPI_REG_CMDCTRL_WR_BYTES_MASK)
+ << SPI_REG_CMDCTRL_WR_BYTES_LSB;
+
+ WriteLen = TxLen > 4 ? 4 : TxLen;
+ CopyMem (&WriteData, TxBuf, WriteLen);
+ MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATALOWER, WriteData);
+
+ if (TxLen > 4) {
+ TxBuf += WriteLen;
+ WriteLen = TxLen - WriteLen;
+ CopyMem (&WriteData, TxBuf, WriteLen);
+ MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATAUPPER, WriteData);
+ }
+ }
+
+ Status = SpiExecFlashCmd (Slave->RegBase, Reg);
+ if (EFI_ERROR (Status)) {
+ goto Fail;
+ }
+
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+ return EFI_SUCCESS;
+
+Fail:
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+ return Status;
+}
+
+STATIC
+VOID
+SpiDelayNanoSec (
+ IN UINTN nsec
+ )
+{
+ UINT32 Timeout = DIV_ROUND_UP (nsec, 1000);
+
+ do {
+ Timeout--;
+ gBS->Stall (1);
+ } while (Timeout);
+}
+
+STATIC
+VOID
+SpiWriteLong (
+ IN VOID *Addr,
+ IN CONST VOID *Data,
+ IN INTN LongLen
+ )
+{
+ UINT32 *AddrPtr;
+ UINT32 *DataPtr;
+
+ AddrPtr = (UINT32 *)Addr;
+ DataPtr = (UINT32 *)Data;
+
+ while (LongLen) {
+ *AddrPtr = *DataPtr;
+ DataPtr++;
+ LongLen--;
+ }
+}
+
+STATIC
+VOID
+SpiWriteByte (
+ IN VOID *Addr,
+ IN CONST VOID *Data,
+ IN INTN ByteLen
+ )
+{
+ UINT8 *AddrPtr;
+ UINT8 *DataPtr;
+
+ AddrPtr = (UINT8 *)Addr;
+ DataPtr = (UINT8 *)Data;
+
+ while (ByteLen) {
+ *AddrPtr = *DataPtr;
+ DataPtr++;
+ ByteLen--;
+ }
+}
+
+EFI_STATUS
+SpiDataWrite (
+ IN SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN OUT SPI_OP_PARAMS *Cmds
+ )
+{
+ UINT32 Reg;
+ SPI_MASTER *SpiMaster;
+ UINT32 PageSize = Slave->Info->PageSize;
+ UINT32 Remaining = Cmds->Data.NBytes;
+ CONST UINT8 *TxBuf = Cmds->Data.Buf.Out;
+ UINT32 WriteBytes;
+ EFI_STATUS Status;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (&SpiMaster->Lock);
+ }
+
+ if (!Cmds->Addr.NBytes) {
+ return EFI_ABORTED;
+ }
+
+ /* Write opcode to write instruction register */
+ Reg = Cmds->Cmd.OpCode << SPI_REG_WR_INSTR_OPCODE_LSB;
+ MmioWrite32 (Slave->RegBase + SPI_REG_WR_INSTR, Reg);
+
+ /* Set buffer address */
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWRSTARTADDR, Cmds->Addr.Val);
+
+ /* Configure device size */
+ Reg = MmioRead32 (Slave->RegBase + SPI_REG_SIZE);
+ Reg &= ~SPI_REG_SIZE_ADDRESS_MASK;
+ Reg |= (Cmds->Addr.NBytes - 1);
+ MmioWrite32 (Slave->RegBase + SPI_REG_SIZE, Reg);
+
+ /* Configure the indirect read transfer bytes */
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWRBYTES, Remaining);
+
+ /* Start the indirect write transfer */
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_START);
+
+ /* Delay is required for QSPI module to synchronized internally */
+ SpiDelayNanoSec (Slave->WriteDelay);
+
+ while (Remaining > 0) {
+ WriteBytes = Remaining > PageSize ? PageSize : Remaining;
+ SpiWriteLong (Slave->AhbBase, TxBuf, WriteBytes >> 2);
+ if (WriteBytes % 4) {
+ SpiWriteByte (
+ Slave->AhbBase,
+ TxBuf + ROUND_DOWN (WriteBytes, 4),
+ WriteBytes % 4
+ );
+ }
+
+ Status = SpiWaitForBitLe32 (
+ Slave->RegBase + SPI_REG_SDRAMLEVEL,
+ SPI_REG_SDRAMLEVEL_WR_MASK <<
+ SPI_REG_SDRAMLEVEL_WR_LSB,
+ 0,
+ 10
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out (%d)\n", __func__, Status));
+ goto FailWrite;
+ }
+
+ TxBuf += WriteBytes;
+ Remaining -= WriteBytes;
+ }
+
+ /* Check indirect done status */
+ Status = SpiWaitForBitLe32 (
+ Slave->RegBase + SPI_REG_INDIRECTWR,
+ SPI_REG_INDIRECTWR_DONE,
+ 1,
+ 10
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Indirect write completion error (%d)\n", Status));
+ goto FailWrite;
+ }
+
+ /* Clear indirect completion status */
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_DONE);
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+ return EFI_SUCCESS;
+
+FailWrite:
+ MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_CANCEL);
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+ return Status;
+}
+
+STATIC
+VOID
+SpiConfigGetDataCapture (
+ IN UINT32 RegBase,
+ IN UINT32 ByPass,
+ IN UINT32 Delay
+ )
+{
+ UINT32 Reg;
+
+ SpiControllerDisable (RegBase);
+
+ Reg = MmioRead32 (RegBase + SPI_REG_RD_DATA_CAPTURE);
+
+ if (ByPass) {
+ Reg |= SPI_REG_RD_DATA_CAPTURE_BYPASS;
+ } else {
+ Reg &= ~SPI_REG_RD_DATA_CAPTURE_BYPASS;
+ }
+
+ Reg &= ~(SPI_REG_RD_DATA_CAPTURE_DELAY_MASK
+ << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB);
+
+ Reg |= (Delay & SPI_REG_RD_DATA_CAPTURE_DELAY_MASK)
+ << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB;
+
+ MmioWrite32 (RegBase + SPI_REG_RD_DATA_CAPTURE, Reg);
+
+ SpiControllerEnable (RegBase);
+}
+
+STATIC
+EFI_STATUS
+SpiSpeedCalibration (
+ IN SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN SPI_TIMING_PARAMS *Timing
+ )
+{
+ UINT8 IdLen = 3;
+ UINT32 IdInit = 0, IdCali = 0;
+ INTN RangeLow = -1, RangeHigh = -1;
+ SPI_OP_PARAMS CmdsInitialId = SPI_READID_OP ((UINT8 *)&IdInit, IdLen);
+ SPI_OP_PARAMS CmdsCalibrateId = SPI_READID_OP ((UINT8 *)&IdCali, IdLen);
+ EFI_STATUS Status;
+
+ /* Start calibration with slowest clock speed at 1 MHz */
+ SpiWriteSpeed (Slave, SPI_MIN_HZ, Timing);
+
+ /* Set the read data capture delay register to 0 */
+ SpiConfigGetDataCapture (Slave->RegBase, 1, 0);
+
+ /* Get flash ID value as reference */
+ Status = SpiCommandRead (This, Slave, &CmdsInitialId);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read id)\n"));
+ return EFI_ABORTED;
+ }
+
+ /* Use the input speed */
+ SpiWriteSpeed (Slave, SPI_MAX_HZ, Timing);
+
+ /* Find high and low range */
+ for (UINT8 i = 0; i < SPI_READ_CAPTURE_MAX_DELAY; i++) {
+ /* Change the read data capture delay register */
+ SpiConfigGetDataCapture (Slave->RegBase, 1, i);
+
+ /* Read flash ID for comparison later */
+ Status = SpiCommandRead (This, Slave, &CmdsCalibrateId);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read)\n"));
+ return EFI_ABORTED;
+ }
+
+ /* Verify low range */
+ if ((RangeLow == -1) && (IdCali == IdInit)) {
+ RangeLow = i;
+ continue;
+ }
+
+ /* Verify high range */
+ if ((RangeLow != -1) && (IdCali != IdInit)) {
+ RangeHigh = i - 1;
+ break;
+ }
+
+ RangeHigh = i;
+ }
+
+ if (RangeLow == -1) {
+ DEBUG ((DEBUG_ERROR, "Spi: Calibration failed\n"));
+ return EFI_ABORTED;
+ }
+
+ /*
+ * Set the final value for read data capture delay register based
+ * on the calibrated value
+ */
+ SpiConfigGetDataCapture (Slave->RegBase, 1, (RangeHigh + RangeLow) / 2);
+ DEBUG (
+ (DEBUG_INFO, "Spi: Read data capture delay calibrated to %d (%d - %d)\n",
+ (RangeHigh + RangeLow) / 2, RangeLow, RangeHigh)
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiSetupDevice (
+ IN SPI_MASTER_PROTOCOL *This,
+ OUT SPI_DEVICE_PARAMS *Slave
+ )
+{
+ SPI_TIMING_PARAMS *Timing;
+ EFI_STATUS Status;
+
+ if (!Slave) {
+ Slave = AllocateZeroPool (sizeof (SPI_DEVICE_PARAMS));
+ if (Slave == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave\n", __func__));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Fail;
+ }
+ }
+
+ if (!Slave->Info) {
+ Slave->Info = AllocateZeroPool (sizeof (NOR_FLASH_INFO));
+ if (Slave->Info == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave->Info\n", __func__));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Fail;
+ }
+ }
+
+ Timing = AllocateZeroPool (sizeof (SPI_TIMING_PARAMS));
+ if (Timing == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Timing\n", __func__));
+ FreePool(Slave);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Fail;
+ }
+
+ Slave->RegBase = PcdGet32 (PcdSpiFlashRegBase);
+ Slave->AhbBase = (VOID *)(UINTN)PcdGet64 (PcdSpiFlashAhbBase);
+ Slave->FifoWidth = PcdGet8 (PcdSpiFlashFifoWidth);
+ Timing->RefClkHz = PcdGet32 (PcdSpiFlashRefClkHz);
+ Timing->TshslNs = PcdGet32 (PcdSpiFlashTshslNs);
+ Timing->Tsd2dNs = PcdGet32 (PcdSpiFlashTsd2dNs);
+ Timing->TchshNs = PcdGet32 (PcdSpiFlashTchshNs);
+ Timing->TslchNs = PcdGet32 (PcdSpiFlashTslchNs);
+
+ Slave->WriteDelay = 50 * DIV_ROUND_UP (NSEC_PER_SEC, Timing->RefClkHz);
+
+ Status = SpiSpeedCalibration (This, Slave, Timing);
+ if (EFI_ERROR (Status)) {
+ goto Fail;
+ }
+
+ FreePool(Timing);
+ return EFI_SUCCESS;
+
+Fail:
+ FreePool(Slave);
+ FreePool(Timing);
+ return Status;
+}
+
+EFI_STATUS
+SpiFreeDevice (
+ IN SPI_DEVICE_PARAMS *Slave
+ )
+{
+ FreePool (Slave);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiMasterInitProtocol (
+ IN SPI_MASTER_PROTOCOL *SpiMasterProtocol
+ )
+{
+ SpiMasterProtocol->SetupDevice = SpiSetupDevice;
+ SpiMasterProtocol->FreeDevice = SpiFreeDevice;
+ SpiMasterProtocol->CmdRead = SpiCommandRead;
+ SpiMasterProtocol->DataRead = SpiDataRead;
+ SpiMasterProtocol->CmdWrite = SpiCommandWrite;
+ SpiMasterProtocol->DataWrite = SpiDataWrite;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mSpiMasterInstance = AllocateRuntimeZeroPool (sizeof (SPI_MASTER));
+ if (mSpiMasterInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY);
+
+ SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol);
+
+ mSpiMasterInstance->Signature = SPI_MASTER_SIGNATURE;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiMasterInstance->Handle),
+ &gJH7110SpiMasterProtocolGuid,
+ &(mSpiMasterInstance->SpiMasterProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (mSpiMasterInstance);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h
new file mode 100644
index 000000000000..804ee29c5ff1
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h
@@ -0,0 +1,188 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __SPI_DXE_H__
+#define __SPI_DXE_H__
+
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/Spi.h>
+
+#define SPI_MASTER_SIGNATURE SIGNATURE_32 ('M', 'S', 'P', 'I')
+#define SPI_MASTER_FROM_SPI_MASTER_PROTOCOL(a) CR (a, SPI_MASTER, SpiMasterProtocol, SPI_MASTER_SIGNATURE)
+
+#ifndef BIT
+#define BIT(nr) (1 << (nr))
+#endif
+
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#define ROUND_DOWN(x, y) (\
+{ \
+ typeof(x) __x = (x); \
+ __x - (__x % (y)); \
+} \
+)
+#define NSEC_PER_SEC 1000000000L
+
+/* Configs */
+#define SPI_READ_CAPTURE_MAX_DELAY 16
+#define SPI_REG_RETRY 10000
+#define SPI_POLL_IDLE_RETRY 3
+#define SPI_STIG_DATA_LEN_MAX 8
+#define SPI_MIN_HZ 1000000
+#define SPI_MAX_HZ 100000000
+
+/*
+* QSPI controller's config and status register (offset from QSPI_BASE)
+*/
+#define SPI_REG_CONFIG 0x00
+#define SPI_REG_CONFIG_ENABLE BIT(0)
+#define SPI_REG_CONFIG_CLK_POL BIT(1)
+#define SPI_REG_CONFIG_CLK_PHA BIT(2)
+#define SPI_REG_CONFIG_DIRECT BIT(7)
+#define SPI_REG_CONFIG_DECODE BIT(9)
+#define SPI_REG_CONFIG_XIP_IMM BIT(18)
+#define SPI_REG_CONFIG_CHIPSELECT_LSB 10
+#define SPI_REG_CONFIG_BAUD_LSB 19
+#define SPI_REG_CONFIG_DTR_PROTO BIT(24)
+#define SPI_REG_CONFIG_DUAL_OPCODE BIT(30)
+#define SPI_REG_CONFIG_IDLE_LSB 31
+#define SPI_REG_CONFIG_CHIPSELECT_MASK 0xF
+#define SPI_REG_CONFIG_BAUD_MASK 0xF
+
+#define SPI_REG_RD_INSTR 0x04
+#define SPI_REG_RD_INSTR_OPCODE_LSB 0
+#define SPI_REG_RD_INSTR_TYPE_INSTR_LSB 8
+#define SPI_REG_RD_INSTR_TYPE_ADDR_LSB 12
+#define SPI_REG_RD_INSTR_TYPE_DATA_LSB 16
+#define SPI_REG_RD_INSTR_MODE_EN_LSB 20
+#define SPI_REG_RD_INSTR_DUMMY_LSB 24
+#define SPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3
+#define SPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
+#define SPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
+#define SPI_REG_RD_INSTR_DUMMY_MASK 0x1F
+
+#define SPI_REG_WR_INSTR 0x08
+#define SPI_REG_WR_INSTR_OPCODE_LSB 0
+#define SPI_REG_WR_INSTR_TYPE_ADDR_LSB 12
+#define SPI_REG_WR_INSTR_TYPE_DATA_LSB 16
+
+#define SPI_REG_DELAY 0x0C
+#define SPI_REG_DELAY_TSLCH_LSB 0
+#define SPI_REG_DELAY_TCHSH_LSB 8
+#define SPI_REG_DELAY_TSD2D_LSB 16
+#define SPI_REG_DELAY_TSHSL_LSB 24
+#define SPI_REG_DELAY_TSLCH_MASK 0xFF
+#define SPI_REG_DELAY_TCHSH_MASK 0xFF
+#define SPI_REG_DELAY_TSD2D_MASK 0xFF
+#define SPI_REG_DELAY_TSHSL_MASK 0xFF
+
+#define SPI_REG_RD_DATA_CAPTURE 0x10
+#define SPI_REG_RD_DATA_CAPTURE_BYPASS BIT(0)
+#define SPI_REG_RD_DATA_CAPTURE_DELAY_LSB 1
+#define SPI_REG_RD_DATA_CAPTURE_DELAY_MASK 0xF
+
+#define SPI_REG_SIZE 0x14
+#define SPI_REG_SIZE_ADDRESS_LSB 0
+#define SPI_REG_SIZE_PAGE_LSB 4
+#define SPI_REG_SIZE_BLOCK_LSB 16
+#define SPI_REG_SIZE_ADDRESS_MASK 0xF
+#define SPI_REG_SIZE_PAGE_MASK 0xFFF
+#define SPI_REG_SIZE_BLOCK_MASK 0x3F
+
+#define SPI_REG_SRAMPARTITION 0x18
+#define SPI_REG_INDIRECTTRIGGER 0x1C
+
+#define SPI_REG_REMAP 0x24
+#define SPI_REG_MODE_BIT 0x28
+
+#define SPI_REG_SDRAMLEVEL 0x2C
+#define SPI_REG_SDRAMLEVEL_RD_LSB 0
+#define SPI_REG_SDRAMLEVEL_WR_LSB 16
+#define SPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF
+#define SPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF
+
+#define SPI_REG_WR_COMPLETION_CTRL 0x38
+#define SPI_REG_WR_DISABLE_AUTO_POLL BIT(14)
+
+#define SPI_REG_IRQSTATUS 0x40
+#define SPI_REG_IRQMASK 0x44
+
+#define SPI_REG_INDIRECTRD 0x60
+#define SPI_REG_INDIRECTRD_START BIT(0)
+#define SPI_REG_INDIRECTRD_CANCEL BIT(1)
+#define SPI_REG_INDIRECTRD_INPROGRESS BIT(2)
+#define SPI_REG_INDIRECTRD_DONE BIT(5)
+
+#define SPI_REG_INDIRECTRDWATERMARK 0x64
+#define SPI_REG_INDIRECTRDSTARTADDR 0x68
+#define SPI_REG_INDIRECTRDBYTES 0x6C
+
+#define SPI_REG_CMDCTRL 0x90
+#define SPI_REG_CMDCTRL_EXECUTE BIT(0)
+#define SPI_REG_CMDCTRL_INPROGRESS BIT(1)
+#define SPI_REG_CMDCTRL_DUMMY_LSB 7
+#define SPI_REG_CMDCTRL_WR_BYTES_LSB 12
+#define SPI_REG_CMDCTRL_WR_EN_LSB 15
+#define SPI_REG_CMDCTRL_ADD_BYTES_LSB 16
+#define SPI_REG_CMDCTRL_ADDR_EN_LSB 19
+#define SPI_REG_CMDCTRL_RD_BYTES_LSB 20
+#define SPI_REG_CMDCTRL_RD_EN_LSB 23
+#define SPI_REG_CMDCTRL_OPCODE_LSB 24
+#define SPI_REG_CMDCTRL_DUMMY_MASK 0x1F
+#define SPI_REG_CMDCTRL_WR_BYTES_MASK 0x7
+#define SPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3
+#define SPI_REG_CMDCTRL_RD_BYTES_MASK 0x7
+#define SPI_REG_CMDCTRL_OPCODE_MASK 0xFF
+
+#define SPI_REG_INDIRECTWR 0x70
+#define SPI_REG_INDIRECTWR_START BIT(0)
+#define SPI_REG_INDIRECTWR_CANCEL BIT(1)
+#define SPI_REG_INDIRECTWR_INPROGRESS BIT(2)
+#define SPI_REG_INDIRECTWR_DONE BIT(5)
+
+#define SPI_REG_INDIRECTWRWATERMARK 0x74
+#define SPI_REG_INDIRECTWRSTARTADDR 0x78
+#define SPI_REG_INDIRECTWRBYTES 0x7C
+
+#define SPI_REG_CMDADDRESS 0x94
+#define SPI_REG_CMDREADDATALOWER 0xA0
+#define SPI_REG_CMDREADDATAUPPER 0xA4
+#define SPI_REG_CMDWRITEDATALOWER 0xA8
+#define SPI_REG_CMDWRITEDATAUPPER 0xAC
+
+#define SPI_REG_OP_EXT_LOWER 0xE0
+#define SPI_REG_OP_EXT_READ_LSB 24
+#define SPI_REG_OP_EXT_WRITE_LSB 16
+#define SPI_REG_OP_EXT_STIG_LSB 0
+
+typedef struct {
+ SPI_MASTER_PROTOCOL SpiMasterProtocol;
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_LOCK Lock;
+} SPI_MASTER;
+
+typedef struct {
+ UINT32 RefClkHz;
+ UINT32 TshslNs;
+ UINT32 TchshNs;
+ UINT32 TslchNs;
+ UINT32 Tsd2dNs;
+}SPI_TIMING_PARAMS;
+
+#endif //__SPI_DXE_H__
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf
new file mode 100644
index 000000000000..ed3f639346b2
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf
@@ -0,0 +1,52 @@
+## @file
+#
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SpiDxe
+ FILE_GUID = 2FBD9E55-9BC7-4EEF-BF93-0D5582FE647B
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SpiEntryPoint
+
+[Sources]
+ SpiDxe.c
+ SpiDxe.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+ DebugLib
+ DxeServicesTableLib
+ IoLib
+ MemoryAllocationLib
+ NorFlashInfoLib
+ TimerLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeLib
+
+[FixedPcd]
+ gJH7110TokenSpaceGuid.PcdSpiFlashRegBase
+ gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase
+ gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth
+ gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz
+ gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs
+ gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs
+ gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs
+ gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs
+
+[Protocols]
+ gJH7110SpiMasterProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c
new file mode 100755
index 000000000000..cd508e53eb06
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c
@@ -0,0 +1,571 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Library/NorFlashInfoLib.h>
+#include "SpiFlashDxe.h"
+
+SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+SPI_FLASH_INSTANCE *mSpiFlashInstance;
+
+STATIC
+EFI_STATUS
+SpiFlashWriteEnableCmd (
+ IN SPI_DEVICE_PARAMS *Slave
+ )
+{
+ EFI_STATUS Status;
+ SPI_OP_PARAMS Op = SPI_WRITE_EN_OP();
+
+ /* Send write enable command */
+ Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+SpiFlashWriteDisableCmd (
+ IN SPI_DEVICE_PARAMS *Slave
+ )
+{
+ EFI_STATUS Status;
+ SPI_OP_PARAMS Op = SPI_WRITE_DIS_OP();
+
+ /* Send write disable command */
+ Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+SpiFlashPoll (
+ IN SPI_DEVICE_PARAMS *Slave
+)
+{
+ EFI_STATUS Status;
+ UINT16 State;
+ UINT32 Counter = 0xFFFFF;
+ UINT8 ReadLength = 2;
+
+ SPI_OP_PARAMS OpRdSts = SPI_OP (
+ SPI_OP_CMD (SPI_CMD_READ_STATUS),
+ SPI_OP_NO_ADDR,
+ SPI_OP_NO_DUMMY,
+ SPI_OP_DATA_IN (ReadLength, (VOID *)&State)
+ );
+
+ Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRdSts);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __func__));
+ return Status;
+ }
+
+ do {
+ Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRdSts);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __func__));
+ return Status;
+ }
+
+ Counter--;
+ if (!(State & STATUS_REG_POLL_WIP_MSK)) {
+ break;
+ }
+ } while (Counter > 0);
+
+ if (Counter == 0) {
+ DEBUG ((DEBUG_ERROR, "%a(): Timeout while writing to spi flash\n", __func__));
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashErase (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ UINT32 EraseAddr;
+ UINTN EraseSize;
+ UINT8 EraseCmd;
+
+ if (Slave->Info->Flags & NOR_FLASH_ERASE_4K) {
+ EraseCmd = SPI_CMD_ERASE_4K;
+ EraseSize = SIZE_4KB;
+ } else if (Slave->Info->Flags & NOR_FLASH_ERASE_32K) {
+ EraseCmd = SPI_CMD_ERASE_32K;
+ EraseSize = SIZE_32KB;
+ } else {
+ EraseCmd = SPI_CMD_ERASE_64K;
+ EraseSize = Slave->Info->SectorSize;
+ }
+
+ /* Verify input parameters */
+ if (Offset % EraseSize || Length % EraseSize) {
+ DEBUG (
+ (DEBUG_ERROR, "%a(): Either erase offset or length "
+ "is not multiple of erase size\n, __func__")
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = SpiFlashWriteEnableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_enable\n", __func__));
+ return Status;
+ }
+
+ while (Length) {
+ EraseAddr = Offset;
+
+ SPI_OP_PARAMS OpErase = SPI_OP (
+ SPI_OP_CMD (EraseCmd),
+ SPI_OP_ADDR (3, EraseAddr),
+ SPI_OP_NO_DUMMY,
+ SPI_OP_NO_DATA
+ );
+
+ Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpErase);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Spi erase fail\n", __func__));
+ return Status;
+ }
+
+ Status = SpiFlashPoll(Slave);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Offset += EraseSize;
+ Length -= EraseSize;
+ }
+
+ Status = SpiFlashWriteDisableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_disable\n", __func__));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashRead (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN ReadAddr, ReadLength, RemainLength;
+ UINT32 FlashSize;
+
+ FlashSize = Slave->Info->PageSize * Slave->Info->SectorSize;
+
+ /* Current handling is only limit for single flash Bank */
+ while (Length) {
+ ReadAddr = Offset;
+
+ RemainLength = (FlashSize - Offset);
+ if (Length < RemainLength) {
+ ReadLength = Length;
+ } else {
+ ReadLength = RemainLength;
+ }
+
+ /* Send read command */
+ SPI_OP_PARAMS OpRead = SPI_OP (
+ SPI_OP_CMD (SPI_CMD_READ_DATA),
+ SPI_OP_ADDR (Slave->AddrSize, ReadAddr),
+ SPI_OP_NO_DUMMY,
+ SPI_OP_DATA_IN (ReadLength, Buffer)
+ );
+
+ Status = SpiMasterProtocol->DataRead (SpiMasterProtocol, Slave, &OpRead);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading data\n", __func__));
+ return Status;
+ }
+
+ Offset += ReadLength;
+ Length -= ReadLength;
+ Buffer = (VOID *)((UINTN)Buffer + ReadLength);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashWrite (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN ByteAddr, ChunkLength, ActualIndex, PageSize;
+ UINT32 WriteAddr;
+
+ PageSize = Slave->Info->PageSize;
+
+ Status = SpiFlashWriteEnableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __func__));
+ return Status;
+ }
+
+ for (ActualIndex = 0; ActualIndex < Length; ActualIndex += ChunkLength) {
+ WriteAddr = Offset;
+
+ ByteAddr = Offset % PageSize;
+ ChunkLength = MIN (Length - ActualIndex, (UINT64)(PageSize - ByteAddr));
+
+ SPI_OP_PARAMS OpPgProg = SPI_OP (
+ SPI_OP_CMD (SPI_CMD_PAGE_PROGRAM),
+ SPI_OP_ADDR (3, WriteAddr),
+ SPI_OP_NO_DUMMY,
+ SPI_OP_DATA_OUT (ChunkLength, (VOID *)((UINTN)Buffer + ActualIndex))
+ );
+
+ Status = SpiMasterProtocol->DataWrite (SpiMasterProtocol, Slave, &OpPgProg);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while programming write address\n", __func__));
+ return Status;
+ }
+
+ Status = SpiFlashPoll(Slave);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Offset += ChunkLength;
+ }
+
+ Status = SpiFlashWriteDisableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __func__));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SpiFlashUpdateBlock (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN ToUpdate,
+ IN UINT8 *Buffer,
+ IN UINT8 *TmpBuf,
+ IN UINTN EraseSize
+ )
+{
+ EFI_STATUS Status;
+
+ /* Read backup */
+ Status = SpiFlashRead (Slave, Offset, EraseSize, TmpBuf);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(): Update: Error while reading old data\n", __func__));
+ return Status;
+ }
+
+ /* Erase entire sector */
+ Status = SpiFlashErase (Slave, Offset, EraseSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(): Update: Error while erasing block\n", __func__));
+ return Status;
+ }
+
+ /* Write new data */
+ SpiFlashWrite (Slave, Offset, ToUpdate, Buffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(): Update: Error while writing new data\n", __func__));
+ return Status;
+ }
+
+ /* Write backup */
+ if (ToUpdate != EraseSize) {
+ Status = SpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpdate,
+ &TmpBuf[ToUpdate]);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(): Update: Error while writing backup\n", __func__));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashUpdate (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN ByteCount,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT64 SectorSize, ToUpdate, Scale = 1;
+ UINT8 *TmpBuf, *End;
+
+ SectorSize = Slave->Info->SectorSize;
+
+ End = Buffer + ByteCount;
+
+ TmpBuf = (UINT8 *)AllocateZeroPool (SectorSize);
+ if (TmpBuf == NULL) {
+ DEBUG((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (End - Buffer >= 200)
+ Scale = (End - Buffer) / 100;
+
+ for (; Buffer < End; Buffer += ToUpdate, Offset += ToUpdate) {
+ ToUpdate = MIN((UINT64)(End - Buffer), SectorSize);
+ Print (L" \rUpdating, %d%%", 100 - (End - Buffer) / Scale);
+ Status = SpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buffer, TmpBuf, SectorSize);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "%a(): Error while updating\n", __func__));
+ return Status;
+ }
+ }
+
+ Print(L"\n");
+ FreePool (TmpBuf);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashUpdateWithProgress (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN ByteCount,
+ IN UINT8 *Buffer,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, OPTIONAL
+ IN UINTN StartPercentage,
+ IN UINTN EndPercentage
+ )
+{
+ EFI_STATUS Status;
+ UINTN SectorSize;
+ UINTN SectorNum;
+ UINTN ToUpdate;
+ UINTN Index;
+ UINT8 *TmpBuf;
+
+ SectorSize = Slave->Info->SectorSize;
+ SectorNum = (ByteCount / SectorSize) + 1;
+ ToUpdate = SectorSize;
+
+ TmpBuf = (UINT8 *)AllocateZeroPool (SectorSize);
+ if (TmpBuf == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < SectorNum; Index++) {
+ if (Progress != NULL) {
+ Progress (StartPercentage +
+ ((Index * (EndPercentage - StartPercentage)) / SectorNum));
+ }
+
+ /* In the last chunk update only an actual number of remaining bytes */
+ if (Index + 1 == SectorNum) {
+ ToUpdate = ByteCount % SectorSize;
+ }
+
+ Status = SpiFlashUpdateBlock (Slave,
+ Offset + Index * SectorSize,
+ ToUpdate,
+ Buffer + Index * SectorSize,
+ TmpBuf,
+ SectorSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while updating\n", __func__));
+ return Status;
+ }
+ }
+ FreePool (TmpBuf);
+
+ if (Progress != NULL) {
+ Progress (EndPercentage);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiFlashReadId (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN BOOLEAN UseInRuntime
+ )
+{
+ EFI_STATUS Status;
+ UINT8 IdLen = 3;
+ UINT8 Id[IdLen];
+
+ SPI_OP_PARAMS Op = SPI_READID_OP (Id, IdLen);
+
+ Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &Op);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading id\n", __func__));
+ return Status;
+ }
+
+ Status = NorFlashGetInfo (Id, &Slave->Info, UseInRuntime);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a: Unrecognized JEDEC Id bytes: 0x%02x%02x%02x\n",
+ __func__,
+ Id[0],
+ Id[1],
+ Id[2])
+ );
+ return Status;
+ }
+
+ NorFlashPrintInfo (Slave->Info);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiFlashInit (
+ IN SPI_FLASH_PROTOCOL *This,
+ IN SPI_DEVICE_PARAMS *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINT8 StatusRegister;
+
+ Slave->AddrSize = (Slave->Info->Flags & NOR_FLASH_4B_ADDR) ? 4 : 3;
+
+ Status = SpiFlashWriteEnableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __func__));
+ return Status;
+ }
+
+ if (Slave->AddrSize == 4) {
+
+ /* Enable 4byte addressing */
+ SPI_OP_PARAMS Op4BAddEn = SPI_OP (
+ SPI_OP_CMD (SPI_CMD_4B_ADDR_ENABLE),
+ SPI_OP_NO_ADDR,
+ SPI_OP_NO_DUMMY,
+ SPI_OP_NO_DATA
+ );
+ Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op4BAddEn);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while setting 4B address\n", __func__));
+ return Status;
+ }
+ }
+
+ /* Initialize flash status register */
+ StatusRegister = 0x0;
+ SPI_OP_PARAMS OpWrSts = SPI_OP (
+ SPI_OP_CMD (SPI_CMD_WRITE_STATUS_REG),
+ SPI_OP_NO_ADDR,
+ SPI_OP_NO_DUMMY,
+ SPI_OP_DATA_OUT (1, (VOID *)&StatusRegister)
+ );
+
+ Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpWrSts);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while writing status register\n", __func__));
+ return Status;
+ }
+
+ Status = SpiFlashWriteDisableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __func__));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SpiFlashInitProtocol (
+ IN SPI_FLASH_PROTOCOL *SpiFlashProtocol
+ )
+{
+ SpiFlashProtocol->Read = SpiFlashRead;
+ SpiFlashProtocol->Write = SpiFlashWrite;
+ SpiFlashProtocol->Update = SpiFlashUpdate;
+ SpiFlashProtocol->UpdateWithProgress = SpiFlashUpdateWithProgress;
+ SpiFlashProtocol->Erase = SpiFlashErase;
+ SpiFlashProtocol->ReadId = SpiFlashReadId;
+ SpiFlashProtocol->Init = SpiFlashInit;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiFlashEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ &gJH7110SpiMasterProtocolGuid,
+ NULL,
+ (VOID **)&SpiMasterProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SPI Master protocol\n", __func__));
+ return EFI_DEVICE_ERROR;
+ }
+
+ mSpiFlashInstance = AllocateRuntimeZeroPool (sizeof (SPI_FLASH_INSTANCE));
+ if (mSpiFlashInstance == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol);
+
+ mSpiFlashInstance->Signature = SPI_FLASH_SIGNATURE;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiFlashInstance->Handle),
+ &gJH7110SpiFlashProtocolGuid,
+ &(mSpiFlashInstance->SpiFlashProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot install SPI flash protocol\n", __func__));
+ goto ErrorInstallProto;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorInstallProto:
+ FreePool (mSpiFlashInstance);
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h
new file mode 100755
index 000000000000..f3bb300334c0
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h
@@ -0,0 +1,35 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __SPI_FLASH_DXE_H__
+#define __SPI_FLASH_DXE_H__
+
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define SPI_FLASH_SIGNATURE SIGNATURE_32 ('F', 'S', 'P', 'I')
+
+#define STATUS_REG_POLL_WIP_MSK (1 << 0)
+
+typedef struct {
+ SPI_FLASH_PROTOCOL SpiFlashProtocol;
+ UINTN Signature;
+ EFI_HANDLE Handle;
+} SPI_FLASH_INSTANCE;
+
+#endif //__SPI_FLASH_DXE_H__
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf
new file mode 100644
index 000000000000..3ca429fdc2dd
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf
@@ -0,0 +1,44 @@
+## @file
+#
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SpiFlashDxe
+ FILE_GUID = D3DF07BE-3810-4521-89EF-C4E22E0B2484
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SpiFlashEntryPoint
+
+[Sources]
+ SpiFlashDxe.c
+ SpiFlashDxe.h
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+ DebugLib
+ MemoryAllocationLib
+ NorFlashInfoLib
+ TimerLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+ gJH7110SpiFlashProtocolGuid
+ gJH7110SpiMasterProtocolGuid
+
+[Depex]
+ gJH7110SpiMasterProtocolGuid
diff --git a/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h b/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h
new file mode 100644
index 000000000000..b8db3ad4c5b0
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h
@@ -0,0 +1,163 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __SPI_MASTER_PROTOCOL_H__
+#define __SPI_MASTER_PROTOCOL_H__
+
+#include <Library/NorFlashInfoLib.h>
+
+typedef struct _SPI_MASTER_PROTOCOL SPI_MASTER_PROTOCOL;
+
+
+#define SPI_CMD_WRITE_STATUS_REG 0x01
+#define SPI_CMD_PAGE_PROGRAM 0x02
+#define SPI_CMD_READ_DATA 0x03
+#define SPI_CMD_WRITE_DISABLE 0x04
+#define SPI_CMD_READ_STATUS 0x05
+#define SPI_CMD_WRITE_ENABLE 0x06
+#define SPI_CMD_READ_ARRAY_FAST 0x0b
+#define SPI_CMD_BANKADDR_BRWR 0x17
+#define SPI_CMD_ERASE_4K 0x20
+#define SPI_CMD_ERASE_32K 0x52
+#define SPI_CMD_FLAG_STATUS 0x70
+#define SPI_CMD_READ_ID 0x9f
+#define SPI_CMD_4B_ADDR_ENABLE 0xb7
+#define SPI_CMD_BANK_WRITE 0xc5
+#define SPI_CMD_ERASE_64K 0xd8
+
+
+
+#define SPI_OP_CMD(__OpCode) \
+ { \
+ .OpCode = __OpCode, \
+ .NBytes = 1, \
+ }
+
+#define SPI_OP_ADDR(__NBytes, __Val) \
+ { \
+ .NBytes = __NBytes, \
+ .Val = __Val, \
+ }
+
+#define SPI_OP_NO_ADDR { }
+
+#define SPI_OP_DUMMY(__NBytes) \
+ { \
+ .NBytes = __NBytes, \
+ }
+
+#define SPI_OP_NO_DUMMY { }
+
+#define SPI_OP_DATA_IN(__NBytes, __Buf) \
+ { \
+ .NBytes = __NBytes, \
+ .Buf.In = __Buf, \
+ }
+
+#define SPI_OP_DATA_OUT(__NBytes, __Buf) \
+ { \
+ .NBytes = __NBytes, \
+ .Buf.Out = __Buf, \
+ }
+
+#define SPI_OP_NO_DATA { }
+
+#define SPI_OP(__Cmd, __Addr, __Dummy, __Data) \
+ { \
+ .Cmd = __Cmd, \
+ .Addr = __Addr, \
+ .Dummy = __Dummy, \
+ .Data = __Data, \
+ }
+
+/**
+ * Standard SPI NOR flash operations
+ */
+#define SPI_WRITE_EN_OP() \
+ SPI_OP(SPI_OP_CMD(SPI_CMD_WRITE_ENABLE), \
+ SPI_OP_NO_ADDR, \
+ SPI_OP_NO_DUMMY, \
+ SPI_OP_NO_DATA)
+
+#define SPI_WRITE_DIS_OP() \
+ SPI_OP(SPI_OP_CMD(SPI_CMD_WRITE_DISABLE), \
+ SPI_OP_NO_ADDR, \
+ SPI_OP_NO_DUMMY, \
+ SPI_OP_NO_DATA)
+
+#define SPI_READID_OP(Buf, Len) \
+ SPI_OP(SPI_OP_CMD(SPI_CMD_READ_ID), \
+ SPI_OP_NO_ADDR, \
+ SPI_OP_NO_DUMMY, \
+ SPI_OP_DATA_IN(Len, Buf))
+
+typedef struct {
+ struct {
+ UINT8 NBytes;
+ UINT16 OpCode;
+ } Cmd;
+
+ struct {
+ UINT8 NBytes;
+ UINT64 Val;
+ } Addr;
+
+ struct {
+ UINT8 NBytes;
+ } Dummy;
+
+ struct {
+ UINT32 NBytes;
+ union {
+ VOID *In;
+ CONST VOID *Out;
+ } Buf;
+ } Data;
+} SPI_OP_PARAMS;
+
+typedef struct {
+ UINT32 AddrSize;
+ NOR_FLASH_INFO *Info;
+ UINT32 RegBase;
+ VOID *AhbBase;
+ UINT8 FifoWidth;
+ UINT32 WriteDelay;
+} SPI_DEVICE_PARAMS;
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_DEVICE_SETUP)(
+ IN SPI_MASTER_PROTOCOL *This,
+ OUT SPI_DEVICE_PARAMS *Slave
+ );
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_DEVICE_FREE)(
+ IN SPI_DEVICE_PARAMS *Slave
+ );
+
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_EXECUTE_RW)(
+ IN SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN OUT SPI_OP_PARAMS *Cmds
+ );
+
+struct _SPI_MASTER_PROTOCOL {
+ SPI_DEVICE_SETUP SetupDevice;
+ SPI_DEVICE_FREE FreeDevice;
+ SPI_EXECUTE_RW CmdRead;
+ SPI_EXECUTE_RW DataRead;
+ SPI_EXECUTE_RW CmdWrite;
+ SPI_EXECUTE_RW DataWrite;
+};
+
+#endif // __SPI_MASTER_PROTOCOL_H__
diff --git a/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h b/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h
new file mode 100644
index 000000000000..cdbe4d0b6b67
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h
@@ -0,0 +1,88 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __SPI_FLASH_PROTOCOL_H__
+#define __SPI_FLASH_PROTOCOL_H__
+
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/Spi.h>
+
+typedef struct _SPI_FLASH_PROTOCOL SPI_FLASH_PROTOCOL;
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_FLASH_INIT) (
+ IN SPI_FLASH_PROTOCOL *This,
+ IN SPI_DEVICE_PARAMS *SpiDev
+ );
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_FLASH_READ_ID) (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN BOOLEAN UseInRuntime
+ );
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_FLASH_READ) (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ OUT VOID *Buffer
+ );
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_FLASH_WRITE) (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buffer
+ );
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_FLASH_ERASE) (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length
+ );
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_FLASH_UPDATE) (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Address,
+ IN UINTN DataByteCount,
+ IN UINT8 *Buffer
+ );
+
+typedef
+ EFI_STATUS
+(EFIAPI *SPI_FLASH_UPDATE_WITH_PROGRESS) (
+ IN SPI_DEVICE_PARAMS *Slave,
+ IN UINT32 Offset,
+ IN UINTN ByteCount,
+ IN UINT8 *Buffer,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, OPTIONAL
+ IN UINTN StartPercentage,
+ IN UINTN EndPercentage
+ );
+
+struct _SPI_FLASH_PROTOCOL {
+ SPI_FLASH_INIT Init;
+ SPI_FLASH_READ_ID ReadId;
+ SPI_FLASH_READ Read;
+ SPI_FLASH_WRITE Write;
+ SPI_FLASH_ERASE Erase;
+ SPI_FLASH_UPDATE Update;
+ SPI_FLASH_UPDATE_WITH_PROGRESS UpdateWithProgress;
+};
+
+#endif // __SPI_FLASH_PROTOCOL_H__
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109780): https://edk2.groups.io/g/devel/message/109780
Mute This Topic: https://groups.io/mt/102053681/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [edk2-devel] [PATCH v1 3/6] StarFive/JH7110Pkg: Add firmware volume block protocol
2023-10-19 2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
@ 2023-10-19 2:59 ` John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library John Chew
` (2 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-19 2:59 UTC (permalink / raw)
To: devel; +Cc: John Chew, Sunil V L
Support for efi variable to store in QSPI flash
Cc: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
---
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c | 909 ++++++++++++++++++++
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h | 138 +++
Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf | 70 ++
3 files changed, 1117 insertions(+)
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c
new file mode 100644
index 000000000000..c30e82ed0871
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.c
@@ -0,0 +1,909 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include "FvbDxe.h"
+
+STATIC FVB_DEVICE *mFvbDevice;
+
+STATIC CONST FVB_DEVICE mFvbFlashInstanceTemplate = {
+ {
+ 0, /* AddrSize ... NEED TO BE FILLED */
+ NULL, /* Read from NOR FLASH ... NEED TO BE FILLED */
+ 0, /* RegBase ... NEED TO BE FILLED */
+ 0, /* AbhBase ... NEED TO BE FILLED */
+ 0, /* FifoWidth ... NEED TO BE FILLED */
+ 0, /* WriteDelay ... NEED TO BE FILLED */
+ }, /* SPI_DEVICE_PARAMS */
+
+ NULL, /* SpiFlashProtocol ... NEED TO BE FILLED */
+ NULL, /* SpiMasterProtocol ... NEED TO BE FILLED */
+ NULL, /* Handle ... NEED TO BE FILLED */
+
+ FVB_FLASH_SIGNATURE, /* Signature ... NEED TO BE FILLED */
+
+ 0, /* ShadowBufBaseAddr ... NEED TO BE FILLED */
+ 0, /* ShadowBufSize ... NEED TO BE FILLED */
+ 0, /* FvbFlashVarOffset ... NEED TO BE FILLED */
+ 0, /* FvbFlashVarSize ... NEED TO BE FILLED */
+ 0, /* BlockSize ... NEED TO BE FILLED */
+ 0, /* LastBlock ... NEED TO BE FILLED */
+ 0, /* StartLba */
+
+ {
+ FvbGetAttributes, /* GetAttributes */
+ FvbSetAttributes, /* SetAttributes */
+ FvbGetPhysicalAddress, /* GetPhysicalAddress */
+ FvbGetBlockSize, /* GetBlockSize */
+ FvbRead, /* Read */
+ FvbWrite, /* Write */
+ FvbEraseBlocks, /* EraseBlocks */
+ NULL, /* ParentHandle */
+ }, /* EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL */
+
+ {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)sizeof (VENDOR_DEVICE_PATH),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ { 0xfc0cb972, 0x21df, 0x44d2, { 0x92, 0xa5, 0x78, 0x98, 0x99, 0xcb, 0xf6, 0x61 }
+ }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+ }
+ } /* FVB_DEVICE_PATH */
+};
+
+STATIC
+EFI_STATUS
+FvbInitFvAndVariableStoreHeaders (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ EFI_STATUS Status;
+ VOID *Headers;
+ UINTN HeadersLength;
+ UINTN BlockSize;
+
+ HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+ sizeof (EFI_FV_BLOCK_MAP_ENTRY) +
+ sizeof (VARIABLE_STORE_HEADER);
+ Headers = AllocateZeroPool (HeadersLength);
+
+ BlockSize = FlashInstance->BlockSize;
+
+ /* VariableBase -> FtwWOrkingBase -> FtwSpareBase are declared
+ * consecutively in contiguous memory
+ */
+ ASSERT (
+ PcdGet64 (PcdFlashNvStorageVariableBase64) +
+ PcdGet32 (PcdFlashNvStorageVariableSize) ==
+ PcdGet64 (PcdFlashNvStorageFtwWorkingBase64)
+ );
+ ASSERT (
+ PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) +
+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ==
+ PcdGet64 (PcdFlashNvStorageFtwSpareBase64)
+ );
+
+ /* Ensure the size of the variable area is at least one block size */
+ ASSERT (
+ (PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0)
+ );
+ ASSERT (
+ (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0)
+ );
+ ASSERT (
+ (PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0)
+ );
+
+ /* Ensure the Variable areas are aligned on block size boundaries */
+ ASSERT ((PcdGet64 (PcdFlashNvStorageVariableBase64) % BlockSize) == 0);
+ ASSERT ((PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % BlockSize) == 0);
+ ASSERT ((PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % BlockSize) == 0);
+
+ /* ---------------------------------------------
+ * | Firmware Volume Header | |
+ * -------------------------- Non-Volatile |
+ * | Variable Store Header | Storage Variable |
+ * -------------------------- Region |
+ * | Variables | |
+ * ---------------------------------------------
+ */
+
+ /* Prepare Firmware Volume Header */
+ FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Headers;
+ CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
+ FirmwareVolumeHeader->FvLength = FlashInstance->FvbFlashVarSize;
+ FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
+ FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP | /* Reads may be enabled */
+ EFI_FVB2_READ_STATUS | /* Reads are currently enabled */
+ EFI_FVB2_STICKY_WRITE | /* A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY */
+ EFI_FVB2_ERASE_POLARITY | /* After erasure all bits take this value (i.e. '1') */
+ EFI_FVB2_WRITE_STATUS | /* Writes are currently enabled */
+ EFI_FVB2_WRITE_ENABLED_CAP; /* Writes may be enabled */
+
+ FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+ sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+ FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
+ FirmwareVolumeHeader->BlockMap[0].NumBlocks = FlashInstance->LastBlock + 1;
+ FirmwareVolumeHeader->BlockMap[0].Length = FlashInstance->BlockSize;
+ FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
+ FirmwareVolumeHeader->BlockMap[1].Length = 0;
+ FirmwareVolumeHeader->Checksum = CalculateCheckSum16 (
+ (UINT16 *)FirmwareVolumeHeader,
+ FirmwareVolumeHeader->HeaderLength
+ );
+
+ /* Prepare Variable Store Header */
+ VariableStoreHeader = (VOID *)((UINTN)Headers +
+ FirmwareVolumeHeader->HeaderLength);
+ CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
+ VariableStoreHeader->Size = PcdGet32 (PcdFlashNvStorageVariableSize) -
+ FirmwareVolumeHeader->HeaderLength;
+ VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
+ VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;
+
+ /* Write both header to the flash device on the base address of the
+ * declared variable base address in the flash. CAUTIONS! This will
+ * replace the existing firmware volume and variable header or possibly
+ * cause data corruption. Make sure the declared base address and size
+ * in the flash is only use for EFI Variable Storage.
+ * Offset = 0, LastBlockAdress = 0;
+ */
+ Status = FvbWrite (&FlashInstance->FvbProtocol, 0, 0, &HeadersLength, Headers);
+
+ FreePool (Headers);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+FvbValidateFvHeader (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ UINT16 Checksum;
+ EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VariableStoreLength;
+
+ FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->ShadowBufBaseAddr;
+
+ /* Verify the header revision, header signature, length from the flash */
+ if ((FirmwareVolumeHeader->Revision != EFI_FVH_REVISION) ||
+ (FirmwareVolumeHeader->Signature != EFI_FVH_SIGNATURE) ||
+ (FirmwareVolumeHeader->FvLength != FlashInstance->FvbFlashVarSize))
+ {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): No Firmware Volume header present\n",
+ __func__)
+ );
+ return EFI_NOT_FOUND;
+ }
+
+ /* Verify the Firmware Volume Guid from the flash */
+ if (!CompareGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Firmware Volume Guid non-compatible\n",
+ __func__)
+ );
+ return EFI_NOT_FOUND;
+ }
+
+ /* Verify the header checksum from the flash */
+ Checksum = CalculateSum16 ((UINT16 *)FirmwareVolumeHeader, FirmwareVolumeHeader->HeaderLength);
+ if (Checksum != 0) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): FV checksum is invalid (Checksum:0x%x)\n",
+ __func__,
+ Checksum)
+ );
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStoreHeader = (VOID *)((UINTN)FirmwareVolumeHeader + FirmwareVolumeHeader->HeaderLength);
+
+ /* Verify the Variable Store Guid */
+ if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
+ !CompareGuid (
+ &VariableStoreHeader->Signature,
+ &gEfiAuthenticatedVariableGuid
+ ))
+ {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Variable Store Guid non-compatible\n",
+ __func__)
+ );
+ return EFI_NOT_FOUND;
+ }
+
+ /* Verify the actual Variable Store length with declare size in header*/
+ VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -
+ FirmwareVolumeHeader->HeaderLength;
+ if (VariableStoreHeader->Size != VariableStoreLength) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Variable Store Length does not match\n",
+ __func__)
+ );
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
+ EFI_FVB_ATTRIBUTES_2 *FlashFvbAttributes;
+ FVB_DEVICE *FlashInstance;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->ShadowBufBaseAddr;
+ FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2 *)&(FirmwareVolumeHeader->Attributes);
+
+ *Attributes = *FlashFvbAttributes;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FVB_ATTRIBUTES_2 OldAttributes;
+ EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
+ EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
+ FVB_DEVICE *FlashInstance;
+ UINT32 Capabilities;
+ UINT32 OldStatus;
+ UINT32 NewStatus;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ /* Read current attribute from the Frimware Volume Header */
+ FvbGetAttributes (This, &FlashFvbAttributes);
+
+ OldAttributes = FlashFvbAttributes;
+ Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;
+ OldStatus = OldAttributes & EFI_FVB2_STATUS;
+ NewStatus = *Attributes & EFI_FVB2_STATUS;
+
+ UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP | \
+ EFI_FVB2_STICKY_WRITE | \
+ EFI_FVB2_ERASE_POLARITY | \
+ EFI_FVB2_READ_LOCK_CAP | \
+ EFI_FVB2_WRITE_LOCK_CAP | \
+ EFI_FVB2_ALIGNMENT;
+
+ /* Some attributes of FV is read only can *not* be set */
+ if ((OldAttributes & UnchangedAttributes) ^
+ (*Attributes & UnchangedAttributes))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* If firmware volume is locked, no status bit can be updated */
+ if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
+ if (OldStatus ^ NewStatus) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ /* Test read disable */
+ if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ /* Test read enable */
+ if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_READ_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ /* Test write disable */
+ if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ /* Test write enable */
+ if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_WRITE_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ /* Test lock */
+ if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_LOCK_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ FlashFvbAttributes = FlashFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
+ FlashFvbAttributes = FlashFvbAttributes | NewStatus;
+ *Attributes = FlashFvbAttributes;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ FVB_DEVICE *FlashInstance;
+
+ ASSERT (Address != NULL);
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ /* Do not support MMIO, return the shadow buffer instead */
+ *Address = FlashInstance->ShadowBufBaseAddr;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+{
+ FVB_DEVICE *FlashInstance;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ if (Lba > FlashInstance->LastBlock) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Error: Requested LBA %ld is beyond the last available LBA (%ld).\n",
+ __func__,
+ Lba,
+ FlashInstance->LastBlock)
+ );
+ return EFI_INVALID_PARAMETER;
+ } else {
+ /* Assume equal sized blocks in all flash devices */
+ *BlockSize = (UINTN)FlashInstance->BlockSize;
+ *NumberOfBlocks = (UINTN)(FlashInstance->LastBlock - Lba + 1);
+
+ return EFI_SUCCESS;
+ }
+}
+
+EFI_STATUS
+EFIAPI
+FvbRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ FVB_DEVICE *FlashInstance;
+ UINTN BlockSize;
+ UINTN DataOffset;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ /* Cache the block size to avoid de-referencing pointers all the time */
+ BlockSize = FlashInstance->BlockSize;
+
+ /* Offset + byte have to be within the define block size.
+ * The read must not span block boundaries. We need to
+ * check each variable individually because adding two
+ * large values together migght cause overflows.
+ */
+ if ((Offset >= BlockSize) ||
+ (*NumBytes > BlockSize) ||
+ ((Offset + *NumBytes) > BlockSize))
+ {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Wrong buffer size: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
+ __func__,
+ Offset,
+ *NumBytes,
+ BlockSize)
+ );
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ /* No bytes to read */
+ if (*NumBytes == 0) {
+ return EFI_SUCCESS;
+ }
+
+ DataOffset = GET_DATA_OFFSET (
+ FlashInstance->ShadowBufBaseAddr + Offset,
+ FlashInstance->StartLba + Lba,
+ FlashInstance->BlockSize
+ );
+
+ /* Copy variable from the shadow buffer */
+ CopyMem (Buffer, (UINTN *)DataOffset, *NumBytes);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ FVB_DEVICE *FlashInstance;
+ UINTN DataOffset;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ DataOffset = GET_DATA_OFFSET (
+ FlashInstance->FvbFlashVarOffset + Offset,
+ FlashInstance->StartLba + Lba,
+ FlashInstance->BlockSize
+ );
+
+ Status = FlashInstance->SpiFlashProtocol->Write (
+ &FlashInstance->SpiDevice,
+ DataOffset,
+ *NumBytes,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Failed to write to Spi device\n",
+ __func__)
+ );
+ return Status;
+ }
+
+ DataOffset = GET_DATA_OFFSET (
+ FlashInstance->ShadowBufBaseAddr + Offset,
+ FlashInstance->StartLba + Lba,
+ FlashInstance->BlockSize
+ );
+
+ /* Update shadow buffer */
+ CopyMem ((UINTN *)DataOffset, Buffer, *NumBytes);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+ )
+{
+ EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
+ FVB_DEVICE *FlashInstance;
+ EFI_STATUS Status;
+ VA_LIST Args;
+ UINTN BlockAddress; /* Physical address of Lba to erase */
+ EFI_LBA StartingLba; /* Lba from which we start erasing */
+ UINTN NumOfLba; /* Number of Lba blocks to erase */
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ Status = EFI_SUCCESS;
+
+ /* Detect WriteDisabled state */
+ FvbGetAttributes (This, &FlashFvbAttributes);
+ if ((FlashFvbAttributes & EFI_FVB2_WRITE_STATUS) == 0) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Device is in WriteDisabled state.\n",
+ __func__)
+ );
+ return EFI_ACCESS_DENIED;
+ }
+
+ /*
+ * Before erasing, check the entire list of parameters to ensure
+ * all specified blocks are valid.
+ */
+ VA_START (Args, This);
+ do {
+ /* Get the Lba from which we start erasing */
+ StartingLba = VA_ARG (Args, EFI_LBA);
+
+ /* Have we reached the end of the list? */
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ break;
+ }
+
+ /* How many Lba blocks are we requested to erase? */
+ NumOfLba = VA_ARG (Args, UINT32);
+
+ /* All blocks must be within range */
+ if ((NumOfLba == 0) ||
+ ((FlashInstance->StartLba + StartingLba + NumOfLba - 1) >
+ FlashInstance->LastBlock))
+ {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Error: Requested LBA are beyond the last available LBA (%ld).\n",
+ __func__,
+ FlashInstance->LastBlock)
+ );
+
+ VA_END (Args);
+
+ return EFI_INVALID_PARAMETER;
+ }
+ } while (TRUE);
+
+ VA_END (Args);
+
+ /* Start erasing */
+ VA_START (Args, This);
+ do {
+ /* Get the Lba from which we start erasing */
+ StartingLba = VA_ARG (Args, EFI_LBA);
+
+ /* Have we reached the end of the list? */
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ break;
+ }
+
+ /* How many Lba blocks are we requested to erase? */
+ NumOfLba = VA_ARG (Args, UINT32);
+
+ /* Go through each requested block and erase it */
+ while (NumOfLba > 0) {
+ /* Get the offset address of Lba to erase */
+ BlockAddress = GET_DATA_OFFSET (
+ FlashInstance->FvbFlashVarOffset,
+ FlashInstance->StartLba + StartingLba,
+ FlashInstance->BlockSize
+ );
+
+ /* Erase single block */
+ Status = FlashInstance->SpiFlashProtocol->Erase (
+ &FlashInstance->SpiDevice,
+ BlockAddress,
+ FlashInstance->BlockSize
+ );
+ if (EFI_ERROR (Status)) {
+ VA_END (Args);
+ return EFI_DEVICE_ERROR;
+ }
+
+ StartingLba++;
+ NumOfLba--;
+ }
+ } while (TRUE);
+
+ VA_END (Args);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FvbFlashProbe (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ SPI_FLASH_PROTOCOL *SpiFlashProtocol;
+ EFI_STATUS Status;
+
+ SpiFlashProtocol = FlashInstance->SpiFlashProtocol;
+
+ /* Read SPI flash ID */
+ Status = SpiFlashProtocol->ReadId (&FlashInstance->SpiDevice, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = SpiFlashProtocol->Init (SpiFlashProtocol, &FlashInstance->SpiDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot initialize flash device\n", __func__));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FvbPrepareFvHeader (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_BOOT_MODE BootMode;
+ EFI_STATUS Status;
+
+ /* Check if it is required to use default environment */
+ BootMode = GetBootModeHob ();
+ if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ /* Validate header at the beginning of FV region */
+ Status = FvbValidateFvHeader (FlashInstance);
+ }
+
+ /* Install the default FVB header if required */
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): The FVB Header is not valid.\n", __func__));
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Installing a correct one for this volume.\n",
+ __func__)
+ );
+
+ /* Erase entire region that is reserved for variable storage in flash */
+ Status = FlashInstance->SpiFlashProtocol->Erase (
+ &FlashInstance->SpiDevice,
+ FlashInstance->FvbFlashVarOffset,
+ FlashInstance->FvbFlashVarSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ /* Write a new firmware volume and varaible storage headers */
+ Status = FvbInitFvAndVariableStoreHeaders (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FvbConfigureFlashInstance (
+ IN OUT FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataOffset;
+ UINTN VariableSize, FtwWorkingSize, FtwSpareSize, MemorySize;
+
+ Status = gBS->LocateProtocol (
+ &gJH7110SpiFlashProtocolGuid,
+ NULL,
+ (VOID **)&FlashInstance->SpiFlashProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiFlash protocol\n", __func__));
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gJH7110SpiMasterProtocolGuid,
+ NULL,
+ (VOID **)&FlashInstance->SpiMasterProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SpiMaster protocol\n", __func__));
+ return Status;
+ }
+
+ /* Setup and probe SPI flash */
+ FlashInstance->SpiMasterProtocol->SetupDevice (
+ FlashInstance->SpiMasterProtocol,
+ &FlashInstance->SpiDevice
+ );
+ Status = FvbFlashProbe (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Error while performing SPI flash probe\n",
+ __func__)
+ );
+ return Status;
+ }
+
+ /* Fill remaining flash description */
+ VariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+ FtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
+ FtwSpareSize = PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+ FlashInstance->FvbFlashVarSize = VariableSize + FtwWorkingSize + FtwSpareSize;
+ FlashInstance->FvbFlashVarOffset = PcdGet32(PcdJH7110FlashVarOffset);
+ FlashInstance->BlockSize = FlashInstance->SpiDevice.Info->SectorSize;
+ FlashInstance->LastBlock = (FlashInstance->FvbFlashVarSize /
+ FlashInstance->BlockSize) - 1;
+ FlashInstance->ShadowBufSize = FlashInstance->FvbFlashVarSize;
+
+ /* Allocate memory for shadow buffer */
+ MemorySize = EFI_SIZE_TO_PAGES (FlashInstance->FvbFlashVarSize);
+
+ /* FaultTolerantWriteDxe requires memory to be aligned to FtwWorkingSize */
+ FlashInstance->ShadowBufBaseAddr = (UINTN)AllocateAlignedRuntimePages (
+ MemorySize,
+ SIZE_64KB
+ );
+ if (FlashInstance->ShadowBufBaseAddr == (UINTN)NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Update PCDs value according to allocated memory */
+ Status = PcdSet64S (
+ PcdFlashNvStorageVariableBase64,
+ (UINT64)FlashInstance->ShadowBufBaseAddr
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet64S (
+ PcdFlashNvStorageFtwWorkingBase64,
+ (UINT64)FlashInstance->ShadowBufBaseAddr
+ + VariableSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet64S (
+ PcdFlashNvStorageFtwSpareBase64,
+ (UINT64)FlashInstance->ShadowBufBaseAddr
+ + VariableSize
+ + FtwWorkingSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ /* ill the shadow buffer with data from flash */
+ DataOffset = GET_DATA_OFFSET (
+ FlashInstance->FvbFlashVarOffset,
+ FlashInstance->StartLba,
+ FlashInstance->BlockSize
+ );
+ Status = FlashInstance->SpiFlashProtocol->Read (
+ &FlashInstance->SpiDevice,
+ DataOffset,
+ FlashInstance->FvbFlashVarSize,
+ (VOID *)FlashInstance->ShadowBufBaseAddr
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorFreeAllocatedPages;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &FlashInstance->Handle,
+ &gEfiDevicePathProtocolGuid,
+ &FlashInstance->DevicePath,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ &FlashInstance->FvbProtocol,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorFreeAllocatedPages;
+ }
+
+ Status = FvbPrepareFvHeader (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ goto ErrorPrepareFvbHeader;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorPrepareFvbHeader:
+ gBS->UninstallMultipleProtocolInterfaces (
+ &FlashInstance->Handle,
+ &gEfiDevicePathProtocolGuid,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL
+ );
+
+ErrorFreeAllocatedPages:
+ FreeAlignedPages (
+ (VOID *)FlashInstance->ShadowBufBaseAddr,
+ MemorySize
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FvbEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ /* Allocate memory for FVB flash device*/
+ mFvbDevice = AllocateRuntimeCopyPool (
+ sizeof (mFvbFlashInstanceTemplate),
+ &mFvbFlashInstanceTemplate
+ );
+ if (mFvbDevice == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Detect and configure flash device */
+ Status = FvbConfigureFlashInstance (mFvbDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a(): Fail to configure Fvb SPI device\n", __func__));
+ goto ErrorConfigureFlash;
+ }
+
+ /* The driver implementing the variable read service can now be dispatched;
+ * the varstore headers are in place.
+ */
+ Status = gBS->InstallProtocolInterface (
+ &gImageHandle,
+ &gEdkiiNvVarStoreFormattedGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "%a(): Failed to install gEdkiiNvVarStoreFormattedGuid\n",
+ __func__)
+ );
+ goto ErrorInstallNvVarStoreFormatted;
+ }
+
+ return Status;
+
+ErrorInstallNvVarStoreFormatted:
+ gBS->UninstallMultipleProtocolInterfaces (
+ &mFvbDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL
+ );
+
+ErrorConfigureFlash:
+ FreePool (mFvbDevice);
+
+ return Status;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h
new file mode 100644
index 000000000000..6b0450b17275
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.h
@@ -0,0 +1,138 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef __FVB_DXE_H__
+#define __FVB_DXE_H__
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Guid/NvVarStoreFormatted.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/VariableFormat.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize) ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))
+
+#define FVB_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r')
+#define INSTANCE_FROM_FVB_THIS(a) CR(a, FVB_DEVICE, FvbProtocol, FVB_FLASH_SIGNATURE)
+
+//
+// Define two helper macro to extract the Capability field or Status field in FVB
+// bit fields.
+//
+#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP |\
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP)
+
+#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | \
+ EFI_FVB2_WRITE_STATUS | \
+ EFI_FVB2_LOCK_STATUS)
+
+typedef struct {
+ VENDOR_DEVICE_PATH Vendor;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} FVB_DEVICE_PATH;
+
+typedef struct {
+ SPI_DEVICE_PARAMS SpiDevice;
+
+ SPI_FLASH_PROTOCOL *SpiFlashProtocol;
+ SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+
+ EFI_HANDLE Handle;
+
+ UINT32 Signature;
+
+ UINTN ShadowBufBaseAddr;
+ UINTN ShadowBufSize;
+ UINTN FvbFlashVarOffset;
+ UINTN FvbFlashVarSize;
+ UINTN BlockSize;
+ UINTN LastBlock;
+ EFI_LBA StartLba;
+
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol;
+
+ FVB_DEVICE_PATH DevicePath;
+} FVB_DEVICE;
+
+EFI_STATUS
+EFIAPI
+FvbGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+FvbSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ );
+
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ );
+
+EFI_STATUS
+EFIAPI
+FvbRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+FvbWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+ );
+
+#endif //__FVB_DXE_H__
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf
new file mode 100644
index 000000000000..715989bfcc2b
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/FvbDxe/FvbDxe.inf
@@ -0,0 +1,70 @@
+## @file
+#
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = FvbDxe
+ FILE_GUID = DB8BFC83-6DEA-4AD1-AD3D-FDC579430233
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 0.1
+ ENTRY_POINT = FvbEntryPoint
+
+[Sources]
+ FvbDxe.c
+
+[Packages]
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ DxeServicesTableLib
+ HobLib
+ IoLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeLib
+ UefiRuntimeServicesTableLib
+
+[Guids]
+ gEdkiiNvVarStoreFormattedGuid
+ gEfiAuthenticatedVariableGuid
+ gEfiEventVirtualAddressChangeGuid
+ gEfiSystemNvDataFvGuid
+ gEfiVariableGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiFirmwareVolumeBlockProtocolGuid
+ gJH7110SpiFlashProtocolGuid
+ gJH7110SpiMasterProtocolGuid
+
+[FixedPcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+ gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
+
+[Depex]
+ gEfiCpuArchProtocolGuid AND
+ gJH7110SpiMasterProtocolGuid AND
+ gJH7110SpiFlashProtocolGuid
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109781): https://edk2.groups.io/g/devel/message/109781
Mute This Topic: https://groups.io/mt/102053682/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library
2023-10-19 2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 3/6] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
@ 2023-10-19 2:59 ` John Chew
2023-10-19 12:12 ` Sunil V L
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
4 siblings, 1 reply; 12+ messages in thread
From: John Chew @ 2023-10-19 2:59 UTC (permalink / raw)
To: devel; +Cc: JohnChew, Sunil V L, Yong Li
From: JohnChew <yuinyee.chew@starfivetech.com>
For JH7110 with graphic console
Cc: Sunil V L <sunilvl@ventanamicro.com>
Co-authored-by: Yong Li <yong.li@intel.com>
Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
---
Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c | 1014 ++++++++++++++++++++
Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h | 46 +
Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf | 71 ++
3 files changed, 1131 insertions(+)
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c
new file mode 100755
index 000000000000..b58d2c7cbcd5
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c
@@ -0,0 +1,1014 @@
+/** @file
+* Implementation for PlatformBootManagerLib library class interfaces.
+*
+* Copyright (C) 2015-2016, Red Hat, Inc.
+* Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+* Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+* Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <IndustryStandard/Pci22.h>
+#include <IndustryStandard/Virtio095.h>
+#include <Library/BootLogoLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PlatformBmPrintScLib.h>
+#include <Library/QemuBootOrderLib.h>
+#include <Library/TpmPlatformHierarchyLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/VirtioDevice.h>
+#include <Guid/EventGroup.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/RootBridgesConnectedEventGroup.h>
+#include <Guid/SerialPortLibVendor.h>
+#include <Guid/TtyTerm.h>
+
+#include "PlatformBm.h"
+
+#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
+
+#define VERSION_STRING_PREFIX L"RISC-V EDK2 firmware version "
+
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH SerialDxe;
+ UART_DEVICE_PATH Uart;
+ VENDOR_DEFINED_DEVICE_PATH TermType;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_SERIAL_CONSOLE;
+#pragma pack ()
+
+STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
+ //
+ // VENDOR_DEVICE_PATH SerialDxe
+ //
+ {
+ { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
+ EDKII_SERIAL_PORT_LIB_VENDOR_GUID
+ },
+
+ //
+ // UART_DEVICE_PATH Uart
+ //
+ {
+ { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
+ 0, // Reserved
+ FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
+ FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
+ FixedPcdGet8 (PcdUartDefaultParity), // Parity
+ FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
+ },
+
+ //
+ // VENDOR_DEFINED_DEVICE_PATH TermType
+ //
+ {
+ {
+ MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
+ DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
+ }
+ //
+ // Guid to be filled in dynamically
+ //
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+#pragma pack (1)
+typedef struct {
+ USB_CLASS_DEVICE_PATH Keyboard;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_USB_KEYBOARD;
+#pragma pack ()
+
+STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
+ //
+ // USB_CLASS_DEVICE_PATH Keyboard
+ //
+ {
+ {
+ MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
+ DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
+ },
+ 0xFFFF, // VendorId: any
+ 0xFFFF, // ProductId: any
+ 3, // DeviceClass: HID
+ 1, // DeviceSubClass: boot
+ 1 // DeviceProtocol: keyboard
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+/**
+ Check if the handle satisfies a particular condition.
+
+ @param[in] Handle The handle to check.
+ @param[in] ReportText A caller-allocated string passed in for reporting
+ purposes. It must never be NULL.
+
+ @retval TRUE The condition is satisfied.
+ @retval FALSE Otherwise. This includes the case when the condition could not
+ be fully evaluated due to an error.
+**/
+typedef
+BOOLEAN
+(EFIAPI *FILTER_FUNCTION)(
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ );
+
+/**
+ Process a handle.
+
+ @param[in] Handle The handle to process.
+ @param[in] ReportText A caller-allocated string passed in for reporting
+ purposes. It must never be NULL.
+**/
+typedef
+VOID
+(EFIAPI *CALLBACK_FUNCTION)(
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ );
+
+/**
+ Locate all handles that carry the specified protocol, filter them with a
+ callback function, and pass each handle that passes the filter to another
+ callback.
+
+ @param[in] ProtocolGuid The protocol to look for.
+
+ @param[in] Filter The filter function to pass each handle to. If this
+ parameter is NULL, then all handles are processed.
+
+ @param[in] Process The callback function to pass each handle to that
+ clears the filter.
+**/
+STATIC
+VOID
+FilterAndProcess (
+ IN EFI_GUID *ProtocolGuid,
+ IN FILTER_FUNCTION Filter OPTIONAL,
+ IN CALLBACK_FUNCTION Process
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN NoHandles;
+ UINTN Idx;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ ProtocolGuid,
+ NULL /* SearchKey */,
+ &NoHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // This is not an error, just an informative condition.
+ //
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: %g: %r\n",
+ __func__,
+ ProtocolGuid,
+ Status
+ ));
+ return;
+ }
+
+ ASSERT (NoHandles > 0);
+ for (Idx = 0; Idx < NoHandles; ++Idx) {
+ CHAR16 *DevicePathText;
+ STATIC CHAR16 Fallback[] = L"<device path unavailable>";
+
+ //
+ // The ConvertDevicePathToText() function handles NULL input transparently.
+ //
+ DevicePathText = ConvertDevicePathToText (
+ DevicePathFromHandle (Handles[Idx]),
+ FALSE, // DisplayOnly
+ FALSE // AllowShortcuts
+ );
+ if (DevicePathText == NULL) {
+ DevicePathText = Fallback;
+ }
+
+ if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {
+ Process (Handles[Idx], DevicePathText);
+ }
+
+ if (DevicePathText != Fallback) {
+ FreePool (DevicePathText);
+ }
+ }
+
+ gBS->FreePool (Handles);
+}
+
+/**
+ This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+IsPciDisplay (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // This is not an error worth reporting.
+ //
+ return FALSE;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0 /* Offset */,
+ sizeof Pci / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __func__, ReportText, Status));
+ return FALSE;
+ }
+
+ return IS_PCI_DISPLAY (&Pci);
+}
+
+
+/**
+ This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
+ the EFI_PCI_IO_PROTOCOL level.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+IsVirtioPciRng (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT8 RevisionId;
+ BOOLEAN Virtio10;
+ UINT16 SubsystemId;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Read and check VendorId.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_VENDOR_ID_OFFSET,
+ 1,
+ &VendorId
+ );
+ if (EFI_ERROR (Status)) {
+ goto PciError;
+ }
+
+ if (VendorId != VIRTIO_VENDOR_ID) {
+ return FALSE;
+ }
+
+ //
+ // Read DeviceId and RevisionId.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_DEVICE_ID_OFFSET,
+ 1,
+ &DeviceId
+ );
+ if (EFI_ERROR (Status)) {
+ goto PciError;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_REVISION_ID_OFFSET,
+ 1,
+ &RevisionId
+ );
+ if (EFI_ERROR (Status)) {
+ goto PciError;
+ }
+
+ //
+ // From DeviceId and RevisionId, determine whether the device is a
+ // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
+ // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
+ // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
+ // only be sanity-checked, and SubsystemId will decide.
+ //
+ if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&
+ (RevisionId >= 0x01))
+ {
+ Virtio10 = TRUE;
+ } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {
+ Virtio10 = FALSE;
+ } else {
+ return FALSE;
+ }
+
+ //
+ // Read and check SubsystemId as dictated by Virtio10.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ PCI_SUBSYSTEM_ID_OFFSET,
+ 1,
+ &SubsystemId
+ );
+ if (EFI_ERROR (Status)) {
+ goto PciError;
+ }
+
+ if (Virtio10 && (SubsystemId >= 0x40)) {
+ return TRUE;
+ }
+
+ if (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
+ return TRUE;
+ }
+
+ return FALSE;
+
+PciError:
+ DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __func__, ReportText, Status));
+ return FALSE;
+}
+
+/**
+ This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
+ the matching driver to produce all first-level child handles.
+**/
+STATIC
+VOID
+EFIAPI
+Connect (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->ConnectController (
+ Handle, // ControllerHandle
+ NULL, // DriverImageHandle
+ NULL, // RemainingDevicePath -- produce all children
+ FALSE // Recursive
+ );
+ DEBUG ((
+ EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
+ "%a: %s: %r\n",
+ __func__,
+ ReportText,
+ Status
+ ));
+}
+
+/**
+ This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
+ handle, and adds it to ConOut and ErrOut.
+**/
+STATIC
+VOID
+EFIAPI
+AddOutput (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ DevicePath = DevicePathFromHandle (Handle);
+ if (DevicePath == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: %s: handle %p: device path not found\n",
+ __func__,
+ ReportText,
+ Handle
+ ));
+ return;
+ }
+
+ Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: %s: adding to ConOut: %r\n",
+ __func__,
+ ReportText,
+ Status
+ ));
+ return;
+ }
+
+ Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: %s: adding to ErrOut: %r\n",
+ __func__,
+ ReportText,
+ Status
+ ));
+ return;
+ }
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: %s: added to ConOut and ErrOut\n",
+ __func__,
+ ReportText
+ ));
+}
+
+STATIC
+VOID
+PlatformRegisterFvBootOption (
+ EFI_GUID *FileGuid,
+ CHAR16 *Description,
+ UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ INTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+ DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
+ ASSERT (DevicePath != NULL);
+ DevicePath = AppendDevicePathNode (
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
+ );
+ ASSERT (DevicePath != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ Attributes,
+ Description,
+ DevicePath,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DevicePath);
+
+ BootOptions = EfiBootManagerGetLoadOptions (
+ &BootOptionCount,
+ LoadOptionTypeBoot
+ );
+
+ OptionIndex = EfiBootManagerFindLoadOption (
+ &NewOption,
+ BootOptions,
+ BootOptionCount
+ );
+
+ if (OptionIndex == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ EfiBootManagerFreeLoadOption (&NewOption);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+/**
+ Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
+ whose device paths do not resolve exactly to an FvFile in the system.
+
+ This removes any boot options that point to binaries built into the firmware
+ and have become stale due to any of the following:
+ - FvMain's base address or size changed (historical),
+ - FvMain's FvNameGuid changed,
+ - the FILE_GUID of the pointed-to binary changed,
+ - the referenced binary is no longer built into the firmware.
+
+ EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
+ avoids exact duplicates.
+**/
+STATIC
+VOID
+RemoveStaleFvFileOptions (
+ VOID
+ )
+{
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ UINTN Index;
+
+ BootOptions = EfiBootManagerGetLoadOptions (
+ &BootOptionCount,
+ LoadOptionTypeBoot
+ );
+
+ for (Index = 0; Index < BootOptionCount; ++Index) {
+ EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
+ EFI_STATUS Status;
+ EFI_HANDLE FvHandle;
+
+ //
+ // If the device path starts with neither MemoryMapped(...) nor Fv(...),
+ // then keep the boot option.
+ //
+ Node1 = BootOptions[Index].FilePath;
+ if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&
+ (DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&
+ !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
+ {
+ continue;
+ }
+
+ //
+ // If the second device path node is not FvFile(...), then keep the boot
+ // option.
+ //
+ Node2 = NextDevicePathNode (Node1);
+ if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||
+ (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
+ {
+ continue;
+ }
+
+ //
+ // Locate the Firmware Volume2 protocol instance that is denoted by the
+ // boot option. If this lookup fails (i.e., the boot option references a
+ // firmware volume that doesn't exist), then we'll proceed to delete the
+ // boot option.
+ //
+ SearchNode = Node1;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &SearchNode,
+ &FvHandle
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The firmware volume was found; now let's see if it contains the FvFile
+ // identified by GUID.
+ //
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
+ UINTN BufferSize;
+ EFI_FV_FILETYPE FoundType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINT32 AuthenticationStatus;
+
+ Status = gBS->HandleProtocol (
+ FvHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **)&FvProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
+ //
+ // Buffer==NULL means we request metadata only: BufferSize, FoundType,
+ // FileAttributes.
+ //
+ Status = FvProtocol->ReadFile (
+ FvProtocol,
+ &FvFileNode->FvFileName, // NameGuid
+ NULL, // Buffer
+ &BufferSize,
+ &FoundType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The FvFile was found. Keep the boot option.
+ //
+ continue;
+ }
+ }
+
+ //
+ // Delete the boot option.
+ //
+ Status = EfiBootManagerDeleteLoadOptionVariable (
+ BootOptions[Index].OptionNumber,
+ LoadOptionTypeBoot
+ );
+ DEBUG_CODE_BEGIN ();
+ CHAR16 *DevicePathString;
+
+ DevicePathString = ConvertDevicePathToText (
+ BootOptions[Index].FilePath,
+ FALSE,
+ FALSE
+ );
+ DEBUG ((
+ EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
+ "%a: removing stale Boot#%04x %s: %r\n",
+ __func__,
+ (UINT32)BootOptions[Index].OptionNumber,
+ DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
+ Status
+ ));
+ if (DevicePathString != NULL) {
+ FreePool (DevicePathString);
+ }
+
+ DEBUG_CODE_END ();
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+STATIC
+VOID
+PlatformRegisterOptionsAndKeys (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Enter;
+ EFI_INPUT_KEY F2;
+ EFI_INPUT_KEY Esc;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+ //
+ // Register ENTER as CONTINUE key
+ //
+ Enter.ScanCode = SCAN_NULL;
+ Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+ Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Map F2 and ESC to Boot Manager Menu
+ //
+ F2.ScanCode = SCAN_F2;
+ F2.UnicodeChar = CHAR_NULL;
+ Esc.ScanCode = SCAN_ESC;
+ Esc.UnicodeChar = CHAR_NULL;
+ Status = EfiBootManagerGetBootManagerMenu (&BootOption);
+ ASSERT_EFI_ERROR (Status);
+ Status = EfiBootManagerAddKeyOptionVariable (
+ NULL,
+ (UINT16)BootOption.OptionNumber,
+ 0,
+ &F2,
+ NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+ Status = EfiBootManagerAddKeyOptionVariable (
+ NULL,
+ (UINT16)BootOption.OptionNumber,
+ 0,
+ &Esc,
+ NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+}
+
+//
+// BDS Platform Functions
+//
+
+/**
+ Do the platform init, can be customized by OEM/IBV
+ Possible things that can be done in PlatformBootManagerBeforeConsole:
+ > Update console variable: 1. include hot-plug devices;
+ > 2. Clear ConIn and add SOL for AMT
+ > Register new Driver#### or Boot####
+ > Register new Key####: e.g.: F12
+ > Signal ReadyToLock event
+ > Authentication action: 1. connect Auth devices;
+ > 2. Identify auto logon user.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+ VOID
+ )
+{
+ UINT16 FrontPageTimeout;
+ EFI_STATUS Status;
+
+ //
+ // Signal EndOfDxe PI Event
+ //
+ EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+
+ //
+ // Dispatch deferred images after EndOfDxe event.
+ //
+ EfiBootManagerDispatchDeferredImages ();
+
+ //
+ // Locate the PCI root bridges and make the PCI bus driver connect each,
+ // non-recursively. This will produce a number of child handles with PciIo on
+ // them.
+ //
+ FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
+
+ //
+ // Signal the ACPI platform driver that it can download QEMU ACPI tables.
+ //
+ EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
+
+ //
+ // Find all display class PCI devices (using the handles from the previous
+ // step), and connect them non-recursively. This should produce a number of
+ // child handles with GOPs on them.
+ //
+ FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
+
+ //
+ // Now add the device path of all handles with GOP on them to ConOut and
+ // ErrOut.
+ //
+ FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
+
+ //
+ // Add the hardcoded short-form USB keyboard device path to ConIn.
+ //
+ EfiBootManagerUpdateConsoleVariable (
+ ConIn,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,
+ NULL
+ );
+
+ //
+ // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
+ //
+ CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
+
+ EfiBootManagerUpdateConsoleVariable (
+ ConIn,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
+ NULL
+ );
+ EfiBootManagerUpdateConsoleVariable (
+ ConOut,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
+ NULL
+ );
+ EfiBootManagerUpdateConsoleVariable (
+ ErrOut,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
+ NULL
+ );
+
+ //
+ // Reflect the PCD in the standard Timeout variable.
+ //
+ Status = gRT->SetVariable (
+ EFI_TIME_OUT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ (EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS),
+ sizeof FrontPageTimeout,
+ &FrontPageTimeout
+ );
+ DEBUG ((
+ EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
+ "%a: SetVariable(%s, %u): %r\n",
+ __func__,
+ EFI_TIME_OUT_VARIABLE_NAME,
+ FrontPageTimeout,
+ Status
+ ));
+
+ //
+ // Register platform-specific boot options and keyboard shortcuts.
+ //
+ PlatformRegisterOptionsAndKeys ();
+
+ //
+ // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
+ // instances on Virtio PCI RNG devices.
+ //
+ FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);
+}
+
+/**
+ Do the platform specific action after the console is ready
+ Possible things that can be done in PlatformBootManagerAfterConsole:
+ > Console post action:
+ > Dynamically switch output mode from 100x31 to 80x25 for certain scenario
+ > Signal console ready platform customized event
+ > Run diagnostics like memory testing
+ > Connect certain devices
+ > Dispatch additional option roms
+ > Special boot: e.g.: USB boot, enter UI
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ UINTN FirmwareVerLength;
+
+ FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));
+ //
+ // Show the splash screen.
+ //
+ BootLogoEnableLogo ();
+
+ if (FirmwareVerLength > 0) {
+ Print (
+ VERSION_STRING_PREFIX L"%s\n",
+ PcdGetPtr (PcdFirmwareVersionString)
+ );
+ }
+
+ Print (L"Press ESCAPE within 10 seconds for boot options ");
+
+ //
+ // Enumerate all possible boot options, then filter and reorder them based on
+ // the QEMU configuration.
+ //
+ EfiBootManagerRefreshAllBootOption ();
+
+ //
+ // Register UEFI Shell
+ //
+ PlatformRegisterFvBootOption (
+ &gUefiShellFileGuid,
+ L"EFI Internal Shell",
+ LOAD_OPTION_ACTIVE
+ );
+
+ RemoveStaleFvFileOptions ();
+
+ PlatformBmPrintScRegisterHandler ();
+}
+
+/**
+ This function is called each second during the boot manager waits the
+ timeout.
+
+ @param TimeoutRemain The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ UINT16 TimeoutRemain
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
+ UINT16 TimeoutInitial;
+
+ TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);
+
+ //
+ // If PcdPlatformBootTimeOut is set to zero, then we consider
+ // that no progress update should be enacted.
+ //
+ if (TimeoutInitial == 0) {
+ return;
+ }
+
+ Black.Raw = 0x00000000;
+ White.Raw = 0x00FFFFFF;
+
+ BootLogoUpdateProgress (
+ White.Pixel,
+ Black.Pixel,
+ L"Start boot option",
+ White.Pixel,
+ (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,
+ 0
+ );
+}
+
+/**
+ The function is called when no boot option could be launched,
+ including platform recovery options and options pointing to applications
+ built into firmware volumes.
+
+ If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+ UINTN Index;
+
+ //
+ // BootManagerMenu doesn't contain the correct information when return status
+ // is EFI_NOT_FOUND.
+ //
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Normally BdsDxe does not print anything to the system console, but this is
+ // a last resort -- the end-user will likely not see any DEBUG messages
+ // logged in this situation.
+ //
+ // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
+ // here to see if it makes sense to request and wait for a keypress.
+ //
+ if (gST->ConIn != NULL) {
+ AsciiPrint (
+ "%a: No bootable option or device was found.\n"
+ "%a: Press any key to enter the Boot Manager Menu.\n",
+ gEfiCallerBaseName,
+ gEfiCallerBaseName
+ );
+ Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Index == 0);
+
+ //
+ // Drain any queued keys.
+ //
+ while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
+ //
+ // just throw away Key
+ //
+ }
+ }
+
+ for ( ; ;) {
+ EfiBootManagerBoot (&BootManagerMenu);
+ }
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h
new file mode 100755
index 000000000000..067af555ad31
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h
@@ -0,0 +1,46 @@
+/** @file
+* Head file for BDS Platform specific code
+*
+* Copyright (C) 2015-2016, Red Hat, Inc.
+* Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+* Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#ifndef _PLATFORM_BM_H_
+#define _PLATFORM_BM_H_
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+/**
+ Download the kernel, the initial ramdisk, and the kernel command line from
+ QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
+ image files, and load and start the kernel from it.
+
+ The kernel will be instructed via its command line to load the initrd from
+ the same Simple FileSystem.
+
+ @retval EFI_NOT_FOUND Kernel image was not found.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
+
+ @return Error codes from any of the underlying
+ functions. On success, the function doesn't
+ return.
+**/
+EFI_STATUS
+EFIAPI
+TryRunningQemuKernel (
+ VOID
+ );
+
+#endif // _PLATFORM_BM_H_
diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
new file mode 100755
index 000000000000..d967f808cf7f
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -0,0 +1,71 @@
+## @file
+# Implementation for PlatformBootManagerLib library class interfaces for RISC-V.
+#
+# Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = DxeRiscV64PlatformBootManagerLib
+ FILE_GUID = 900C3D64-E5EA-0F56-1F51-64D593F374D2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = RISCV64
+#
+
+[Sources]
+ PlatformBm.c
+ PlatformBm.h
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ SecurityPkg/SecurityPkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ BootLogoLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ PcdLib
+ PlatformBmPrintScLib
+ ReportStatusCodeLib
+ UefiBootManagerLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString
+
+[Guids]
+ gEfiEndOfDxeEventGroupGuid
+ gEfiGlobalVariableGuid
+ gRootBridgesConnectedEventGroupGuid
+ gUefiShellFileGuid
+ gEfiTtyTermGuid
+
+[Protocols]
+ gEfiGenericMemTestProtocolGuid ## CONSUMES
+ gEfiGraphicsOutputProtocolGuid ## CONSUMES
+ gEfiPciRootBridgeIoProtocolGuid
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109782): https://edk2.groups.io/g/devel/message/109782
Mute This Topic: https://groups.io/mt/102053683/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver
2023-10-19 2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
` (2 preceding siblings ...)
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library John Chew
@ 2023-10-19 2:59 ` John Chew
2023-10-19 12:14 ` Sunil V L
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
4 siblings, 1 reply; 12+ messages in thread
From: John Chew @ 2023-10-19 2:59 UTC (permalink / raw)
To: devel; +Cc: John Chew, Sunil V L
Some DXE drivers such as MMC's DMA can only work with 32-bit addressing.
So, EfiBootServicesData need to set within 32-bit range only.
This is achieved by setting all EfiConventionalMemory to
EfiBootServicesData before any memory allocations in the early stage of
DXE.
Cc: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
---
Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.c | 108 ++++++++++++++++++++
Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.inf | 34 ++++++
2 files changed, 142 insertions(+)
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.c
new file mode 100644
index 000000000000..a26a77661d4e
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.c
@@ -0,0 +1,108 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+EFI_STATUS
+EFIAPI
+BootServicesInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap, *Desc;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ EFI_PHYSICAL_ADDRESS Addr;
+ UINTN Idx;
+ UINTN Pages;
+
+ MemoryMap = NULL;
+ MemoryMapSize = 0;
+ Pages = 0;
+
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
+ MemoryMap = AllocatePages (Pages);
+
+ //
+ // Get System MemoryMap
+ //
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ }
+
+ if (EFI_ERROR (Status) || (MemoryMap == NULL)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to get memory map\n", __func__));
+ if (MemoryMap) {
+ FreePages ((VOID *)MemoryMap, Pages);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ Desc = MemoryMap;
+
+ //
+ // Change 64-bit EfiConventionalMemory with EfiBootServicesData
+ // So that DXE driver only allocate EfiBootServicesData in 32-bit addresses
+ //
+ for (Idx = 0; Idx < (MemoryMapSize / DescriptorSize); Idx++) {
+ if ((Desc->Type == EfiConventionalMemory) &&
+ ((Desc->PhysicalStart > MAX_UINT32) || ((Desc->PhysicalStart + Desc->NumberOfPages * EFI_PAGE_SIZE) > MAX_UINT32)))
+ {
+ if (Desc->PhysicalStart > MAX_UINT32) {
+ Addr = Desc->PhysicalStart;
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiBootServicesData,
+ Desc->NumberOfPages,
+ &Addr
+ );
+ } else {
+ Addr = 0x100000000ULL;
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiBootServicesData,
+ Desc->NumberOfPages - EFI_SIZE_TO_PAGES (0x100000000 - Desc->PhysicalStart),
+ &Addr
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to allocate boot service data at %llX\n", __func__, Addr));
+ }
+ }
+
+ Desc = (EFI_MEMORY_DESCRIPTOR *)((UINT64)Desc + DescriptorSize);
+ }
+
+ FreePages ((VOID *)MemoryMap, Pages);
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.inf
new file mode 100644
index 000000000000..33a777ae5a24
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/BootServicesDxe/BootServicesDxe.inf
@@ -0,0 +1,34 @@
+## @file
+# DXE Boot Service driver for StarFive JH7110 SoC
+#
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = BootServicesDxe
+ FILE_GUID = E7B2A7CF-4A9B-4F63-9B9E-12B34C5D6E78
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BootServicesInitialize
+
+[Sources]
+ BootServicesDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ MemoryAllocationLib
+
+[Guids]
+ gEfiEventReadyToBootGuid
+
+[Depex]
+ TRUE
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109783): https://edk2.groups.io/g/devel/message/109783
Mute This Topic: https://groups.io/mt/102053685/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package
2023-10-19 2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
` (3 preceding siblings ...)
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver John Chew
@ 2023-10-19 2:59 ` John Chew
2023-10-19 12:34 ` Sunil V L
4 siblings, 1 reply; 12+ messages in thread
From: John Chew @ 2023-10-19 2:59 UTC (permalink / raw)
To: devel; +Cc: mindachen1987, Sunil V L, John Chew
From: mindachen1987 <minda.chen@starfivetech.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Co-authored-by: John Chew <yuinyee.chew@starfivetech.com>
Signed-off-by: mindachen1987 <minda.chen@starfivetech.com>
---
Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h | 24 +++++++++++
Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec | 45 ++++++++++++++++++++
2 files changed, 69 insertions(+)
diff --git a/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
new file mode 100644
index 000000000000..b6875f6aa82b
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
@@ -0,0 +1,24 @@
+/** @file
+ *
+ * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#ifndef JH7110_H__
+#define JH7110_H__
+
+// #define JH7110_SOC_REGISTERS (FixedPcdGet64 (PcdJH7110RegistersAddress))
+// #define JH7110_SOC_REGISTER_LENGTH 0x02000000
+
+/* Generic PCI addresses */
+#define PCIE_TOP_OF_MEM_WIN (FixedPcdGet64 (PcdJH7110PciBusMmioAdr))
+#define PCIE_CPU_MMIO_WINDOW (FixedPcdGet64 (PcdJH7110PciCpuMmioAdr))
+#define PCIE_BRIDGE_MMIO_LEN (FixedPcdGet32 (PcdJH7110PciBusMmioLen))
+
+/* PCI root bridge control registers location */
+#define PCIE_REG_BASE (FixedPcdGet64 (PcdJH7110PciRegBase))
+#define PCIE_CONFIG_BASE (FixedPcdGet64 (PcdJH7110PciConfigRegBase))
+
+#endif /* JH7110_H__ */
diff --git a/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
new file mode 100644
index 000000000000..438557a15500
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
@@ -0,0 +1,45 @@
+## @file
+#
+# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x0001001A
+ PACKAGE_NAME = JH7110Pkg
+ PACKAGE_GUID = D4B585C5-EBCA-4779-B974-05A3CF2F10C4
+ PACKAGE_VERSION = 1.0
+
+[Includes]
+ Include
+
+[Guids]
+ gJH7110TokenSpaceGuid = {0x44045e56, 0x7056, 0x4be6, {0x88, 0xc0, 0x49, 0x0c, 0x67, 0x90, 0x2f, 0xba}}
+
+[PcdsFixedAtBuild.common]
+# Memory map
+ gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset|0x0|UINT32|0x00000001
+
+# PCIe
+ gJH7110TokenSpaceGuid.PcdJH7110RegistersAddress|0|UINT32|0x00000002
+ gJH7110TokenSpaceGuid.PcdJH7110PciRegBase|0x2b000000|UINT64|0x00000003
+ gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioAdr|0x0|UINT64|0x00000004
+ gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioLen|0x0|UINT32|0x00000005
+ gJH7110TokenSpaceGuid.PcdJH7110PciCpuMmioAdr|0x0|UINT64|0x00000006
+ gJH7110TokenSpaceGuid.PcdJH7110PciConfigRegBase|0x940000000|UINT64|0x00000007
+
+# SPI
+ gJH7110TokenSpaceGuid.PcdSpiFlashRegBase|0|UINT32|0x10000008
+ gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase|0|UINT64|0x10000009
+ gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth|0|UINT8|0x10000010
+ gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz|0|UINT32|0x10000011
+ gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs|0|UINT32|0x10000012
+ gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs|0|UINT32|0x1000013
+ gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs|0|UINT32|0x1000014
+ gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs|0|UINT32|0x1000015
+
+[Protocols]
+ gJH7110SpiMasterProtocolGuid = { 0xA33C46E0, 0x4FB6, 0x4AA3, { 0x8E, 0x66, 0x00, 0x06, 0x9F, 0x3A, 0x11, 0x81 }}
+ gJH7110SpiFlashProtocolGuid = { 0x5ECECDF6, 0x81DA, 0x4E10, { 0x9D, 0x4B, 0x26, 0x65, 0x8C, 0x03, 0xAB, 0xBC }}
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109784): https://edk2.groups.io/g/devel/message/109784
Mute This Topic: https://groups.io/mt/102053687/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library John Chew
@ 2023-10-19 12:12 ` Sunil V L
2023-10-20 9:34 ` John Chew
0 siblings, 1 reply; 12+ messages in thread
From: Sunil V L @ 2023-10-19 12:12 UTC (permalink / raw)
To: John Chew; +Cc: devel, Yong Li
Hi John,
On Thu, Oct 19, 2023 at 10:59:19AM +0800, John Chew wrote:
> From: JohnChew <yuinyee.chew@starfivetech.com>
>
> For JH7110 with graphic console
>
This commit message needs to be improved. From the code, I can't find
why this library needs to be copied for your platform. Why not migrate
and use the library in ArmPkg to MdePkg?
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Co-authored-by: Yong Li <yong.li@intel.com>
> Signed-off-by: John Chew <yuinyee.chew@starfivetech.com>
> ---
> Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c | 1014 ++++++++++++++++++++
> Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h | 46 +
> Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf | 71 ++
> 3 files changed, 1131 insertions(+)
>
> diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c
> new file mode 100755
> index 000000000000..b58d2c7cbcd5
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.c
> @@ -0,0 +1,1014 @@
> +/** @file
> +* Implementation for PlatformBootManagerLib library class interfaces.
> +*
> +* Copyright (C) 2015-2016, Red Hat, Inc.
> +* Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
> +* Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
> +* Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> +*
> +* SPDX-License-Identifier: BSD-2-Clause-Patent
> +*
> +**/
> +
> +#include <IndustryStandard/Pci22.h>
> +#include <IndustryStandard/Virtio095.h>
> +#include <Library/BootLogoLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PlatformBmPrintScLib.h>
> +#include <Library/QemuBootOrderLib.h>
> +#include <Library/TpmPlatformHierarchyLib.h>
> +#include <Library/UefiBootManagerLib.h>
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/FirmwareVolume2.h>
> +#include <Protocol/GraphicsOutput.h>
> +#include <Protocol/LoadedImage.h>
> +#include <Protocol/PciIo.h>
> +#include <Protocol/PciRootBridgeIo.h>
> +#include <Protocol/VirtioDevice.h>
> +#include <Guid/EventGroup.h>
> +#include <Guid/GlobalVariable.h>
> +#include <Guid/RootBridgesConnectedEventGroup.h>
> +#include <Guid/SerialPortLibVendor.h>
> +#include <Guid/TtyTerm.h>
> +
> +#include "PlatformBm.h"
> +
> +#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
> +
> +#define VERSION_STRING_PREFIX L"RISC-V EDK2 firmware version "
> +
> +#pragma pack (1)
> +typedef struct {
> + VENDOR_DEVICE_PATH SerialDxe;
> + UART_DEVICE_PATH Uart;
> + VENDOR_DEFINED_DEVICE_PATH TermType;
> + EFI_DEVICE_PATH_PROTOCOL End;
> +} PLATFORM_SERIAL_CONSOLE;
> +#pragma pack ()
> +
> +STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
> + //
> + // VENDOR_DEVICE_PATH SerialDxe
> + //
> + {
> + { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
> + EDKII_SERIAL_PORT_LIB_VENDOR_GUID
> + },
> +
> + //
> + // UART_DEVICE_PATH Uart
> + //
> + {
> + { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
> + 0, // Reserved
> + FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
> + FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
> + FixedPcdGet8 (PcdUartDefaultParity), // Parity
> + FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
> + },
> +
> + //
> + // VENDOR_DEFINED_DEVICE_PATH TermType
> + //
> + {
> + {
> + MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
> + DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
> + }
> + //
> + // Guid to be filled in dynamically
> + //
> + },
> +
> + //
> + // EFI_DEVICE_PATH_PROTOCOL End
> + //
> + {
> + END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
> + DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
> + }
> +};
> +
> +#pragma pack (1)
> +typedef struct {
> + USB_CLASS_DEVICE_PATH Keyboard;
> + EFI_DEVICE_PATH_PROTOCOL End;
> +} PLATFORM_USB_KEYBOARD;
> +#pragma pack ()
> +
> +STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
> + //
> + // USB_CLASS_DEVICE_PATH Keyboard
> + //
> + {
> + {
> + MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
> + DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
> + },
> + 0xFFFF, // VendorId: any
> + 0xFFFF, // ProductId: any
> + 3, // DeviceClass: HID
> + 1, // DeviceSubClass: boot
> + 1 // DeviceProtocol: keyboard
> + },
> +
> + //
> + // EFI_DEVICE_PATH_PROTOCOL End
> + //
> + {
> + END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
> + DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
> + }
> +};
> +
> +/**
> + Check if the handle satisfies a particular condition.
> +
> + @param[in] Handle The handle to check.
> + @param[in] ReportText A caller-allocated string passed in for reporting
> + purposes. It must never be NULL.
> +
> + @retval TRUE The condition is satisfied.
> + @retval FALSE Otherwise. This includes the case when the condition could not
> + be fully evaluated due to an error.
> +**/
> +typedef
> +BOOLEAN
> +(EFIAPI *FILTER_FUNCTION)(
> + IN EFI_HANDLE Handle,
> + IN CONST CHAR16 *ReportText
> + );
> +
> +/**
> + Process a handle.
> +
> + @param[in] Handle The handle to process.
> + @param[in] ReportText A caller-allocated string passed in for reporting
> + purposes. It must never be NULL.
> +**/
> +typedef
> +VOID
> +(EFIAPI *CALLBACK_FUNCTION)(
> + IN EFI_HANDLE Handle,
> + IN CONST CHAR16 *ReportText
> + );
> +
> +/**
> + Locate all handles that carry the specified protocol, filter them with a
> + callback function, and pass each handle that passes the filter to another
> + callback.
> +
> + @param[in] ProtocolGuid The protocol to look for.
> +
> + @param[in] Filter The filter function to pass each handle to. If this
> + parameter is NULL, then all handles are processed.
> +
> + @param[in] Process The callback function to pass each handle to that
> + clears the filter.
> +**/
> +STATIC
> +VOID
> +FilterAndProcess (
> + IN EFI_GUID *ProtocolGuid,
> + IN FILTER_FUNCTION Filter OPTIONAL,
> + IN CALLBACK_FUNCTION Process
> + )
> +{
> + EFI_STATUS Status;
> + EFI_HANDLE *Handles;
> + UINTN NoHandles;
> + UINTN Idx;
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + ProtocolGuid,
> + NULL /* SearchKey */,
> + &NoHandles,
> + &Handles
> + );
> + if (EFI_ERROR (Status)) {
> + //
> + // This is not an error, just an informative condition.
> + //
> + DEBUG ((
> + DEBUG_VERBOSE,
> + "%a: %g: %r\n",
> + __func__,
> + ProtocolGuid,
> + Status
> + ));
> + return;
> + }
> +
> + ASSERT (NoHandles > 0);
> + for (Idx = 0; Idx < NoHandles; ++Idx) {
> + CHAR16 *DevicePathText;
> + STATIC CHAR16 Fallback[] = L"<device path unavailable>";
> +
> + //
> + // The ConvertDevicePathToText() function handles NULL input transparently.
> + //
> + DevicePathText = ConvertDevicePathToText (
> + DevicePathFromHandle (Handles[Idx]),
> + FALSE, // DisplayOnly
> + FALSE // AllowShortcuts
> + );
> + if (DevicePathText == NULL) {
> + DevicePathText = Fallback;
> + }
> +
> + if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) {
> + Process (Handles[Idx], DevicePathText);
> + }
> +
> + if (DevicePathText != Fallback) {
> + FreePool (DevicePathText);
> + }
> + }
> +
> + gBS->FreePool (Handles);
> +}
> +
> +/**
> + This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
> +**/
> +STATIC
> +BOOLEAN
> +EFIAPI
> +IsPciDisplay (
> + IN EFI_HANDLE Handle,
> + IN CONST CHAR16 *ReportText
> + )
> +{
> + EFI_STATUS Status;
> + EFI_PCI_IO_PROTOCOL *PciIo;
> + PCI_TYPE00 Pci;
> +
> + Status = gBS->HandleProtocol (
> + Handle,
> + &gEfiPciIoProtocolGuid,
> + (VOID **)&PciIo
> + );
> + if (EFI_ERROR (Status)) {
> + //
> + // This is not an error worth reporting.
> + //
> + return FALSE;
> + }
> +
> + Status = PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint32,
> + 0 /* Offset */,
> + sizeof Pci / sizeof (UINT32),
> + &Pci
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __func__, ReportText, Status));
> + return FALSE;
> + }
> +
> + return IS_PCI_DISPLAY (&Pci);
> +}
> +
> +
> +/**
> + This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at
> + the EFI_PCI_IO_PROTOCOL level.
> +**/
> +STATIC
> +BOOLEAN
> +EFIAPI
> +IsVirtioPciRng (
Is this required?
Thanks,
Sunil
> + IN EFI_HANDLE Handle,
> + IN CONST CHAR16 *ReportText
> + )
> +{
> + EFI_STATUS Status;
> + EFI_PCI_IO_PROTOCOL *PciIo;
> + UINT16 VendorId;
> + UINT16 DeviceId;
> + UINT8 RevisionId;
> + BOOLEAN Virtio10;
> + UINT16 SubsystemId;
> +
> + Status = gBS->HandleProtocol (
> + Handle,
> + &gEfiPciIoProtocolGuid,
> + (VOID **)&PciIo
> + );
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + //
> + // Read and check VendorId.
> + //
> + Status = PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint16,
> + PCI_VENDOR_ID_OFFSET,
> + 1,
> + &VendorId
> + );
> + if (EFI_ERROR (Status)) {
> + goto PciError;
> + }
> +
> + if (VendorId != VIRTIO_VENDOR_ID) {
> + return FALSE;
> + }
> +
> + //
> + // Read DeviceId and RevisionId.
> + //
> + Status = PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint16,
> + PCI_DEVICE_ID_OFFSET,
> + 1,
> + &DeviceId
> + );
> + if (EFI_ERROR (Status)) {
> + goto PciError;
> + }
> +
> + Status = PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint8,
> + PCI_REVISION_ID_OFFSET,
> + 1,
> + &RevisionId
> + );
> + if (EFI_ERROR (Status)) {
> + goto PciError;
> + }
> +
> + //
> + // From DeviceId and RevisionId, determine whether the device is a
> + // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
> + // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
> + // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
> + // only be sanity-checked, and SubsystemId will decide.
> + //
> + if ((DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) &&
> + (RevisionId >= 0x01))
> + {
> + Virtio10 = TRUE;
> + } else if ((DeviceId >= 0x1000) && (DeviceId <= 0x103F) && (RevisionId == 0x00)) {
> + Virtio10 = FALSE;
> + } else {
> + return FALSE;
> + }
> +
> + //
> + // Read and check SubsystemId as dictated by Virtio10.
> + //
> + Status = PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint16,
> + PCI_SUBSYSTEM_ID_OFFSET,
> + 1,
> + &SubsystemId
> + );
> + if (EFI_ERROR (Status)) {
> + goto PciError;
> + }
> +
> + if (Virtio10 && (SubsystemId >= 0x40)) {
> + return TRUE;
> + }
> +
> + if (!Virtio10 && (SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
> + return TRUE;
> + }
> +
> + return FALSE;
> +
> +PciError:
> + DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __func__, ReportText, Status));
> + return FALSE;
> +}
> +
> +/**
> + This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
> + the matching driver to produce all first-level child handles.
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +Connect (
> + IN EFI_HANDLE Handle,
> + IN CONST CHAR16 *ReportText
> + )
> +{
> + EFI_STATUS Status;
> +
> + Status = gBS->ConnectController (
> + Handle, // ControllerHandle
> + NULL, // DriverImageHandle
> + NULL, // RemainingDevicePath -- produce all children
> + FALSE // Recursive
> + );
> + DEBUG ((
> + EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
> + "%a: %s: %r\n",
> + __func__,
> + ReportText,
> + Status
> + ));
> +}
> +
> +/**
> + This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
> + handle, and adds it to ConOut and ErrOut.
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +AddOutput (
> + IN EFI_HANDLE Handle,
> + IN CONST CHAR16 *ReportText
> + )
> +{
> + EFI_STATUS Status;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> +
> + DevicePath = DevicePathFromHandle (Handle);
> + if (DevicePath == NULL) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "%a: %s: handle %p: device path not found\n",
> + __func__,
> + ReportText,
> + Handle
> + ));
> + return;
> + }
> +
> + Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "%a: %s: adding to ConOut: %r\n",
> + __func__,
> + ReportText,
> + Status
> + ));
> + return;
> + }
> +
> + Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "%a: %s: adding to ErrOut: %r\n",
> + __func__,
> + ReportText,
> + Status
> + ));
> + return;
> + }
> +
> + DEBUG ((
> + DEBUG_VERBOSE,
> + "%a: %s: added to ConOut and ErrOut\n",
> + __func__,
> + ReportText
> + ));
> +}
> +
> +STATIC
> +VOID
> +PlatformRegisterFvBootOption (
> + EFI_GUID *FileGuid,
> + CHAR16 *Description,
> + UINT32 Attributes
> + )
> +{
> + EFI_STATUS Status;
> + INTN OptionIndex;
> + EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
> + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
> + UINTN BootOptionCount;
> + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
> + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> +
> + Status = gBS->HandleProtocol (
> + gImageHandle,
> + &gEfiLoadedImageProtocolGuid,
> + (VOID **)&LoadedImage
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
> + DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
> + ASSERT (DevicePath != NULL);
> + DevicePath = AppendDevicePathNode (
> + DevicePath,
> + (EFI_DEVICE_PATH_PROTOCOL *)&FileNode
> + );
> + ASSERT (DevicePath != NULL);
> +
> + Status = EfiBootManagerInitializeLoadOption (
> + &NewOption,
> + LoadOptionNumberUnassigned,
> + LoadOptionTypeBoot,
> + Attributes,
> + Description,
> + DevicePath,
> + NULL,
> + 0
> + );
> + ASSERT_EFI_ERROR (Status);
> + FreePool (DevicePath);
> +
> + BootOptions = EfiBootManagerGetLoadOptions (
> + &BootOptionCount,
> + LoadOptionTypeBoot
> + );
> +
> + OptionIndex = EfiBootManagerFindLoadOption (
> + &NewOption,
> + BootOptions,
> + BootOptionCount
> + );
> +
> + if (OptionIndex == -1) {
> + Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
> + ASSERT_EFI_ERROR (Status);
> + }
> +
> + EfiBootManagerFreeLoadOption (&NewOption);
> + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
> +}
> +
> +/**
> + Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
> + whose device paths do not resolve exactly to an FvFile in the system.
> +
> + This removes any boot options that point to binaries built into the firmware
> + and have become stale due to any of the following:
> + - FvMain's base address or size changed (historical),
> + - FvMain's FvNameGuid changed,
> + - the FILE_GUID of the pointed-to binary changed,
> + - the referenced binary is no longer built into the firmware.
> +
> + EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
> + avoids exact duplicates.
> +**/
> +STATIC
> +VOID
> +RemoveStaleFvFileOptions (
> + VOID
> + )
> +{
> + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
> + UINTN BootOptionCount;
> + UINTN Index;
> +
> + BootOptions = EfiBootManagerGetLoadOptions (
> + &BootOptionCount,
> + LoadOptionTypeBoot
> + );
> +
> + for (Index = 0; Index < BootOptionCount; ++Index) {
> + EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
> + EFI_STATUS Status;
> + EFI_HANDLE FvHandle;
> +
> + //
> + // If the device path starts with neither MemoryMapped(...) nor Fv(...),
> + // then keep the boot option.
> + //
> + Node1 = BootOptions[Index].FilePath;
> + if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&
> + (DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&
> + !((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&
> + (DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)))
> + {
> + continue;
> + }
> +
> + //
> + // If the second device path node is not FvFile(...), then keep the boot
> + // option.
> + //
> + Node2 = NextDevicePathNode (Node1);
> + if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||
> + (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
> + {
> + continue;
> + }
> +
> + //
> + // Locate the Firmware Volume2 protocol instance that is denoted by the
> + // boot option. If this lookup fails (i.e., the boot option references a
> + // firmware volume that doesn't exist), then we'll proceed to delete the
> + // boot option.
> + //
> + SearchNode = Node1;
> + Status = gBS->LocateDevicePath (
> + &gEfiFirmwareVolume2ProtocolGuid,
> + &SearchNode,
> + &FvHandle
> + );
> +
> + if (!EFI_ERROR (Status)) {
> + //
> + // The firmware volume was found; now let's see if it contains the FvFile
> + // identified by GUID.
> + //
> + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
> + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
> + UINTN BufferSize;
> + EFI_FV_FILETYPE FoundType;
> + EFI_FV_FILE_ATTRIBUTES FileAttributes;
> + UINT32 AuthenticationStatus;
> +
> + Status = gBS->HandleProtocol (
> + FvHandle,
> + &gEfiFirmwareVolume2ProtocolGuid,
> + (VOID **)&FvProtocol
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
> + //
> + // Buffer==NULL means we request metadata only: BufferSize, FoundType,
> + // FileAttributes.
> + //
> + Status = FvProtocol->ReadFile (
> + FvProtocol,
> + &FvFileNode->FvFileName, // NameGuid
> + NULL, // Buffer
> + &BufferSize,
> + &FoundType,
> + &FileAttributes,
> + &AuthenticationStatus
> + );
> + if (!EFI_ERROR (Status)) {
> + //
> + // The FvFile was found. Keep the boot option.
> + //
> + continue;
> + }
> + }
> +
> + //
> + // Delete the boot option.
> + //
> + Status = EfiBootManagerDeleteLoadOptionVariable (
> + BootOptions[Index].OptionNumber,
> + LoadOptionTypeBoot
> + );
> + DEBUG_CODE_BEGIN ();
> + CHAR16 *DevicePathString;
> +
> + DevicePathString = ConvertDevicePathToText (
> + BootOptions[Index].FilePath,
> + FALSE,
> + FALSE
> + );
> + DEBUG ((
> + EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
> + "%a: removing stale Boot#%04x %s: %r\n",
> + __func__,
> + (UINT32)BootOptions[Index].OptionNumber,
> + DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
> + Status
> + ));
> + if (DevicePathString != NULL) {
> + FreePool (DevicePathString);
> + }
> +
> + DEBUG_CODE_END ();
> + }
> +
> + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
> +}
> +
> +STATIC
> +VOID
> +PlatformRegisterOptionsAndKeys (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + EFI_INPUT_KEY Enter;
> + EFI_INPUT_KEY F2;
> + EFI_INPUT_KEY Esc;
> + EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
> +
> + //
> + // Register ENTER as CONTINUE key
> + //
> + Enter.ScanCode = SCAN_NULL;
> + Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
> + Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
> + ASSERT_EFI_ERROR (Status);
> +
> + //
> + // Map F2 and ESC to Boot Manager Menu
> + //
> + F2.ScanCode = SCAN_F2;
> + F2.UnicodeChar = CHAR_NULL;
> + Esc.ScanCode = SCAN_ESC;
> + Esc.UnicodeChar = CHAR_NULL;
> + Status = EfiBootManagerGetBootManagerMenu (&BootOption);
> + ASSERT_EFI_ERROR (Status);
> + Status = EfiBootManagerAddKeyOptionVariable (
> + NULL,
> + (UINT16)BootOption.OptionNumber,
> + 0,
> + &F2,
> + NULL
> + );
> + ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
> + Status = EfiBootManagerAddKeyOptionVariable (
> + NULL,
> + (UINT16)BootOption.OptionNumber,
> + 0,
> + &Esc,
> + NULL
> + );
> + ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
> +}
> +
> +//
> +// BDS Platform Functions
> +//
> +
> +/**
> + Do the platform init, can be customized by OEM/IBV
> + Possible things that can be done in PlatformBootManagerBeforeConsole:
> + > Update console variable: 1. include hot-plug devices;
> + > 2. Clear ConIn and add SOL for AMT
> + > Register new Driver#### or Boot####
> + > Register new Key####: e.g.: F12
> + > Signal ReadyToLock event
> + > Authentication action: 1. connect Auth devices;
> + > 2. Identify auto logon user.
> +**/
> +VOID
> +EFIAPI
> +PlatformBootManagerBeforeConsole (
> + VOID
> + )
> +{
> + UINT16 FrontPageTimeout;
> + EFI_STATUS Status;
> +
> + //
> + // Signal EndOfDxe PI Event
> + //
> + EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
> +
> + //
> + // Dispatch deferred images after EndOfDxe event.
> + //
> + EfiBootManagerDispatchDeferredImages ();
> +
> + //
> + // Locate the PCI root bridges and make the PCI bus driver connect each,
> + // non-recursively. This will produce a number of child handles with PciIo on
> + // them.
> + //
> + FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
> +
> + //
> + // Signal the ACPI platform driver that it can download QEMU ACPI tables.
> + //
> + EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
> +
> + //
> + // Find all display class PCI devices (using the handles from the previous
> + // step), and connect them non-recursively. This should produce a number of
> + // child handles with GOPs on them.
> + //
> + FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
> +
> + //
> + // Now add the device path of all handles with GOP on them to ConOut and
> + // ErrOut.
> + //
> + FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
> +
> + //
> + // Add the hardcoded short-form USB keyboard device path to ConIn.
> + //
> + EfiBootManagerUpdateConsoleVariable (
> + ConIn,
> + (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard,
> + NULL
> + );
> +
> + //
> + // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
> + //
> + CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
> +
> + EfiBootManagerUpdateConsoleVariable (
> + ConIn,
> + (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
> + NULL
> + );
> + EfiBootManagerUpdateConsoleVariable (
> + ConOut,
> + (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
> + NULL
> + );
> + EfiBootManagerUpdateConsoleVariable (
> + ErrOut,
> + (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole,
> + NULL
> + );
> +
> + //
> + // Reflect the PCD in the standard Timeout variable.
> + //
> + Status = gRT->SetVariable (
> + EFI_TIME_OUT_VARIABLE_NAME,
> + &gEfiGlobalVariableGuid,
> + (EFI_VARIABLE_NON_VOLATILE |
> + EFI_VARIABLE_BOOTSERVICE_ACCESS |
> + EFI_VARIABLE_RUNTIME_ACCESS),
> + sizeof FrontPageTimeout,
> + &FrontPageTimeout
> + );
> + DEBUG ((
> + EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
> + "%a: SetVariable(%s, %u): %r\n",
> + __func__,
> + EFI_TIME_OUT_VARIABLE_NAME,
> + FrontPageTimeout,
> + Status
> + ));
> +
> + //
> + // Register platform-specific boot options and keyboard shortcuts.
> + //
> + PlatformRegisterOptionsAndKeys ();
> +
> + //
> + // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
> + // instances on Virtio PCI RNG devices.
> + //
> + FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);
> +}
> +
> +/**
> + Do the platform specific action after the console is ready
> + Possible things that can be done in PlatformBootManagerAfterConsole:
> + > Console post action:
> + > Dynamically switch output mode from 100x31 to 80x25 for certain scenario
> + > Signal console ready platform customized event
> + > Run diagnostics like memory testing
> + > Connect certain devices
> + > Dispatch additional option roms
> + > Special boot: e.g.: USB boot, enter UI
> +**/
> +VOID
> +EFIAPI
> +PlatformBootManagerAfterConsole (
> + VOID
> + )
> +{
> + UINTN FirmwareVerLength;
> +
> + FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));
> + //
> + // Show the splash screen.
> + //
> + BootLogoEnableLogo ();
> +
> + if (FirmwareVerLength > 0) {
> + Print (
> + VERSION_STRING_PREFIX L"%s\n",
> + PcdGetPtr (PcdFirmwareVersionString)
> + );
> + }
> +
> + Print (L"Press ESCAPE within 10 seconds for boot options ");
> +
> + //
> + // Enumerate all possible boot options, then filter and reorder them based on
> + // the QEMU configuration.
> + //
> + EfiBootManagerRefreshAllBootOption ();
> +
> + //
> + // Register UEFI Shell
> + //
> + PlatformRegisterFvBootOption (
> + &gUefiShellFileGuid,
> + L"EFI Internal Shell",
> + LOAD_OPTION_ACTIVE
> + );
> +
> + RemoveStaleFvFileOptions ();
> +
> + PlatformBmPrintScRegisterHandler ();
> +}
> +
> +/**
> + This function is called each second during the boot manager waits the
> + timeout.
> +
> + @param TimeoutRemain The remaining timeout.
> +**/
> +VOID
> +EFIAPI
> +PlatformBootManagerWaitCallback (
> + UINT16 TimeoutRemain
> + )
> +{
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
> + UINT16 TimeoutInitial;
> +
> + TimeoutInitial = PcdGet16 (PcdPlatformBootTimeOut);
> +
> + //
> + // If PcdPlatformBootTimeOut is set to zero, then we consider
> + // that no progress update should be enacted.
> + //
> + if (TimeoutInitial == 0) {
> + return;
> + }
> +
> + Black.Raw = 0x00000000;
> + White.Raw = 0x00FFFFFF;
> +
> + BootLogoUpdateProgress (
> + White.Pixel,
> + Black.Pixel,
> + L"Start boot option",
> + White.Pixel,
> + (TimeoutInitial - TimeoutRemain) * 100 / TimeoutInitial,
> + 0
> + );
> +}
> +
> +/**
> + The function is called when no boot option could be launched,
> + including platform recovery options and options pointing to applications
> + built into firmware volumes.
> +
> + If this function returns, BDS attempts to enter an infinite loop.
> +**/
> +VOID
> +EFIAPI
> +PlatformBootManagerUnableToBoot (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + EFI_INPUT_KEY Key;
> + EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
> + UINTN Index;
> +
> + //
> + // BootManagerMenu doesn't contain the correct information when return status
> + // is EFI_NOT_FOUND.
> + //
> + Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + //
> + // Normally BdsDxe does not print anything to the system console, but this is
> + // a last resort -- the end-user will likely not see any DEBUG messages
> + // logged in this situation.
> + //
> + // AsciiPrint() will NULL-check gST->ConOut internally. We check gST->ConIn
> + // here to see if it makes sense to request and wait for a keypress.
> + //
> + if (gST->ConIn != NULL) {
> + AsciiPrint (
> + "%a: No bootable option or device was found.\n"
> + "%a: Press any key to enter the Boot Manager Menu.\n",
> + gEfiCallerBaseName,
> + gEfiCallerBaseName
> + );
> + Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
> + ASSERT_EFI_ERROR (Status);
> + ASSERT (Index == 0);
> +
> + //
> + // Drain any queued keys.
> + //
> + while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
> + //
> + // just throw away Key
> + //
> + }
> + }
> +
> + for ( ; ;) {
> + EfiBootManagerBoot (&BootManagerMenu);
> + }
> +}
> diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h
> new file mode 100755
> index 000000000000..067af555ad31
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBm.h
> @@ -0,0 +1,46 @@
> +/** @file
> +* Head file for BDS Platform specific code
> +*
> +* Copyright (C) 2015-2016, Red Hat, Inc.
> +* Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
> +* Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> +*
> +* SPDX-License-Identifier: BSD-2-Clause-Patent
> +*
> +**/
> +
> +#ifndef _PLATFORM_BM_H_
> +#define _PLATFORM_BM_H_
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +
> +/**
> + Download the kernel, the initial ramdisk, and the kernel command line from
> + QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
> + image files, and load and start the kernel from it.
> +
> + The kernel will be instructed via its command line to load the initrd from
> + the same Simple FileSystem.
> +
> + @retval EFI_NOT_FOUND Kernel image was not found.
> + @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
> + @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
> +
> + @return Error codes from any of the underlying
> + functions. On success, the function doesn't
> + return.
> +**/
> +EFI_STATUS
> +EFIAPI
> +TryRunningQemuKernel (
> + VOID
> + );
> +
> +#endif // _PLATFORM_BM_H_
> diff --git a/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> new file mode 100755
> index 000000000000..d967f808cf7f
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> @@ -0,0 +1,71 @@
> +## @file
> +# Implementation for PlatformBootManagerLib library class interfaces for RISC-V.
> +#
> +# Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>
> +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = DxeRiscV64PlatformBootManagerLib
> + FILE_GUID = 900C3D64-E5EA-0F56-1F51-64D593F374D2
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER
> +
> +#
> +# The following information is for reference only and not required by the build tools.
> +#
> +# VALID_ARCHITECTURES = RISCV64
> +#
> +
> +[Sources]
> + PlatformBm.c
> + PlatformBm.h
> +
> +[Packages]
> + MdeModulePkg/MdeModulePkg.dec
> + MdePkg/MdePkg.dec
> + OvmfPkg/OvmfPkg.dec
> + SecurityPkg/SecurityPkg.dec
> + ShellPkg/ShellPkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + BaseMemoryLib
> + BootLogoLib
> + DebugLib
> + DevicePathLib
> + MemoryAllocationLib
> + PcdLib
> + PlatformBmPrintScLib
> + ReportStatusCodeLib
> + UefiBootManagerLib
> + UefiBootServicesTableLib
> + UefiLib
> + UefiRuntimeServicesTableLib
> +
> +[FixedPcd]
> + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
> + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
> + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
> + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
> +
> +[Pcd]
> + gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString
> +
> +[Guids]
> + gEfiEndOfDxeEventGroupGuid
> + gEfiGlobalVariableGuid
> + gRootBridgesConnectedEventGroupGuid
> + gUefiShellFileGuid
> + gEfiTtyTermGuid
> +
> +[Protocols]
> + gEfiGenericMemTestProtocolGuid ## CONSUMES
> + gEfiGraphicsOutputProtocolGuid ## CONSUMES
> + gEfiPciRootBridgeIoProtocolGuid
> --
> 2.34.1
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109800): https://edk2.groups.io/g/devel/message/109800
Mute This Topic: https://groups.io/mt/102053683/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver John Chew
@ 2023-10-19 12:14 ` Sunil V L
2023-10-20 8:45 ` John Chew
0 siblings, 1 reply; 12+ messages in thread
From: Sunil V L @ 2023-10-19 12:14 UTC (permalink / raw)
To: John Chew; +Cc: devel
On Thu, Oct 19, 2023 at 10:59:20AM +0800, John Chew wrote:
> Some DXE drivers such as MMC's DMA can only work with 32-bit addressing.
> So, EfiBootServicesData need to set within 32-bit range only.
>
> This is achieved by setting all EfiConventionalMemory to
> EfiBootServicesData before any memory allocations in the early stage of
> DXE.
>
Hi John,
I think this is a fragile workaround. Why not MMC driver allocate 32-bit
memory using EFI API?
Thanks,
Sunil
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109801): https://edk2.groups.io/g/devel/message/109801
Mute This Topic: https://groups.io/mt/102053685/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
@ 2023-10-19 12:34 ` Sunil V L
2023-10-20 8:58 ` John Chew
0 siblings, 1 reply; 12+ messages in thread
From: Sunil V L @ 2023-10-19 12:34 UTC (permalink / raw)
To: John Chew; +Cc: devel, mindachen1987
Hi John,
On Thu, Oct 19, 2023 at 10:59:21AM +0800, John Chew wrote:
> From: mindachen1987 <minda.chen@starfivetech.com>
>
The patch should have commit message more than one liner. Same comment
for PATCH 1/6 and 2/6.
Also, there should be a patch in the series to add maintainer entry for
your platform.
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Co-authored-by: John Chew <yuinyee.chew@starfivetech.com>
> Signed-off-by: mindachen1987 <minda.chen@starfivetech.com>
> ---
> Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h | 24 +++++++++++
> Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec | 45 ++++++++++++++++++++
> 2 files changed, 69 insertions(+)
>
> diff --git a/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
> new file mode 100644
> index 000000000000..b6875f6aa82b
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/Include/IndustryStandard/JH7110.h
> @@ -0,0 +1,24 @@
> +/** @file
> + *
> + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> + **/
> +
> +#ifndef JH7110_H__
> +#define JH7110_H__
> +
> +// #define JH7110_SOC_REGISTERS (FixedPcdGet64 (PcdJH7110RegistersAddress))
> +// #define JH7110_SOC_REGISTER_LENGTH 0x02000000
> +
Could you remove these commented code?
Thanks,
Sunil
> +/* Generic PCI addresses */
> +#define PCIE_TOP_OF_MEM_WIN (FixedPcdGet64 (PcdJH7110PciBusMmioAdr))
> +#define PCIE_CPU_MMIO_WINDOW (FixedPcdGet64 (PcdJH7110PciCpuMmioAdr))
> +#define PCIE_BRIDGE_MMIO_LEN (FixedPcdGet32 (PcdJH7110PciBusMmioLen))
> +
> +/* PCI root bridge control registers location */
> +#define PCIE_REG_BASE (FixedPcdGet64 (PcdJH7110PciRegBase))
> +#define PCIE_CONFIG_BASE (FixedPcdGet64 (PcdJH7110PciConfigRegBase))
> +
> +#endif /* JH7110_H__ */
> diff --git a/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
> new file mode 100644
> index 000000000000..438557a15500
> --- /dev/null
> +++ b/Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec
> @@ -0,0 +1,45 @@
> +## @file
> +#
> +# Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + DEC_SPECIFICATION = 0x0001001A
> + PACKAGE_NAME = JH7110Pkg
> + PACKAGE_GUID = D4B585C5-EBCA-4779-B974-05A3CF2F10C4
> + PACKAGE_VERSION = 1.0
> +
> +[Includes]
> + Include
> +
> +[Guids]
> + gJH7110TokenSpaceGuid = {0x44045e56, 0x7056, 0x4be6, {0x88, 0xc0, 0x49, 0x0c, 0x67, 0x90, 0x2f, 0xba}}
> +
> +[PcdsFixedAtBuild.common]
> +# Memory map
> + gJH7110TokenSpaceGuid.PcdJH7110FlashVarOffset|0x0|UINT32|0x00000001
> +
> +# PCIe
> + gJH7110TokenSpaceGuid.PcdJH7110RegistersAddress|0|UINT32|0x00000002
> + gJH7110TokenSpaceGuid.PcdJH7110PciRegBase|0x2b000000|UINT64|0x00000003
> + gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioAdr|0x0|UINT64|0x00000004
> + gJH7110TokenSpaceGuid.PcdJH7110PciBusMmioLen|0x0|UINT32|0x00000005
> + gJH7110TokenSpaceGuid.PcdJH7110PciCpuMmioAdr|0x0|UINT64|0x00000006
> + gJH7110TokenSpaceGuid.PcdJH7110PciConfigRegBase|0x940000000|UINT64|0x00000007
> +
> +# SPI
> + gJH7110TokenSpaceGuid.PcdSpiFlashRegBase|0|UINT32|0x10000008
> + gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase|0|UINT64|0x10000009
> + gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth|0|UINT8|0x10000010
> + gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz|0|UINT32|0x10000011
> + gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs|0|UINT32|0x10000012
> + gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs|0|UINT32|0x1000013
> + gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs|0|UINT32|0x1000014
> + gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs|0|UINT32|0x1000015
> +
> +[Protocols]
> + gJH7110SpiMasterProtocolGuid = { 0xA33C46E0, 0x4FB6, 0x4AA3, { 0x8E, 0x66, 0x00, 0x06, 0x9F, 0x3A, 0x11, 0x81 }}
> + gJH7110SpiFlashProtocolGuid = { 0x5ECECDF6, 0x81DA, 0x4E10, { 0x9D, 0x4B, 0x26, 0x65, 0x8C, 0x03, 0xAB, 0xBC }}
> --
> 2.34.1
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109803): https://edk2.groups.io/g/devel/message/109803
Mute This Topic: https://groups.io/mt/102053687/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver
2023-10-19 12:14 ` Sunil V L
@ 2023-10-20 8:45 ` John Chew
0 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-20 8:45 UTC (permalink / raw)
To: Sunil V L, devel
[-- Attachment #1: Type: text/plain, Size: 970 bytes --]
Hi Sunil,
You're right.
The MMC DMA destination buffer (64-bit) actually allocated in EDK2 code and passed into the EDK2-platform MMC driver.
Now that you mention it, I think I can allocate another buffer (force to use 32-bit) in the MMC driver and use that buffer for tx/rx.
Then, copy the content from the buffer (32-bit) to the MMC destination buffer (64-bit). In this case, there is no need to change any code
in EDK2 and this "boot service memory allocation" driver is no longer needed.
I will remove this driver and add the handling in DwEmmcDxe.c in Patch V2.
Thank you!! =)
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109826): https://edk2.groups.io/g/devel/message/109826
Mute This Topic: https://groups.io/mt/102053685/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 1496 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package
2023-10-19 12:34 ` Sunil V L
@ 2023-10-20 8:58 ` John Chew
0 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-20 8:58 UTC (permalink / raw)
To: Sunil V L, devel
[-- Attachment #1: Type: text/plain, Size: 683 bytes --]
On Thu, Oct 19, 2023 at 08:34 PM, Sunil V L wrote:
>
> The patch should have commit message more than one liner. Same comment
> for PATCH 1/6 and 2/6
Hi Sunil,
Okay sure. I will remove the commented code.
Let me improve the commit message and include all maintainers in patch V2.
Thanks =)
John
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109829): https://edk2.groups.io/g/devel/message/109829
Mute This Topic: https://groups.io/mt/102053687/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 1175 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library
2023-10-19 12:12 ` Sunil V L
@ 2023-10-20 9:34 ` John Chew
0 siblings, 0 replies; 12+ messages in thread
From: John Chew @ 2023-10-20 9:34 UTC (permalink / raw)
To: Sunil V L, devel
[-- Attachment #1: Type: text/plain, Size: 683 bytes --]
Hi Sunil,
Actually, we can use:
Platform/RISC-V/PlatformPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
I think there is no need for us to have our own PlatformBootManager library.
This library is here for debugging and development.
I will update this in patch v2.
Thanks! =)
John
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109831): https://edk2.groups.io/g/devel/message/109831
Mute This Topic: https://groups.io/mt/102053683/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 1188 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2023-10-20 9:34 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-19 2:59 [edk2-devel] [PATCH v1 1/6] StarFive/JH7110Pkg: Add Pci controller driver John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 2/6] StarFive/JH7110Pkg: Add SPI protocol and driver support John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 3/6] StarFive/JH7110Pkg: Add firmware volume block protocol John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 4/6] StarFive/JH7110Pkg: Add PlatformBootManagerLib library John Chew
2023-10-19 12:12 ` Sunil V L
2023-10-20 9:34 ` John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 5/6] StarFive/JH7110Pkg: Implement boot services memory allocation driver John Chew
2023-10-19 12:14 ` Sunil V L
2023-10-20 8:45 ` John Chew
2023-10-19 2:59 ` [edk2-devel] [PATCH v1 6/6] StarFive/JH7110Pkg: Add JH7110 Silicon Package John Chew
2023-10-19 12:34 ` Sunil V L
2023-10-20 8:58 ` John Chew
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox