From: Duke Zhai <Duke.Zhai@amd.com>
BZ #:4640
In V3: Improve coding style follow edk2 C coding standard.
1.Remove macro definition extra underscores.
2.Putting some AMD copyright in the right place.
In V2: Improve coding style.
1.Remove the leading underscore and use double underscore at trailing in C header files.
2.Remove old tianocore licenses and redundant license description.
3.Improve coding style. For example: remove space between @param.
In V1:
Initial FchSpi module. FCH SPI Common Driver implements
the SPI Host Controller Compatibility Interface.
Signed-off-by: Duke Zhai <duke.zhai@amd.com>
Cc: Eric Xing <eric.xing@amd.com>
Cc: Ken Yao <ken.yao@amd.com>
Cc: Igniculus Fu <igniculus.fu@amd.com>
Cc: Abner Chang <abner.chang@amd.com>
---
.../Universal/FchSpi/FchSpiProtect.c | 67 ++
.../Universal/FchSpi/FchSpiProtect.h | 38 +
.../Universal/FchSpi/FchSpiRuntimeDxe.c | 163 ++++
.../Universal/FchSpi/FchSpiRuntimeDxe.h | 49 ++
.../Universal/FchSpi/FchSpiRuntimeDxe.inf | 84 ++
.../VanGoghBoard/Universal/FchSpi/FchSpiSmm.c | 112 +++
.../VanGoghBoard/Universal/FchSpi/FchSpiSmm.h | 32 +
.../Universal/FchSpi/FchSpiSmm.inf | 94 +++
.../VanGoghBoard/Universal/FchSpi/SpiCommon.c | 790 ++++++++++++++++++
.../VanGoghBoard/Universal/FchSpi/SpiInfo.h | 24 +
10 files changed, 1453 insertions(+)
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiProtect.c
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiProtect.h
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.c
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.h
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.inf
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.c
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.h
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.inf
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/SpiCommon.c
create mode 100644 Platform/AMD/VanGoghBoard/Universal/FchSpi/SpiInfo.h
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiProtect.c b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiProtect.c
new file mode 100644
index 0000000000..658d9b063d
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiProtect.c
@@ -0,0 +1,67 @@
+/** @file
+ Implements FchSpiProtect.c
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+
+#include "FchSpiProtect.h"
+
+/**
+
+ Fch Spi Protect Lock
+
+ @param SpiMmioBase
+
+**/
+EFI_STATUS
+EFIAPI
+FchSpiProtect_Lock (
+ IN UINTN SpiMmioBase
+ )
+{
+ if (!(MmioRead8 (SpiMmioBase + 2) & 0xC0)) {
+ // Check BIT7+BIT6
+ return EFI_SUCCESS;
+ } else {
+ MmioWrite8 (SpiMmioBase + 9, 0x6); // PrefixOpCode WRITE_ENABLE
+ MmioWrite8 (SpiMmioBase + 2, MmioRead8 (SpiMmioBase + 2) & 0x3F); // Clear BIT7+BIT6
+ if (MmioRead8 (SpiMmioBase + 2) & 0xC0) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Fch Spi Protect UnLock
+
+ @param SpiMmioBase
+
+**/
+EFI_STATUS
+EFIAPI
+FchSpiProtect_UnLock (
+ IN UINTN SpiMmioBase
+ )
+{
+ if ((MmioRead8 (SpiMmioBase + 2) & 0xC0) || (6 != MmioRead8 (SpiMmioBase + 9))) {
+ return EFI_SUCCESS;
+ } else {
+ MmioWrite8 (SpiMmioBase + 9, 0x0);
+ MmioWrite8 (SpiMmioBase + 2, MmioRead8 (SpiMmioBase + 2) | 0xC0); // Set BIT7+BIT6
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiProtect.h b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiProtect.h
new file mode 100644
index 0000000000..e46a1a066a
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiProtect.h
@@ -0,0 +1,38 @@
+/** @file
+ Implements FchSpiProtect.h
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef FCH_SPI_PROTECT_H_
+#define FCH_SPI_PROTECT_H_
+
+/**
+
+ Fch Spi Protect Lock
+
+ @param UINTN SpiMmioBase
+
+**/
+EFI_STATUS
+EFIAPI
+FchSpiProtect_Lock (
+ IN UINTN SpiMmioBase
+ );
+
+/**
+
+ Fch Spi Protect UnLock
+
+ @param UINTN SpiMmioBase
+
+**/
+EFI_STATUS
+EFIAPI
+FchSpiProtect_UnLock (
+ IN UINTN SpiMmioBase
+ );
+
+#endif
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.c b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.c
new file mode 100644
index 0000000000..7bb402402c
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.c
@@ -0,0 +1,163 @@
+/** @file
+PCH SPI Runtime Driver implements the SPI Host Controller Compatibility Interface.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifdef _MSC_VER
+ #pragma optimize( "", off )
+#endif
+
+#ifdef __GNUC__
+ #ifndef __clang__
+ #pragma GCC push_options
+ #pragma GCC optimize ("O0")
+ #else
+ #pragma clang optimize off
+ #endif
+#endif
+
+#include "FchSpiRuntimeDxe.h"
+
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
+CONST BOOLEAN gInSmm = FALSE;
+
+//
+// Global variables
+//
+SPI_INSTANCE *mSpiInstance;
+
+/**
+
+ Fixup internal data pointers so that the services can be called in virtual mode.
+
+ @param Event The event registered.
+ @param Context Event context. Not used in this event handler.
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+FchSpiVirtualddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *)&(mSpiInstance->SpiBar));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *)&(mSpiInstance->SpiProtocol.Init));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *)&(mSpiInstance->SpiProtocol.Lock));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *)&(mSpiInstance->SpiProtocol.Execute));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *)&(mSpiInstance));
+}
+
+/**
+
+ Entry point for the SPI host controller driver.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Global system service table.
+
+ @retval EFI_SUCCESS Initialization complete.
+ @retval EFI_UNSUPPORTED The chipset is unsupported by this driver.
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver.
+ @retval EFI_DEVICE_ERROR Device error, driver exits abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallFchSpiRuntimeDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT64 BaseAddress;
+ UINT64 Length;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdMemorySpaceDescriptor;
+ UINT64 Attributes;
+ EFI_EVENT Event;
+
+ DEBUG ((DEBUG_INFO, "InstallFchSpiRuntimeDxe() Start\n"));
+
+ //
+ // Allocate Runtime memory for the SPI protocol instance.
+ //
+ mSpiInstance = AllocateRuntimeZeroPool (sizeof (SPI_INSTANCE));
+ if (mSpiInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize the SPI protocol instance
+ //
+ Status = SpiProtocolConstructor (mSpiInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install the EFI_SPI_PROTOCOL interface
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiInstance->Handle),
+ &gEfiSpiProtocolGuid,
+ &(mSpiInstance->SpiProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (mSpiInstance);
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = mSpiInstance->SpiProtocol.Init (&(mSpiInstance->SpiProtocol));
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set Spi space in GCD to be RUNTIME so that the range will be supported in
+ // virtual address mode in EFI aware OS runtime.
+ // It will assert if Spi Memory Space is not allocated
+ // The caller is responsible for the existence and allocation of the Spi Memory Spaces
+ //
+ BaseAddress = (EFI_PHYSICAL_ADDRESS)(mSpiInstance->SpiBar);
+ Length = 0x1000;
+
+ Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdMemorySpaceDescriptor);
+ ASSERT_EFI_ERROR (Status);
+
+ Attributes = GcdMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
+
+ Status = gDS->SetMemorySpaceAttributes (
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FchSpiVirtualddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "InstallFchSpiRuntimeDxe() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+#ifdef _MSC_VER
+ #pragma optimize( "", on )
+#endif
+#ifdef __GNUC__
+ #ifndef __clang__
+ #pragma GCC pop_options
+ #endif
+#endif
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.h b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.h
new file mode 100644
index 0000000000..929e821294
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.h
@@ -0,0 +1,49 @@
+/** @file
+Header file for the PCH SPI Runtime Driver.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef FCH_SPI_RUNTIME_DXE_H_
+#define FCH_SPI_RUNTIME_DXE_H_
+
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PciExpressLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/TimerLib.h>
+#include <Library/SpiFlashDeviceLib.h>
+
+#include <Protocol/Spi.h>
+#include <Protocol/SpiCommon.h>
+
+#define EFI_INTERNAL_POINTER 0x00000004
+
+/**
+
+ Fixup internal data pointers so that the services can be called in virtual mode.
+
+ @param Event The event registered.
+ @param Context Event context. Not used in this event handler.
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+FchSpiVirtualddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.inf b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.inf
new file mode 100644
index 0000000000..c2af195d05
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiRuntimeDxe.inf
@@ -0,0 +1,84 @@
+## @file
+# Component description file for the SPI Runtime driver.
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FchSpiRuntimeDxe
+ FILE_GUID = B9B0740A-B4E9-46FF-AAC7-C632BAC15834
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InstallFchSpiRuntimeDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+[Sources]
+ FchSpiRuntimeDxe.c
+ FchSpiRuntimeDxe.h
+ FchSpiProtect.c
+ FchSpiProtect.h
+ SpiCommon.c
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+[Packages]
+ MdePkg/MdePkg.dec
+ ChachaniBoardPkg/Project.dec
+ VanGoghCommonPkg/AmdCommonPkg.dec
+
+################################################################################
+#
+# Library Class Section - list of Library Classes that are required for
+# this module.
+#
+################################################################################
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiRuntimeLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ DxeServicesTableLib
+ UefiLib
+ DebugLib
+ MemoryAllocationLib
+ PciExpressLib
+ SpiFlashDeviceLib
+
+################################################################################
+#
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names
+# that this module uses or produces.
+#
+################################################################################
+[Protocols]
+ gEfiSpiProtocolGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+ gPlatformPkgTokenSpaceGuid.PcdFlashAreaSize
+
+[Depex]
+ TRUE
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.c b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.c
new file mode 100644
index 0000000000..1f842685a8
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.c
@@ -0,0 +1,112 @@
+/** @file
+
+PCH SPI SMM Driver implements the SPI Host Controller Compatibility Interface.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+#ifdef _MSC_VER
+ #pragma optimize( "", off )
+#endif
+
+#ifdef __GNUC__
+ #ifndef __clang__
+ #pragma GCC push_options
+ #pragma GCC optimize ("O0")
+ #else
+ #pragma clang optimize off
+ #endif
+#endif
+
+#include "FchSpiSmm.h"
+
+CONST BOOLEAN gInSmm = TRUE;
+
+//
+// Global variables
+//
+SPI_INSTANCE *mSpiInstance;
+
+/**
+
+ Entry point for the SPI host controller driver.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Global system service table.
+
+ @retval EFI_SUCCESS Initialization complete.
+ @retval EFI_UNSUPPORTED The chipset is unsupported by this driver.
+ @retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver.
+ @retval EFI_DEVICE_ERROR Device error, driver exits abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallFchSpiSmm (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ // VOID *SmmReadyToBootRegistration;
+
+ DEBUG ((DEBUG_INFO, "InstallFchSpiSmm() Start\n"));
+
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof (SPI_INSTANCE),
+ (VOID **)&mSpiInstance
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (mSpiInstance, sizeof (SPI_INSTANCE));
+
+ if (mSpiInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize the SPI protocol instance
+ //
+ Status = SpiProtocolConstructor (mSpiInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install the EFI_SPI_PROTOCOL interface
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &(mSpiInstance->Handle),
+ &gEfiSmmSpiProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &(mSpiInstance->SpiProtocol)
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (mSpiInstance);
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = mSpiInstance->SpiProtocol.Init (&(mSpiInstance->SpiProtocol));
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "InstallFchSpiSmm() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+#ifdef _MSC_VER
+ #pragma optimize( "", on )
+#endif
+#ifdef __GNUC__
+ #ifndef __clang__
+ #pragma GCC pop_options
+ #endif
+#endif
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.h b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.h
new file mode 100644
index 0000000000..e7e9ed6033
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.h
@@ -0,0 +1,32 @@
+/** @file
+Header file for the PCH SPI SMM Driver.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef FCH_SPI_SMM_H_
+#define FCH_SPI_SMM_H_
+
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PciExpressLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/TimerLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/SpiFlashDeviceLib.h>
+
+#include <Protocol/SmmReadyToBoot.h>
+#include <Protocol/Spi.h>
+#include <Protocol/SpiCommon.h>
+
+#endif
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.inf b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.inf
new file mode 100644
index 0000000000..b30a17119d
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/FchSpiSmm.inf
@@ -0,0 +1,94 @@
+## @file
+# Spi smm driver
+#
+# Component description file for the SPI SMM driver.
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FchSpiSmm
+ FILE_GUID = 9D63F99F-609D-4EB3-A9D1-5ACE2E25792A
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.1
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = InstallFchSpiSmm
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+[Sources]
+ FchSpiSmm.c
+ FchSpiSmm.h
+ FchSpiProtect.c
+ FchSpiProtect.h
+ SpiCommon.c
+
+[sources.ia32]
+
+[sources.x64]
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ VanGoghCommonPkg/AmdCommonPkg.dec
+ ChachaniBoardPkg/Project.dec
+
+################################################################################
+#
+# Library Class Section - list of Library Classes that are required for
+# this module.
+#
+################################################################################
+[LibraryClasses]
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ DxeServicesTableLib
+ UefiLib
+ DebugLib
+ MemoryAllocationLib
+ PciExpressLib
+ SmmServicesTableLib
+ SpiFlashDeviceLib
+
+################################################################################
+#
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names
+# that this module uses or produces.
+#
+################################################################################
+[Protocols]
+ gEfiSmmSpiProtocolGuid
+ gEfiSmmBase2ProtocolGuid
+ gEdkiiSmmReadyToBootProtocolGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+ gPlatformPkgTokenSpaceGuid.PcdFlashAreaSize
+
+[Depex]
+ gEfiSmmBase2ProtocolGuid
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/SpiCommon.c b/Platform/AMD/VanGoghBoard/Universal/FchSpi/SpiCommon.c
new file mode 100644
index 0000000000..4aab7294cb
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/SpiCommon.c
@@ -0,0 +1,790 @@
+/** @file
+PCH SPI Common Driver implements the SPI Host Controller Compatibility Interface.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2013-2015 Intel Corporation.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifdef _MSC_VER
+ #pragma optimize( "", off )
+#endif
+
+#ifdef __GNUC__
+ #ifndef __clang__
+ #pragma GCC push_options
+ #pragma GCC optimize ("O0")
+ #else
+ #pragma clang optimize off
+ #endif
+#endif
+
+#include "FchSpiProtect.h"
+#include "SpiInfo.h"
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SpiFlashDeviceLib.h>
+#include <Protocol/SpiCommon.h>
+#include <Protocol/SmmBase2.h>
+
+#define SPI_WREN_INDEX 0 // Prefix Opcode 0: SPI_COMMAND_WRITE_ENABLE
+#define SPI_EWSR_INDEX 1 // Prefix Opcode 1: SPI_COMMAND_WRITE_S_EN
+
+#define FCH_SPI_MMIO_REG48_TXBYTECOUNT 0x48
+#define FCH_SPI_MMIO_REG4B_RXBYTECOUNT 0x4B
+#define FCH_SPI_MMIO_REG80_FIFO 0x80
+#define FCH_SPI_MMIO_REG50_ADDR32CTRL0 0x50
+#define FCH_SPI_MMIO_REG5C_ADDR32CTRL3 0x5C
+
+volatile UINTN mFchSpiProtect_LOCKED_ReadyToBoot = FALSE;
+volatile UINTN mSpiMmioBase;
+extern CONST BOOLEAN gInSmm;
+volatile BOOLEAN mSupport4ByteAddrFlag = FALSE;
+
+STATIC
+EFI_STATUS
+WaitForSpiDeviceWriteEnabled (
+ IN EFI_SPI_PROTOCOL *This
+ );
+
+/**
+
+ Initialize an SPI protocol instance.
+ The function will assert in debug if FCH SPI has not been initialized
+
+ @param SpiInstance - Pointer to SpiInstance to initialize
+
+ @retval EFI_SUCCESS The protocol instance was properly initialized
+ @retval EFI_UNSUPPORTED The FCH is not supported by this module
+
+**/
+EFI_STATUS
+SpiProtocolConstructor (
+ SPI_INSTANCE *SpiInstance
+ )
+{
+ DEBUG ((DEBUG_INFO, "SpiProtocolConstructor enter!\n"));
+
+ SpiInstance->InitDone = FALSE; // Indicate NOT READY.
+ //
+ // Initialize the SPI protocol instance
+ //
+ SpiInstance->Signature = FCH_SPI_PRIVATE_DATA_SIGNATURE;
+ SpiInstance->Handle = NULL;
+ SpiInstance->SpiProtocol.Init = SpiProtocolInit;
+ SpiInstance->SpiProtocol.Lock = SpiProtocolLock;
+ SpiInstance->SpiProtocol.Execute = SpiProtocolExecute;
+
+ //
+ // Sanity check to ensure FCH SPI initialization has occurred previously.
+ //
+ SpiInstance->SpiBar = (EFI_PHYSICAL_ADDRESS)PciRead32 (
+ PCI_LIB_ADDRESS (
+ 0,
+ 20,
+ 3,
+ 0xA0
+ )
+ )&0x00000000FFFFFFE0;
+ ASSERT (SpiInstance->SpiBar != 0);
+ mSpiMmioBase = SpiInstance->SpiBar;
+
+ DEBUG ((DEBUG_VERBOSE, "SpiInstance->SpiBar = 0x%x\n", SpiInstance->SpiBar));
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Initialize the host controller to execute SPI command.
+
+ @param This Pointer to the EFI_SPI_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Initialization completed.
+ @retval EFI_ACCESS_DENIED The SPI static configuration interface has been locked-down.
+ @retval EFI_INVALID_PARAMETER Bad input parameters.
+ @retval EFI_UNSUPPORTED Can't get Descriptor mode VSCC values
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolInit (
+ IN EFI_SPI_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ SPI_INSTANCE *SpiInstance;
+ UINT8 FlashPartId[3];
+ UINT8 FlashIndex;
+
+ DEBUG ((DEBUG_INFO, "SpiProtocolInit enter!\n"));
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ CopyMem (&SpiInstance->SpiInitTable, &mSpiInitTable[0], sizeof (SPI_INIT_TABLE));
+
+ Status = SpiProtocolExecute (
+ This,
+ SPI_OPCODE_JEDEC_ID_INDEX,
+ 0,
+ TRUE,
+ TRUE,
+ FALSE,
+ (UINTN)0,
+ 3,
+ FlashPartId,
+ EnumSpiRegionDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (FlashIndex = 0; FlashIndex < mNumSpiFlashMax; FlashIndex++) {
+ CopyMem (&SpiInstance->SpiInitTable, &mSpiInitTable[FlashIndex], sizeof (SPI_INIT_TABLE));
+
+ if ((FlashPartId[0] != SpiInstance->SpiInitTable.VendorId) ||
+ (FlashPartId[1] != SpiInstance->SpiInitTable.DeviceId0) ||
+ (FlashPartId[2] != SpiInstance->SpiInitTable.DeviceId1))
+ {
+ DEBUG ((
+ DEBUG_INFO,
+ "SpiProtocolInit() Target SPI Flash Device [VendorID 0x%02x, DeviceID 0x%02x%02x] ",
+ FlashPartId[0],
+ FlashPartId[1],
+ FlashPartId[2]
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ "but Current SPI Flash device [VendorId 0x%02x, DeviceID 0x%02x%02x]!\n",
+ SpiInstance->SpiInitTable.VendorId,
+ SpiInstance->SpiInitTable.DeviceId0,
+ SpiInstance->SpiInitTable.DeviceId1
+ )
+ );
+ } else {
+ DEBUG ((
+ DEBUG_INFO,
+ "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
+ FlashPartId[0],
+ FlashPartId[1],
+ FlashPartId[2]
+ ));
+ break;
+ }
+ }
+
+ if (FlashIndex >= mNumSpiFlashMax) {
+ Status = EFI_UNSUPPORTED;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
+ FlashPartId[0],
+ FlashPartId[1],
+ FlashPartId[2]
+ ));
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ SpiInstance->InitDone = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Lock the SPI Static Configuration Interface.
+ Once locked, the interface can not be changed and can only be clear by system reset.
+
+ @param This Pointer to the EFI_SPI_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Lock operation succeed.
+ @retval EFI_DEVICE_ERROR Device error, operation failed.
+ @retval EFI_ACCESS_DENIED The interface has already been locked.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolLock (
+ IN EFI_SPI_PROTOCOL *This
+ )
+{
+ if (gInSmm) {
+ // Trigger FCH SPI Protect/Lock
+ if (EFI_SUCCESS == FchSpiProtect_Lock (mSpiMmioBase)) {
+ mFchSpiProtect_LOCKED_ReadyToBoot = TRUE;
+ DEBUG ((DEBUG_INFO, "Set FchSpiProtect to LOCK SUCCESS! \n"));
+ } else {
+ DEBUG ((DEBUG_INFO, "Set FchSpiProtect to LOCK FAILED!!! \n"));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Execute SPI commands from the host controller.
+ This function would be called by runtime driver, please do not use any MMIO marco here
+
+ @param This Pointer to the EFI_SPI_PROTOCOL instance.
+ @param OpcodeIndex Index of the command in the OpCode Menu.
+ @param PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+ @param DataCycle TRUE if the SPI cycle contains data
+ @param Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+ @param ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+ @param Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+ Region, this value specifies the offset from the Region Base; for BIOS Region,
+ this value specifies the offset from the start of the BIOS Image. In Non
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+ the flash (in Non Descriptor Mode)
+ @param DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the
+ data transfer into multiple operations. This function ensures each operation does
+ not cross 256 byte flash address boundary.
+ *NOTE: if there is some SPI chip that has a stricter address boundary requirement
+ (e.g., its write page size is < 256 byte), then the caller cannot rely on this
+ function to cut the data transfer at proper address boundaries, and it's the
+ caller's reponsibility to pass in a properly cut DataByteCount parameter.
+ @param Buffer Pointer to caller-allocated buffer containing the dada received or sent during the
+ SPI cycle.
+ @param SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+ @retval EFI_SUCCESS Command succeed.
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.
+ @retval EFI_UNSUPPORTED Command not supported.
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolExecute (
+ IN EFI_SPI_PROTOCOL *This,
+ IN UINT8 OpcodeIndex,
+ IN UINT8 PrefixOpcodeIndex,
+ IN BOOLEAN DataCycle,
+ IN BOOLEAN Atomic,
+ IN BOOLEAN ShiftOut,
+ IN UINTN Address,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer,
+ IN SPI_REGION_TYPE SpiRegionType
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SpiStatus;
+
+ //
+ // Check if the parameters are valid.
+ //
+ if ((OpcodeIndex >= SPI_NUM_OPCODE) || (PrefixOpcodeIndex >= SPI_NUM_PREFIX_OPCODE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (gInSmm) {
+ if (mFchSpiProtect_LOCKED_ReadyToBoot) {
+ FchSpiProtect_UnLock (mSpiMmioBase);
+ DEBUG ((DEBUG_INFO, "FchSpiProtect UnLock!\n"));
+ }
+ }
+
+ SendSpiCmd (
+ This,
+ SPI_OPCODE_READ_S_INDEX,
+ 0,
+ TRUE,
+ FALSE,
+ FALSE,
+ 0,
+ 1,
+ &SpiStatus,
+ EnumSpiRegionAll
+ );
+ if ((SpiStatus & 1) != 0) {
+ if ((OpcodeIndex == SPI_OPCODE_ERASE_INDEX) && (ShiftOut == FALSE)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ DEBUG ((DEBUG_INFO, "SPI Busy, WaitForSpiCycleComplete\n"));
+ WaitForSpiCycleComplete (This);
+ }
+
+ //
+ // Enter 4 bytes address
+ //
+ if (MmioRead8 (mSpiMmioBase+FCH_SPI_MMIO_REG50_ADDR32CTRL0) & BIT0) {
+ DEBUG ((DEBUG_INFO, "Enter 4-Byte address mode\n"));
+ mSupport4ByteAddrFlag = TRUE;
+ Status = SendSpiCmd (
+ This,
+ SPI_COMMAND_Enter_4Byte_Addr_INDEX,
+ SPI_WREN_INDEX,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0,
+ 0,
+ NULL,
+ EnumSpiRegionDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Enter 4-Byte address mode fail\n"));
+ goto Exit;
+ }
+ }
+
+ //
+ // Sends the command to the SPI interface to execute.
+ //
+ Status = SendSpiCmd (
+ This,
+ OpcodeIndex,
+ PrefixOpcodeIndex,
+ DataCycle,
+ Atomic,
+ ShiftOut,
+ Address,
+ DataByteCount,
+ Buffer,
+ SpiRegionType
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Operate SPI Flash fail\n"));
+ goto Exit;
+ }
+
+ //
+ // Exit 32-bit address
+ //
+ if (mSupport4ByteAddrFlag) {
+ mSupport4ByteAddrFlag = FALSE;
+ Status = SendSpiCmd (
+ This,
+ SPI_COMMAND_Exit_4Byte_Addr_INDEX,
+ SPI_WREN_INDEX,
+ FALSE,
+ TRUE,
+ FALSE,
+ 0,
+ 0,
+ NULL,
+ EnumSpiRegionDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Exit 4-Byte address mode fail\n"));
+ goto Exit;
+ }
+ }
+
+Exit:
+ if (gInSmm) {
+ if (mFchSpiProtect_LOCKED_ReadyToBoot) {
+ FchSpiProtect_Lock (mSpiMmioBase);
+ DEBUG ((DEBUG_INFO, "FchSpiProtect Lock again!\n"));
+ }
+ }
+
+ return Status;
+}
+
+/**
+
+ Waits for SPI device not busy
+
+ @param SpiBar The SPI Bar Address
+
+ @retval EFI_SUCCESS Function successfully returned
+ @retval EFI_TIMEOUT timeout, SPI device busy more than 6s.
+
+**/
+EFI_STATUS
+FchSpiControllerNotBusy (
+ UINTN SpiBar
+ )
+{
+ volatile UINT32 SpiStatus;
+ UINT64 WaitTicks;
+ UINT64 WaitCount;
+
+ //
+ // Convert the wait period allowed into to tick count
+ //
+ WaitCount = WAIT_TIME / WAIT_PERIOD;
+ //
+ // Wait until SPI Conroller Not Busy
+ //
+ for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {
+ SpiStatus = MmioRead32 (SpiBar + FCH_SPI_MMIO_REG4C);
+ if (SpiStatus & FCH_SPI_BUSY) {
+ MicroSecondDelay (WAIT_PERIOD);
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_TIMEOUT;
+}
+
+STATIC
+EFI_STATUS
+ResetFifoIndex (
+ SPI_INSTANCE *SpiInstance
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function sends the programmed SPI command to the slave device.
+
+ @param OpcodeIndex Index of the command in the OpCode Menu.
+ @param PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
+ @param DataCycle TRUE if the SPI cycle contains data
+ @param Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
+ @param ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
+ @param Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
+ Region, this value specifies the offset from the Region Base; for BIOS Region,
+ this value specifies the offset from the start of the BIOS Image. In Non
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
+ the flash (in Non Descriptor Mode)
+ @param DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the
+ data transfer into multiple operations. This function ensures each operation does
+ not cross 256 byte flash address boundary.
+ *NOTE: if there is some SPI chip that has a stricter address boundary requirement
+ (e.g., its write page size is < 256 byte), then the caller cannot rely on this
+ function to cut the data transfer at proper address boundaries, and it's the
+ caller's reponsibility to pass in a properly cut DataByteCount parameter.
+ @param Buffer Data received or sent during the SPI cycle.
+ @param SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).
+
+ @retval EFI_SUCCESS SPI command completes successfully.
+ @retval EFI_DEVICE_ERROR Device error, the command aborts abnormally.
+ @retval EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.
+
+**/
+EFI_STATUS
+SendSpiCmd (
+ IN EFI_SPI_PROTOCOL *This,
+ IN UINT8 OpcodeIndex,
+ IN UINT8 PrefixOpcodeIndex,
+ IN BOOLEAN DataCycle,
+ IN BOOLEAN Atomic,
+ IN BOOLEAN ShiftOut,
+ IN UINTN Address,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer,
+ IN SPI_REGION_TYPE SpiRegionType
+ )
+{
+ SPI_INSTANCE *SpiInstance;
+ UINTN SpiBiosSize;
+ UINT32 SpiDataCount;
+ UINT32 TxByteCount;
+ UINT32 RxByteCount;
+ UINTN Addr, Retry;
+ INTN Index, CountIndex;
+ UINTN SpiBar;
+ BOOLEAN WriteFlag;
+ BOOLEAN AddressFlag;
+ UINT8 PrefixOpcode;
+ SPI_OPCODE_MENU_ENTRY OPCodeMenu;
+ UINT8 Dummy;
+ UINT8 AddressByteNum;
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+ SpiBiosSize = SpiInstance->SpiInitTable.BiosSize;
+ OPCodeMenu = SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex];
+ PrefixOpcode = SpiInstance->SpiInitTable.PrefixOpcode[PrefixOpcodeIndex];
+ SpiBar = SpiInstance->SpiBar;
+ Dummy = 0;
+ AddressByteNum = 3;
+
+ AddressFlag = (OPCodeMenu.Type == EnumSpiOpcodeWrite);
+ WriteFlag = AddressFlag;
+ AddressFlag |= (OPCodeMenu.Type == EnumSpiOpcodeRead);
+ WriteFlag |= (OPCodeMenu.Type == EnumSpiOpcodeWriteNoAddr);
+
+ //
+ // Check if the value of opcode register is 0 or the BIOS Size of SpiInitTable is 0
+ //
+ if (SpiBiosSize == 0) {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DataCycle == FALSE) && (DataByteCount > 0)) {
+ DataByteCount = 0;
+ }
+
+ do {
+ SpiDataCount = DataByteCount;
+ TxByteCount = 0;
+ RxByteCount = 0;
+
+ //
+ // Calculate the number of bytes to shift in/out during the SPI data cycle.
+ // Valid settings for the number of bytes duing each data portion of the
+ // FCH SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64
+ //
+ if ((Address & 0xFF) == 0) {
+ SpiDataCount = (DataByteCount > 0x100) ? 0x100 : DataByteCount;
+ } else {
+ SpiDataCount = (DataByteCount > ((~Address + 1) & 0xFF)) ? ((~Address + 1) & 0xFF) : DataByteCount;
+ }
+
+ SpiDataCount = (SpiDataCount > 64) ? 64 : SpiDataCount;
+
+ if (Atomic) {
+ Retry = 0;
+ do {
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG45, PrefixOpcode);
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG48_TXBYTECOUNT, 0);
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG4B_RXBYTECOUNT, 0);
+ MmioOr8 (SpiBar + FCH_SPI_MMIO_REG47, FCH_SPI_EXEC_OPCODE);
+ if (EFI_ERROR (FchSpiControllerNotBusy (SpiBar))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (PrefixOpcodeIndex == SPI_WREN_INDEX) {
+ if (WaitForSpiDeviceWriteEnabled (This) == EFI_SUCCESS) {
+ Retry = 0;
+ } else {
+ Retry++;
+ if (Retry >= 3) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ }
+ } while (Retry);
+ }
+
+ Index = 0;
+ //
+ // Check Address Mode
+ //
+ if (AddressFlag) {
+ ResetFifoIndex (SpiInstance);
+ Addr = (UINTN)Address;
+ // if not SPI_COMMAND_READ_SFDP and 32bit address
+ if ((OPCodeMenu.Code != SPI_COMMAND_READ_SFDP) && mSupport4ByteAddrFlag) {
+ AddressByteNum = 4;
+ Addr = Addr | (UINT32)((MmioRead8 (SpiBar+FCH_SPI_MMIO_REG5C_ADDR32CTRL3) & BIT0) << 24);
+ }
+
+ for (CountIndex = 0; CountIndex < AddressByteNum; CountIndex++) {
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG80_FIFO + Index, (UINT8)((Addr >> (AddressByteNum - CountIndex - 1) * 8) & 0xff));
+ Index++;
+ }
+
+ TxByteCount += AddressByteNum;
+ }
+
+ if ((OPCodeMenu.Code == SPI_COMMAND_READ_SFDP) || (OPCodeMenu.Code == SPI_COMMAND_RPMC_OP2)) {
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG80_FIFO + Index, Dummy);
+ Index++;
+ TxByteCount += 1;
+ }
+
+ if (DataCycle) {
+ //
+ // Check Read/Write Mode
+ //
+ if (WriteFlag) {
+ TxByteCount += SpiDataCount;
+ for (CountIndex = 0; CountIndex < (INTN)(SpiDataCount); CountIndex++) {
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG80_FIFO + Index, Buffer[CountIndex]);
+ Index++;
+ }
+ } else {
+ RxByteCount = SpiDataCount;
+ }
+ }
+
+ // Set SPI Command
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG45, OPCodeMenu.Code);
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG48_TXBYTECOUNT, (UINT8)TxByteCount);
+ MmioWrite8 (SpiBar + FCH_SPI_MMIO_REG4B_RXBYTECOUNT, (UINT8)RxByteCount);
+ MmioOr8 (SpiBar + FCH_SPI_MMIO_REG47, FCH_SPI_EXEC_OPCODE);
+ if (EFI_ERROR (FchSpiControllerNotBusy (SpiBar))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ShiftOut) {
+ Retry = 0;
+ do {
+ if (WaitForSpiCycleComplete (This)) {
+ Retry = 0;
+ } else {
+ Retry++;
+ if (Retry >= FCH_SPI_RETRY_TIMES) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ } while (Retry);
+ }
+
+ if (DataCycle && RxByteCount) {
+ //
+ // Reset Fifo Ptr
+ //
+ ResetFifoIndex (SpiInstance);
+
+ for (CountIndex = 0; CountIndex < (INTN)(SpiDataCount); CountIndex++) {
+ Buffer[CountIndex] = MmioRead8 (SpiBar + FCH_SPI_MMIO_REG80_FIFO + Index);
+ Index++;
+ }
+ }
+
+ //
+ // If shifts data in, get data from the SPI data buffer.
+ //
+ Address += SpiDataCount;
+ Buffer += SpiDataCount;
+ DataByteCount -= SpiDataCount;
+ } while (DataByteCount > 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Wait execution cycle to complete on the SPI interface. Check both Hardware
+ and Software Sequencing status registers
+
+ @param This The SPI protocol instance
+
+ @retval TRUE SPI cycle completed on the interface.
+ @retval FALSE Time out while waiting the SPI cycle to complete.
+ It's not safe to program the next command on the SPI interface.
+
+**/
+BOOLEAN
+WaitForSpiCycleComplete (
+ IN EFI_SPI_PROTOCOL *This
+ )
+{
+ UINT8 SpiStatus;
+ UINT64 WaitTicks;
+ UINT64 WaitCount;
+
+ //
+ // Convert the wait period allowed into to tick count
+ //
+ WaitCount = WAIT_TIME / WAIT_PERIOD;
+
+ //
+ // Wait for the SPI cycle to complete.
+ //
+ for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {
+ //
+ // Execute Read Status Command
+ //
+ SendSpiCmd (
+ This,
+ SPI_OPCODE_READ_S_INDEX,
+ 0,
+ TRUE,
+ FALSE,
+ FALSE,
+ 0,
+ 1,
+ &SpiStatus,
+ EnumSpiRegionAll
+ );
+
+ if ((SpiStatus & 1) != 0) {
+ MicroSecondDelay (WAIT_PERIOD);
+ } else {
+ return TRUE;
+ }
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "WaitForSpiCycleComplete() Timeout\n"));
+ return FALSE;
+}
+
+/**
+
+ Wait execution cycle to complete on the SPI interface. Check both Hardware
+ and Software Sequencing status registers
+
+ @param This The SPI protocol instance
+
+ @retval EFI_SUCCESS SPI cycle completed on the interface.
+ @retval EFI_TIMEOUT Time out while waiting the SPI cycle to complete.
+ It's not safe to program the next command on the SPI interface.
+
+**/
+STATIC
+EFI_STATUS
+WaitForSpiDeviceWriteEnabled (
+ IN EFI_SPI_PROTOCOL *This
+ )
+{
+ UINT8 SpiStatus;
+ UINT64 WaitTicks;
+ UINT64 WaitCount;
+
+ DEBUG ((DEBUG_VERBOSE, "WaitForSpiDeviceWriteEnabled() Enter!\n"));
+
+ //
+ // Convert the wait period allowed into to tick count
+ //
+ WaitCount = WAIT_TIME / WAIT_PERIOD;
+
+ //
+ // Wait for the SPI cycle to complete.
+ //
+ for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {
+ //
+ // Execute Read Status Command
+ //
+ SendSpiCmd (
+ This,
+ SPI_OPCODE_READ_S_INDEX,
+ 0,
+ TRUE,
+ FALSE,
+ FALSE,
+ 0,
+ 1,
+ &SpiStatus,
+ EnumSpiRegionAll
+ );
+
+ if ((SpiStatus & 2) == 0) {
+ MicroSecondDelay (WAIT_PERIOD);
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "WaitForSpiCycleComplete() Exit\n"));
+ return EFI_SUCCESS;
+ }
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "WaitForSpiDeviceWriteEnabled() Exit Timeout !\n"));
+ return EFI_TIMEOUT;
+}
+
+#ifdef _MSC_VER
+ #pragma optimize( "", on )
+#endif
+#ifdef __GNUC__
+ #ifndef __clang__
+ #pragma GCC pop_options
+ #endif
+#endif
diff --git a/Platform/AMD/VanGoghBoard/Universal/FchSpi/SpiInfo.h b/Platform/AMD/VanGoghBoard/Universal/FchSpi/SpiInfo.h
new file mode 100644
index 0000000000..28b67ea991
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/Universal/FchSpi/SpiInfo.h
@@ -0,0 +1,24 @@
+/** @file
+ Implements SpiInfo.h
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SPI_INFO_H_
+#define SPI_INFO_H_
+
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/Spi.h>
+
+#ifdef FCH_SPI_EXEC_OPCODE
+ #undef FCH_SPI_EXEC_OPCODE
+#define FCH_SPI_EXEC_OPCODE BIT7
+#endif
+
+#define FCH_SPI_MMIO_REG45 0x45 // OpCode Access
+#define FCH_SPI_MMIO_REG47 0x47 // Execute Access
+#define FCH_SPI_MMIO_REG4C 0x4C // SPI Status
+
+#endif
--
2.31.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#114600): https://edk2.groups.io/g/devel/message/114600
Mute This Topic: https://groups.io/mt/103975480/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2024 Red Hat, Inc.