/** @file\r
Implement EFI RealTimeClock runtime services via RTC Lib.\r
\r
- Currently this driver does not support runtime virtual calling.\r
-\r
Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
- Copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2011 - 2014, ARM 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
#include <Library/MemoryAllocationLib.h>\r
#include <Library/PcdLib.h>\r
#include <Library/ArmPlatformSysConfigLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
#include <Library/UefiBootServicesTableLib.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 <ArmPlatform.h>\r
\r
-STATIC CONST CHAR16 mTimeZoneVariableName[] = L"PL031RtcTimeZone";\r
-STATIC CONST CHAR16 mDaylightVariableName[] = L"PL031RtcDaylight";\r
-STATIC BOOLEAN mPL031Initialized = FALSE;\r
+STATIC CONST CHAR16 mTimeZoneVariableName[] = L"PL031RtcTimeZone";\r
+STATIC CONST CHAR16 mDaylightVariableName[] = L"PL031RtcDaylight";\r
+STATIC BOOLEAN mPL031Initialized = FALSE;\r
+STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;\r
+STATIC UINTN mPL031RtcBase;\r
+STATIC EFI_RUNTIME_SERVICES *mRT;\r
\r
EFI_STATUS\r
IdentifyPL031 (\r
EFI_STATUS Status;\r
\r
// Check if this is a PrimeCell Peripheral\r
- if ( (MmioRead8 (PL031_RTC_PCELL_ID0) != 0x0D)\r
- || (MmioRead8 (PL031_RTC_PCELL_ID1) != 0xF0)\r
- || (MmioRead8 (PL031_RTC_PCELL_ID2) != 0x05)\r
- || (MmioRead8 (PL031_RTC_PCELL_ID3) != 0xB1)) {\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
Status = EFI_NOT_FOUND;\r
goto EXIT;\r
}\r
\r
// Check if this PrimeCell Peripheral is the PL031 Real Time Clock\r
- if ( (MmioRead8 (PL031_RTC_PERIPH_ID0) != 0x31)\r
- || (MmioRead8 (PL031_RTC_PERIPH_ID1) != 0x10)\r
- || ((MmioRead8 (PL031_RTC_PERIPH_ID2) & 0xF) != 0x04)\r
- || (MmioRead8 (PL031_RTC_PERIPH_ID3) != 0x00)) {\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
Status = EFI_NOT_FOUND;\r
goto EXIT;\r
}\r
}\r
\r
// Ensure interrupts are masked. We do not want RTC interrupts in UEFI\r
- if ((MmioRead32 (PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER) & PL031_SET_IRQ_MASK) != PL031_SET_IRQ_MASK) {\r
- MmioOr32 (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) != PL031_SET_IRQ_MASK) {\r
+ MmioOr32 (mPL031RtcBase + PL031_RTC_IMSC_IRQ_MASK_SET_CLEAR_REGISTER, PL031_SET_IRQ_MASK);\r
}\r
\r
// Clear any existing interrupts\r
- if ((MmioRead32 (PL031_RTC_RIS_RAW_IRQ_STATUS_REGISTER) & PL031_IRQ_TRIGGERED) == PL031_IRQ_TRIGGERED) {\r
- MmioOr32 (PL031_RTC_ICR_IRQ_CLEAR_REGISTER, PL031_CLEAR_IRQ);\r
+ if ((MmioRead32 (mPL031RtcBase + PL031_RTC_RIS_RAW_IRQ_STATUS_REGISTER) & PL031_IRQ_TRIGGERED) == PL031_IRQ_TRIGGERED) {\r
+ MmioOr32 (mPL031RtcBase + PL031_RTC_ICR_IRQ_CLEAR_REGISTER, PL031_CLEAR_IRQ);\r
}\r
\r
// Start the clock counter\r
- if ((MmioRead32 (PL031_RTC_CR_CONTROL_REGISTER) & PL031_RTC_ENABLED) != PL031_RTC_ENABLED) {\r
- MmioOr32 (PL031_RTC_CR_CONTROL_REGISTER, PL031_RTC_ENABLED);\r
+ if ((MmioRead32 (mPL031RtcBase + PL031_RTC_CR_CONTROL_REGISTER) & PL031_RTC_ENABLED) != PL031_RTC_ENABLED) {\r
+ MmioOr32 (mPL031RtcBase + PL031_RTC_CR_CONTROL_REGISTER, PL031_RTC_ENABLED);\r
}\r
\r
mPL031Initialized = TRUE;\r
IN EFI_TIME *Time\r
)\r
{\r
- INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
+ STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
\r
if (Time->Day < 1 ||\r
Time->Day > DayOfMonth[Time->Month - 1] ||\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 (PL031_RTC_DR_DATA_REGISTER);\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
} 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 (PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
+ MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
}\r
\r
// Ensure Time is a valid pointer\r
\r
// Get the current time zone information from non-volatile storage\r
Size = sizeof (TimeZone);\r
- Status = gRT->GetVariable (\r
+ Status = mRT->GetVariable (\r
(CHAR16 *)mTimeZoneVariableName,\r
&gEfiCallerIdGuid,\r
NULL,\r
// The time zone variable does not exist in non-volatile storage, so create it.\r
Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
// Store it\r
- Status = gRT->SetVariable (\r
+ Status = mRT->SetVariable (\r
(CHAR16 *)mTimeZoneVariableName,\r
&gEfiCallerIdGuid,\r
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
\r
// Get the current daylight information from non-volatile storage\r
Size = sizeof (Daylight);\r
- Status = gRT->GetVariable (\r
+ Status = mRT->GetVariable (\r
(CHAR16 *)mDaylightVariableName,\r
&gEfiCallerIdGuid,\r
NULL,\r
// The daylight variable does not exist in non-volatile storage, so create it.\r
Time->Daylight = 0;\r
// Store it\r
- Status = gRT->SetVariable (\r
+ Status = mRT->SetVariable (\r
(CHAR16 *)mDaylightVariableName,\r
&gEfiCallerIdGuid,\r
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
\r
\r
// Set the PL031\r
- MmioWrite32 (PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
+ MmioWrite32 (mPL031RtcBase + PL031_RTC_LR_LOAD_REGISTER, EpochSeconds);\r
\r
// The accesses to Variable Services can be very slow, because we may be writing to Flash.\r
// Do this after having set the RTC.\r
\r
// Save the current time zone information into non-volatile storage\r
- Status = gRT->SetVariable (\r
+ Status = mRT->SetVariable (\r
(CHAR16 *)mTimeZoneVariableName,\r
&gEfiCallerIdGuid,\r
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
}\r
\r
// Save the current daylight information into non-volatile storage\r
- Status = gRT->SetVariable (\r
+ Status = mRT->SetVariable (\r
(CHAR16 *)mDaylightVariableName,\r
&gEfiCallerIdGuid,\r
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
return EFI_UNSUPPORTED;\r
}\r
\r
+/**\r
+ Fixup internal data so that EFI can be call in virtual mode.\r
+ Call the passed in Child Notify event and convert any pointers in\r
+ lib to virtual mode.\r
\r
+ @param[in] Event The Event that is being processed\r
+ @param[in] Context Event Context\r
+**/\r
+VOID\r
+EFIAPI\r
+LibRtcVirtualNotifyEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ //\r
+ // Only needed if you are going to support the OS calling RTC functions in virtual mode.\r
+ // You will need to call EfiConvertPointer (). To convert any stored physical addresses\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**)&mRT);\r
+ return;\r
+}\r
\r
/**\r
This is the declaration of an EFI image entry point. This can be the entry point to an application\r
EFI_STATUS Status;\r
EFI_HANDLE Handle;\r
\r
+ // Initialize RTC Base Address\r
+ mPL031RtcBase = PcdGet32 (PcdPL031RtcBase);\r
+\r
+ // Declare the controller as EFI_MEMORY_RUNTIME\r
+ Status = gDS->AddMemorySpace (\r
+ EfiGcdMemoryTypeMemoryMappedIo,\r
+ mPL031RtcBase, SIZE_4KB,\r
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gDS->SetMemorySpaceAttributes (mPL031RtcBase, SIZE_4KB, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
// Setup the setters and getters\r
gRT->GetTime = LibGetTime;\r
gRT->SetTime = LibSetTime;\r
gRT->GetWakeupTime = LibGetWakeupTime;\r
gRT->SetWakeupTime = LibSetWakeupTime;\r
\r
+ mRT = gRT;\r
+\r
// Install the protocol\r
Handle = NULL;\r
Status = gBS->InstallMultipleProtocolInterfaces (\r
&gEfiRealTimeClockArchProtocolGuid, NULL,\r
NULL\r
);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Fixup internal data so that EFI can be call in virtual mode.\r
- Call the passed in Child Notify event and convert any pointers in\r
- lib to virtual mode.\r
-\r
- @param[in] Event The Event that is being processed\r
- @param[in] Context Event Context\r
-**/\r
-VOID\r
-EFIAPI\r
-LibRtcVirtualNotifyEvent (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
//\r
- // Only needed if you are going to support the OS calling RTC functions in virtual mode.\r
- // You will need to call EfiConvertPointer (). To convert any stored physical addresses\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
+ // Register for the virtual address change event\r
//\r
- return;\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ LibRtcVirtualNotifyEvent,\r
+ NULL,\r
+ &gEfiEventVirtualAddressChangeGuid,\r
+ &mRtcVirtualAddrChangeEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
}\r