On 6/5/21 06:26, Leif Lindholm wrote:
On Wed, May 26, 2021 at 17:06:59 +0700, Nhi Pham wrote:
From: Vu Nguyen <vungu...@os.amperecomputing.com>

This library adds the support for retrieving and updating system
datetime over real RTC PCF85063 device on Mt. Jade platform instead of
using virtual RTC.

Cc: Thang Nguyen <th...@os.amperecomputing.com>
Cc: Chuong Tran <chu...@os.amperecomputing.com>
Cc: Phong Vo <ph...@os.amperecomputing.com>
Cc: Leif Lindholm <l...@nuviainc.com>
Cc: Michael D Kinney <michael.d.kin...@intel.com>
Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desim...@intel.com>

Signed-off-by: Vu Nguyen <vungu...@os.amperecomputing.com>
---
  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc                          
        |   2 +
  Platform/Ampere/JadePkg/Jade.dsc                                              
        |   2 +-
  
Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.inf
 |  44 +++
  Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.h           
        |  91 ++++++
  Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c           
        | 317 ++++++++++++++++++++
  
Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.c
   | 257 ++++++++++++++++
  6 files changed, 712 insertions(+), 1 deletion(-)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc 
b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index 6a6f72e995af..9f19f495fad2 100755
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -84,6 +84,8 @@ [LibraryClasses.common]
    
SystemFirmwareInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/SystemFirmwareInterfaceLib/SystemFirmwareInterfaceLib.inf
    
AmpereCpuLib|Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLib.inf
    TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
+  I2cLib|Silicon/Ampere/AmpereAltraPkg/Library/DwI2cLib/DwI2cLib.inf
+  GpioLib|Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.inf
    
MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Library/MmCommunicationLib/MmCommunicationLib.inf
#
diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index f92855af99ab..f37ab1a92e44 100755
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -73,7 +73,7 @@ [LibraryClasses]
    #
    # RTC Library: Common RTC
    #
-  
RealTimeClockLib|EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
+  
RealTimeClockLib|Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.inf
#
    # Library for FailSafe support
diff --git 
a/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.inf
 
