--- /dev/null
+/** @file\r
+ FDT client library for motorola,mc146818 RTC driver\r
+\r
+ Copyright (c) 2020, ARM Limited. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Protocol/FdtClient.h>\r
+\r
+/** RTC Index register is at offset 0x0\r
+*/\r
+#define RTC_INDEX_REG_OFFSET 0x0ULL\r
+\r
+/** RTC Target register is at offset 0x1\r
+*/\r
+#define RTC_TARGET_REG_OFFSET 0x1ULL\r
+\r
+/** Add the RTC controller address range to the memory map.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] RtcPageBase Base address of the RTC controller.\r
+\r
+ @retval EFI_SUCCESS Success.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND Flash device not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+KvmtoolRtcMapMemory (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_PHYSICAL_ADDRESS RtcPageBase\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gDS->AddMemorySpace (\r
+ EfiGcdMemoryTypeMemoryMappedIo,\r
+ RtcPageBase,\r
+ EFI_PAGE_SIZE,\r
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR, "Failed to add memory space. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ Status = gDS->AllocateMemorySpace (\r
+ EfiGcdAllocateAddress,\r
+ EfiGcdMemoryTypeMemoryMappedIo,\r
+ 0,\r
+ EFI_PAGE_SIZE,\r
+ &RtcPageBase,\r
+ ImageHandle,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "Failed to allocate memory space. Status = %r\n",\r
+ Status\r
+ ));\r
+ gDS->RemoveMemorySpace (\r
+ RtcPageBase,\r
+ EFI_PAGE_SIZE\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ Status = gDS->SetMemorySpaceAttributes (\r
+ RtcPageBase,\r
+ EFI_PAGE_SIZE,\r
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "Failed to set memory attributes. Status = %r\n",\r
+ Status\r
+ ));\r
+ gDS->FreeMemorySpace (\r
+ RtcPageBase,\r
+ EFI_PAGE_SIZE\r
+ );\r
+ gDS->RemoveMemorySpace (\r
+ RtcPageBase,\r
+ EFI_PAGE_SIZE\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/** Entrypoint for KvmtoolRtcFdtClientLib.\r
+\r
+ Locate the RTC node in the DT and update the Index and\r
+ Target register base addresses in the respective PCDs.\r
+ Add the RTC memory region to the memory map.\r
+ Disable the RTC node as the RTC is owned by UEFI.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS Success.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND Flash device not found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+KvmtoolRtcFdtClientLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FDT_CLIENT_PROTOCOL *FdtClient;\r
+ INT32 Node;\r
+ CONST UINT32 *Reg;\r
+ UINT32 RegSize;\r
+ UINT64 RegBase;\r
+ UINT64 Range;\r
+ RETURN_STATUS PcdStatus;\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gFdtClientProtocolGuid,\r
+ NULL,\r
+ (VOID **)&FdtClient\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = FdtClient->FindCompatibleNode (\r
+ FdtClient,\r
+ "motorola,mc146818",\r
+ &Node\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: No 'motorola,mc146818' compatible DT node found\n",\r
+ __FUNCTION__\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ Status = FdtClient->GetNodeProperty (\r
+ FdtClient,\r
+ Node,\r
+ "reg",\r
+ (CONST VOID **)&Reg,\r
+ &RegSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: No 'reg' property found in 'motorola,mc146818' compatible DT node\n",\r
+ __FUNCTION__\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ ASSERT (RegSize == 16);\r
+\r
+ RegBase = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));\r
+ Range = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "Found motorola,mc146818 RTC @ 0x%Lx Range = 0x%x\n",\r
+ RegBase,\r
+ Range\r
+ ));\r
+\r
+ // The address range must cover the RTC Index and the Target registers.\r
+ ASSERT (Range >= 0x2);\r
+\r
+ // RTC Index register is at offset 0x0\r
+ PcdStatus = PcdSet64S (\r
+ PcdRtcIndexRegister64,\r
+ (RegBase + RTC_INDEX_REG_OFFSET)\r
+ );\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+ // RTC Target register is at offset 0x1\r
+ PcdStatus = PcdSet64S (\r
+ PcdRtcTargetRegister64,\r
+ (RegBase + RTC_TARGET_REG_OFFSET)\r
+ );\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+ Status = KvmtoolRtcMapMemory (ImageHandle, (RegBase & ~EFI_PAGE_MASK));\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "Failed to map memory for motorola,mc146818. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // UEFI takes ownership of the RTC hardware, and exposes its functionality\r
+ // through the UEFI Runtime Services GetTime, SetTime, etc. This means we\r
+ // need to disable it in the device tree to prevent the OS from attaching\r
+ // its device driver as well.\r
+ //\r
+ Status = FdtClient->SetNodeProperty (\r
+ FdtClient,\r
+ Node,\r
+ "status",\r
+ "disabled",\r
+ sizeof ("disabled")\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_WARN,\r
+ "Failed to set motorola,mc146818 status to 'disabled', Status = %r\n",\r
+ Status\r
+ ));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r