Add the LoongArch64 CPU Timer library, using CPUCFG 0x4 and 0x5 for Stable Counter frequency.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584 Cc: Eric Dong <eric.d...@intel.com> Cc: Ray Ni <ray...@intel.com> Cc: Rahul Kumar <rahul1.ku...@intel.com> Cc: Gerd Hoffmann <kra...@redhat.com> Signed-off-by: Chao Li <lic...@loongson.cn> --- .../BaseLoongArch64CpuTimerLib.inf | 30 +++ .../BaseLoongArch64CpuTimerLib.uni | 15 ++ .../BaseLoongArch64CpuTimerLib/CpuTimerLib.c | 226 ++++++++++++++++++ UefiCpuPkg/UefiCpuPkg.dsc | 3 + 4 files changed, 274 insertions(+) create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf new file mode 100644 index 0000000000..c00c215aec --- /dev/null +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf @@ -0,0 +1,30 @@ +## @file +# Base CPU Timer Library +# +# Provides base timer support using CPUCFG 0x4 and 0x5 stable counter frequency. +# +# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseLoongArch64CpuTimerLib + FILE_GUID = 740389C7-CC44-4A2F-88DC-89D97D312E7C + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib + MODULE_UNI_FILE = BaseLoongArch64CpuTimerLib.uni + +[Sources.common] + CpuTimerLib.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + DebugLib diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni new file mode 100644 index 0000000000..72d38ec679 --- /dev/null +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni @@ -0,0 +1,15 @@ +// /** @file +// Base CPU Timer Library +// +// Provides base timer support using CPUCFG 0x4 and 0x5 stable counter frequency. +// +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "LOONGARCH CPU Timer Library" + +#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUCFG 0x4 and 0x5 stable counter frequency." diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c new file mode 100644 index 0000000000..349b881cbc --- /dev/null +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c @@ -0,0 +1,226 @@ +/** @file + CPUCFG 0x4 and 0x5 for Stable Counter frequency instance of Timer Library. + + Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Base.h> +#include <Library/TimerLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Register/LoongArch64/Cpucfg.h> + +/** + Calculate clock frequency using CPUCFG 0x4 and 0x5 registers. + + @param VOID. + + @return The frequency in Hz. + +**/ +UINT32 +EFIAPI +CalcConstFreq ( + VOID + ) +{ + UINT32 BaseFreq; + UINT32 ClockMultiplier; + UINT32 ClockDivide; + CPUCFG_REG4_INFO_DATA CCFreq; + CPUCFG_REG5_INFO_DATA CpucfgReg5Data; + UINT32 StableTimerFreq; + + // + // Get the the crystal frequency corresponding to the constant + // frequency timer and the clock used by the timer. + // + AsmCpucfg (CPUCFG_REG4_INFO, &CCFreq.Uint32); + + // + // Get the multiplication factor and frequency division factor + // corresponding to the constant frequency timer and the clock + // used by the timer. + // + AsmCpucfg (CPUCFG_REG5_INFO, &CpucfgReg5Data.Uint32); + + BaseFreq = CCFreq.Bits.CC_FREQ; + ClockMultiplier = CpucfgReg5Data.Bits.CC_MUL & 0xFFFFULL; + ClockDivide = CpucfgReg5Data.Bits.CC_DIV & 0xFFFFULL; + + if (!BaseFreq || !ClockMultiplier || !ClockDivide) { + DEBUG ((DEBUG_ERROR, "LoongArch Stable Timer is not available in the CPU, hence this library cannot be used.\n")); + StableTimerFreq = 0; + ASSERT (0); + } else { + StableTimerFreq = (BaseFreq * ClockMultiplier / ClockDivide); + } + + return StableTimerFreq; +} + +/** + Stalls the CPU for at least the given number of microseconds. + + Stalls the CPU for the number of microseconds specified by MicroSeconds. + + @param MicroSeconds The minimum number of microseconds to delay. + + @return MicroSeconds + +**/ +UINTN +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + UINTN Count, Ticks, Start, End; + + Count = (CalcConstFreq () * MicroSeconds) / 1000000; + Start = AsmReadStableCounter (); + End = Start + Count; + + do { + Ticks = AsmReadStableCounter (); + } while (Ticks < End); + + return MicroSeconds; +} + +/** + Stalls the CPU for at least the given number of nanoseconds. + + Stalls the CPU for the number of nanoseconds specified by NanoSeconds. + + @param NanoSeconds The minimum number of nanoseconds to delay. + + @return NanoSeconds + +**/ +UINTN +EFIAPI +NanoSecondDelay ( + IN UINTN NanoSeconds + ) +{ + UINT32 MicroSeconds; + + if (NanoSeconds % 1000 == 0) { + MicroSeconds = NanoSeconds/1000; + } else { + MicroSeconds = NanoSeconds/1000 + 1; + } + + MicroSecondDelay (MicroSeconds); + + return NanoSeconds; +} + +/** + Retrieves the current value of a 64-bit free running performance counter. + + Retrieves the current value of a 64-bit free running performance counter. The + counter can either count up by 1 or count down by 1. If the physical + performance counter counts by a larger increment, then the counter values + must be translated. The properties of the counter can be retrieved from + GetPerformanceCounterProperties(). + + @return The current value of the free running performance counter. + +**/ +UINT64 +EFIAPI +GetPerformanceCounter ( + VOID + ) +{ + return AsmReadStableCounter (); +} + +/** + Retrieves the 64-bit frequency in Hz and the range of performance counter + values. + + If StartValue is not NULL, then the value that the performance counter starts + with immediately after is it rolls over is returned in StartValue. If + EndValue is not NULL, then the value that the performance counter end with + immediately before it rolls over is returned in EndValue. The 64-bit + frequency of the performance counter in Hz is always returned. If StartValue + is less than EndValue, then the performance counter counts up. If StartValue + is greater than EndValue, then the performance counter counts down. For + example, a 64-bit free running counter that counts up would have a StartValue + of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter + that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0. + + @param StartValue The value the performance counter starts with when it + rolls over. + @param EndValue The value that the performance counter ends with before + it rolls over. + + @return The frequency in Hz. + +**/ +UINT64 +EFIAPI +GetPerformanceCounterProperties ( + OUT UINT64 *StartValue OPTIONAL, + OUT UINT64 *EndValue OPTIONAL + ) +{ + if (StartValue != NULL) { + *StartValue = BIT2; + } + + if (EndValue != NULL) { + *EndValue = BIT48 - 1; + } + + return CalcConstFreq (); +} + +/** + Converts elapsed ticks of performance counter to time in nanoseconds. + + This function converts the elapsed ticks of running performance counter to + time value in unit of nanoseconds. + + @param Ticks The number of elapsed ticks of running performance counter. + + @return The elapsed time in nanoseconds. + +**/ +UINT64 +EFIAPI +GetTimeInNanoSecond ( + IN UINT64 Ticks + ) +{ + UINT64 Frequency; + UINT64 NanoSeconds; + UINT64 Remainder; + INTN Shift; + + Frequency = GetPerformanceCounterProperties (NULL, NULL); + + // + // Ticks + // Time = --------- x 1,000,000,000 + // Frequency + // + NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u); + + // + // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit. + // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34, + // i.e. highest bit set in Remainder should <= 33. + // + Shift = MAX (0, HighBitSet64 (Remainder) - 33); + Remainder = RShiftU64 (Remainder, (UINTN)Shift); + Frequency = RShiftU64 (Frequency, (UINTN)Shift); + NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL); + + return NanoSeconds; +} diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 074fd77461..8e34a9cd6b 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -205,5 +205,8 @@ UefiCpuPkg/CpuTimerDxeRiscV64/CpuTimerDxeRiscV64.inf UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf +[Components.LOONGARCH64] + UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf + [BuildOptions] *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES -- 2.27.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#110536): https://edk2.groups.io/g/devel/message/110536 Mute This Topic: https://groups.io/mt/102342225/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-