/** @file\r
RTC Architectural Protocol GUID as defined in DxeCis 0.96.\r
\r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2017, AMD Inc. All rights reserved.<BR>\r
\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "PcRtc.h"\r
\r
+//\r
+// Days of month.\r
+//\r
+UINTN mDayOfMonth[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
+\r
+//\r
+// The name of NV variable to store the timezone and daylight saving information.\r
+//\r
+CHAR16 mTimeZoneVariableName[] = L"RTC";\r
+\r
/**\r
Compare the Hour, Minute and Second of the From time and the To time.\r
- \r
+\r
Only compare H/M/S in EFI_TIME and ignore other fields here.\r
\r
@param From the first time\r
IN UINT8 Address\r
)\r
{\r
- IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));\r
- return IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));\r
+ return IoRead8 (PcdGet8 (PcdRtcTargetRegister));\r
}\r
\r
/**\r
IN UINT8 Data\r
)\r
{\r
- IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));\r
- IoWrite8 (PCAT_RTC_DATA_REGISTER, Data);\r
+ IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));\r
+ IoWrite8 (PcdGet8 (PcdRtcTargetRegister), Data);\r
}\r
\r
/**\r
RTC_REGISTER_A RegisterA;\r
RTC_REGISTER_B RegisterB;\r
RTC_REGISTER_D RegisterD;\r
- UINT8 Century;\r
EFI_TIME Time;\r
UINTN DataSize;\r
UINT32 TimerVar;\r
+ BOOLEAN Enabled;\r
+ BOOLEAN Pending;\r
\r
//\r
// Acquire RTC Lock to make access to RTC atomic\r
// Make sure Division Chain is properly configured,\r
// or RTC clock won't "tick" -- time won't increment\r
//\r
- RegisterA.Data = RTC_INIT_REGISTER_A;\r
+ RegisterA.Data = FixedPcdGet8 (PcdInitialValueRtcRegisterA);\r
RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data);\r
\r
//\r
//\r
// Clear RTC register D\r
//\r
- RegisterD.Data = RTC_INIT_REGISTER_D;\r
+ RegisterD.Data = FixedPcdGet8 (PcdInitialValueRtcRegisterD);\r
RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data);\r
\r
//\r
//\r
Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
if (EFI_ERROR (Status)) {\r
+ //\r
+ // Set the variable with default value if the RTC is functioning incorrectly.\r
+ //\r
+ Global->SavedTimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
+ Global->Daylight = 0;\r
if (!EfiAtRuntime ()) {\r
EfiReleaseLock (&Global->RtcLock);\r
}\r
Time.Month = RtcRead (RTC_ADDRESS_MONTH);\r
Time.Year = RtcRead (RTC_ADDRESS_YEAR);\r
\r
- Century = RtcRead (RTC_ADDRESS_CENTURY);\r
- \r
//\r
// Set RTC configuration after get original time\r
// The value of bit AIE should be reserved.\r
//\r
- RtcWrite (RTC_ADDRESS_REGISTER_B, (UINT8)(RTC_INIT_REGISTER_B | (RegisterB.Data & BIT5)));\r
+ RegisterB.Data = FixedPcdGet8 (PcdInitialValueRtcRegisterB) | (RegisterB.Data & BIT5);\r
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
\r
//\r
// Release RTC Lock.\r
if (!EfiAtRuntime ()) {\r
EfiReleaseLock (&Global->RtcLock);\r
}\r
- \r
+\r
//\r
// Get the data of Daylight saving and time zone, if they have been\r
// stored in NV variable during previous boot.\r
//\r
DataSize = sizeof (UINT32);\r
Status = EfiGetVariable (\r
- L"RTC",\r
+ mTimeZoneVariableName,\r
&gEfiCallerIdGuid,\r
NULL,\r
&DataSize,\r
- (VOID *) &TimerVar\r
+ &TimerVar\r
);\r
if (!EFI_ERROR (Status)) {\r
Time.TimeZone = (INT16) TimerVar;\r
Time.Daylight = (UINT8) (TimerVar >> 16);\r
} else {\r
Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
- Time.Daylight = 0; \r
+ Time.Daylight = 0;\r
}\r
\r
//\r
// Validate time fields\r
//\r
- Status = ConvertRtcTimeToEfiTime (&Time, Century, RegisterB);\r
+ Status = ConvertRtcTimeToEfiTime (&Time, RegisterB);\r
if (!EFI_ERROR (Status)) {\r
Status = RtcTimeFieldsValid (&Time);\r
}\r
if (EFI_ERROR (Status)) {\r
+ //\r
+ // Report Status Code to indicate that the RTC has bad date and time\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_SOFTWARE_DXE_RT_DRIVER | EFI_SW_EC_BAD_DATE_TIME)\r
+ );\r
Time.Second = RTC_INIT_SECOND;\r
Time.Minute = RTC_INIT_MINUTE;\r
Time.Hour = RTC_INIT_HOUR;\r
Time.Day = RTC_INIT_DAY;\r
Time.Month = RTC_INIT_MONTH;\r
- Time.Year = RTC_INIT_YEAR;\r
+ Time.Year = PcdGet16 (PcdMinimalValidYear);\r
Time.Nanosecond = 0;\r
+ Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
+ Time.Daylight = 0;\r
}\r
\r
//\r
// Reset time value according to new RTC configuration\r
//\r
Status = PcRtcSetTime (&Time, Global);\r
- if(!EFI_ERROR (Status)) {\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Reset wakeup time value to valid state when wakeup alarm is disabled and wakeup time is invalid.\r
+ // Global variable has already had valid SavedTimeZone and Daylight,\r
+ // so we can use them to get and set wakeup time.\r
+ //\r
+ Status = PcRtcGetWakeupTime (&Enabled, &Pending, &Time, Global);\r
+ if ((Enabled) || (!EFI_ERROR (Status))) {\r
return EFI_SUCCESS;\r
- } else {\r
+ }\r
+\r
+ //\r
+ // When wakeup time is disabled and invalid, reset wakeup time register to valid state\r
+ // but keep wakeup alarm disabled.\r
+ //\r
+ Time.Second = RTC_INIT_SECOND;\r
+ Time.Minute = RTC_INIT_MINUTE;\r
+ Time.Hour = RTC_INIT_HOUR;\r
+ Time.Day = RTC_INIT_DAY;\r
+ Time.Month = RTC_INIT_MONTH;\r
+ Time.Year = PcdGet16 (PcdMinimalValidYear);\r
+ Time.Nanosecond = 0;\r
+ Time.TimeZone = Global->SavedTimeZone;\r
+ Time.Daylight = Global->Daylight;;\r
+\r
+ //\r
+ // Acquire RTC Lock to make access to RTC atomic\r
+ //\r
+ if (!EfiAtRuntime ()) {\r
+ EfiAcquireLock (&Global->RtcLock);\r
+ }\r
+ //\r
+ // Wait for up to 0.1 seconds for the RTC to be updated\r
+ //\r
+ Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
+ if (EFI_ERROR (Status)) {\r
+ if (!EfiAtRuntime ()) {\r
+ EfiReleaseLock (&Global->RtcLock);\r
+ }\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ ConvertEfiTimeToRtcTime (&Time, RegisterB);\r
+\r
+ //\r
+ // Set the Y/M/D info to variable as it has no corresponding hw registers.\r
+ //\r
+ Status = EfiSetVariable (\r
+ L"RTCALARM",\r
+ &gEfiCallerIdGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ sizeof (Time),\r
+ &Time\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ if (!EfiAtRuntime ()) {\r
+ EfiReleaseLock (&Global->RtcLock);\r
+ }\r
return EFI_DEVICE_ERROR;\r
}\r
+\r
+ //\r
+ // Inhibit updates of the RTC\r
+ //\r
+ RegisterB.Bits.Set = 1;\r
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
+\r
+ //\r
+ // Set RTC alarm time registers\r
+ //\r
+ RtcWrite (RTC_ADDRESS_SECONDS_ALARM, Time.Second);\r
+ RtcWrite (RTC_ADDRESS_MINUTES_ALARM, Time.Minute);\r
+ RtcWrite (RTC_ADDRESS_HOURS_ALARM, Time.Hour);\r
+\r
+ //\r
+ // Allow updates of the RTC registers\r
+ //\r
+ RegisterB.Bits.Set = 0;\r
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
+\r
+ //\r
+ // Release RTC Lock.\r
+ //\r
+ if (!EfiAtRuntime ()) {\r
+ EfiReleaseLock (&Global->RtcLock);\r
+ }\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
{\r
EFI_STATUS Status;\r
RTC_REGISTER_B RegisterB;\r
- UINT8 Century;\r
\r
//\r
// Check parameters for null pointer\r
Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
\r
- Century = RtcRead (RTC_ADDRESS_CENTURY);\r
- \r
//\r
// Release RTC Lock.\r
//\r
//\r
// Make sure all field values are in correct range\r
//\r
- Status = ConvertRtcTimeToEfiTime (Time, Century, RegisterB);\r
+ Status = ConvertRtcTimeToEfiTime (Time, RegisterB);\r
if (!EFI_ERROR (Status)) {\r
Status = RtcTimeFieldsValid (Time);\r
}\r
EFI_STATUS Status;\r
EFI_TIME RtcTime;\r
RTC_REGISTER_B RegisterB;\r
- UINT8 Century;\r
UINT32 TimerVar;\r
\r
if (Time == NULL) {\r
}\r
return Status;\r
}\r
+\r
+ //\r
+ // Write timezone and daylight to RTC variable\r
+ //\r
+ if ((Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE) && (Time->Daylight == 0)) {\r
+ Status = EfiSetVariable (\r
+ mTimeZoneVariableName,\r
+ &gEfiCallerIdGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+ if (Status == EFI_NOT_FOUND) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ } else {\r
+ TimerVar = Time->Daylight;\r
+ TimerVar = (UINT32) ((TimerVar << 16) | (UINT16)(Time->TimeZone));\r
+ Status = EfiSetVariable (\r
+ mTimeZoneVariableName,\r
+ &gEfiCallerIdGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ sizeof (TimerVar),\r
+ &TimerVar\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (!EfiAtRuntime ()) {\r
+ EfiReleaseLock (&Global->RtcLock);\r
+ }\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
//\r
// Read Register B, and inhibit updates of the RTC\r
//\r
RegisterB.Bits.Set = 1;\r
RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
\r
- ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);\r
+ //\r
+ // Store the century value to RTC before converting to BCD format.\r
+ //\r
+ if (Global->CenturyRtcAddress != 0) {\r
+ RtcWrite (Global->CenturyRtcAddress, DecimalToBcd8 ((UINT8) (RtcTime.Year / 100)));\r
+ }\r
+\r
+ ConvertEfiTimeToRtcTime (&RtcTime, RegisterB);\r
\r
RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);\r
RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);\r
RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);\r
RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);\r
RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);\r
- RtcWrite (RTC_ADDRESS_CENTURY, Century);\r
\r
//\r
// Allow updates of the RTC registers\r
Global->SavedTimeZone = Time->TimeZone;\r
Global->Daylight = Time->Daylight;\r
\r
- TimerVar = Time->Daylight;\r
- TimerVar = (UINT32) ((TimerVar << 16) | (UINT16)(Time->TimeZone));\r
- Status = EfiSetVariable (\r
- L"RTC",\r
- &gEfiCallerIdGuid,\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
- sizeof (TimerVar),\r
- &TimerVar\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
return EFI_SUCCESS;\r
}\r
\r
EFI_STATUS Status;\r
RTC_REGISTER_B RegisterB;\r
RTC_REGISTER_C RegisterC;\r
- UINT8 Century;\r
EFI_TIME RtcTime;\r
UINTN DataSize;\r
\r
Time->TimeZone = Global->SavedTimeZone;\r
Time->Daylight = Global->Daylight;\r
\r
- Century = RtcRead (RTC_ADDRESS_CENTURY);\r
-\r
//\r
// Get the alarm info from variable\r
//\r
+ DataSize = sizeof (EFI_TIME);\r
Status = EfiGetVariable (\r
L"RTCALARM",\r
&gEfiCallerIdGuid,\r
//\r
// Make sure all field values are in correct range\r
//\r
- Status = ConvertRtcTimeToEfiTime (Time, Century, RegisterB);\r
+ Status = ConvertRtcTimeToEfiTime (Time, RegisterB);\r
if (!EFI_ERROR (Status)) {\r
Status = RtcTimeFieldsValid (Time);\r
}\r
EFI_STATUS Status;\r
EFI_TIME RtcTime;\r
RTC_REGISTER_B RegisterB;\r
- UINT8 Century;\r
EFI_TIME_CAPABILITIES Capabilities;\r
\r
ZeroMem (&RtcTime, sizeof (RtcTime));\r
return EFI_DEVICE_ERROR;\r
}\r
//\r
- // Read Register B, and inhibit updates of the RTC\r
+ // Read Register B\r
//\r
- RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
-\r
- RegisterB.Bits.Set = 1;\r
- RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
+ RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
\r
if (Enable) {\r
- ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);\r
-\r
- //\r
- // Set RTC alarm time\r
- //\r
- RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);\r
- RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);\r
- RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);\r
-\r
- RegisterB.Bits.Aie = 1;\r
-\r
+ ConvertEfiTimeToRtcTime (&RtcTime, RegisterB);\r
} else {\r
- RegisterB.Bits.Aie = 0;\r
//\r
// if the alarm is disable, record the current setting.\r
//\r
RtcTime.TimeZone = Global->SavedTimeZone;\r
RtcTime.Daylight = Global->Daylight;\r
}\r
- //\r
- // Allow updates of the RTC registers\r
- //\r
- RegisterB.Bits.Set = 0;\r
- RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
\r
//\r
// Set the Y/M/D info to variable as it has no corresponding hw registers.\r
&RtcTime\r
);\r
if (EFI_ERROR (Status)) {\r
+ if (!EfiAtRuntime ()) {\r
+ EfiReleaseLock (&Global->RtcLock);\r
+ }\r
return EFI_DEVICE_ERROR;\r
}\r
\r
+ //\r
+ // Inhibit updates of the RTC\r
+ //\r
+ RegisterB.Bits.Set = 1;\r
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
+\r
+ if (Enable) {\r
+ //\r
+ // Set RTC alarm time\r
+ //\r
+ RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);\r
+ RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);\r
+ RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);\r
+\r
+ RegisterB.Bits.Aie = 1;\r
+\r
+ } else {\r
+ RegisterB.Bits.Aie = 0;\r
+ }\r
+ //\r
+ // Allow updates of the RTC registers\r
+ //\r
+ RegisterB.Bits.Set = 0;\r
+ RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
+\r
//\r
// Release RTC Lock.\r
//\r
\r
@param Time On input, the time data read from RTC to convert\r
On output, the time converted to UEFI format\r
- @param Century Value of century read from RTC.\r
@param RegisterB Value of Register B of RTC, indicating data mode\r
and hour format.\r
\r
EFI_STATUS\r
ConvertRtcTimeToEfiTime (\r
IN OUT EFI_TIME *Time,\r
- IN UINT8 Century,\r
IN RTC_REGISTER_B RegisterB\r
)\r
{\r
BOOLEAN IsPM;\r
+ UINT8 Century;\r
\r
if ((Time->Hour & 0x80) != 0) {\r
IsPM = TRUE;\r
Time->Minute = CheckAndConvertBcd8ToDecimal8 (Time->Minute);\r
Time->Second = CheckAndConvertBcd8ToDecimal8 (Time->Second);\r
}\r
- Century = CheckAndConvertBcd8ToDecimal8 (Century);\r
\r
if (Time->Year == 0xff || Time->Month == 0xff || Time->Day == 0xff ||\r
- Time->Hour == 0xff || Time->Minute == 0xff || Time->Second == 0xff ||\r
- Century == 0xff) {\r
+ Time->Hour == 0xff || Time->Minute == 0xff || Time->Second == 0xff) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ //\r
+ // For minimal/maximum year range [1970, 2069],\r
+ // Century is 19 if RTC year >= 70,\r
+ // Century is 20 otherwise.\r
+ //\r
+ Century = (UINT8) (PcdGet16 (PcdMinimalValidYear) / 100);\r
+ if (Time->Year < PcdGet16 (PcdMinimalValidYear) % 100) {\r
+ Century++;\r
+ }\r
Time->Year = (UINT16) (Century * 100 + Time->Year);\r
\r
//\r
@param Timeout Tell how long it should take to wait.\r
\r
@retval EFI_DEVICE_ERROR RTC device error.\r
- @retval EFI_SUCCESS RTC is updated and ready. \r
+ @retval EFI_SUCCESS RTC is updated and ready.\r
**/\r
EFI_STATUS\r
RtcWaitToUpdate (\r
IN EFI_TIME *Time\r
)\r
{\r
- if (Time->Year < 1998 ||\r
- Time->Year > 2099 ||\r
+ if (Time->Year < PcdGet16 (PcdMinimalValidYear) ||\r
+ Time->Year > PcdGet16 (PcdMaximalValidYear) ||\r
Time->Month < 1 ||\r
Time->Month > 12 ||\r
(!DayValid (Time)) ||\r
IN EFI_TIME *Time\r
)\r
{\r
- INTN DayOfMonth[12];\r
-\r
- DayOfMonth[0] = 31;\r
- DayOfMonth[1] = 29;\r
- DayOfMonth[2] = 31;\r
- DayOfMonth[3] = 30;\r
- DayOfMonth[4] = 31;\r
- DayOfMonth[5] = 30;\r
- DayOfMonth[6] = 31;\r
- DayOfMonth[7] = 31;\r
- DayOfMonth[8] = 30;\r
- DayOfMonth[9] = 31;\r
- DayOfMonth[10] = 30;\r
- DayOfMonth[11] = 31;\r
-\r
//\r
// The validity of Time->Month field should be checked before\r
//\r
ASSERT (Time->Month >=1);\r
ASSERT (Time->Month <=12);\r
if (Time->Day < 1 ||\r
- Time->Day > DayOfMonth[Time->Month - 1] ||\r
+ Time->Day > mDayOfMonth[Time->Month - 1] ||\r
(Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))\r
) {\r
return FALSE;\r
}\r
\r
/**\r
- Converts time from EFI_TIME format defined by UEFI spec to RTC's.\r
+ Converts time from EFI_TIME format defined by UEFI spec to RTC format.\r
\r
- This function converts time from EFI_TIME format defined by UEFI spec to RTC's.\r
+ This function converts time from EFI_TIME format defined by UEFI spec to RTC format.\r
If data mode of RTC is BCD, then converts EFI_TIME to it.\r
If RTC is in 12-hour format, then converts EFI_TIME to it.\r
\r
@param Time On input, the time data read from UEFI to convert\r
On output, the time converted to RTC format\r
@param RegisterB Value of Register B of RTC, indicating data mode\r
- @param Century It is set according to EFI_TIME Time.\r
-\r
**/\r
VOID\r
ConvertEfiTimeToRtcTime (\r
IN OUT EFI_TIME *Time,\r
- IN RTC_REGISTER_B RegisterB,\r
- OUT UINT8 *Century\r
+ IN RTC_REGISTER_B RegisterB\r
)\r
{\r
BOOLEAN IsPM;\r
}\r
}\r
//\r
- // Set the Time/Date/Daylight Savings values.\r
+ // Set the Time/Date values.\r
//\r
- *Century = DecimalToBcd8 ((UINT8) (Time->Year / 100));\r
-\r
Time->Year = (UINT16) (Time->Year % 100);\r
\r
if (RegisterB.Bits.Dm == 0) {\r
\r
/**\r
Compare the Hour, Minute and Second of the From time and the To time.\r
- \r
+\r
Only compare H/M/S in EFI_TIME and ignore other fields here.\r
\r
@param From the first time\r
IN EFI_TIME *To\r
)\r
{\r
- UINT8 DayOfMonth[12];\r
BOOLEAN Adjacent;\r
\r
- DayOfMonth[0] = 31;\r
- DayOfMonth[1] = 29;\r
- DayOfMonth[2] = 31;\r
- DayOfMonth[3] = 30;\r
- DayOfMonth[4] = 31;\r
- DayOfMonth[5] = 30;\r
- DayOfMonth[6] = 31;\r
- DayOfMonth[7] = 31;\r
- DayOfMonth[8] = 30;\r
- DayOfMonth[9] = 31;\r
- DayOfMonth[10] = 30;\r
- DayOfMonth[11] = 31;\r
-\r
Adjacent = FALSE;\r
\r
//\r
//\r
ASSERT (From->Month >=1);\r
ASSERT (From->Month <=12);\r
- \r
+\r
if (From->Year == To->Year) {\r
if (From->Month == To->Month) {\r
if ((From->Day + 1) == To->Day) {\r
Adjacent = TRUE;\r
}\r
}\r
- } else if (From->Day == DayOfMonth[From->Month - 1]) {\r
+ } else if (From->Day == mDayOfMonth[From->Month - 1]) {\r
if ((CompareHMS(From, To) >= 0)) {\r
Adjacent = TRUE;\r
}\r
return Adjacent;\r
}\r
\r
+/**\r
+ Get the century RTC address from the ACPI FADT table.\r
+\r
+ @return The century RTC address or 0 if not found.\r
+**/\r
+UINT8\r
+GetCenturyRtcAddress (\r
+ VOID\r
+ )\r
+{\r
+ EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
+\r
+ Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) EfiLocateFirstAcpiTable (\r
+ EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE\r
+ );\r
+\r
+ if ((Fadt != NULL) &&\r
+ (Fadt->Century > RTC_ADDRESS_REGISTER_D) && (Fadt->Century < 0x80)\r
+ ) {\r
+ return Fadt->Century;\r
+ } else {\r
+ return 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Notification function of ACPI Table change.\r
+\r
+ This is a notification function registered on ACPI Table change event.\r
+ It saves the Century address stored in ACPI FADT table.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PcRtcAcpiTableChangeCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_TIME Time;\r
+ UINT8 CenturyRtcAddress;\r
+ UINT8 Century;\r
+\r
+ CenturyRtcAddress = GetCenturyRtcAddress ();\r
+ if ((CenturyRtcAddress != 0) && (mModuleGlobal.CenturyRtcAddress != CenturyRtcAddress)) {\r
+ mModuleGlobal.CenturyRtcAddress = CenturyRtcAddress;\r
+ Status = PcRtcGetTime (&Time, NULL, &mModuleGlobal);\r
+ if (!EFI_ERROR (Status)) {\r
+ Century = (UINT8) (Time.Year / 100);\r
+ Century = DecimalToBcd8 (Century);\r
+ DEBUG ((EFI_D_INFO, "PcRtc: Write 0x%x to CMOS location 0x%x\n", Century, mModuleGlobal.CenturyRtcAddress));\r
+ RtcWrite (mModuleGlobal.CenturyRtcAddress, Century);\r
+ }\r
+ }\r
+}\r