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 FlashUpdate module for Chachani platform flash IC.
It provides mEfiSpiFlashUpdateProtocol for other module to access flash.
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>
---
.../FlashUpdate/FlashUpdateCommon.h | 143 +++++
.../FlashUpdate/FlashUpdateSmm.c | 512 ++++++++++++++++++
.../FlashUpdate/FlashUpdateSmm.h | 123 +++++
.../FlashUpdate/FlashUpdateSmm.inf | 59 ++
.../FlashUpdate/FlashUpdateSmmRuntimeDxe.c | 407 ++++++++++++++
.../FlashUpdate/FlashUpdateSmmRuntimeDxe.inf | 48 ++
.../VanGoghCommonPkg/FlashUpdate/PcRtc.h | 375 +++++++++++++
7 files changed, 1667 insertions(+)
create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateCommon.h
create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.c
create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.h
create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.inf
create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmmRuntimeDxe.c
create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmmRuntimeDxe.inf
create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/PcRtc.h
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateCommon.h b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateCommon.h
new file mode 100644
index 0000000000..77967f1f26
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateCommon.h
@@ -0,0 +1,143 @@
+/** @file
+ Implements AMD FlashUpdateCommon.h
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef FLASH_UPDATE_COMMON_H_
+#define FLASH_UPDATE_COMMON_H_
+
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/SpiFlashUpdate.h>
+#include <Protocol/SmmCommunication.h>
+
+#include <Uefi/UefiAcpiDataTable.h>
+#include <Uefi/UefiSpec.h>
+
+#include <Guid/EventGroup.h>
+
+#define SPI_SMM_COMM_ID_GET_FLASH_SIZE_BLOCK_SIZE 0x0 // ID for get flash size and block size
+#define SPI_SMM_COMM_ID_READ_FLASH 0x1 // ID for Read Flash
+#define SPI_SMM_COMM_ID_WRITE_FALSH 0x2 // ID for Write Flash
+#define SPI_SMM_COMM_ID_ERASE_FALSH 0x3 // ID for Erase Flash
+
+//
+// SMM communication common buffer
+//
+typedef struct _FLASH_UPDATE_SMM_COMMUNICATION_CMN {
+ UINT32 id; // Function ID of smm communication buffer
+} FLASH_UPDATE_SMM_COMMUNICATION_CMN;
+
+#pragma pack(1)
+
+//
+// SMM communication common buffer
+//
+typedef struct _SMM_COMM_RWE_FLASH {
+ UINT32 id; // ID of smm communication buffer
+ UINTN FlashAddress; // Flash devicd physical flash address
+ UINTN NumBytes; // Number in byte
+ EFI_STATUS ReturnStatus; // Return status
+ UINT8 Buffer[1]; // Buffer start
+} SMM_COMM_RWE_FLASH;
+
+//
+// SMM communication common buffer
+//
+typedef struct _SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE {
+ UINT32 id; // ID of smm communication buffer
+ UINTN FlashSize; // Flash size
+ UINTN BlockSize; // Block size of flash device
+ EFI_STATUS ReturnStatus; // Return status
+} SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE;
+
+#pragma pack()
+
+#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))
+#define SMM_COMM_RWE_FLASH_SIZE (OFFSET_OF (SMM_COMM_RWE_FLASH, Buffer))
+
+/**
+ Read data from flash device.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte.
+ @param[out] Buffer Buffer contain the read data.
+
+ @retval EFI_SUCCESS Read successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+SfuProtocolFlashFdRead (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes,
+ OUT VOID *Buffer
+ );
+
+/**
+ Erase flash region according to input in a block size.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte, a block size in flash device.
+
+ @retval EFI_SUCCESS Erase successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+SfuProtocolFlashFdErase (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes
+ );
+
+/**
+ Write data to flash device.
+
+ Write Buffer(FlashAddress|NumBytes) to flash device.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte.
+ @param[in] Buffer Buffer contain the write data.
+
+ @retval EFI_SUCCESS Write successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+SfuProtocolFlashFdWrite (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Get flash device size and flash block size.
+
+ @param[out] FlashSize Pointer to the size of flash device.
+ @param[out] BlockSize Pointer to the size of block in flash device.
+
+ @retval EFI_SUCCESS Get successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+SfuProtocolGetFlashSizeBlockSize (
+ OUT UINTN *FlashSize,
+ OUT UINTN *BlockSize
+ );
+
+#endif // _FLASH_UPDATE_COMMON_H_
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.c b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.c
new file mode 100644
index 0000000000..42991295d7
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.c
@@ -0,0 +1,512 @@
+/** @file
+ Implements AMD FlashUpdateSmm.c
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FlashUpdateSmm.h"
+
+#define PM1_EN_HIGH_BYTE 0x03
+#define RTC_EVENT_ENABLE 0x04
+#define ACPIMMIO16(x) (*(volatile UINT16*)(UINTN)(x))
+#define ACPI_MMIO_BASE 0xFED80000ul
+#define ACPI_PM1_EVT_BLK 0x60
+#define ACPI_PM1_CNT_BLK 0x62
+#define PMIO_BASE 0x300 // DWORD
+#define SUS_S3 0x0C00U // S3
+#define SUS_S5 0x1400U // S5
+#define SLP_TYPE 0x1C00U // MASK
+#define SLP_EN 0x2000U // BIT13
+
+EFI_SPI_PROTOCOL *mSmmSpiProtocol = NULL;
+UINTN mFlashAreaBaseAddress;
+UINTN mFlashSize;
+UINTN mBlockSize;
+
+EFI_SMM_SPI_FLASH_UPDATE_PROTOCOL mEfiSmmSpiFlashUpdateProtocol = {
+ FlashUpdateServiceFlashFdRead,
+ FlashUpdateServiceFlashFdErase,
+ FlashUpdateServiceFlashFdWrite,
+ FlashUpdateServiceGetFlashSizeBlockSize,
+};
+
+/**
+ Read data from flash device.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte.
+ @param[out] Buffer Buffer contain the read data.
+
+ @retval EFI_SUCCESS Read successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceFlashFdRead (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes,
+ OUT VOID *Buffer
+ )
+{
+ if ((FlashAddress >= mFlashSize) || (NumBytes == 0) || (NumBytes > mFlashSize) ||
+ (Buffer == NULL) || (FlashAddress + NumBytes > mFlashSize))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (Buffer, (UINT8 *)(FlashAddress + mFlashAreaBaseAddress), NumBytes);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Erase flash region according to input in a block size.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte, a block size in flash device.
+
+ @retval EFI_SUCCESS Erase successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceFlashFdErase (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes
+ )
+{
+ EFI_STATUS Status;
+
+ if ((FlashAddress >= mFlashSize) || (NumBytes == 0) || (NumBytes > mFlashSize) ||
+ (FlashAddress + NumBytes > mFlashSize))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mSmmSpiProtocol == NULL) {
+ DEBUG ((DEBUG_ERROR, "mSmmSpiProtocol = NULL\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ Status = mSmmSpiProtocol->Execute (
+ mSmmSpiProtocol,
+ SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
+ 0, // PrefixOpcodeIndex
+ FALSE, // DataCycle
+ TRUE, // Atomic
+ TRUE, // ShiftOut
+ FlashAddress, // Address
+ 0, // Data Number
+ NULL, // Buffer
+ EnumSpiRegionBios // SpiRegionType
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "!!!ERROR: Erase flash %r\n", Status));
+ return Status;
+ }
+
+ AsmWbinvd ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write data to flash device.
+
+ Write Buffer(FlashAddress|NumBytes) to flash device.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte.
+ @param[in] Buffer Buffer contain the write data.
+
+ @retval EFI_SUCCESS Write successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceFlashFdWrite (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ if ((FlashAddress >= mFlashSize) || (NumBytes == 0) || (NumBytes > mFlashSize) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (FlashAddress + NumBytes > mFlashSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mSmmSpiProtocol == NULL) {
+ DEBUG ((DEBUG_ERROR, "mSmmSpiProtocol = NULL\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ Status = mSmmSpiProtocol->Execute (
+ mSmmSpiProtocol,
+ SPI_OPCODE_WRITE_INDEX, // OpcodeIndex
+ 0, // PrefixOpcodeIndex
+ TRUE, // DataCycle
+ TRUE, // Atomic
+ TRUE, // ShiftOut
+ FlashAddress, // Address
+ (UINT32)NumBytes, // Data Number
+ Buffer, // Buffer
+ EnumSpiRegionBios // Spi Region Type
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "!!!ERROR: Write flash %r\n", Status));
+ return Status;
+ }
+
+ AsmWbinvd ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get flash device size and flash block size.
+
+ @param[out] FlashSize Pointer to the size of flash device.
+ @param[out] BlockSize Pointer to the size of block in flash device.
+
+ @retval EFI_SUCCESS Get successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceGetFlashSizeBlockSize (
+ OUT UINTN *FlashSize,
+ OUT UINTN *BlockSize
+ )
+{
+ if ((FlashSize == 0) || (BlockSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *FlashSize = mFlashSize;
+ *BlockSize = mBlockSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for the update flash routines.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ FLASH_UPDATE_SMM_COMMUNICATION_CMN *Buffer;
+ SMM_COMM_RWE_FLASH *RweBuffer;
+ SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE *GetFlashSizeBlockSizeBuffer;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {
+ DEBUG ((DEBUG_ERROR, "!!!ERROR: FlashUpdateServiceHandler: Invalid parameter!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, *CommBufferSize)) {
+ DEBUG ((DEBUG_ERROR, "!!!ERROR: FlashUpdateServiceHandler: SMM communication buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ GetFlashSizeBlockSizeBuffer = NULL;
+ Buffer = (FLASH_UPDATE_SMM_COMMUNICATION_CMN *)CommBuffer;
+ RweBuffer = (SMM_COMM_RWE_FLASH *)CommBuffer;
+
+ switch (Buffer->id) {
+ case SPI_SMM_COMM_ID_GET_FLASH_SIZE_BLOCK_SIZE:
+ GetFlashSizeBlockSizeBuffer = (SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE *)CommBuffer;
+ GetFlashSizeBlockSizeBuffer->ReturnStatus = EFI_SUCCESS;
+ GetFlashSizeBlockSizeBuffer->FlashSize = mFlashSize;
+ GetFlashSizeBlockSizeBuffer->BlockSize = mBlockSize;
+ break;
+
+ case SPI_SMM_COMM_ID_READ_FLASH:
+ Status = mEfiSmmSpiFlashUpdateProtocol.Read (
+ RweBuffer->FlashAddress,
+ RweBuffer->NumBytes,
+ RweBuffer->Buffer
+ );
+ RweBuffer->ReturnStatus = Status;
+ break;
+
+ case SPI_SMM_COMM_ID_WRITE_FALSH:
+ Status = mEfiSmmSpiFlashUpdateProtocol.Write (
+ RweBuffer->FlashAddress,
+ RweBuffer->NumBytes,
+ RweBuffer->Buffer
+ );
+ RweBuffer->ReturnStatus = Status;
+ break;
+
+ case SPI_SMM_COMM_ID_ERASE_FALSH:
+ Status = mEfiSmmSpiFlashUpdateProtocol.Erase (
+ RweBuffer->FlashAddress,
+ RweBuffer->NumBytes
+ );
+ RweBuffer->ReturnStatus = Status;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read RTC through its registers using IO access.
+
+ @param Address Address offset of RTC. It is recommended to use
+ macros such as RTC_ADDRESS_SECONDS.
+ @param Data The content you want to write into RTC.
+
+**/
+STATIC
+UINT8
+IoRtcRead (
+ IN UINT8 Address
+ )
+{
+ IoWrite8 (0x70, Address);
+ return IoRead8 (0x71);
+}
+
+/**
+ Write RTC through its registers using IO access.
+
+ @param Address Address offset of RTC. It is recommended to use
+ macros such as RTC_ADDRESS_SECONDS.
+ @param Data The content you want to write into RTC.
+
+**/
+STATIC
+VOID
+IoRtcWrite (
+ IN UINT8 Address,
+ IN UINT8 Data
+ )
+{
+ IoWrite8 (0x70, Address);
+ IoWrite8 (0x71, Data);
+}
+
+/**
+ Write RTC through its registers using IO access.
+
+ @param Address Address offset of RTC. It is recommended to use
+ macros such as RTC_ADDRESS_SECONDS.
+ @param Data The content you want to write into RTC.
+
+**/
+VOID
+EnableRtcWakeup (
+ IN UINT16 AcpiBaseAddr,
+ IN UINT8 WakeAfter
+ )
+{
+ volatile RTC_REGISTER_B RtcRegisterB;
+
+ RtcRegisterB.Data = IoRtcRead (RTC_ADDRESS_REGISTER_B);
+ UINT8 CurrentSecond = IoRtcRead (RTC_ADDRESS_SECONDS);
+ UINT8 CurrentMinute = IoRtcRead (RTC_ADDRESS_MINUTES);
+ UINT8 CurrentHour = IoRtcRead (RTC_ADDRESS_HOURS);
+
+ if (!(RtcRegisterB.Bits.Dm)) {
+ CurrentSecond = BcdToDecimal8 (CurrentSecond);
+ CurrentMinute = BcdToDecimal8 (CurrentMinute);
+ CurrentHour = BcdToDecimal8 (CurrentHour);
+ }
+
+ CurrentSecond += WakeAfter;
+ CurrentMinute += CurrentSecond/60;
+ CurrentHour += CurrentMinute/60;
+
+ CurrentSecond %= 60;
+ CurrentMinute %= 60;
+ CurrentHour %= 24;
+
+ if (!(RtcRegisterB.Bits.Dm)) {
+ CurrentSecond = DecimalToBcd8 (CurrentSecond);
+ CurrentMinute = DecimalToBcd8 (CurrentMinute);
+ CurrentHour = DecimalToBcd8 (CurrentHour);
+ }
+
+ IoRtcWrite (RTC_ADDRESS_SECONDS_ALARM, CurrentSecond);
+ IoRtcWrite (RTC_ADDRESS_MINUTES_ALARM, CurrentMinute);
+ IoRtcWrite (RTC_ADDRESS_HOURS_ALARM, CurrentHour);
+ IoRtcRead (RTC_ADDRESS_REGISTER_C);
+
+ RtcRegisterB.Data = IoRtcRead (RTC_ADDRESS_REGISTER_B);
+ RtcRegisterB.Bits.Aie = 1;
+ IoRtcWrite (RTC_ADDRESS_REGISTER_B, RtcRegisterB.Data);
+
+ UINT8 RtcSts = IoRead8 (AcpiBaseAddr);
+
+ RtcSts |= 0x400;
+ IoWrite8 (AcpiBaseAddr, RtcSts);
+
+ UINT8 RtcEn = IoRead8 (AcpiBaseAddr + PM1_EN_HIGH_BYTE);
+
+ RtcEn |= RTC_EVENT_ENABLE;
+ IoWrite8 (AcpiBaseAddr + PM1_EN_HIGH_BYTE, RtcEn);
+ return;
+}
+
+/**
+ Set Capsule S3 Flag SMI Handler.
+
+ This SMI handler provides services for marking capsule update.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+
+**/
+EFI_STATUS
+EFIAPI
+SetCapsuleS3FlagHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ AMD_CAPSULE_SMM_HOOK_PROTOCOL *AmdCapsuleSmmHookProtocol;
+
+ AmdCapsuleSmmHookProtocol = NULL;
+ Status = gSmst->SmmLocateProtocol (
+ &gAmdCapsuleSmmHookProtocolGuid,
+ NULL,
+ (VOID **)&AmdCapsuleSmmHookProtocol
+ );
+ if (!EFI_ERROR (Status)) {
+ AmdCapsuleSmmHookProtocol->Hook (0);
+ }
+
+ DEBUG ((DEBUG_INFO, "Entering S3 sleep.\n"));
+ // Transform system into S3 sleep state
+ EnableRtcWakeup (ACPIMMIO16 (ACPI_MMIO_BASE + PMIO_BASE + ACPI_PM1_EVT_BLK), 2);
+ UINTN AcpiPm1CntBase = ACPIMMIO16 (ACPI_MMIO_BASE + PMIO_BASE + ACPI_PM1_CNT_BLK);
+ UINT16 PmCntl = IoRead16 (AcpiPm1CntBase);
+
+ PmCntl = (PmCntl & ~SLP_TYPE) | SUS_S3 | SLP_EN;
+ IoWrite16 (AcpiPm1CntBase, PmCntl);
+ return Status;
+}
+
+/**
+ Smm Flash Update Driver main entry point.
+
+ Install the Smm Flash Update Protocol on a new handle. Register SMM flash update
+ SMI handler. Locate SmmSpiProtocol and init the flash device size and block size.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Variable service successfully initialized.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE FlashUpdateRegisterHandle;
+ EFI_HANDLE FlashUpdateInstallHandle;
+ SPI_INSTANCE *SpiInstance;
+ EFI_HANDLE SetCapsuleS3FlagHandle;
+
+ SpiInstance = NULL;
+
+ //
+ // Install the Smm Flash Update Protocol on a new handle
+ //
+ FlashUpdateInstallHandle = NULL;
+ Status = gSmst->SmmInstallProtocolInterface (
+ &FlashUpdateInstallHandle,
+ &gEfiSmmSpiFlashUpdateProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mEfiSmmSpiFlashUpdateProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register SMM flash update SMI handler
+ //
+ FlashUpdateRegisterHandle = NULL;
+ Status = gSmst->SmiHandlerRegister (
+ FlashUpdateServiceHandler,
+ &gEfiSmmSpiFlashUpdateProtocolGuid,
+ &FlashUpdateRegisterHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ SetCapsuleS3FlagHandle = NULL;
+ Status = gSmst->SmiHandlerRegister (
+ SetCapsuleS3FlagHandler,
+ &gAmdSetCapsuleS3FlagGuid,
+ &SetCapsuleS3FlagHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmSpiProtocolGuid,
+ NULL,
+ (VOID **)&mSmmSpiProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (mSmmSpiProtocol);
+ mFlashSize = SpiInstance->SpiInitTable.BiosSize;
+ mFlashAreaBaseAddress = FixedPcdGet32 (PcdFlashAreaBaseAddress);
+ mBlockSize = SpiInstance->SpiInitTable.OpcodeMenu[SPI_OPCODE_ERASE_INDEX].Operation;
+
+ return Status;
+}
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.h b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.h
new file mode 100644
index 0000000000..6019e635c5
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.h
@@ -0,0 +1,123 @@
+/** @file
+ Implements AMD FlashUpdateSmm.h
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef FLASH_UPDATE_SMM_H_
+#define FLASH_UPDATE_SMM_H_
+
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SmmMemLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/SpiFlashUpdate.h>
+#include <Protocol/SpiCommon.h>
+
+#include <Uefi/UefiBaseType.h>
+
+#include "FlashUpdateCommon.h"
+#include "PcRtc.h"
+
+/**
+ Read data from flash device.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte.
+ @param[out] Buffer Buffer contain the read data.
+
+ @retval EFI_SUCCESS Read successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceFlashFdRead (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes,
+ OUT VOID *Buffer
+ );
+
+/**
+ Erase flash region according to input in a block size.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte, a block size in flash device.
+
+ @retval EFI_SUCCESS Erase successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceFlashFdErase (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes
+ );
+
+/**
+ Write data to flash device.
+
+ Write Buffer(FlashAddress|NumBytes) to flash device.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte.
+ @param[in] Buffer Buffer contain the write data.
+
+ @retval EFI_SUCCESS Write successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceFlashFdWrite (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Get flash device size and flash block size.
+
+ @param[out] FlashSize Pointer to the size of flash device.
+ @param[out] BlockSize Pointer to the size of block in flash device.
+
+ @retval EFI_SUCCESS Get successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateServiceGetFlashSizeBlockSize (
+ OUT UINTN *FlashSize,
+ OUT UINTN *BlockSize
+ );
+
+/**
+ Set AMD Capsule SMM Flag hook
+
+ @param[out] Reserved Not used; Must be 0.
+
+ @retval EFI_SUCCESS Set successfully.
+
+**/
+
+typedef EFI_STATUS (*AMD_CAPSULE_SMM_HOOK) (
+ IN UINT32 Reserved
+ );
+
+typedef struct _AMD_CAPSULE_SMM_HOOK_PROTOCOL {
+ AMD_CAPSULE_SMM_HOOK Hook;
+} AMD_CAPSULE_SMM_HOOK_PROTOCOL;
+
+extern EFI_GUID gAmdSetCapsuleS3FlagGuid;
+extern EFI_GUID gAmdCapsuleSmmHookProtocolGuid;
+
+#endif // _FLASH_UPDATE_SMM_H_
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.inf b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.inf
new file mode 100644
index 0000000000..f39e814512
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmm.inf
@@ -0,0 +1,59 @@
+## @file
+# Flash UpdateSmm
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FlashUpdateSmm
+ FILE_GUID = 42859181-A407-4CF2-A9A7-5848FEAA8958
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = FlashUpdateServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ FlashUpdateSmm.c
+ FlashUpdateSmm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VanGoghCommonPkg/AmdCommonPkg.dec
+ AgesaPublic/AgesaPublic.dec
+ ChachaniBoardPkg/Project.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ DebugLib
+ BaseLib
+ MemoryAllocationLib
+ SmmMemLib
+ PcdLib
+ IoLib
+
+[Protocols]
+ gEfiSmmSpiProtocolGuid ## CONSUME
+
+ gEfiSmmSpiFlashUpdateProtocolGuid ## PRODUCE
+
+ gAmdCapsuleSmmHookProtocolGuid ## CONSUME
+
+[Guids]
+ gAmdSetCapsuleS3FlagGuid
+
+[Pcd]
+ gPlatformPkgTokenSpaceGuid.PcdFlashAreaBaseAddress
+
+[Depex]
+ gEfiSmmSpiProtocolGuid
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmmRuntimeDxe.c b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmmRuntimeDxe.c
new file mode 100644
index 0000000000..80e60b30fd
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmmRuntimeDxe.c
@@ -0,0 +1,407 @@
+/*****************************************************************************
+ *
+ * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ ******************************************************************************
+ */
+
+#include "FlashUpdateCommon.h"
+
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+UINTN *mFlashSize = NULL;
+UINTN *mBlockSize = NULL;
+EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
+UINT8 *mRweBuffer = NULL;
+UINTN mRweBufferSize;
+
+EFI_SPI_FLASH_UPDATE_PROTOCOL mEfiSpiFlashUpdateProtocol = {
+ SfuProtocolFlashFdRead,
+ SfuProtocolFlashFdErase,
+ SfuProtocolFlashFdWrite,
+ SfuProtocolGetFlashSizeBlockSize,
+};
+
+/**
+ Initialize the communicate buffer.
+
+ The communicate buffer is: SMM_COMMUNICATE_HEADER + SMM_COMM_RWE_FLASH + Payload.
+ The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_COMM_RWE_FLASH_SIZE + FlashSize.
+
+ @param[out] DataPtr Points to the data in the communicate buffer.
+
+**/
+VOID
+EFIAPI
+InitCommunicateBuffer (
+ OUT VOID **DataPtr
+ )
+{
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)mRweBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmSpiFlashUpdateProtocolGuid);
+ SmmCommunicateHeader->MessageLength = SMM_COMM_RWE_FLASH_SIZE;
+
+ *DataPtr = (SMM_COMM_RWE_FLASH *)((EFI_SMM_COMMUNICATE_HEADER *)mRweBuffer)->Data;
+}
+
+/**
+ Read data from flash device.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte.
+ @param[out] Buffer Buffer contain the read data.
+
+ @retval EFI_SUCCESS Read successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+SfuProtocolFlashFdRead (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SMM_COMM_RWE_FLASH *RweFlashBuffer;
+
+ if ((FlashAddress >= *mFlashSize) || (NumBytes == 0) || (Buffer == NULL) ||
+ (FlashAddress + NumBytes > *mFlashSize))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RweFlashBuffer = NULL;
+
+ InitCommunicateBuffer ((VOID **)&RweFlashBuffer);
+
+ if (RweFlashBuffer == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ RweFlashBuffer->id = SPI_SMM_COMM_ID_READ_FLASH;
+ RweFlashBuffer->FlashAddress = FlashAddress;
+ RweFlashBuffer->NumBytes = NumBytes;
+ CopyMem (RweFlashBuffer->Buffer, Buffer, NumBytes);
+
+ //
+ // Send data to SMM.
+ //
+ Status = mSmmCommunication->Communicate (
+ mSmmCommunication,
+ mRweBuffer,
+ &mRweBufferSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get data from SMM
+ //
+ if (!EFI_ERROR (RweFlashBuffer->ReturnStatus)) {
+ CopyMem (Buffer, RweFlashBuffer->Buffer, NumBytes);
+ }
+
+ return RweFlashBuffer->ReturnStatus;
+}
+
+/**
+ Erase flash region according to input in a block size.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte, a block size in flash device.
+
+ @retval EFI_SUCCESS Erase successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+SfuProtocolFlashFdErase (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes
+ )
+{
+ EFI_STATUS Status;
+ SMM_COMM_RWE_FLASH *RweFlashBuffer;
+
+ if ((FlashAddress >= *mFlashSize) || (NumBytes == 0) || (NumBytes > *mFlashSize) ||
+ (FlashAddress + NumBytes > *mFlashSize))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RweFlashBuffer = NULL;
+
+ InitCommunicateBuffer ((VOID **)&RweFlashBuffer);
+
+ if (RweFlashBuffer == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ RweFlashBuffer->id = SPI_SMM_COMM_ID_ERASE_FALSH;
+ RweFlashBuffer->FlashAddress = FlashAddress;
+ RweFlashBuffer->NumBytes = NumBytes;
+
+ //
+ // Send data to SMM.
+ //
+ Status = mSmmCommunication->Communicate (
+ mSmmCommunication,
+ mRweBuffer,
+ &mRweBufferSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return RweFlashBuffer->ReturnStatus;
+}
+
+/**
+ Write data to flash device.
+
+ Write Buffer(FlashAddress|NumBytes) to flash device.
+
+ @param[in] FlashAddress Physical flash address.
+ @param[in] NumBytes Number in Byte.
+ @param[in] Buffer Buffer contain the write data.
+
+ @retval EFI_SUCCESS Write successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+SfuProtocolFlashFdWrite (
+ IN UINTN FlashAddress,
+ IN UINTN NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SMM_COMM_RWE_FLASH *RweFlashBuffer;
+
+ if ((FlashAddress >= *mFlashSize) || (NumBytes == 0) || (NumBytes > *mFlashSize) || (Buffer == NULL) ||
+ (FlashAddress + NumBytes > *mFlashSize))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RweFlashBuffer = NULL;
+
+ InitCommunicateBuffer ((VOID **)&RweFlashBuffer);
+
+ if (RweFlashBuffer == NULL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ RweFlashBuffer->id = SPI_SMM_COMM_ID_WRITE_FALSH;
+ RweFlashBuffer->FlashAddress = FlashAddress;
+ RweFlashBuffer->NumBytes = NumBytes;
+ CopyMem (RweFlashBuffer->Buffer, Buffer, NumBytes);
+
+ //
+ // Send data to SMM.
+ //
+ Status = mSmmCommunication->Communicate (
+ mSmmCommunication,
+ mRweBuffer,
+ &mRweBufferSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return RweFlashBuffer->ReturnStatus;
+}
+
+/**
+ Get flash device size and flash block size.
+
+ @param[out] FlashSize Pointer to the size of flash device.
+ @param[out] BlockSize Pointer to the size of block in flash device.
+
+ @retval EFI_SUCCESS Get successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+SfuProtocolGetFlashSizeBlockSize (
+ OUT UINTN *FlashSize,
+ OUT UINTN *BlockSize
+ )
+{
+ if ((FlashSize == NULL) || (BlockSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *FlashSize = *mFlashSize;
+ *BlockSize = *mBlockSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+SpiFlashAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **)&mRweBuffer);
+ EfiConvertPointer (0x0, (VOID **)&mSmmCommunication);
+ EfiConvertPointer (0x0, (VOID **)&mBlockSize);
+ EfiConvertPointer (0x0, (VOID **)&mFlashSize);
+}
+
+/**
+ Get flash device size and flash block size from SMM.
+
+ @param[in] VOID
+
+ @retval EFI_SUCCESS Get successfully.
+ @retval others Some error occurs when executing this routine.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFlashSizeBlockSize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CommSize;
+ UINT8 *CommBuffer;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE *SmmGetFlashSizeBlockSize;
+
+ CommBuffer = NULL;
+ SmmCommunicateHeader = NULL;
+ SmmGetFlashSizeBlockSize = NULL;
+
+ //
+ // Init the communicate buffer. The buffer size is:
+ // SMM_COMMUNICATE_HEADER_SIZE + sizeof (SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE)
+ //
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + sizeof (SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE);
+ CommBuffer = AllocateRuntimePool (CommSize);
+ if (CommBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmSpiFlashUpdateProtocolGuid);
+ SmmCommunicateHeader->MessageLength = sizeof (SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE);
+
+ SmmGetFlashSizeBlockSize = (SMM_COMM_GET_FLASH_SIZE_BLOCK_SIZE *)SmmCommunicateHeader->Data;
+ SmmGetFlashSizeBlockSize->id = SPI_SMM_COMM_ID_GET_FLASH_SIZE_BLOCK_SIZE;
+
+ //
+ // Send data to SMM.
+ //
+ Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SmmGetFlashSizeBlockSize->ReturnStatus;
+ if (EFI_ERROR (Status)) {
+ if (CommBuffer != NULL) {
+ FreePool (CommBuffer);
+ }
+
+ return Status;
+ }
+
+ //
+ // Get data from SMM.
+ //
+ *mFlashSize = SmmGetFlashSizeBlockSize->FlashSize;
+ *mBlockSize = SmmGetFlashSizeBlockSize->BlockSize;
+
+ if (CommBuffer != NULL) {
+ FreePool (CommBuffer);
+ }
+
+ return Status;
+}
+
+/**
+ Update Flash Driver main entry point.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Update Flash service successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashUpdateSmmRuntimeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Status = gBS->LocateProtocol (
+ &gEfiSmmCommunicationProtocolGuid,
+ NULL,
+ (VOID **)&mSmmCommunication
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate memory for flash device size communicate buffer.
+ //
+ mFlashSize = AllocateRuntimePool (sizeof (UINTN));
+ ASSERT (mFlashSize != NULL);
+
+ //
+ // Allocate memory for flash device block size communicate buffer.
+ //
+ mBlockSize = AllocateRuntimePool (sizeof (UINTN));
+ ASSERT (mBlockSize != NULL);
+
+ Status = GetFlashSizeBlockSize ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate memory for update flash communicate buffer.
+ //
+ mRweBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_COMM_RWE_FLASH_SIZE + *mFlashSize;
+ mRweBuffer = AllocateRuntimePool (mRweBufferSize);
+ ASSERT (mRweBuffer != NULL);
+
+ gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ SpiFlashAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiSpiFlashUpdateProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mEfiSpiFlashUpdateProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmmRuntimeDxe.inf b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmmRuntimeDxe.inf
new file mode 100644
index 0000000000..7f606dd048
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/FlashUpdateSmmRuntimeDxe.inf
@@ -0,0 +1,48 @@
+## @file
+# Flash Update SmmRuntimeDxe
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FlashUpdateSmmRuntimeDxe
+ FILE_GUID = FA08552D-9666-42A0-A327-BF342B03DA2C
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FlashUpdateSmmRuntimeInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ FlashUpdateSmmRuntimeDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VanGoghCommonPkg/AmdCommonPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiRuntimeLib
+
+[Protocols]
+ gEfiSmmCommunicationProtocolGuid ## CONSUME
+ gEfiSmmSpiFlashUpdateProtocolGuid ## CONSUME
+ gEfiSpiFlashUpdateProtocolGuid ## PRODUCE
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid ## CONSUME ## Event
+
+[Depex]
+ gEfiSmmCommunicationProtocolGuid
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/PcRtc.h b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/PcRtc.h
new file mode 100644
index 0000000000..2354eaa2b7
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FlashUpdate/PcRtc.h
@@ -0,0 +1,375 @@
+/** @file
+ Implements AMD PcRtc
+ Header file for real time clock driver.
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef RTC_H_
+#define RTC_H_
+
+#include <Uefi.h>
+
+#include <Guid/Acpi.h>
+
+#include <Protocol/RealTimeClock.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+typedef struct {
+ EFI_LOCK RtcLock;
+ INT16 SavedTimeZone;
+ UINT8 Daylight;
+ UINT8 CenturyRtcAddress;
+} PC_RTC_MODULE_GLOBALS;
+
+extern PC_RTC_MODULE_GLOBALS mModuleGlobal;
+
+#define PCAT_RTC_ADDRESS_REGISTER 0x70
+#define PCAT_RTC_DATA_REGISTER 0x71
+
+//
+// Dallas DS12C887 Real Time Clock
+//
+#define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59
+#define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59
+#define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59
+#define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59
+#define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM
+#define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM
+#define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7
+#define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31
+#define RTC_ADDRESS_MONTH 8 // R/W Range 1..12
+#define RTC_ADDRESS_YEAR 9 // R/W Range 0..99
+#define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7]
+#define RTC_ADDRESS_REGISTER_B 11 // R/W
+#define RTC_ADDRESS_REGISTER_C 12 // RO
+#define RTC_ADDRESS_REGISTER_D 13 // RO
+//
+// Date and time initial values.
+// They are used if the RTC values are invalid during driver initialization
+//
+#define RTC_INIT_SECOND 0
+#define RTC_INIT_MINUTE 0
+#define RTC_INIT_HOUR 0
+#define RTC_INIT_DAY 1
+#define RTC_INIT_MONTH 1
+
+#pragma pack(1)
+//
+// Register A
+//
+typedef struct {
+ UINT8 Rs : 4; // Rate Selection Bits
+ UINT8 Dv : 3; // Divisor
+ UINT8 Uip : 1; // Update in progress
+} RTC_REGISTER_A_BITS;
+
+typedef union {
+ RTC_REGISTER_A_BITS Bits;
+ UINT8 Data;
+} RTC_REGISTER_A;
+
+//
+// Register B
+//
+typedef struct {
+ UINT8 Dse : 1; // 0 - Daylight saving disabled 1 - Daylight savings enabled
+ UINT8 Mil : 1; // 0 - 12 hour mode 1 - 24 hour mode
+ UINT8 Dm : 1; // 0 - BCD Format 1 - Binary Format
+ UINT8 Sqwe : 1; // 0 - Disable SQWE output 1 - Enable SQWE output
+ UINT8 Uie : 1; // 0 - Update INT disabled 1 - Update INT enabled
+ UINT8 Aie : 1; // 0 - Alarm INT disabled 1 - Alarm INT Enabled
+ UINT8 Pie : 1; // 0 - Periodic INT disabled 1 - Periodic INT Enabled
+ UINT8 Set : 1; // 0 - Normal operation. 1 - Updates inhibited
+} RTC_REGISTER_B_BITS;
+
+typedef union {
+ RTC_REGISTER_B_BITS Bits;
+ UINT8 Data;
+} RTC_REGISTER_B;
+
+//
+// Register C
+//
+typedef struct {
+ UINT8 Reserved : 4; // Read as zero. Can not be written.
+ UINT8 Uf : 1; // Update End Interrupt Flag
+ UINT8 Af : 1; // Alarm Interrupt Flag
+ UINT8 Pf : 1; // Periodic Interrupt Flag
+ UINT8 Irqf : 1; // Iterrupt Request Flag = PF & PIE | AF & AIE | UF & UIE
+} RTC_REGISTER_C_BITS;
+
+typedef union {
+ RTC_REGISTER_C_BITS Bits;
+ UINT8 Data;
+} RTC_REGISTER_C;
+
+//
+// Register D
+//
+typedef struct {
+ UINT8 Reserved : 7; // Read as zero. Can not be written.
+ UINT8 Vrt : 1; // Valid RAM and Time
+} RTC_REGISTER_D_BITS;
+
+typedef union {
+ RTC_REGISTER_D_BITS Bits;
+ UINT8 Data;
+} RTC_REGISTER_D;
+
+#pragma pack()
+
+/**
+ Initialize RTC.
+
+ @param Global For global use inside this module.
+
+ @retval EFI_DEVICE_ERROR Initialization failed due to device error.
+ @retval EFI_SUCCESS Initialization successful.
+
+**/
+EFI_STATUS
+PcRtcInit (
+ IN PC_RTC_MODULE_GLOBALS *Global
+ );
+
+/**
+ Sets the current local time and date information.
+
+ @param Time A pointer to the current time.
+ @param Global For global use inside this module.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
+
+**/
+EFI_STATUS
+PcRtcSetTime (
+ IN EFI_TIME *Time,
+ IN PC_RTC_MODULE_GLOBALS *Global
+ );
+
+/**
+ Returns the current time and date information, and the time-keeping capabilities
+ of the hardware platform.
+
+ @param Time A pointer to storage to receive a snapshot of the current time.
+ @param Capabilities An optional pointer to a buffer to receive the real time clock
+ device's capabilities.
+ @param Global For global use inside this module.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
+
+**/
+EFI_STATUS
+PcRtcGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities, OPTIONAL
+ IN PC_RTC_MODULE_GLOBALS *Global
+ );
+
+/**
+ Sets the system wakeup alarm clock time.
+
+ @param Enabled Enable or disable the wakeup alarm.
+ @param Time If Enable is TRUE, the time to set the wakeup alarm for.
+ If Enable is FALSE, then this parameter is optional, and may be NULL.
+ @param Global For global use inside this module.
+
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled.
+ If Enable is FALSE, then the wakeup alarm was disabled.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+PcRtcSetWakeupTime (
+ IN BOOLEAN Enable,
+ IN EFI_TIME *Time, OPTIONAL
+ IN PC_RTC_MODULE_GLOBALS *Global
+ );
+
+/**
+ Returns the current wakeup alarm clock setting.
+
+ @param Enabled Indicates if the alarm is currently enabled or disabled.
+ @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
+ @param Time The current alarm setting.
+ @param Global For global use inside this module.
+
+ @retval EFI_SUCCESS The alarm settings were returned.
+ @retval EFI_INVALID_PARAMETER Enabled is NULL.
+ @retval EFI_INVALID_PARAMETER Pending is NULL.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+PcRtcGetWakeupTime (
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time,
+ IN PC_RTC_MODULE_GLOBALS *Global
+ );
+
+/**
+ The user Entry Point for PcRTC module.
+
+ This is the entrhy point for PcRTC module. It installs the UEFI runtime service
+ including GetTime(),SetTime(),GetWakeupTime(),and SetWakeupTime().
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval Others Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePcRtc (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ See if all fields of a variable of EFI_TIME type is correct.
+
+ @param Time The time to be checked.
+
+ @retval EFI_INVALID_PARAMETER Some fields of Time are not correct.
+ @retval EFI_SUCCESS Time is a valid EFI_TIME variable.
+
+**/
+EFI_STATUS
+RtcTimeFieldsValid (
+ IN EFI_TIME *Time
+ );
+
+/**
+ Converts time from EFI_TIME format defined by UEFI spec to RTC's.
+
+ This function converts time from EFI_TIME format defined by UEFI spec to RTC's.
+ If data mode of RTC is BCD, then converts EFI_TIME to it.
+ If RTC is in 12-hour format, then converts EFI_TIME to it.
+
+ @param Time On input, the time data read from UEFI to convert
+ On output, the time converted to RTC format
+ @param RegisterB Value of Register B of RTC, indicating data mode
+**/
+VOID
+ConvertEfiTimeToRtcTime (
+ IN OUT EFI_TIME *Time,
+ IN RTC_REGISTER_B RegisterB
+ );
+
+/**
+ Converts time read from RTC to EFI_TIME format defined by UEFI spec.
+
+ This function converts raw time data read from RTC to the EFI_TIME format
+ defined by UEFI spec.
+ If data mode of RTC is BCD, then converts it to decimal,
+ If RTC is in 12-hour format, then converts it to 24-hour format.
+
+ @param Time On input, the time data read from RTC to convert
+ On output, the time converted to UEFI format
+ @param RegisterB Value of Register B of RTC, indicating data mode
+ and hour format.
+
+ @retval EFI_INVALID_PARAMETER Parameters passed in are invalid.
+ @retval EFI_SUCCESS Convert RTC time to EFI time successfully.
+
+**/
+EFI_STATUS
+ConvertRtcTimeToEfiTime (
+ IN OUT EFI_TIME *Time,
+ IN RTC_REGISTER_B RegisterB
+ );
+
+/**
+ Wait for a period for the RTC to be ready.
+
+ @param Timeout Tell how long it should take to wait.
+
+ @retval EFI_DEVICE_ERROR RTC device error.
+ @retval EFI_SUCCESS RTC is updated and ready.
+**/
+EFI_STATUS
+RtcWaitToUpdate (
+ UINTN Timeout
+ );
+
+/**
+ See if field Day of an EFI_TIME is correct.
+
+ @param Time Its Day field is to be checked.
+
+ @retval TRUE Day field of Time is correct.
+ @retval FALSE Day field of Time is NOT correct.
+**/
+BOOLEAN
+DayValid (
+ IN EFI_TIME *Time
+ );
+
+/**
+ Check if it is a leapyear.
+
+ @param Time The time to be checked.
+
+ @retval TRUE It is a leapyear.
+ @retval FALSE It is NOT a leapyear.
+**/
+BOOLEAN
+IsLeapYear (
+ IN EFI_TIME *Time
+ );
+
+/**
+ Get the century RTC address from the ACPI FADT table.
+
+ @return The century RTC address or 0 if not found.
+**/
+UINT8
+GetCenturyRtcAddress (
+ VOID
+ );
+
+/**
+ Notification function of ACPI Table change.
+
+ This is a notification function registered on ACPI Table change event.
+ It saves the Century address stored in ACPI FADT table.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+PcRtcAcpiTableChangeCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
--
2.31.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#114586): https://edk2.groups.io/g/devel/message/114586
Mute This Topic: https://groups.io/mt/103975450/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2024 Red Hat, Inc.