b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.inf
new file mode 100644
index 000000000000..1fe561cc0ec9
--- /dev/null
+++ 
b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.inf
@@ -0,0 +1,44 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                      = 0x0001001B
+  MODULE_TYPE                      = BASE
+  BASE_NAME                        = PCF85063RealTimeClockLib
+  FILE_GUID                        = 271569F6-5522-4006-9FF5-F07A59473AAC
+  LIBRARY_CLASS                    = RealTimeClockLib
+  VERSION_STRING                   = 1.0
+
+[Sources.common]
+  PCF85063.c
+  PCF85063.h
+  PCF85063RealTimeClockLib.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+  ArmGenericTimerCounterLib
+  ArmLib
+  BaseLib
+  DebugLib
+  GpioLib
+  DxeServicesTableLib
+  I2cLib
+  TimeBaseLib
+  TimerLib
+  UefiLib
+  UefiRuntimeLib
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid
diff --git 
a/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.h 
b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.h
new file mode 100644
index 000000000000..03ce4d29a03f
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.h
@@ -0,0 +1,91 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PCF85063_H_
+#define PCF85063_H_
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/RealTimeClockLib.h>
+
+//
+// I2C bus address that RTC connected to
+//
+#define I2C_RTC_BUS_ADDRESS        1
+
+//
+// I2C RTC bus speed
+//
+#define I2C_RTC_BUS_SPEED          100000
+
+//
+// I2C chip address that RTC connected to
+//
+#define I2C_RTC_CHIP_ADDRESS       0x51
+
+//
+// The GPI PIN that tell if RTC can be access
+//
+#define I2C_RTC_ACCESS_GPIO_PIN    28
+
+/**
+ * Returns the current time and date information of the hardware platform.
+ *
+ * @param  Time                  A pointer to storage to receive a snapshot of 
the current time.
+ *
+ *
+ * @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
+EFIAPI
+PlatformGetTime (
+  OUT EFI_TIME *Time
+  );
+
+/**
+ * Set the time and date information to the hardware platform.
+ *
+ * @param  Time                  A pointer to storage to set the current time 
to hardware platform.
+ *
+ *
+ * @retval EFI_SUCCESS           The operation completed successfully.
+ * @retval EFI_INVALID_PARAMETER Time is NULL.
+ * @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware 
error.
+ **/
+EFI_STATUS
+EFIAPI
+PlatformSetTime (
+  IN EFI_TIME *Time
+  );
+
+/**
+ * Callback function for hardware platform to convert data pointers to virtual 
address
+ */
+VOID
+EFIAPI
+PlatformVirtualAddressChangeEvent (
+  VOID
+  );
+
+/**
+ * Callback function for hardware platform to initialize private data
+ *
+ *
+ * @retval EFI_SUCCESS           The operation completed successfully.
+ * @retval Others                The error status indicates the error
+ */
+EFI_STATUS
+EFIAPI
+PlatformInitialize (
+  VOID
+  );
+
+#endif /* PCF85063_H_ */
diff --git 
a/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c 
b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c
new file mode 100644
index 000000000000..f9fa125d9d7e
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063.c
@@ -0,0 +1,317 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/GpioLib.h>
+#include <Library/I2cLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include "PCF85063.h"
+
+#define RTC_TIMEOUT_WAIT_ACCESS        100000 /* 100 miliseconds */
+#define RTC_DEFAULT_MIN_YEAR           2000
+#define RTC_DEFAULT_MAX_YEAR           2099
+
+#define RTC_ADDR                       0x4
+#define RTC_DATA_BUF_LEN               8
+
+/**
+ * PCF85063 register offsets
+ */
+#define PCF85063_OFFSET_SEC            0x0
+#define PCF85063_OFFSET_MIN            0x1
+#define PCF85063_OFFSET_HR             0x2
+#define PCF85063_OFFSET_DAY            0x3
+#define PCF85063_OFFSET_WKD            0x4
+#define PCF85063_OFFSET_MON            0x5
+#define PCF85063_OFFSET_YEA            0x6
+
+/**
+ * PCF85063 encoding macros
+ */
+#define PCF85063_SEC_ENC(s) (((((s) / 10) & 0x7) << 4) | (((s) % 10) & 0xf))
+#define PCF85063_MIN_ENC(m) (((((m) / 10) & 0x7) << 4) | (((m) % 10) & 0xf))
+#define PCF85063_HR_ENC(h)  (((((h) / 10) & 0x3) << 4) | (((h) % 10) & 0xf))
+#define PCF85063_DAY_ENC(d) (((((d) / 10) & 0x3) << 4) | (((d) % 10) & 0xf))
+#define PCF85063_WKD_ENC(w) ((w) & 0x7)
+#define PCF85063_MON_ENC(m) (((((m) / 10) & 0x1) << 4) | (((m) % 10) & 0xf))
+#define PCF85063_YEA_ENC(y) (((((y) / 10) & 0xf) << 4) | (((y) % 10) & 0xf))
+
+/**
+ * PCF85063 decoding macros
+ */
+#define PCF85063_SEC_DEC(s) (((((s) & 0x70) >> 4) * 10) + ((s) & 0xf))
+#define PCF85063_MIN_DEC(m) (((((m) & 0x70) >> 4) * 10) + ((m) & 0xf))
+#define PCF85063_HR_DEC(h)  (((((h) & 0x30) >> 4) * 10) + ((h) & 0xf))
+#define PCF85063_DAY_DEC(d) (((((d) & 0x30) >> 4)* 10) + ((d) & 0xf))
*twitch*
Please add that space before '*' like on all other lines.

Thanks. Will fix it in the v3.

Best regards,

Nhi


With that:
Reviewed-by: Leif Lindholm <l...@nuviainc.com>

/
     Leif

