From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from huawei.com (huawei.com [45.249.212.190]) by mx.groups.io with SMTP id smtpd.web12.9704.1589886652138845907 for ; Tue, 19 May 2020 04:10:53 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: huawei.com, ip: 45.249.212.190, mailfrom: huangming23@huawei.com) Received: from DGGEMS409-HUB.china.huawei.com (unknown [172.30.72.60]) by Forcepoint Email with ESMTP id 843EE274822EEC6D61F7; Tue, 19 May 2020 19:10:47 +0800 (CST) Received: from HGH1000039998.huawei.com (10.184.68.188) by DGGEMS409-HUB.china.huawei.com (10.3.19.209) with Microsoft SMTP Server id 14.3.487.0; Tue, 19 May 2020 19:10:41 +0800 From: Ming Huang To: , , CC: , , , , Subject: [RFC edk2-platforms v2 3/3] Silicon/Hisilicon: Add RX8900RealTimeClockLib Date: Tue, 19 May 2020 19:08:41 +0800 Message-ID: <1589886521-82250-4-git-send-email-huangming23@huawei.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1589886521-82250-1-git-send-email-huangming23@huawei.com> References: <1589886521-82250-1-git-send-email-huangming23@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.184.68.188] X-CFilter-Loop: Reflected Content-Type: text/plain There are some boards base on D06, but use RX8900 RTC, so upstream the RX8900RealTimeClockLib. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ming Huang --- Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClock.h | 39 ++ Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClockLib.c | 468 ++++++++++++++++++++ Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClockLib.inf | 33 ++ 3 files changed, 540 insertions(+) diff --git a/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClock.h b/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClock.h new file mode 100644 index 0000000..ac2be7e --- /dev/null +++ b/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClock.h @@ -0,0 +1,39 @@ +/** @file + + Copyright (c) 2020, Hisilicon Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef RX8900_REAL_TIME_CLOCK_H__ +#define RX8900_REAL_TIME_CLOCK_H__ + +#define RX8900_REGADDR_SECONDS 0x00 +#define RX8900_REGADDR_MIUTES 0x01 +#define RX8900_REGADDR_HOURS 0x02 +#define RX8900_REGADDR_DAY 0x03 +#define RX8900_REGADDR_DATE 0x04 +#define RX8900_REGADDR_MONTH 0x05 +#define RX8900_REGADDR_YEAR 0x06 +#define RX8900_REGADDR_RAM 0x07 +#define RX8900_REGADDR_ALARMMIN 0x08 +#define RX8900_REGADDR_ALARMHOUR 0x09 +#define RX8900_REGADDR_ALARMDAY 0x0A +#define RX8900_REGADDR_ALARMWEEK 0x0A +#define RX8900_REGADDR_TIMECOUNTER_0 0x0B +#define RX8900_REGADDR_TIMECOUNTER_1 0x0C +#define RX8900_REGADDR_EXTENSIONREG 0x0D +#define RX8900_REGADDR_FLAGREG 0x0E +#define RX8900_REGADDR_CONTRLREG 0xF +#define RX8900_REGADDR_BACKUP_FUN 0x18 + +#define RX8900_VDETOFF_SWOFF 0x0C +#define TEMPERATURE_COMPENSATION_2S 0x40 +#define OUTPUT_FREQUENCY_32768 0x0C +#define FLAG_REG_DEFAULT 0x00 +#define RX8900_RAM_REG_DEFAULT 0x5A + +#define EFI_TIMEOFFSET_TIMEZONE 0x5A0 + +#endif diff --git a/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClockLib.c b/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClockLib.c new file mode 100644 index 0000000..713bb7f --- /dev/null +++ b/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClockLib.c @@ -0,0 +1,468 @@ +/** @file + + Copyright (c) 2020, Hisilicon Limited. 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 "RX8900RealTimeClock.h" + +extern I2C_DEVICE gRtcDevice; + +STATIC BOOLEAN mRX8900Initialized = FALSE; +STATIC CONST CHAR16 mTimeZoneVariableName[] = L"RX8900RtcTimeZone"; +STATIC CONST CHAR16 mDaylightVariableName[] = L"RX8900RtcDaylight"; + +EFI_STATUS +InitializeRX8900 ( + VOID + ) +{ + EFI_STATUS Status; + unsigned char writeTemp; + + Status = OemSwitchRtcI2cChannelAndLock (); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + Status = I2CInit (gRtcDevice.Socket, gRtcDevice.Port, Normal); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + writeTemp = RX8900_VDETOFF_SWOFF; + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_BACKUP_FUN, 1, &writeTemp); + if (EFI_ERROR (Status)) { + goto EXIT; + } + writeTemp = TEMPERATURE_COMPENSATION_2S; + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_CONTRLREG, 1, &writeTemp); + if (EFI_ERROR (Status)) { + goto EXIT; + } + writeTemp = OUTPUT_FREQUENCY_32768; + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_EXTENSIONREG, 1, &writeTemp); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + writeTemp = FLAG_REG_DEFAULT; + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_FLAGREG, 1, &writeTemp); + if (EFI_ERROR (Status)) { + goto EXIT; + } + writeTemp = RX8900_RAM_REG_DEFAULT; + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_RAM, 1, &writeTemp); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + mRX8900Initialized = TRUE; + + EXIT: + + OemReleaseOwnershipOfRtc (); + return Status; +} + +STATIC +INT16 +GetTimeZone ( + VOID + ) +{ + EFI_STATUS Status; + INT16 TimeZone; + UINTN Size; + + TimeZone = EFI_UNSPECIFIED_TIMEZONE; + Size = sizeof (TimeZone); + Status = EfiGetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + NULL, + &Size, + (VOID *)&TimeZone + ); + + if (EFI_ERROR (Status)) { + TimeZone = EFI_UNSPECIFIED_TIMEZONE; + // The time zone variable does not exist in non-volatile storage, so create it. + Status = EfiSetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + (VOID *)&TimeZone + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Failed to save %s variable, Status = %r\n", + mTimeZoneVariableName, Status)); + } + } else { + // Check TimeZone bounds: -1440 to 1440 or 2047 + if ((TimeZone < -EFI_TIMEOFFSET_TIMEZONE) || (TimeZone > EFI_TIMEOFFSET_TIMEZONE)) { + TimeZone = EFI_UNSPECIFIED_TIMEZONE; + } + } + + return TimeZone; +} + +STATIC +UINT8 +GetDayLight ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 DayLight; + UINTN Size; + + DayLight = 0; + // Get the current daylight information from non-volatile storage + Size = sizeof (DayLight); + Status = EfiGetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + NULL, + &Size, + (VOID *)&DayLight + ); + + if (EFI_ERROR (Status)) { + DayLight = 0; + // The daylight variable does not exist in non-volatile storage, so create it. + Status = EfiSetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + (VOID *)&DayLight + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Failed to save %s variable, Status = %r\n", + mDaylightVariableName, Status)); + } + } + + return DayLight; +} + +EFI_STATUS +EFIAPI +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + EFI_STATUS Status; + UINT8 Temp[7] = {0}; + UINT16 BaseYear = 2000; + UINTN EpochSeconds; + UINT8 TryCount = 0; + + // Ensure Time is a valid pointer + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Initialize the hardware if not already done + if (!mRX8900Initialized) { + Status = InitializeRX8900 (); + if (EFI_ERROR (Status)) { + return EFI_NOT_READY; + } + } + + Status = OemSwitchRtcI2cChannelAndLock (); + if (EFI_ERROR (Status)) { + OemReleaseOwnershipOfRtc (); + return Status; + } + + do { + Status = I2CRead (&gRtcDevice, RX8900_REGADDR_SECONDS, 7, Temp); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Err; + } + + Time->Second = BcdToDecimal8 (Temp[0]); + Time->Minute = BcdToDecimal8 (Temp[1]); + Time->Hour = BcdToDecimal8 (Temp[2]); + Time->Day = BcdToDecimal8 (Temp[4]); + Time->Month = BcdToDecimal8 (Temp[5]); + Time->Year = BaseYear + BcdToDecimal8 (Temp[6]); + Time->Nanosecond = 0; + + EpochSeconds = EfiTimeToEpoch (Time); + + Time->TimeZone = GetTimeZone (); + // Adjust for the correct time zone + if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) { + EpochSeconds += Time->TimeZone * SEC_PER_MIN; + } + + Time->Daylight = GetDayLight (); + // 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; + } + + // Convert from internal 32-bit time to UEFI time + EpochToEfiTime (EpochSeconds, Time); + if ((!IsTimeValid (Time)) || ((Time->Year - BaseYear) > 99) || (Time->Year < 2000)) { + DEBUG ((DEBUG_INFO, "LibGetTime: %d-%d-%d %d-%d-%d EpochSeconds:%llx is invalid time!\n", + Time->Second, Time->Minute, Time->Hour, Time->Day, Time->Month, + Time->Year, EpochSeconds)); + Status = EFI_DEVICE_ERROR; + } + +Err: + TryCount++; + } while ((TryCount < 3) && (EFI_ERROR (Status))); + + OemReleaseOwnershipOfRtc (); + return Status; +} + +STATIC +EFI_STATUS +SetTimeToRX8900 ( + IN EFI_TIME *Time + ) +{ + EFI_STATUS Status; + UINT8 Temp; + + (VOID)MicroSecondDelay (RTC_DELAY_1000_MICROSECOND); + Temp = DecimalToBcd8 (Time->Second); + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_SECONDS, 1, &Temp); + if(EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + return Status; + } + + Temp = DecimalToBcd8 (Time->Minute); + (VOID)MicroSecondDelay (RTC_DELAY_1000_MICROSECOND); + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_MIUTES, 1, &Temp); + if(EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + return Status; + } + + Temp = DecimalToBcd8 (Time->Hour); + (VOID)MicroSecondDelay (RTC_DELAY_1000_MICROSECOND); + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_HOURS, 1, &Temp); + if(EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + return Status; + } + + Temp = DecimalToBcd8 (Time->Day); + (VOID)MicroSecondDelay (RTC_DELAY_1000_MICROSECOND); + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_DATE, 1, &Temp); + if(EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + return Status; + } + + Temp = DecimalToBcd8 (Time->Month); + (VOID)MicroSecondDelay (RTC_DELAY_1000_MICROSECOND); + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_MONTH, 1, &Temp); + if(EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + return Status; + } + + Time->Year= Time->Year % 100; + Temp = Time->Year; + Temp = DecimalToBcd8 (Temp); + (VOID)MicroSecondDelay (RTC_DELAY_1000_MICROSECOND); + Status = I2CWrite (&gRtcDevice, RX8900_REGADDR_YEAR, 1, &Temp); + if(EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + return Status; + } + + return Status; +} + +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ) +{ + EFI_STATUS Status; + UINTN EpochSeconds; + + // Initialize the hardware if not already done + if (!mRX8900Initialized) { + Status = InitializeRX8900 (); + if (EFI_ERROR (Status)) { + goto EXIT; + } + } + + Status = OemSwitchRtcI2cChannelAndLock (); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + if(!IsTimeValid(Time)){ + return EFI_INVALID_PARAMETER; + } + + 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 + if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) { + // Convert to un-adjusted time, i.e. fall back one hour + EpochSeconds -= SEC_PER_HOUR; + } + + EpochToEfiTime (EpochSeconds, Time); + Status = SetTimeToRX8900 (Time); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + // Save the current time zone information into non-volatile storage + Status = EfiSetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (Time->TimeZone), + (VOID *)&(Time->TimeZone) + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "LibSetTime: Failed to save %s variable, Status = %r\n", + mTimeZoneVariableName, Status)); + goto EXIT; + } + + // Save the current daylight information into non-volatile storage + Status = EfiSetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(Time->Daylight), + (VOID *)&(Time->Daylight) + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "LibSetTime: Failed to save %s variable, Status = %r\n", + mDaylightVariableName, Status)); + goto EXIT; + } + + EXIT: + OemReleaseOwnershipOfRtc (); + return Status; +} + +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + // Not a required feature + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + // Not a required feature + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +LibRtcInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_TIME EfiTime; + + // Setup the setters and getters + gRT->GetTime = LibGetTime; + gRT->SetTime = LibSetTime; + gRT->GetWakeupTime = LibGetWakeupTime; + gRT->SetWakeupTime = LibSetWakeupTime; + + Status = gRT->GetTime (&EfiTime, NULL); + if (EFI_ERROR (Status) || (EfiTime.Year < 2000) || (EfiTime.Year > 2099) || + (!IsTimeValid (&EfiTime))) { + EfiTime.Year = 2000; + EfiTime.Month = 1; + EfiTime.Day = 1; + EfiTime.Hour = 0; + EfiTime.Minute = 0; + EfiTime.Second = 0; + EfiTime.Nanosecond = 0; + EfiTime.Daylight = 0; + EfiTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE; + + Status = gRT->SetTime (&EfiTime); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SetTime Status : %r\n", Status)); + } + } + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiRealTimeClockArchProtocolGuid, + NULL, + NULL + ); + + return Status; +} + + +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + return; +} diff --git a/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClockLib.inf b/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClockLib.inf new file mode 100644 index 0000000..aa07a06 --- /dev/null +++ b/Silicon/Hisilicon/Library/RX8900RealTimeClockLib/RX8900RealTimeClockLib.inf @@ -0,0 +1,33 @@ +/** @file + + Copyright (c) 2020, Hisilicon Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = RX8900RealTimeClockLib + FILE_GUID = 55BBD010-EA76-4836-8FEA-99CBAA6664F4 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RealTimeClockLib + +[Sources.common] + RX8900RealTimeClockLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Silicon/Hisilicon/HisiPkg.dec + +[LibraryClasses] + DebugLib + I2CLib + IoLib + RtcHelperLib + TimeBaseLib + TimerLib + UefiLib + UefiRuntimeLib -- 2.8.1