Implement EFI RealTimeClock runtime services via RTC Lib.\r
\r
Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
- Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>\r
+ Copyright (c) 2019, Linaro Ltd. All rights reserved.<BR>\r
\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
-\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 <Uefi.h>\r
#include <PiDxe.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/GlobalVariable.h>\r
+\r
#include <Library/BaseLib.h>\r
#include <Library/DebugLib.h>\r
-#include <Library/UefiLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
#include <Library/IoLib.h>\r
-#include <Library/RealTimeClockLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/PcdLib.h>\r
-#include <Library/ArmPlatformSysConfigLib.h>\r
-#include <Library/DxeServicesTableLib.h>\r
+#include <Library/RealTimeClockLib.h>\r
+#include <Library/TimeBaseLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
#include <Library/UefiRuntimeServicesTableLib.h>\r
#include <Library/UefiRuntimeLib.h>\r
\r
#include <Protocol/RealTimeClock.h>\r
\r
-#include <Guid/GlobalVariable.h>\r
-#include <Guid/EventGroup.h>\r
-\r
-#include <Drivers/PL031RealTimeClock.h>\r
-\r
-#include <Library/TimeBaseLib.h>\r
-\r
-#include <ArmPlatform.h>\r
+#include "PL031RealTimeClock.h"\r
\r
-STATIC BOOLEAN mPL031Initialized = FALSE;\r
-STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;\r
-STATIC UINTN mPL031RtcBase;\r
+STATIC BOOLEAN mPL031Initialized = FALSE;\r
+STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;\r
+STATIC UINTN mPL031RtcBase;\r
\r
EFI_STATUS\r
IdentifyPL031 (\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
\r
// Check if this is a PrimeCell Peripheral\r
if ( (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID0) != 0x0D)\r
- || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID1) != 0xF0)\r
- || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID2) != 0x05)\r
- || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID3) != 0xB1)) {\r
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID1) != 0xF0)\r
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID2) != 0x05)\r
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PCELL_ID3) != 0xB1))\r
+ {\r
Status = EFI_NOT_FOUND;\r
goto EXIT;\r
}\r
\r
// Check if this PrimeCell Peripheral is the PL031 Real Time Clock\r
if ( (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID0) != 0x31)\r
- || (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID1) != 0x10)\r
- || ((MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID2) & 0xF) != 0x04)\r
- || (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID3) != 0x00)) {\r
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID1) != 0x10)\r
+ || ((MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID2) & 0xF) != 0x04)\r
+ || (MmioRead8 (mPL031RtcBase + PL031_RTC_PERIPH_ID3) != 0x00))\r
+ {\r
Status = EFI_NOT_FOUND;\r
goto EXIT;\r
}\r
\r
Status = EFI_SUCCESS;\r
\r
- EXIT:\r
+EXIT:\r
return Status;\r
}\r
\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
\r
// Prepare the hardware\r
- Status = IdentifyPL031();\r
+ Status = IdentifyPL031 ();\r
if (EFI_ERROR (Status)) {\r
goto EXIT;\r
}\r
\r
// Ensure interrupts are masked. We do not want RTC interrupts in UEFI\r
- if ((MmioRead32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER) & PL031_SET_IRQ_MASK) != PL031_SET_IRQ_MASK) {\r
- MmioOr32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER, PL031_SET_IRQ_MASK);\r
+ if ((MmioRead32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER) & PL031_SET_IRQ_MASK) != 0) {\r
+ MmioWrite32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER, 0);\r
}\r
\r
// Clear any existing interrupts\r
\r
mPL031Initialized = TRUE;\r
\r
- EXIT:\r
+EXIT:\r
return Status;\r
}\r
\r
EFI_STATUS\r
EFIAPI\r
LibGetTime (\r
- OUT EFI_TIME *Time,\r
- OUT EFI_TIME_CAPABILITIES *Capabilities\r
+ OUT EFI_TIME *Time,\r
+ OUT EFI_TIME_CAPABILITIES *Capabilities\r
)\r
{\r
- EFI_STATUS Status = EFI_SUCCESS;\r
+ EFI_STATUS Status;\r
UINT32 EpochSeconds;\r
\r
+ // Ensure Time is a valid pointer\r
+ if (Time == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
// Initialize the hardware if not already done\r
if (!mPL031Initialized) {\r
Status = InitializePL031 ();\r
}\r
}\r
\r
- // Snapshot the time as early in the function call as possible\r
- // On some platforms we may have access to a battery backed up hardware clock.\r
- // If such RTC exists try to use it first.\r
- Status = ArmPlatformSysConfigGet (SYS_CFG_RTC, &EpochSeconds);\r
- if (Status == EFI_UNSUPPORTED) {\r
- // Battery backed up hardware RTC does not exist, revert to PL031\r
- EpochSeconds = MmioRead32 (mPL031RtcBase + PL031_RTC_DR_DATA_REGISTER);\r
- Status = EFI_SUCCESS;\r
- } else if (EFI_ERROR (Status)) {\r
- // Battery backed up hardware RTC exists but could not be read due to error. Abort.\r
- return Status;\r
- } else {\r
- // Battery backed up hardware RTC exists and we read the time correctly from it.\r
- // Now sync the PL031 to the new time.\r
- MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
- }\r
-\r
- // Ensure Time is a valid pointer\r
- if (Time == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ EpochSeconds = MmioRead32 (mPL031RtcBase + PL031_RTC_DR_DATA_REGISTER);\r
\r
// Adjust for the correct time zone\r
+ // The timezone setting also reflects the DST setting of the clock\r
if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {\r
EpochSeconds += Time->TimeZone * SEC_PER_MIN;\r
- }\r
-\r
- // Adjust for the correct period\r
- if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
+ } else if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
// Convert to adjusted time, i.e. spring forwards one hour\r
EpochSeconds += SEC_PER_HOUR;\r
}\r
// Update the Capabilities info\r
if (Capabilities != NULL) {\r
// PL031 runs at frequency 1Hz\r
- Capabilities->Resolution = PL031_COUNTS_PER_SECOND;\r
+ Capabilities->Resolution = PL031_COUNTS_PER_SECOND;\r
// Accuracy in ppm multiplied by 1,000,000, e.g. for 50ppm set 50,000,000\r
- Capabilities->Accuracy = (UINT32)PcdGet32 (PcdPL031RtcPpmAccuracy);\r
+ Capabilities->Accuracy = (UINT32)PcdGet32 (PcdPL031RtcPpmAccuracy);\r
// FALSE: Setting the time does not clear the values below the resolution level\r
- Capabilities->SetsToZero = FALSE;\r
+ Capabilities->SetsToZero = FALSE;\r
}\r
\r
return EFI_SUCCESS;\r
}\r
\r
-\r
/**\r
Sets the current local time and date information.\r
\r
EFI_STATUS\r
EFIAPI\r
LibSetTime (\r
- IN EFI_TIME *Time\r
+ IN EFI_TIME *Time\r
)\r
{\r
EFI_STATUS Status;\r
- UINTN EpochSeconds;\r
+ UINT32 EpochSeconds;\r
\r
// Because the PL031 is a 32-bit counter counting seconds,\r
// the maximum time span is just over 136 years.\r
}\r
}\r
\r
- EpochSeconds = EfiTimeToEpoch (Time);\r
+ EpochSeconds = (UINT32)EfiTimeToEpoch (Time);\r
\r
// Adjust for the correct time zone, i.e. convert to UTC time zone\r
+ // The timezone setting also reflects the DST setting of the clock\r
if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {\r
EpochSeconds -= Time->TimeZone * SEC_PER_MIN;\r
- }\r
-\r
- // Adjust for the correct period\r
- if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
+ } else if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) {\r
// Convert to un-adjusted time, i.e. fall back one hour\r
EpochSeconds -= SEC_PER_HOUR;\r
}\r
\r
- // On some platforms we may have access to a battery backed up hardware clock.\r
- //\r
- // If such RTC exists then it must be updated first, before the PL031,\r
- // to minimise any time drift. This is important because the battery backed-up\r
- // RTC maintains the master time for the platform across reboots.\r
- //\r
- // If such RTC does not exist then the following function returns UNSUPPORTED.\r
- Status = ArmPlatformSysConfigSet (SYS_CFG_RTC, EpochSeconds);\r
- if ((EFI_ERROR (Status)) && (Status != EFI_UNSUPPORTED)){\r
- // Any status message except SUCCESS and UNSUPPORTED indicates a hardware failure.\r
- return Status;\r
- }\r
-\r
// Set the PL031\r
MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
\r
return EFI_SUCCESS;\r
}\r
\r
-\r
/**\r
Returns the current wakeup alarm clock setting.\r
\r
EFI_STATUS\r
EFIAPI\r
LibGetWakeupTime (\r
- OUT BOOLEAN *Enabled,\r
- OUT BOOLEAN *Pending,\r
- OUT EFI_TIME *Time\r
+ OUT BOOLEAN *Enabled,\r
+ OUT BOOLEAN *Pending,\r
+ OUT EFI_TIME *Time\r
)\r
{\r
// Not a required feature\r
return EFI_UNSUPPORTED;\r
}\r
\r
-\r
/**\r
Sets the system wakeup alarm clock time.\r
\r
EFI_STATUS\r
EFIAPI\r
LibSetWakeupTime (\r
- IN BOOLEAN Enabled,\r
- OUT EFI_TIME *Time\r
+ IN BOOLEAN Enabled,\r
+ OUT EFI_TIME *Time\r
)\r
{\r
// Not a required feature\r
VOID\r
EFIAPI\r
LibRtcVirtualNotifyEvent (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
)\r
{\r
//\r
// to virtual address. After the OS transitions to calling in virtual mode, all future\r
// runtime calls will be made in virtual mode.\r
//\r
- EfiConvertPointer (0x0, (VOID**)&mPL031RtcBase);\r
+ EfiConvertPointer (0x0, (VOID **)&mPL031RtcBase);\r
return;\r
}\r
\r
EFI_STATUS\r
EFIAPI\r
LibRtcInitialize (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_HANDLE Handle;\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
\r
// Initialize RTC Base Address\r
mPL031RtcBase = PcdGet32 (PcdPL031RtcBase);\r
// Declare the controller as EFI_MEMORY_RUNTIME\r
Status = gDS->AddMemorySpace (\r
EfiGcdMemoryTypeMemoryMappedIo,\r
- mPL031RtcBase, SIZE_4KB,\r
+ mPL031RtcBase,\r
+ SIZE_4KB,\r
EFI_MEMORY_UC | EFI_MEMORY_RUNTIME\r
);\r
if (EFI_ERROR (Status)) {\r
Handle = NULL;\r
Status = gBS->InstallMultipleProtocolInterfaces (\r
&Handle,\r
- &gEfiRealTimeClockArchProtocolGuid, NULL,\r
+ &gEfiRealTimeClockArchProtocolGuid,\r
+ NULL,\r
NULL\r
- );\r
+ );\r
ASSERT_EFI_ERROR (Status);\r
\r
//\r