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