From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.51]) by mx.groups.io with SMTP id smtpd.web12.6382.1622849179595487886 for ; Fri, 04 Jun 2021 16:26:20 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=V//bo0PM; spf=pass (domain: nuviainc.com, ip: 209.85.221.51, mailfrom: leif@nuviainc.com) Received: by mail-wr1-f51.google.com with SMTP id c9so2109478wrt.5 for ; Fri, 04 Jun 2021 16:26:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=P4NUDBXXBBvWsQluEl28GHtJITo/M6NN0GkBnVBIY2Q=; b=V//bo0PMlSjBLevhhH9k1beiM7QscYwomYMRnNy5pHfV0OG98LfRjFEZg8szyIy7R1 rpD8o3Tnj0AU071Djjs7jem2MkTptIlhM2ApP6yn4ipYLcs+GP2bSYFJSFVDaDJBcPzb xFexTCTsUOr8JM8NLu8kKt9ooKwpWmg/xRYb8LpOBlZ9g++EU5KmAK4YCjsC0Lrm1w6M bFNIDf1ySceixnapKA3rt1GwdEQIV8AJu4MhFv99FPkp9l4SOcUp3GCYo81hh7mUrDC/ kHxn/vGCJUillk95O2S8pWydrcxT330R7z1R8/YbgD0DIEGDEFRF3ItsCxzvB7C8j2aK FVbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=P4NUDBXXBBvWsQluEl28GHtJITo/M6NN0GkBnVBIY2Q=; b=dq2QL5GUTutM7+JhaLz55bQraWP3e/CDQIzWxbcSojpjQUG4snqiPvNpSOrzkJoA+s ND1qF95eztbQdpoBJCx8QwSBtYR+f83/Ece7a88BKMWz7zVaD7SpDGE5wjBe1UvLgwT/ LGkpkKAEHxvudZBt4bZZyD+U92ZoSBj2NWga03iDJFbOQWa4gETUO/t03zr2W5ERbJt9 3ySGtCUSSZSINh/3Z25I6hAn6DyIHOnN7sosVo8TOEjS7hYhe7v7aZcTgm9WEw5jRbvi 1n3T4RPy0D37VUesD3vXN7Am8+fRmwNstPKKbaZYe+gwslbsbo5rbcyiVa7ykyvzdT+L /8lw== X-Gm-Message-State: AOAM530Wk9Zs8zZD53bRliU0n98OpminPNk69+JMIXBSOn2yKoYUQLCh 2K9MqseG6QJdXuwvNrXPHR1RBw== X-Google-Smtp-Source: ABdhPJxUZrKkEuqjziY9QnP62XT1tgTDyq+iKTXEUPCINo2eNopgpv3P9OkYTCnZFyOO8Q96s+PA5A== X-Received: by 2002:a5d:5192:: with SMTP id k18mr6076180wrv.163.1622849178008; Fri, 04 Jun 2021 16:26:18 -0700 (PDT) Return-Path: Received: from leviathan (cpc1-cmbg19-2-0-cust915.5-4.cable.virginm.net. [82.27.183.148]) by smtp.gmail.com with ESMTPSA id n17sm973386wmq.24.2021.06.04.16.26.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Jun 2021 16:26:17 -0700 (PDT) Date: Sat, 5 Jun 2021 00:26:15 +0100 From: "Leif Lindholm" To: Nhi Pham Cc: devel@edk2.groups.io, Vu Nguyen , Thang Nguyen , Chuong Tran , Phong Vo , Michael D Kinney , Ard Biesheuvel , Nate DeSimone Subject: Re: [edk2-platforms][PATCH v2 07/32] JadePkg: Implement RealTimeClockLib for PCF85063 Message-ID: <20210604232615.zdpphdmxdj3kvg37@leviathan> References: <20210526100724.5359-1-nhi@os.amperecomputing.com> <20210526100724.5359-9-nhi@os.amperecomputing.com> MIME-Version: 1.0 In-Reply-To: <20210526100724.5359-9-nhi@os.amperecomputing.com> Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, May 26, 2021 at 17:06:59 +0700, Nhi Pham wrote: > From: Vu Nguyen > > 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 > Cc: Chuong Tran > Cc: Phong Vo > Cc: Leif Lindholm > Cc: Michael D Kinney > Cc: Ard Biesheuvel > Cc: Nate DeSimone > > Signed-off-by: Vu Nguyen > --- > 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.
> +# > +# 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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef PCF85063_H_ > +#define PCF85063_H_ > + > +#include > + > +#include > +#include > + > +// > +// 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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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. With that: Reviewed-by: Leif Lindholm / 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.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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 >