+#define PCF85063_WKD_DEC(w) ((w) & 0x7)
+#define PCF85063_MON_DEC(m) (((((m) & 0x10) >> 4) * 10) + ((m) & 0xf))
+#define PCF85063_YEA_DEC(y) (((((y) & 0xf0) >> 4) * 10) + ((y) & 0xf))
+
+/* Buffer pointers to convert Vir2Phys and Phy2Vir */
+STATIC volatile UINT64 RtcBufVir;
+STATIC volatile UINT64 RtcBufPhy;
+
+STATIC
+EFI_STATUS
+RtcI2cWaitAccess (
+  VOID
+  )
+{
+  INTN Timeout;
+
+  Timeout = RTC_TIMEOUT_WAIT_ACCESS;
+  while ((GpioReadBit (I2C_RTC_ACCESS_GPIO_PIN) != 0) && (Timeout > 0)) {
+    MicroSecondDelay (100);
+    Timeout -= 100;
+  }
+
+  if (Timeout <= 0) {
+    DEBUG ((DEBUG_ERROR, "%a: Timeout while waiting access RTC\n", 
__FUNCTION__));
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+RtcI2cRead (
+  IN     UINT8  Addr,
+  IN OUT UINT64 Data,
+  IN     UINT32 DataLen
+  )
+{
+  EFI_STATUS Status;
+  UINT32     TmpLen;
+
+  if (EFI_ERROR (RtcI2cWaitAccess ())) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  Status = I2cProbe (I2C_RTC_BUS_ADDRESS, I2C_RTC_BUS_SPEED);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Send the slave address for read
+  //
+  TmpLen = 1;
+  Status = I2cWrite (I2C_RTC_BUS_ADDRESS, I2C_RTC_CHIP_ADDRESS, (UINT8 *)&Addr, 
&TmpLen);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Read back the time
+  //
+  Status = I2cRead (I2C_RTC_BUS_ADDRESS, I2C_RTC_CHIP_ADDRESS, NULL, 0, (UINT8 
*)Data, &DataLen);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RtcI2cWrite (
+  IN UINT8  Addr,
+  IN UINT64 Data,
+  IN UINT32 DataLen
+  )
+{
+  EFI_STATUS Status;
+  UINT8      TmpBuf[RTC_DATA_BUF_LEN + 1];
+  UINT32     TmpLen;
+
+  if (EFI_ERROR (RtcI2cWaitAccess ())) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (DataLen > sizeof (TmpBuf) - 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = I2cProbe (I2C_RTC_BUS_ADDRESS, I2C_RTC_BUS_SPEED);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // The first byte is the address
+  //
+  TmpBuf[0] = Addr;
+  TmpLen = DataLen + 1;
+  CopyMem ((VOID *)(TmpBuf + 1), (VOID *)Data, DataLen);
+
+  Status = I2cWrite (I2C_RTC_BUS_ADDRESS, I2C_RTC_CHIP_ADDRESS, TmpBuf, 
&TmpLen);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+ * Returns the current time and date information of the hardware platform.
+ *
+ * @param  Time                  A pointer to storage to receive a snapshot of 
the current time.
+ *
+ *
+ * @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
+EFIAPI
+PlatformGetTime (
+  OUT EFI_TIME *Time
+  )
+{
+  EFI_STATUS Status;
+  UINT8      *Data;
+
+  if (Time == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = RtcI2cRead (RTC_ADDR, RtcBufVir, RTC_DATA_BUF_LEN);
+
+  Data = (UINT8 *)RtcBufVir;
+  if (Status == EFI_SUCCESS) {
+    Time->Second = PCF85063_SEC_DEC (Data[PCF85063_OFFSET_SEC]);
+    Time->Minute = PCF85063_MIN_DEC (Data[PCF85063_OFFSET_MIN]);
+    Time->Hour   = PCF85063_HR_DEC (Data[PCF85063_OFFSET_HR]);
+    Time->Day    = PCF85063_DAY_DEC (Data[PCF85063_OFFSET_DAY]);
+    Time->Month  = PCF85063_MON_DEC (Data[PCF85063_OFFSET_MON]);
+    Time->Year   = PCF85063_YEA_DEC (Data[PCF85063_OFFSET_YEA]);
+    Time->Year  += RTC_DEFAULT_MIN_YEAR;
+    if (Time->Year > RTC_DEFAULT_MAX_YEAR) {
+      Time->Year = RTC_DEFAULT_MAX_YEAR;
+    }
+    if (Time->Year < RTC_DEFAULT_MIN_YEAR) {
+      Time->Year = RTC_DEFAULT_MIN_YEAR;
+    }
+  }
+
+  return Status;
+}
+
+/**
+ * Set the time and date information to the hardware platform.
+ *
+ * @param  Time                  A pointer to storage to set the current time 
to hardware platform.
+ *
+ *
+ * @retval EFI_SUCCESS           The operation completed successfully.
+ * @retval EFI_INVALID_PARAMETER Time is NULL.
+ * @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware 
error.
+ **/
+EFI_STATUS
+EFIAPI
+PlatformSetTime (
+  IN EFI_TIME *Time
+  )
+{
+  UINT8 *Data;
+
+  if (Time == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Time->Year < RTC_DEFAULT_MIN_YEAR ||
+      Time->Year > RTC_DEFAULT_MAX_YEAR)
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Data = (UINT8 *)RtcBufVir;
+  Data[PCF85063_OFFSET_SEC] = PCF85063_SEC_ENC (Time->Second);
+  Data[PCF85063_OFFSET_MIN] = PCF85063_MIN_ENC (Time->Minute);
+  Data[PCF85063_OFFSET_HR]  = PCF85063_HR_ENC (Time->Hour);
+  Data[PCF85063_OFFSET_DAY] = PCF85063_DAY_ENC (Time->Day);
+  Data[PCF85063_OFFSET_MON] = PCF85063_MON_ENC (Time->Month);
+  Data[PCF85063_OFFSET_YEA] = PCF85063_YEA_ENC (Time->Year - 
RTC_DEFAULT_MIN_YEAR);
+
+  return RtcI2cWrite (RTC_ADDR, RtcBufVir, RTC_DATA_BUF_LEN);
+}
+
+/**
+ * Callback function for hardware platform to convert data pointers to virtual 
address
+ */
+VOID
+EFIAPI
+PlatformVirtualAddressChangeEvent (
+  VOID
+  )
+{
+  EfiConvertPointer (0x0, (VOID **)&RtcBufVir);
+}
+
+/**
+ * Callback function for hardware platform to initialize private data
+ *
+ *
+ * @retval EFI_SUCCESS           The operation completed successfully.
+ * @retval Others                The error status indicates the error
+ */
+EFI_STATUS
+EFIAPI
+PlatformInitialize (
+  VOID
+  )
+{
+  EFI_STATUS Status;
+
+  /*
+   * Allocate the buffer for RTC data
+   * The buffer can be accessible after ExitBootServices
+   */
+  RtcBufVir = (UINT64)AllocateRuntimeZeroPool (RTC_DATA_BUF_LEN);
+  ASSERT_EFI_ERROR (RtcBufVir);
+  RtcBufPhy = (UINT64)RtcBufVir;
+
+  Status = I2cSetupRuntime (I2C_RTC_BUS_ADDRESS);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a:%d I2cSetupRuntime() failed - %r \n",
+      __FUNCTION__,
+      __LINE__,
+      Status
+      ));
+    return Status;
+  }
+
+  Status = GpioSetupRuntime (I2C_RTC_ACCESS_GPIO_PIN);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a:%d GpioSetupRuntime() failed - %r \n",
+      __FUNCTION__,
+      __LINE__,
+      Status
+      ));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git 
a/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.c
 
b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.c
new file mode 100755
index 000000000000..ef8c71e92c18
--- /dev/null
+++ 
b/Platform/Ampere/JadePkg/Library/PCF85063RealTimeClockLib/PCF85063RealTimeClockLib.c
@@ -0,0 +1,257 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Uefi.h>
+
+#include <Guid/EventGroup.h>
+#include <Library/ArmGenericTimerCounterLib.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/RealTimeClockLib.h>
+#include <Library/TimeBaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/RealTimeClock.h>
+
+#include "PCF85063.h"
+
+#define TICKS_PER_SEC     (ArmGenericTimerGetTimerFreq ())
+
+STATIC EFI_EVENT          mVirtualAddressChangeEvent = NULL;
+
+STATIC UINT64             mLastSavedSystemCount = 0;
+STATIC UINT64             mLastSavedTimeEpoch = 0;
+
+/**
+ * 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.
+ *
+ *
+ * @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
+EFIAPI
+LibGetTime (
+  OUT EFI_TIME                *Time,
+  OUT EFI_TIME_CAPABILITIES   *Capabilities
+  )
+{
+  EFI_STATUS    Status;
+  UINT64        CurrentSystemCount;
+  UINT64        TimeElapsed;
+  UINTN         EpochSeconds;
+
+  if ((mLastSavedTimeEpoch == 0) || EfiAtRuntime ()) {
+    Status = PlatformGetTime (Time);
+    if (EFI_ERROR (Status)) {
+      // Failed to read platform RTC so create fake time
+      Time->Second = 0;
+      Time->Minute = 0;
+      Time->Hour = 10;
+      Time->Day = 1;
+      Time->Month = 1;
+      Time->Year = 2017;
+    }
+
+    EpochSeconds = EfiTimeToEpoch (Time);
+    if (!EfiAtRuntime ()) {
+      mLastSavedTimeEpoch = EpochSeconds;
+      mLastSavedSystemCount = ArmGenericTimerGetSystemCount ();
+    }
+  } else {
+    CurrentSystemCount = ArmGenericTimerGetSystemCount ();
+    if (CurrentSystemCount >= mLastSavedSystemCount) {
+      TimeElapsed = (CurrentSystemCount - mLastSavedSystemCount) / MultU64x32 
(1, TICKS_PER_SEC);
+      EpochSeconds = mLastSavedTimeEpoch + TimeElapsed;
+    } else {
+      // System counter overflow 64 bits
+      // Call GetTime again to read the date from RTC HW, not using generic 
timer system counter
+      mLastSavedTimeEpoch = 0;
+      return LibGetTime (Time, Capabilities);
+    }
+  }
+
+  // Adjust for the correct timezone
+  if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
+    EpochSeconds += Time->TimeZone * SEC_PER_MIN;
+  }
+
+  // Adjust for the correct period
+  if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {
+    // Convert to adjusted time, i.e. spring forwards one hour
+    EpochSeconds += SEC_PER_HOUR;
+  }
+
+  EpochToEfiTime (EpochSeconds, Time);
+
+  return EFI_SUCCESS;
+}
+
+/**
+ * Sets the current local time and date information.
+ *
+ * @param  Time                  A pointer to the current time.
+ *
+ * @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
+EFIAPI
+LibSetTime (
+  IN EFI_TIME                *Time
+  )
+{
+  EFI_STATUS    Status;
+  UINTN         EpochSeconds;
+
+  EpochSeconds = EfiTimeToEpoch (Time);
+
+  // Adjust for the correct time zone, i.e. convert to UTC time zone
+  if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
+    EpochSeconds -= Time->TimeZone * SEC_PER_MIN;
+  }
+
+  // Adjust for the correct period, i.e. fall back one hour
+  if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {
+    EpochSeconds -= SEC_PER_HOUR;
+  }
+
+  EpochToEfiTime (EpochSeconds, Time);
+
+  Status = PlatformSetTime (Time);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (!EfiAtRuntime ()) {
+    mLastSavedTimeEpoch = EpochSeconds;
+    mLastSavedSystemCount = ArmGenericTimerGetSystemCount ();
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+ * 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.
+ *
+ * @retval EFI_SUCCESS           The alarm settings were returned.
+ * @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+ * @retval EFI_DEVICE_ERROR      The wakeup time could not be retrieved due to 
a hardware error.
+ */
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+  OUT BOOLEAN     *Enabled,
+  OUT BOOLEAN     *Pending,
+  OUT EFI_TIME    *Time
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+ * 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.
+ *
+ * @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
+EFIAPI
+LibSetWakeupTime (
+  IN BOOLEAN      Enabled,
+  OUT EFI_TIME    *Time
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Fixup internal data so that EFI can be call in virtual mode.
+  Call the passed in Child Notify event and convert any pointers in
+  lib to virtual mode.
+
+  @param[in]    Event   The Event that is being processed
+  @param[in]    Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  //
+  // Only needed if you are going to support the OS calling RTC functions in 
virtual mode.
+  // You will need to call EfiConvertPointer (). To convert any stored 
physical addresses
+  // to virtual address. After the OS transitions to calling in virtual mode, 
all future
+  // runtime calls will be made in virtual mode.
+  //
+  PlatformVirtualAddressChangeEvent ();
+}
+
+/**
+ * This is the declaration of an EFI image entry point. This can be the entry 
point to an application
+ * written to this specification, an EFI boot service driver, or an EFI 
runtime driver.
+ *
+ * @param  ImageHandle           Handle that identifies the loaded image.
+ * @param  SystemTable           System Table for this image.
+ *
+ * @retval EFI_SUCCESS           The operation completed successfully.
+ */
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+
+  Status = PlatformInitialize ();
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Register for the virtual address change event
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  LibRtcVirtualNotifyEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &mVirtualAddressChangeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
--
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#76544): https://edk2.groups.io/g/devel/message/76544
Mute This Topic: https://groups.io/mt/83097102/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to