summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
authorPierre Gondois <Pierre.Gondois@arm.com>2021-12-09 10:31:58 +0100
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2021-12-14 16:07:00 +0000
commit3ebe1ff5c995b0cbbb7cefa75a4c0fa528d01c85 (patch)
tree570e76ab47a959372b1d13c3883d79010bf3184f /DynamicTablesPkg
parent8d2691c3d5cd13f118be50dca500f3049931b3d9 (diff)
downloadedk2-3ebe1ff5c995b0cbbb7cefa75a4c0fa528d01c85.tar.gz
edk2-3ebe1ff5c995b0cbbb7cefa75a4c0fa528d01c85.tar.bz2
edk2-3ebe1ff5c995b0cbbb7cefa75a4c0fa528d01c85.zip
DynamicTablesPkg: FdtHwInfoParser: Generic Timer Parser
The Generic Timer Description Table (GTDT) is a mandatory table required for booting a standards-based operating system. It provides an OSPM with information about a system's Generic Timer configuration. The Generic Timer (GT) is a standard timer interface implemented on ARM processor-based systems. The GTDT provides OSPM with information about a system's GT interrupt configurations, for both per-processor timers, and platform (memory-mapped) timers. The Generic Timer information is described in the platform Device Tree. The Device Tree bindings for the Generic timers can be found at: - linux/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml The FdtHwInfoParser implements a Generic Timer Parser that parses the platform Device Tree to create a CM_ARM_GENERIC_TIMER_INFO object. The CM_ARM_GENERIC_TIMER_INFO object is encapsulated in a Configuration Manager descriptor object and added to the platform information repository. The platform Configuration Manager can then utilise this information when generating the GTDT table. Note: The Generic Timer Parser currently does not support parsing of memory-mapped platform timers. Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c258
-rw-r--r--DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h66
2 files changed, 324 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c
new file mode 100644
index 0000000000..988a81221d
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c
@@ -0,0 +1,258 @@
+/** @file
+ Arm generic timer parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml
+**/
+
+#include "FdtHwInfoParser.h"
+#include "CmObjectDescUtility.h"
+#include "GenericTimer/ArmGenericTimerParser.h"
+#include "Gic/ArmGicDispatcher.h"
+
+/** List of "compatible" property values for timer nodes.
+
+ Other "compatible" values are not supported by this module.
+*/
+STATIC CONST COMPATIBILITY_STR TimerCompatibleStr[] = {
+ { "arm,armv7-timer" },
+ { "arm,armv8-timer" }
+};
+
+/** Timer compatiblity information.
+*/
+STATIC CONST COMPATIBILITY_INFO TimerCompatibleInfo = {
+ ARRAY_SIZE (TimerCompatibleStr),
+ TimerCompatibleStr
+};
+
+/** Parse a timer node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] TimerNode Offset of a timer node.
+ @param [in] GenericTimerInfo The CM_ARM_BOOT_ARCH_INFO to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+TimerNodeParser (
+ IN CONST VOID *Fdt,
+ IN INT32 TimerNode,
+ IN CM_ARM_GENERIC_TIMER_INFO *GenericTimerInfo
+ )
+{
+ EFI_STATUS Status;
+ CONST UINT32 *Data;
+ INT32 IntcNode;
+ UINT32 GicVersion;
+ INT32 DataSize;
+ INT32 IntCells;
+ BOOLEAN AlwaysOnTimer;
+
+ if ((Fdt == NULL) ||
+ (GenericTimerInfo == NULL))
+ {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data = fdt_getprop (Fdt, TimerNode, "always-on", &DataSize);
+ if ((Data == NULL) || (DataSize < 0)) {
+ AlwaysOnTimer = FALSE;
+ } else {
+ AlwaysOnTimer = TRUE;
+ }
+
+ // Get the associated interrupt-controller.
+ Status = FdtGetIntcParentNode (Fdt, TimerNode, &IntcNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Check that the interrupt-controller node is a Gic.
+ Status = GetGicVersion (Fdt, IntcNode, &GicVersion);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Get the number of cells used to encode an interrupt.
+ Status = FdtGetInterruptCellsInfo (Fdt, IntcNode, &IntCells);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+
+ return Status;
+ }
+
+ Data = fdt_getprop (Fdt, TimerNode, "interrupts", &DataSize);
+ if ((Data == NULL) ||
+ (DataSize != (FdtMaxTimerItem * IntCells * sizeof (UINT32))))
+ {
+ // If error or not FdtMaxTimerItem interrupts.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ GenericTimerInfo->SecurePL1TimerGSIV =
+ FdtGetInterruptId (&Data[FdtSecureTimerIrq * IntCells]);
+ GenericTimerInfo->SecurePL1TimerFlags =
+ FdtGetInterruptFlags (&Data[FdtSecureTimerIrq * IntCells]);
+ GenericTimerInfo->NonSecurePL1TimerGSIV =
+ FdtGetInterruptId (&Data[FdtNonSecureTimerIrq * IntCells]);
+ GenericTimerInfo->NonSecurePL1TimerFlags =
+ FdtGetInterruptFlags (&Data[FdtNonSecureTimerIrq * IntCells]);
+ GenericTimerInfo->VirtualTimerGSIV =
+ FdtGetInterruptId (&Data[FdtVirtualTimerIrq * IntCells]);
+ GenericTimerInfo->VirtualTimerFlags =
+ FdtGetInterruptFlags (&Data[FdtVirtualTimerIrq * IntCells]);
+ GenericTimerInfo->NonSecurePL2TimerGSIV =
+ FdtGetInterruptId (&Data[FdtHypervisorTimerIrq * IntCells]);
+ GenericTimerInfo->NonSecurePL2TimerFlags =
+ FdtGetInterruptFlags (&Data[FdtHypervisorTimerIrq * IntCells]);
+
+ if (AlwaysOnTimer) {
+ GenericTimerInfo->SecurePL1TimerFlags |= BIT2;
+ GenericTimerInfo->NonSecurePL1TimerFlags |= BIT2;
+ GenericTimerInfo->VirtualTimerFlags |= BIT2;
+ GenericTimerInfo->NonSecurePL2TimerFlags |= BIT2;
+ }
+
+ // Setup default values
+ // The CntControlBase & CntReadBase Physical Address are optional if
+ // the system implements EL3 (Security Extensions). So, initialise
+ // these to their default value.
+ GenericTimerInfo->CounterControlBaseAddress = 0xFFFFFFFFFFFFFFFF;
+ GenericTimerInfo->CounterReadBaseAddress = 0xFFFFFFFFFFFFFFFF;
+
+ // For systems not implementing ARMv8.1 VHE, this field is 0.
+ GenericTimerInfo->VirtualPL2TimerGSIV = 0;
+ GenericTimerInfo->VirtualPL2TimerFlags = 0;
+
+ return EFI_SUCCESS;
+}
+
+/** CM_ARM_GENERIC_TIMER_INFO parser function.
+
+ The following structure is populated:
+ typedef struct CmArmGenericTimerInfo {
+ UINT64 CounterControlBaseAddress; // {default}
+ UINT64 CounterReadBaseAddress; // {default}
+ UINT32 SecurePL1TimerGSIV; // {Populated}
+ UINT32 SecurePL1TimerFlags; // {Populated}
+ UINT32 NonSecurePL1TimerGSIV; // {Populated}
+ UINT32 NonSecurePL1TimerFlags; // {Populated}
+ UINT32 VirtualTimerGSIV; // {Populated}
+ UINT32 VirtualTimerFlags; // {Populated}
+ UINT32 NonSecurePL2TimerGSIV; // {Populated}
+ UINT32 NonSecurePL2TimerFlags; // {Populated}
+ UINT32 VirtualPL2TimerGSIV; // {default}
+ UINT32 VirtualPL2TimerFlags; // {default}
+ } CM_ARM_GENERIC_TIMER_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGenericTimerInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ INT32 TimerNode;
+ UINT32 TimerNodeCount;
+ CM_ARM_GENERIC_TIMER_INFO GenericTimerInfo;
+ VOID *Fdt;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fdt = FdtParserHandle->Fdt;
+ Status = FdtCountCompatNodeInBranch (
+ Fdt,
+ FdtBranch,
+ &TimerCompatibleInfo,
+ &TimerNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (TimerNodeCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ // Parse each timer node in the branch.
+ TimerNode = FdtBranch;
+ for (Index = 0; Index < TimerNodeCount; Index++) {
+ ZeroMem (&GenericTimerInfo, sizeof (CM_ARM_GENERIC_TIMER_INFO));
+
+ Status = FdtGetNextCompatNodeInBranch (
+ Fdt,
+ FdtBranch,
+ &TimerCompatibleInfo,
+ &TimerNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+
+ return Status;
+ }
+
+ Status = TimerNodeParser (Fdt, TimerNode, &GenericTimerInfo);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the CmObj to the Configuration Manager.
+ Status = AddSingleCmObj (
+ FdtParserHandle,
+ CREATE_CM_ARM_OBJECT_ID (EArmObjGenericTimerInfo),
+ &GenericTimerInfo,
+ sizeof (CM_ARM_GENERIC_TIMER_INFO),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } // for
+
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h
new file mode 100644
index 0000000000..d7fa278c90
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h
@@ -0,0 +1,66 @@
+/** @file
+ Arm generic timer parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml
+**/
+
+#ifndef ARM_GENERIC_TIMER_PARSER_H_
+#define ARM_GENERIC_TIMER_PARSER_H_
+
+/** An enum listing the FDT interrupt items.
+*/
+typedef enum FdtTimerInterruptItems {
+ FdtSecureTimerIrq, ///< Secure timer IRQ
+ FdtNonSecureTimerIrq, ///< Non-secure timer IRQ
+ FdtVirtualTimerIrq, ///< Virtual timer IRQ
+ FdtHypervisorTimerIrq, ///< Hypervisor timer IRQ
+ FdtMaxTimerItem ///< Max timer item
+} FDT_TIMER_INTERRUPT_ITEMS;
+
+/** CM_ARM_BOOT_ARCH_INFO parser function.
+
+ The following structure is populated:
+ typedef struct CmArmGenericTimerInfo {
+ UINT64 CounterControlBaseAddress; // {default}
+ UINT64 CounterReadBaseAddress; // {default}
+ UINT32 SecurePL1TimerGSIV; // {Populated}
+ UINT32 SecurePL1TimerFlags; // {Populated}
+ UINT32 NonSecurePL1TimerGSIV; // {Populated}
+ UINT32 NonSecurePL1TimerFlags; // {Populated}
+ UINT32 VirtualTimerGSIV; // {Populated}
+ UINT32 VirtualTimerFlags; // {Populated}
+ UINT32 NonSecurePL2TimerGSIV; // {Populated}
+ UINT32 NonSecurePL2TimerFlags; // {Populated}
+ UINT32 VirtualPL2TimerGSIV; // {default}
+ UINT32 VirtualPL2TimerFlags; // {default}
+ } CM_ARM_GENERIC_TIMER_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGenericTimerInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_GENERIC_TIMER_PARSER_H_