From: Duke Zhai <duke.z...@amd.com>

BZ #:4640
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.z...@amd.com>
Cc: Eric Xing <eric.x...@amd.com>
Cc: Ken Yao <ken....@amd.com>
Cc: Igniculus Fu <igniculus...@amd.com>
Cc: Abner Chang <abner.ch...@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..616035b82d
--- /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..14bd37ed2e
--- /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..08caf4257b
--- /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 (#114503): https://edk2.groups.io/g/devel/message/114503
Mute This Topic: https://groups.io/mt/103971400/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to