summaryrefslogtreecommitdiffstats
path: root/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c')
-rw-r--r--EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c861
1 files changed, 861 insertions, 0 deletions
diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c
new file mode 100644
index 0000000000..bb87ba82be
--- /dev/null
+++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c
@@ -0,0 +1,861 @@
+/** @file
+ Simple PC RTC
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+
+
+typedef struct {
+ EFI_LOCK RtcLock;
+ UINT16 SavedTimeZone;
+ UINT8 Daylight;
+} PC_RTC_GLOBALS;
+
+#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
+#define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W
+//
+// 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
+#define RTC_INIT_YEAR 2001
+
+//
+// Register initial values
+//
+#define RTC_INIT_REGISTER_A 0x26
+#define RTC_INIT_REGISTER_B 0x02
+#define RTC_INIT_REGISTER_D 0x0
+
+#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()
+
+PC_RTC_GLOBALS mRtc;
+
+BOOLEAN
+IsLeapYear (
+ IN EFI_TIME *Time
+ )
+{
+ if (Time->Year % 4 == 0) {
+ if (Time->Year % 100 == 0) {
+ if (Time->Year % 400 == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return TRUE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+
+
+const INTN mDayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+BOOLEAN
+DayValid (
+ IN EFI_TIME *Time
+ )
+{
+ if (Time->Day < 1 ||
+ Time->Day > mDayOfMonth[Time->Month - 1] ||
+ (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))
+ ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UINT8
+DecimaltoBcd (
+ IN UINT8 DecValue
+ )
+{
+ UINTN High;
+ UINTN Low;
+
+ High = DecValue / 10;
+ Low = DecValue - (High * 10);
+
+ return (UINT8) (Low + (High << 4));
+}
+
+UINT8
+BcdToDecimal (
+ IN UINT8 BcdValue
+ )
+{
+ UINTN High;
+ UINTN Low;
+
+ High = BcdValue >> 4;
+ Low = BcdValue - (High << 4);
+
+ return (UINT8) (Low + (High * 10));
+}
+
+
+
+
+VOID
+ConvertEfiTimeToRtcTime (
+ IN EFI_TIME *Time,
+ IN RTC_REGISTER_B RegisterB,
+ IN UINT8 *Century
+ )
+{
+ BOOLEAN PM;
+
+ PM = TRUE;
+ //
+ // Adjust hour field if RTC in in 12 hour mode
+ //
+ if (RegisterB.Bits.MIL == 0) {
+ if (Time->Hour < 12) {
+ PM = FALSE;
+ }
+
+ if (Time->Hour >= 13) {
+ Time->Hour = (UINT8) (Time->Hour - 12);
+ } else if (Time->Hour == 0) {
+ Time->Hour = 12;
+ }
+ }
+ //
+ // Set the Time/Date/Daylight Savings values.
+ //
+ *Century = DecimaltoBcd ((UINT8) (Time->Year / 100));
+
+ Time->Year = (UINT16) (Time->Year % 100);
+
+ if (RegisterB.Bits.DM == 0) {
+ Time->Year = DecimaltoBcd ((UINT8) Time->Year);
+ Time->Month = DecimaltoBcd (Time->Month);
+ Time->Day = DecimaltoBcd (Time->Day);
+ Time->Hour = DecimaltoBcd (Time->Hour);
+ Time->Minute = DecimaltoBcd (Time->Minute);
+ Time->Second = DecimaltoBcd (Time->Second);
+ }
+ //
+ // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.
+ //
+ if (RegisterB.Bits.MIL == 0 && PM) {
+ Time->Hour = (UINT8) (Time->Hour | 0x80);
+ }
+}
+
+EFI_STATUS
+RtcTimeFieldsValid (
+ IN EFI_TIME *Time
+ )
+/*++
+
+Routine Description:
+
+ Arguments:
+
+ Returns:
+--*/
+// TODO: Time - add argument and description to function comment
+// TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ if (Time->Year < 1998 ||
+ Time->Year > 2099 ||
+ Time->Month < 1 ||
+ Time->Month > 12 ||
+ (!DayValid (Time)) ||
+ Time->Hour > 23 ||
+ Time->Minute > 59 ||
+ Time->Second > 59 ||
+ Time->Nanosecond > 999999999 ||
+ (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) ||
+ (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+UINT8
+RtcRead (
+ IN UINT8 Address
+ )
+{
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));
+ return IoRead8 (PCAT_RTC_DATA_REGISTER);
+}
+
+VOID
+RtcWrite (
+ IN UINT8 Address,
+ IN UINT8 Data
+ )
+{
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));
+ IoWrite8 (PCAT_RTC_DATA_REGISTER, Data);
+}
+
+
+EFI_STATUS
+RtcTestCenturyRegister (
+ VOID
+ )
+{
+ UINT8 Century;
+ UINT8 Temp;
+
+ Century = RtcRead (RTC_ADDRESS_CENTURY);
+ //
+ // RtcWrite (RTC_ADDRESS_CENTURY, 0x00);
+ //
+ Temp = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f);
+ RtcWrite (RTC_ADDRESS_CENTURY, Century);
+ if (Temp == 0x19 || Temp == 0x20) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+VOID
+ConvertRtcTimeToEfiTime (
+ IN EFI_TIME *Time,
+ IN RTC_REGISTER_B RegisterB
+ )
+{
+ BOOLEAN PM;
+
+ if ((Time->Hour) & 0x80) {
+ PM = TRUE;
+ } else {
+ PM = FALSE;
+ }
+
+ Time->Hour = (UINT8) (Time->Hour & 0x7f);
+
+ if (RegisterB.Bits.DM == 0) {
+ Time->Year = BcdToDecimal ((UINT8) Time->Year);
+ Time->Month = BcdToDecimal (Time->Month);
+ Time->Day = BcdToDecimal (Time->Day);
+ Time->Hour = BcdToDecimal (Time->Hour);
+ Time->Minute = BcdToDecimal (Time->Minute);
+ Time->Second = BcdToDecimal (Time->Second);
+ }
+ //
+ // If time is in 12 hour format, convert it to 24 hour format
+ //
+ if (RegisterB.Bits.MIL == 0) {
+ if (PM && Time->Hour < 12) {
+ Time->Hour = (UINT8) (Time->Hour + 12);
+ }
+
+ if (!PM && Time->Hour == 12) {
+ Time->Hour = 0;
+ }
+ }
+
+ Time->Nanosecond = 0;
+ Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ Time->Daylight = 0;
+}
+
+EFI_STATUS
+RtcWaitToUpdate (
+ UINTN Timeout
+ )
+{
+ RTC_REGISTER_A RegisterA;
+ RTC_REGISTER_D RegisterD;
+
+ //
+ // See if the RTC is functioning correctly
+ //
+ RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
+
+ if (RegisterD.Bits.VRT == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Wait for up to 0.1 seconds for the RTC to be ready.
+ //
+ Timeout = (Timeout / 10) + 1;
+ RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
+ while (RegisterA.Bits.UIP == 1 && Timeout > 0) {
+ MicroSecondDelay (10);
+ RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
+ Timeout--;
+ }
+
+ RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
+ if (Timeout == 0 || RegisterD.Bits.VRT == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities
+ )
+{
+ EFI_STATUS Status;
+ RTC_REGISTER_B RegisterB;
+ UINT8 Century;
+ UINTN BufferSize;
+
+ //
+ // Check parameters for null pointer
+ //
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+
+ }
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return Status;
+ }
+ //
+ // Read Register B
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+
+ //
+ // Get the Time/Date/Daylight Savings values.
+ //
+ Time->Second = RtcRead (RTC_ADDRESS_SECONDS);
+ Time->Minute = RtcRead (RTC_ADDRESS_MINUTES);
+ Time->Hour = RtcRead (RTC_ADDRESS_HOURS);
+ Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+ Time->Month = RtcRead (RTC_ADDRESS_MONTH);
+ Time->Year = RtcRead (RTC_ADDRESS_YEAR);
+
+ ConvertRtcTimeToEfiTime (Time, RegisterB);
+
+ if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+ Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
+ } else {
+ Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
+ }
+
+ Time->Year = (UINT16) (Century * 100 + Time->Year);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ //
+ // Get the variable that containts the TimeZone and Daylight fields
+ //
+ Time->TimeZone = mRtc.SavedTimeZone;
+ Time->Daylight = mRtc.Daylight;
+
+ BufferSize = sizeof (INT16) + sizeof (UINT8);
+
+ //
+ // Make sure all field values are in correct range
+ //
+ Status = RtcTimeFieldsValid (Time);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Fill in Capabilities if it was passed in
+ //
+ if (Capabilities) {
+ Capabilities->Resolution = 1;
+ //
+ // 1 hertz
+ //
+ Capabilities->Accuracy = 50000000;
+ //
+ // 50 ppm
+ //
+ Capabilities->SetsToZero = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+EFI_STATUS
+LibSetTime (
+ IN EFI_TIME *Time
+ )
+{
+ EFI_STATUS Status;
+ EFI_TIME RtcTime;
+ RTC_REGISTER_B RegisterB;
+ UINT8 Century;
+
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Make sure that the time fields are valid
+ //
+ Status = RtcTimeFieldsValid (Time);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (&RtcTime, Time, sizeof (EFI_TIME));
+
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return Status;
+ }
+ //
+ // Read Register B, and inhibit updates of the RTC
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+ RegisterB.Bits.SET = 1;
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
+
+ ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
+
+ RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);
+ RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);
+ RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour);
+ RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);
+ RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);
+ RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);
+ if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+ Century = (UINT8) ((Century & 0x7f) | (RtcRead (RTC_ADDRESS_CENTURY) & 0x80));
+ }
+
+ RtcWrite (RTC_ADDRESS_CENTURY, Century);
+
+ //
+ // Allow updates of the RTC registers
+ //
+ RegisterB.Bits.SET = 0;
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ //
+ // Set the variable that containts the TimeZone and Daylight fields
+ //
+ mRtc.SavedTimeZone = Time->TimeZone;
+ mRtc.Daylight = Time->Daylight;
+ return Status;
+}
+
+EFI_STATUS
+libGetWakeupTime (
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ )
+{
+ EFI_STATUS Status;
+ RTC_REGISTER_B RegisterB;
+ RTC_REGISTER_C RegisterC;
+ UINT8 Century;
+
+ //
+ // Check paramters for null pointers
+ //
+ if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) {
+ return EFI_INVALID_PARAMETER;
+
+ }
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Read Register B and Register C
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+ RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);
+
+ //
+ // Get the Time/Date/Daylight Savings values.
+ //
+ *Enabled = RegisterB.Bits.AIE;
+ if (*Enabled) {
+ Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM);
+ Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM);
+ Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM);
+ Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+ Time->Month = RtcRead (RTC_ADDRESS_MONTH);
+ Time->Year = RtcRead (RTC_ADDRESS_YEAR);
+ } else {
+ Time->Second = 0;
+ Time->Minute = 0;
+ Time->Hour = 0;
+ Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+ Time->Month = RtcRead (RTC_ADDRESS_MONTH);
+ Time->Year = RtcRead (RTC_ADDRESS_YEAR);
+ }
+
+ ConvertRtcTimeToEfiTime (Time, RegisterB);
+
+ if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+ Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
+ } else {
+ Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
+ }
+
+ Time->Year = (UINT16) (Century * 100 + Time->Year);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ //
+ // Make sure all field values are in correct range
+ //
+ Status = RtcTimeFieldsValid (Time);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *Pending = RegisterC.Bits.AF;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibSetWakeupTime (
+ IN BOOLEAN Enabled,
+ OUT EFI_TIME *Time
+ )
+{
+ EFI_STATUS Status;
+ EFI_TIME RtcTime;
+ RTC_REGISTER_B RegisterB;
+ UINT8 Century;
+ EFI_TIME_CAPABILITIES Capabilities;
+
+ if (Enabled) {
+
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Make sure that the time fields are valid
+ //
+ Status = RtcTimeFieldsValid (Time);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Just support set alarm time within 24 hours
+ //
+ LibGetTime (&RtcTime, &Capabilities);
+ if (Time->Year != RtcTime.Year ||
+ Time->Month != RtcTime.Month ||
+ (Time->Day != RtcTime.Day && Time->Day != (RtcTime.Day + 1))
+ ) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Make a local copy of the time and date
+ //
+ CopyMem (&RtcTime, Time, sizeof (EFI_TIME));
+
+ }
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Read Register B, and inhibit updates of the RTC
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+
+ RegisterB.Bits.SET = 1;
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
+
+ if (Enabled) {
+ ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
+
+ //
+ // Set RTC alarm time
+ //
+ RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);
+ RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);
+ RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);
+
+ RegisterB.Bits.AIE = 1;
+
+ } else {
+ RegisterB.Bits.AIE = 0;
+ }
+ //
+ // Allow updates of the RTC registers
+ //
+ RegisterB.Bits.SET = 0;
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ return EFI_SUCCESS;
+}
+
+
+
+VOID
+LibRtcVirtualAddressChangeEvent (
+ VOID
+ )
+{
+}
+
+
+VOID
+LibRtcInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ RTC_REGISTER_A RegisterA;
+ RTC_REGISTER_B RegisterB;
+ RTC_REGISTER_C RegisterC;
+ RTC_REGISTER_D RegisterD;
+ UINT8 Century;
+ EFI_TIME Time;
+
+ //
+ // Acquire RTC Lock to make access to RTC atomic
+ //
+ EfiAcquireLock (&mRtc.RtcLock);
+
+ //
+ // Initialize RTC Register
+ //
+ // Make sure Division Chain is properly configured,
+ // or RTC clock won't "tick" -- time won't increment
+ //
+ RegisterA.Data = RTC_INIT_REGISTER_A;
+ RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data);
+
+ //
+ // Read Register B
+ //
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
+
+ //
+ // Clear RTC flag register
+ //
+ RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);
+
+ //
+ // Clear RTC register D
+ //
+ RegisterD.Data = RTC_INIT_REGISTER_D;
+ RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data);
+
+ //
+ // Wait for up to 0.1 seconds for the RTC to be updated
+ //
+ Status = RtcWaitToUpdate (100000);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&mRtc.RtcLock);
+ return;
+ }
+
+ //
+ // Get the Time/Date/Daylight Savings values.
+ //
+ Time.Second = RtcRead (RTC_ADDRESS_SECONDS);
+ Time.Minute = RtcRead (RTC_ADDRESS_MINUTES);
+ Time.Hour = RtcRead (RTC_ADDRESS_HOURS);
+ Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
+ Time.Month = RtcRead (RTC_ADDRESS_MONTH);
+ Time.Year = RtcRead (RTC_ADDRESS_YEAR);
+
+ ConvertRtcTimeToEfiTime (&Time, RegisterB);
+
+ if (RtcTestCenturyRegister () == EFI_SUCCESS) {
+ Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
+ } else {
+ Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
+ }
+
+ Time.Year = (UINT16) (Century * 100 + Time.Year);
+
+ //
+ // Set RTC configuration after get original time
+ //
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RTC_INIT_REGISTER_B);
+
+ //
+ // Release RTC Lock.
+ //
+ EfiReleaseLock (&mRtc.RtcLock);
+
+ //
+ // Validate time fields
+ //
+ Status = RtcTimeFieldsValid (&Time);
+ if (EFI_ERROR (Status)) {
+ Time.Second = RTC_INIT_SECOND;
+ Time.Minute = RTC_INIT_MINUTE;
+ Time.Hour = RTC_INIT_HOUR;
+ Time.Day = RTC_INIT_DAY;
+ Time.Month = RTC_INIT_MONTH;
+ Time.Year = RTC_INIT_YEAR;
+ }
+ //
+ // Reset time value according to new RTC configuration
+ //
+ LibSetTime (&Time);
+
+ return;
+}
+
+