On Tue, Mar 14, 2017 at 07:37:26PM +0100, Marcin Wojtas wrote:
This patch enables RTC library that allows to control the real time clock on Armada 7k/8k SoC's. It is possible both from within EDK2 and also from OS via RunTimeServices.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Marcin Wojtas mw@semihalf.com
.../Library/RealTimeClockLib/RealTimeClockLib.c | 350 +++++++++++++++++++++ .../Library/RealTimeClockLib/RealTimeClockLib.inf | 52 +++ Platforms/Marvell/Marvell.dec | 3 + 3 files changed, 405 insertions(+) create mode 100644 Platforms/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c create mode 100644 Platforms/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf
diff --git a/Platforms/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c b/Platforms/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c new file mode 100644 index 0000000..8ee9ea2 --- /dev/null +++ b/Platforms/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.c @@ -0,0 +1,350 @@ +/** @file
- Implement EFI RealTimeClock runtime services via RTC Lib.
- Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
- Copyright (c) 2017, Marvell International Ltd. All rights reserved.<BR>
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/ +/**
- Derived from:
- ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.c
+**/
+#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/EfiTimeBaseLib.h> +#include <Library/IoLib.h> +#include <Library/RealTimeClockLib.h> +#include <Library/TimerLib.h> +#include <Library/UefiRuntimeLib.h> +#include <Protocol/RealTimeClock.h>
+/* Armada 70x0 SoC registers */ +#define RTC_STATUS_REG 0x0 +#define RTC_STATUS_ALARM1_MASK 0x1 +#define RTC_STATUS_ALARM2_MASK 0x2 +#define RTC_TIME_REG 0xC +#define RTC_IRQ_1_CONFIG_REG 0x4 +#define RTC_IRQ_2_CONFIG_REG 0x8 +#define RTC_IRQ_ALARM_EN 0x1 +#define RTC_ALARM_1_REG 0x10 +#define RTC_ALARM_2_REG 0x14 +#define RTC_CCR_REG 0x18 +#define RTC_NOMINAL_TIMING 0x2000 +#define RTC_NOMINAL_TIMING_MASK 0x7FFF +#define RTC_TEST_CONFIG_REG 0x1C +#define RTC_BRIDGE_TIMING_CTRL1_REG_OFFS 0x84 +#define RTC_IRQ_STATUS_REG 0x90 +#define RTC_IRQ_ALARM_MASK 0x1 +#define RTC_READ_OUTPUT_DELAY_MASK 0xFFFF
Could these be split out into a local .h?
+extern EFI_BOOT_SERVICES *gBS;
Much rather #include <Library/UefiBootServicesTableLib.h>, like in the pl031 driver.
+STATIC EFI_EVENT mRtcVirtualAddrChangeEvent; +STATIC UINTN mArmadaRtcBase;
+/* Update RTC-MBUS bridge timing parameters */ +STATIC +VOID +RtcUpdateMbusTimingParams (
- )
+{
- UINT32 RegVal;
- RegVal = MmioRead32 (mArmadaRtcBase + RTC_BRIDGE_TIMING_CTRL1_REG_OFFS);
- RegVal &= ~RTC_READ_OUTPUT_DELAY_MASK;
- RegVal |= 0x1F;
#define please
- MmioWrite32 (mArmadaRtcBase + RTC_BRIDGE_TIMING_CTRL1_REG_OFFS, RegVal);
+}
+/* Reset controller */ +STATIC +VOID +RtcReset (
- )
+{
- // Reset Test register
- MmioWrite32 (mArmadaRtcBase + RTC_TEST_CONFIG_REG, 0);
- MicroSecondDelay (500000);
Half a second? Why? Do you need a barrier before progressing?
- // Reset Time register
- MmioWrite32 (mArmadaRtcBase + RTC_TIME_REG, 0);
- MicroSecondDelay (62);
o.O That's ... very precise ... for an undocumented delay. Why 62? Barrier?
- // Reset Status register
- MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, (RTC_STATUS_ALARM1_MASK | RTC_STATUS_ALARM2_MASK));
- MicroSecondDelay (62);
As above.
- // Turn off Int1 and Int2 sources & clear the Alarm count
- MmioWrite32 (mArmadaRtcBase + RTC_IRQ_1_CONFIG_REG, 0);
- MmioWrite32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG, 0);
- MmioWrite32 (mArmadaRtcBase + RTC_ALARM_1_REG, 0);
- MmioWrite32 (mArmadaRtcBase + RTC_ALARM_2_REG, 0);
- // Setup nominal register access timing
- MmioWrite32 (mArmadaRtcBase + RTC_CCR_REG, RTC_NOMINAL_TIMING);
- // Reset Time register
- MmioWrite32 (mArmadaRtcBase + RTC_TIME_REG, 0);
- MicroSecondDelay (10);
Why 10? Barrier?
- // Reset Status register
- MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, (RTC_STATUS_ALARM1_MASK | RTC_STATUS_ALARM2_MASK));
- MicroSecondDelay (50);
Why 50? Barrier?
+}
+/**
- 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.
+**/ +EFI_STATUS +EFIAPI +LibGetTime (
- OUT EFI_TIME *Time,
- OUT EFI_TIME_CAPABILITIES *Capabilities
- )
+{
- EFI_STATUS Status = EFI_SUCCESS;
- UINT32 RegVal;
- RegVal = MmioRead32 (mArmadaRtcBase + RTC_TIME_REG);
- // Convert from internal 32-bit time to UEFI time
- EpochToEfiTime (RegVal, Time);
- Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
- Time->Daylight = 0;
- return Status;
+}
+/**
- 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
- )
+{
- EFI_STATUS Status = EFI_SUCCESS;
- UINT32 EpochSeconds;
- // Check the input parameters are within the range specified by UEFI
- if (!IsTimeValid (Time)) {
- return EFI_INVALID_PARAMETER;
- }
- // Convert time to raw seconds
- EpochSeconds = EfiTimeToEpoch (Time);
- //
- // According to the datasheet, the OS should wait 5us after every
- // register write to the RTC hard macro so that the required update
- // can occur without holding off the system bus
- // According to errata FE-3124064, Write to RTC TIME register
- // may fail. As a workaround, before writing to RTC TIME register,
- // issue a dummy write of 0x0 twice to RTC Status register.
- //
Exemplary :)
- MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, 0);
- MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, 0);
- MmioWrite32 (mArmadaRtcBase + RTC_TIME_REG, EpochSeconds);
- MicroSecondDelay (5);
- return Status;
+}
+/**
- 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
- )
+{
- UINT32 WakeupSeconds;
- *Enabled = MmioRead32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG) & RTC_IRQ_ALARM_EN;
- *Pending = MmioRead32 (mArmadaRtcBase + RTC_IRQ_STATUS_REG) & RTC_IRQ_ALARM_MASK;
- // Ack pending alarm
- if (Pending) {
- MmioWrite32 (mArmadaRtcBase + RTC_IRQ_STATUS_REG, RTC_IRQ_ALARM_MASK);
- }
- WakeupSeconds = MmioRead32 (mArmadaRtcBase + RTC_ALARM_2_REG);
- EpochToEfiTime (WakeupSeconds, Time);
- return EFI_SUCCESS;
+}
+/**
- 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
- )
+{
- UINT32 WakeupSeconds;
- // Convert time to raw seconds
- WakeupSeconds = EfiTimeToEpoch (Time);
- // Issue delayed write to alarm register
- MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, 0);
- MmioWrite32 (mArmadaRtcBase + RTC_STATUS_REG, 0);
- MmioWrite32 (mArmadaRtcBase + RTC_ALARM_2_REG, WakeupSeconds);
- MicroSecondDelay (5);
Deserves a loopback to the verbose comment above, even if just // See comment in LibSetTime
- if (Enabled) {
- MmioWrite32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG, RTC_IRQ_ALARM_EN);
- } else {
- MmioWrite32 (mArmadaRtcBase + RTC_IRQ_2_CONFIG_REG, 0);
- }
- return EFI_SUCCESS;
+}
+/**
- 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_HANDLE Handle;
- EFI_STATUS Status;
- // Initialize RTC Base Address
- mArmadaRtcBase = PcdGet64 (PcdRtcBaseAddress);
- // Declare the controller as EFI_MEMORY_RUNTIME
- Status = gDS->AddMemorySpace (
EfiGcdMemoryTypeMemoryMappedIo,
mArmadaRtcBase, SIZE_4KB,
EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
);
- ASSERT_EFI_ERROR (Status);
- Status = gDS->SetMemorySpaceAttributes (mArmadaRtcBase, SIZE_4KB, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
- ASSERT_EFI_ERROR (Status);
- // Platform initialization
- RtcUpdateMbusTimingParams();
- // Check if RTC does not require reset
- if ((MmioRead32 (mArmadaRtcBase + RTC_CCR_REG) & RTC_NOMINAL_TIMING_MASK) != RTC_NOMINAL_TIMING) {
- RtcReset();
- }
- // 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;
+}
+/**
- 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 transistions to calling in virtual mode, all future
- // runtime calls will be made in virtual mode.
- //
- EfiConvertPointer (0x0, (VOID**)&mArmadaRtcBase);
+} diff --git a/Platforms/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf b/Platforms/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf new file mode 100644 index 0000000..ee01080 --- /dev/null +++ b/Platforms/Marvell/Armada/Library/RealTimeClockLib/RealTimeClockLib.inf @@ -0,0 +1,52 @@ +#/** @file +# +# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR> +# Copyright (c) 2017, Marvell International Ltd. All rights reserved.<BR> +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ +#/** +# Derived from: +# ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.inf +# +#**/
+[Defines]
- INF_VERSION = 0x00010019
- BASE_NAME = ArmadaRealTimeClockLib
- FILE_GUID = fa81e889-045b-4c96-9093-742554fd0588
- MODULE_TYPE = BASE
- VERSION_STRING = 1.0
- LIBRARY_CLASS = RealTimeClockLib
+[Sources.common]
- RealTimeClockLib.c
+[Packages]
- MdePkg/MdePkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
E before M.
/ Leif
- OpenPlatformPkg/OpenPlatformPkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
+[LibraryClasses]
- DebugLib
- DxeServicesTableLib
- EfiTimeBaseLib
- IoLib
- PcdLib
- TimerLib
- UefiRuntimeLib
+[Guids]
- gEfiEventVirtualAddressChangeGuid
+[Pcd]
- gMarvellTokenSpaceGuid.PcdRtcBaseAddress
diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index f011de1..69152c8 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -219,6 +219,9 @@ gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051 +#RTC
- gMarvellTokenSpaceGuid.PcdRtcBaseAddress|0|UINT64|0x40000052
#SdMmc gMarvellTokenSpaceGuid.PcdXenon1v8Enable|{ 0x0 }|VOID*|0x3000036 gMarvellTokenSpaceGuid.PcdXenon8BitBusEnable|{ 0x0 }|VOID*|0x3000037 -- 1.8.3.1