PcAtChipsetPkg: Add MMIO Support to RTC driver

Some virtual machine managers like Kvmtool emulate the MC146818
RTC controller in the MMIO space so that architectures that do
not support I/O Mapped I/O can use the RTC. This patch adds MMIO
support to the RTC controller driver.

The PCD PcdRtcUseMmio has been added to select I/O or MMIO support.
  If PcdRtcUseMmio is:
    TRUE  - Indicates the RTC port registers are in MMIO space.
    FALSE - Indicates the RTC port registers are in I/O space.
            Default is I/O space.

Additionally two new PCDs PcdRtcIndexRegister64 and
PcdRtcTargetRegister64 have been introduced to provide the base
address for the RTC registers in the MMIO space.

When MMIO support is selected (PcdRtcUseMmio == TRUE) the driver
converts the pointers to the RTC MMIO registers so that the
RTC registers are accessible post ExitBootServices.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
Sami Mujawar 2020-10-02 22:13:55 +01:00 committed by mergify[bot]
parent a7d977040b
commit 015be4075f
4 changed files with 187 additions and 13 deletions

View File

@ -6,6 +6,7 @@
#
# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
# Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@ -41,6 +42,13 @@
# @Prompt Configure HPET to use MSI.
gPcAtChipsetPkgTokenSpaceGuid.PcdHpetMsiEnable|TRUE|BOOLEAN|0x00001000
## Indicates the RTC port registers are in MMIO space, or in I/O space.
# Default is I/O space.<BR><BR>
# TRUE - RTC port registers are in MMIO space.<BR>
# FALSE - RTC port registers are in I/O space.<BR>
# @Prompt RTC port registers use MMIO.
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio|FALSE|BOOLEAN|0x00000021
[PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx, PcdsPatchableInModule]
## This PCD specifies the base address of the HPET timer.
# @Prompt HPET base address.
@ -68,6 +76,14 @@
# @Expression 0x80000001 | gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear < gPcAtChipsetPkgTokenSpaceGuid.PcdMinimalValidYear + 100
gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear|2097|UINT16|0x0000000E
## Specifies RTC Index Register address in MMIO space.
# @Prompt RTC Index Register address
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister64|0x0|UINT64|0x00000022
## Specifies RTC Target Register address in MMIO space.
# @Prompt RTC Target Register address
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister64|0x0|UINT64|0x00000023
[PcdsFixedAtBuild, PcdsPatchableInModule]
## Defines the ACPI register set base address.
# The invalid 0xFFFF is as its default value. It must be configured to the real value.

View File

