[PATCH v3 07/28] JadePkg: Implement RealTimeClockLib for PCF85063


Nhi Pham
 

From: Vu Nguyen <vunguyen@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 <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.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 89c143cd28e6..5f7a56133777 100644
--- 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 0681835dd175..332cd8ac0c8e 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -75,7 +75,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..bc886b530f3c
--- /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))
+#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 100644
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