UefiCpuPkg: TimerLib support to fetch freq from DT

On RISC-V platforms, just like other platforms, we need to pass various
information from one stage to another (hartid/cmo operations etc).
Also there are some settings like Timer freq which are platform dependent
which use PCDs. Today hartid is extracted through Firmware Context
(custom in mem structure passed from one stage to another). For CMO we
have a features HOB. Going forward we would like to have a standard
mechanism to pass on such information and DT is handy as it can easily
carry all this information (in some cases nodes already exists). This
patch implement timebase frequency extraction from DT.

Signed-off-by: Akshay Behl <cap2k4@rivosinc.com>

Co-authored-by: Dhaval Sharma <dhaval@rivosinc.com>
This commit is contained in:
Akshay Behl
2025-06-08 22:49:22 +05:30
committed by mergify[bot]
parent 5ea0be305a
commit 67b744697c
2 changed files with 56 additions and 7 deletions

View File

@@ -28,6 +28,8 @@
BaseLib
PcdLib
DebugLib
FdtLib
HobLib
[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
[Guids]
gFdtHobGuid

View File

@@ -12,6 +12,12 @@
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Register/RiscV64/RiscVImpl.h>
#include <Pi/PiBootMode.h>
#include <Pi/PiHob.h>
#include <Library/HobLib.h>
#include <Library/FdtLib.h>
STATIC UINT64 mTimeBase;
/**
Stalls the CPU for at least the given number of ticks.
@@ -57,7 +63,7 @@ MicroSecondDelay (
DivU64x32 (
MultU64x32 (
MicroSeconds,
PcdGet64 (PcdCpuCoreCrystalClockFrequency)
mTimeBase
),
1000000u
)
@@ -85,7 +91,7 @@ NanoSecondDelay (
DivU64x32 (
MultU64x32 (
NanoSeconds,
PcdGet64 (PcdCpuCoreCrystalClockFrequency)
mTimeBase
),
1000000000u
)
@@ -152,7 +158,48 @@ GetPerformanceCounterProperties (
*EndValue = 32 - 1;
}
return PcdGet64 (PcdCpuCoreCrystalClockFrequency);
if (mTimeBase != 0) {
return mTimeBase;
}
//
// Locate the FDT HOB and validate header
//
CONST EFI_HOB_GUID_TYPE *Hob = GetFirstGuidHob (&gFdtHobGuid);
ASSERT (Hob != NULL);
CONST VOID *DeviceTreeBase =
(CONST VOID *)(UINTN)*(CONST UINT64 *)GET_GUID_HOB_DATA (Hob);
ASSERT (FdtCheckHeader (DeviceTreeBase) == 0);
//
// /cpus node
//
INT32 Node = FdtSubnodeOffsetNameLen (
DeviceTreeBase,
0,
"cpus",
sizeof ("cpus") - 1
);
ASSERT (Node >= 0);
//
// timebase-frequency property
//
INT32 Len;
CONST FDT_PROPERTY *Prop =
FdtGetProperty (DeviceTreeBase, Node, "timebase-frequency", &Len);
ASSERT (Prop != NULL && Len == sizeof (UINT32));
//
// Device-tree cells are big-endian
//
mTimeBase = SwapBytes32 (*(CONST UINT32 *)Prop->Data);
return mTimeBase;
}
/**
@@ -180,13 +227,13 @@ GetTimeInNanoSecond (
// Time = --------- x 1,000,000,000
// Frequency
//
NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, PcdGet64 (PcdCpuCoreCrystalClockFrequency), &Remainder), 1000000000u);
NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, mTimeBase, &Remainder), 1000000000u);
//
// Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)
// will not overflow 64-bit.
//
NanoSeconds += DivU64x32 (MultU64x32 ((UINT64)Remainder, 1000000000u), PcdGet64 (PcdCpuCoreCrystalClockFrequency));
NanoSeconds += DivU64x32 (MultU64x32 ((UINT64)Remainder, 1000000000u), mTimeBase);
return NanoSeconds;
}