@ -3,6 +3,7 @@
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@ -10,6 +11,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "PcRtc.h"
extern UINTN mRtcIndexRegister;
extern UINTN mRtcTargetRegister;
//
// Days of month.
//
@ -54,38 +58,132 @@ IsWithinOneDay (
);
/**
Read RTC content through its registers.
Read RTC content through its registers using IO access.
@param Address Address offset of RTC. It is recommended to use macros such as
RTC_ADDRESS_SECONDS.
@param Address Address offset of RTC. It is recommended to use
macros such as RTC_ADDRESS_SECONDS.
@return The data of UINT8 type read from RTC.
**/
STATIC
UINT8
RtcRead (
IN UINT8 Address
IoRtcRead (
IN UINTN Address
)
{
IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
IoWrite8 (
PcdGet8 (PcdRtcIndexRegister),
(UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80))
);
return IoRead8 (PcdGet8 (PcdRtcTargetRegister));
}
/**
Write RTC through its registers using IO access.
@param Address Address offset of RTC. It is recommended to use
macros such as RTC_ADDRESS_SECONDS.
@param Data The content you want to write into RTC.
**/
STATIC
VOID
IoRtcWrite (
IN UINTN Address,
IN UINT8 Data
)
{
IoWrite8 (
PcdGet8 (PcdRtcIndexRegister),
(UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80))
);
IoWrite8 (PcdGet8 (PcdRtcTargetRegister), Data);
}
/**
Read RTC content through its registers using MMIO access.
@param Address Address offset of RTC. It is recommended to use
macros such as RTC_ADDRESS_SECONDS.
@return The data of UINT8 type read from RTC.
**/
STATIC
UINT8
MmioRtcRead (
IN UINTN Address
)
{
MmioWrite8 (
mRtcIndexRegister,
(UINT8)(Address | (UINT8)(MmioRead8 (mRtcIndexRegister) & 0x80))
);
return MmioRead8 (mRtcTargetRegister);
}
/**
Write RTC through its registers using MMIO access.
@param Address Address offset of RTC. It is recommended to use
macros such as RTC_ADDRESS_SECONDS.
@param Data The content you want to write into RTC.
**/
STATIC
VOID
MmioRtcWrite (
IN UINTN Address,
IN UINT8 Data
)
{
MmioWrite8 (
mRtcIndexRegister,
(UINT8)(Address | (UINT8)(MmioRead8 (mRtcIndexRegister) & 0x80))
);
MmioWrite8 (mRtcTargetRegister, Data);
}
/**
Read RTC content through its registers.
@param Address Address offset of RTC. It is recommended to use
macros such as RTC_ADDRESS_SECONDS.
@return The data of UINT8 type read from RTC.
**/
STATIC
UINT8
RtcRead (
IN UINTN Address
)
{
if (FeaturePcdGet (PcdRtcUseMmio)) {
return MmioRtcRead (Address);
}
return IoRtcRead (Address);
}
/**
Write RTC through its registers.
@param Address Address offset of RTC. It is recommended to use macros such as
RTC_ADDRESS_SECONDS.
@param Data The content you want to write into RTC.
@param Address Address offset of RTC. It is recommended to use
macros such as RTC_ADDRESS_SECONDS.
@param Data The content you want to write into RTC.
**/
STATIC
VOID
RtcWrite (
IN UINT8 Address,
IN UINTN Address,
IN UINT8 Data
)
{
IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
IoWrite8 (PcdGet8 (PcdRtcTargetRegister), Data);
if (FeaturePcdGet (PcdRtcUseMmio)) {
MmioRtcWrite (Address, Data);
} else {
IoRtcWrite (Address, Data);
}
}
/**

View File

@ -2,16 +2,23 @@
Provides Set/Get time operations.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/DxeServicesTableLib.h>
#include "PcRtc.h"
PC_RTC_MODULE_GLOBALS mModuleGlobal;
EFI_HANDLE mHandle = NULL;
STATIC EFI_EVENT mVirtualAddrChangeEvent;
UINTN mRtcIndexRegister;
UINTN mRtcTargetRegister;
/**
Returns the current time and date information, and the time-keeping capabilities
of the hardware platform.
@ -105,6 +112,30 @@ PcRtcEfiSetWakeupTime (
return PcRtcSetWakeupTime (Enabled, Time, &mModuleGlobal);
}
/**
Fixup internal data so that EFI can be called 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**)&mRtcIndexRegister);
EfiConvertPointer (0x0, (VOID**)&mRtcTargetRegister);
}
/**
The user Entry Point for PcRTC module.
@ -131,6 +162,11 @@ InitializePcRtc (
EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_CALLBACK);
mModuleGlobal.CenturyRtcAddress = GetCenturyRtcAddress ();
if (FeaturePcdGet (PcdRtcUseMmio)) {
mRtcIndexRegister = (UINTN)PcdGet64 (PcdRtcIndexRegister64);
mRtcTargetRegister = (UINTN)PcdGet64 (PcdRtcTargetRegister64);
}
Status = PcRtcInit (&mModuleGlobal);
ASSERT_EFI_ERROR (Status);
@ -165,7 +201,23 @@ InitializePcRtc (
NULL,
NULL
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return Status;
}
if (FeaturePcdGet (PcdRtcUseMmio)) {
// Register for the virtual address change event
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
LibRtcVirtualNotifyEvent,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&mVirtualAddrChangeEvent
);
ASSERT_EFI_ERROR (Status);
}
return Status;
}

View File

@ -6,6 +6,7 @@
#
# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
# Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@ -61,6 +62,11 @@
## SOMETIMES_CONSUMES ## SystemTable
gEfiAcpiTableGuid
gEfiEventVirtualAddressChangeGuid
[FeaturePcd]
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio ## CONSUMES
[FixedPcd]
gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterA ## CONSUMES
gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterB ## CONSUMES
@ -72,6 +78,8 @@
gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear ## CONSUMES
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister ## CONSUMES
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister ## CONSUMES
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister64 ## CONSUMES
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister64 ## CONSUMES
[Depex]
gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid