|
@@ -0,0 +1,335 @@
|
|
|
+/** @file
|
|
|
+ Implement EFI RealTimeClock runtime services via RTC Lib.
|
|
|
+
|
|
|
+ Copyright (c) 2022, Loongson Limited. All rights reserved.
|
|
|
+
|
|
|
+ SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
+
|
|
|
+**/
|
|
|
+
|
|
|
+#include <Uefi.h>
|
|
|
+#include <PiDxe.h>
|
|
|
+
|
|
|
+#include <Guid/EventGroup.h>
|
|
|
+#include <Guid/GlobalVariable.h>
|
|
|
+
|
|
|
+#include <Library/BaseLib.h>
|
|
|
+#include <Library/DebugLib.h>
|
|
|
+#include <Library/DxeServicesTableLib.h>
|
|
|
+#include <Library/IoLib.h>
|
|
|
+#include <Library/MemoryAllocationLib.h>
|
|
|
+#include <Library/PcdLib.h>
|
|
|
+#include <Library/RealTimeClockLib.h>
|
|
|
+#include <Library/TimeBaseLib.h>
|
|
|
+#include <Library/UefiBootServicesTableLib.h>
|
|
|
+#include <Library/UefiRuntimeServicesTableLib.h>
|
|
|
+#include <Library/UefiRuntimeLib.h>
|
|
|
+#include <Protocol/RealTimeClock.h>
|
|
|
+#include "LsRealTimeClock.h"
|
|
|
+
|
|
|
+STATIC BOOLEAN mInitialized = FALSE;
|
|
|
+STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;
|
|
|
+STATIC UINTN mRtcBase;
|
|
|
+/*
|
|
|
+ Enable Real-time clock.
|
|
|
+
|
|
|
+ @param VOID
|
|
|
+
|
|
|
+ @retval VOID
|
|
|
+ */
|
|
|
+VOID
|
|
|
+InitRtc (
|
|
|
+ VOID
|
|
|
+ )
|
|
|
+{
|
|
|
+ UINTN Val;
|
|
|
+
|
|
|
+ if (!mInitialized) {
|
|
|
+ /* enable rtc */
|
|
|
+ mRtcBase = (UINTN)PcdGet64 (PcdRtcBaseAddress);
|
|
|
+ Val = MmioRead32 (mRtcBase + RTC_CTRL_REG);
|
|
|
+ Val |= TOY_ENABLE_BIT | OSC_ENABLE_BIT;
|
|
|
+ MmioWrite32 (mRtcBase + RTC_CTRL_REG, Val);
|
|
|
+ mInitialized = TRUE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Returns the current time and date information, and the time-keeping capabilities
|
|
|
+ of the hardware platform.
|
|
|
+
|
|
|
+ @param Time A pointer to storage to receive a snapshot of the current time.
|
|
|
+ @param Capabilities An optional pointer to a buffer to receive the real time clock
|
|
|
+ device's capabilities.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The operation completed successfully.
|
|
|
+ @retval EFI_INVALID_PARAMETER Time is NULL.
|
|
|
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
|
|
|
+ @retval EFI_SECURITY_VIOLATION The time could not be retrieved due to an authentication failure.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+LibGetTime (
|
|
|
+ OUT EFI_TIME *Time,
|
|
|
+ OUT EFI_TIME_CAPABILITIES *Capabilities
|
|
|
+ )
|
|
|
+{
|
|
|
+ UINT32 Val;
|
|
|
+
|
|
|
+ // Ensure Time is a valid pointer
|
|
|
+ if (Time == NULL) {
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+ }
|
|
|
+
|
|
|
+ Val = MmioRead32 (mRtcBase + TOY_READ1_REG);
|
|
|
+ Time->Year = Val + 1900;
|
|
|
+
|
|
|
+ Val = MmioRead32 (mRtcBase + TOY_READ0_REG);
|
|
|
+ Time->Month = (Val >> TOY_MON_SHIFT) & TOY_MON_MASK;
|
|
|
+ Time->Day = (Val >> TOY_DAY_SHIFT) & TOY_DAY_MASK;
|
|
|
+ Time->Hour = (Val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK;
|
|
|
+ Time->Minute = (Val >> TOY_MIN_SHIFT) & TOY_MIN_MASK;
|
|
|
+ Time->Second = (Val >> TOY_SEC_SHIFT) & TOY_SEC_MASK;
|
|
|
+ Time->Nanosecond = 0;
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Sets the current local time and date information.
|
|
|
+
|
|
|
+ @param Time A pointer to the current time.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The operation completed successfully.
|
|
|
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
|
|
|
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+LibSetTime (
|
|
|
+ IN EFI_TIME *Time
|
|
|
+ )
|
|
|
+{
|
|
|
+ UINT32 Val;
|
|
|
+
|
|
|
+ // Initialize the hardware if not already done
|
|
|
+
|
|
|
+ Val = 0;
|
|
|
+ Val |= (Time->Second << TOY_SEC_SHIFT);
|
|
|
+ Val |= (Time->Minute << TOY_MIN_SHIFT);
|
|
|
+ Val |= (Time->Hour << TOY_HOUR_SHIFT);
|
|
|
+ Val |= (Time->Day << TOY_DAY_SHIFT);
|
|
|
+ Val |= (Time->Month << TOY_MON_SHIFT);
|
|
|
+ MmioWrite32 (mRtcBase + TOY_WRITE0_REG, Val);
|
|
|
+
|
|
|
+ Val = Time->Year - 1900;
|
|
|
+ MmioWrite32 (mRtcBase + TOY_WRITE1_REG, Val);
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Returns the current wakeup alarm clock setting.
|
|
|
+
|
|
|
+ @param Enabled Indicates if the alarm is currently enabled or disabled.
|
|
|
+ @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
|
|
|
+ @param Time The current alarm setting.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The alarm settings were returned.
|
|
|
+ @retval EFI_INVALID_PARAMETER Any parameter is NULL.
|
|
|
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+LibGetWakeupTime (
|
|
|
+ OUT BOOLEAN *Enabled,
|
|
|
+ OUT BOOLEAN *Pending,
|
|
|
+ OUT EFI_TIME *Time
|
|
|
+ )
|
|
|
+{
|
|
|
+ // Not a required feature
|
|
|
+ return EFI_UNSUPPORTED;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Sets the system wakeup alarm clock time.
|
|
|
+
|
|
|
+ @param Enabled Enable or disable the wakeup alarm.
|
|
|
+ @param Time If Enable is TRUE, the time to set the wakeup alarm for.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
|
|
|
+ Enable is FALSE, then the wakeup alarm was disabled.
|
|
|
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
|
|
|
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
|
|
|
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+LibSetWakeupTime (
|
|
|
+ IN BOOLEAN Enabled,
|
|
|
+ OUT EFI_TIME *Time
|
|
|
+ )
|
|
|
+{
|
|
|
+ // Not a required feature
|
|
|
+ return EFI_UNSUPPORTED;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Fixup internal data so that EFI can be call in virtual mode.
|
|
|
+ Call the passed in Child Notify event and convert any pointers in
|
|
|
+ lib to virtual mode.
|
|
|
+
|
|
|
+ @param[in] Event The Event that is being processed
|
|
|
+ @param[in] Context Event Context
|
|
|
+**/
|
|
|
+VOID
|
|
|
+EFIAPI
|
|
|
+LibRtcVirtualNotifyEvent (
|
|
|
+ IN EFI_EVENT Event,
|
|
|
+ IN VOID *Context
|
|
|
+ )
|
|
|
+{
|
|
|
+ //
|
|
|
+ // Only needed if you are going to support the OS calling RTC functions in virtual mode.
|
|
|
+ // You will need to call EfiConvertPointer (). To convert any stored physical addresses
|
|
|
+ // to virtual address. After the OS transitions to calling in virtual mode, all future
|
|
|
+ // runtime calls will be made in virtual mode.
|
|
|
+ //
|
|
|
+ EfiConvertPointer (0x0, (VOID**)&mRtcBase);
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+/** Add the RTC controller address range to the memory map.
|
|
|
+
|
|
|
+ @param [in] ImageHandle The handle to the image.
|
|
|
+ @param [in] RtcPageBase Base address of the RTC controller.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS Success.
|
|
|
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
|
|
|
+ @retval EFI_NOT_FOUND Flash device not found.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+KvmtoolRtcMapMemory (
|
|
|
+ IN EFI_HANDLE ImageHandle,
|
|
|
+ IN EFI_PHYSICAL_ADDRESS RtcPageBase
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+
|
|
|
+ Status = gDS->AddMemorySpace (
|
|
|
+ EfiGcdMemoryTypeMemoryMappedIo,
|
|
|
+ RtcPageBase,
|
|
|
+ EFI_PAGE_SIZE,
|
|
|
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
|
|
|
+ );
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ DEBUG ((
|
|
|
+ DEBUG_ERROR, "Failed to add memory space. Status = %r\n",
|
|
|
+ Status
|
|
|
+ ));
|
|
|
+ return Status;
|
|
|
+ }
|
|
|
+
|
|
|
+ Status = gDS->AllocateMemorySpace (
|
|
|
+ EfiGcdAllocateAddress,
|
|
|
+ EfiGcdMemoryTypeMemoryMappedIo,
|
|
|
+ 0,
|
|
|
+ EFI_PAGE_SIZE,
|
|
|
+ &RtcPageBase,
|
|
|
+ ImageHandle,
|
|
|
+ NULL
|
|
|
+ );
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ DEBUG ((
|
|
|
+ DEBUG_ERROR,
|
|
|
+ "Failed to allocate memory space. Status = %r\n",
|
|
|
+ Status
|
|
|
+ ));
|
|
|
+ gDS->RemoveMemorySpace (
|
|
|
+ RtcPageBase,
|
|
|
+ EFI_PAGE_SIZE
|
|
|
+ );
|
|
|
+ return Status;
|
|
|
+ }
|
|
|
+
|
|
|
+ Status = gDS->SetMemorySpaceAttributes (
|
|
|
+ RtcPageBase,
|
|
|
+ EFI_PAGE_SIZE,
|
|
|
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
|
|
|
+ );
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ DEBUG ((
|
|
|
+ DEBUG_ERROR,
|
|
|
+ "Failed to set memory attributes. Status = %r\n",
|
|
|
+ Status
|
|
|
+ ));
|
|
|
+
|
|
|
+ gDS->FreeMemorySpace (
|
|
|
+ RtcPageBase,
|
|
|
+ EFI_PAGE_SIZE
|
|
|
+ );
|
|
|
+
|
|
|
+ gDS->RemoveMemorySpace (
|
|
|
+ RtcPageBase,
|
|
|
+ EFI_PAGE_SIZE
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ return Status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ This is the declaration of an EFI image entry point. This can be the entry point to an application
|
|
|
+ written to this specification, an EFI boot service driver, or an EFI runtime driver.
|
|
|
+
|
|
|
+ @param ImageHandle Handle that identifies the loaded image.
|
|
|
+ @param SystemTable System Table for this image.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The operation completed successfully.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+LibRtcInitialize (
|
|
|
+ IN EFI_HANDLE ImageHandle,
|
|
|
+ IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+ EFI_HANDLE Handle;
|
|
|
+
|
|
|
+ InitRtc ();
|
|
|
+ Status = KvmtoolRtcMapMemory (ImageHandle, (mRtcBase & ~EFI_PAGE_MASK));
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ DEBUG ((
|
|
|
+ DEBUG_ERROR,
|
|
|
+ "Failed to map memory for loongson 7A RTC. Status = %r\n",
|
|
|
+ Status
|
|
|
+ ));
|
|
|
+ return Status;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Setup the setters and getters
|
|
|
+ gRT->GetTime = LibGetTime;
|
|
|
+ gRT->SetTime = LibSetTime;
|
|
|
+
|
|
|
+ // Install the protocol
|
|
|
+ Handle = NULL;
|
|
|
+ Status = gBS->InstallMultipleProtocolInterfaces (
|
|
|
+ &Handle,
|
|
|
+ &gEfiRealTimeClockArchProtocolGuid, NULL,
|
|
|
+ NULL
|
|
|
+ );
|
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
|
+
|
|
|
+ //
|
|
|
+ // Register for the virtual address change event
|
|
|
+ //
|
|
|
+ Status = gBS->CreateEventEx (
|
|
|
+ EVT_NOTIFY_SIGNAL,
|
|
|
+ TPL_NOTIFY,
|
|
|
+ LibRtcVirtualNotifyEvent,
|
|
|
+ NULL,
|
|
|
+ &gEfiEventVirtualAddressChangeGuid,
|
|
|
+ &mRtcVirtualAddrChangeEvent
|
|
|
+ );
|
|
|
+ ASSERT_EFI_ERROR (Status);
|
|
|
+ return Status;
|
|
|
+}
|