From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web11.6914.1624451921995786600 for ; Wed, 23 Jun 2021 05:38:42 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: pierre.gondois@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A0CAC1063; Wed, 23 Jun 2021 05:38:41 -0700 (PDT) Received: from e120189.arm.com (unknown [10.57.78.245]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 4AB3A3F718; Wed, 23 Jun 2021 05:38:40 -0700 (PDT) From: "PierreGondois" To: devel@edk2.groups.io, Sami Mujawar , Alexei Fedorov Cc: Akanksha Jain , Alexandru Elisei Subject: [PATCH v1 05/14] DynamicTablesPkg: FdtHwInfoParser: Generic Timer Parser Date: Wed, 23 Jun 2021 13:38:19 +0100 Message-Id: <20210623123828.23693-6-Pierre.Gondois@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210623123828.23693-1-Pierre.Gondois@arm.com> References: <20210623123828.23693-1-Pierre.Gondois@arm.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable From: Pierre Gondois 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=C2=92s 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=C2=92s 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 Signed-off-by: Sami Mujawar --- .../GenericTimer/ArmGenericTimerParser.c | 254 ++++++++++++++++++ .../GenericTimer/ArmGenericTimerParser.h | 66 +++++ 2 files changed, 320 insertions(+) create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTi= mer/ArmGenericTimerParser.c create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTi= mer/ArmGenericTimerParser.h diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/Arm= GenericTimerParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Generi= cTimer/ArmGenericTimerParser.c new file mode 100644 index 000000000000..e7095396a5a8 --- /dev/null +++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGeneric= TimerParser.c @@ -0,0 +1,254 @@ +/** @file + Arm generic timer parser. + + Copyright (c) 2021, ARM Limited. All rights reserved.
+ 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[] =3D { + {"arm,armv7-timer"}, + {"arm,armv8-timer"} +}; + +/** Timer compatiblity information. +*/ +STATIC CONST COMPATIBILITY_INFO TimerCompatibleInfo =3D { + ARRAY_SIZE (TimerCompatibleStr), + TimerCompatibleStr +}; + +/** Parse a timer node. + + @param [in] Fdt Pointer to a Flattened Device Tree (Fd= t). + @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 =3D=3D NULL) || + (GenericTimerInfo =3D=3D NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + Data =3D fdt_getprop (Fdt, TimerNode, "always-on", &DataSize); + if ((Data =3D=3D NULL) || (DataSize < 0)) { + AlwaysOnTimer =3D FALSE; + } else { + AlwaysOnTimer =3D TRUE; + } + + // Get the associated interrupt-controller. + Status =3D FdtGetIntcParentNode (Fdt, TimerNode, &IntcNode); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + // Check that the interrupt-controller node is a Gic. + Status =3D GetGicVersion (Fdt, IntcNode, &GicVersion); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + // Get the number of cells used to encode an interrupt. + Status =3D FdtGetInterruptCellsInfo (Fdt, IntcNode, &IntCells); + if (EFI_ERROR (Status)) { + ASSERT (0); + if (Status =3D=3D EFI_NOT_FOUND) { + // Should have found the node. + Status =3D EFI_ABORTED; + } + return Status; + } + + Data =3D fdt_getprop (Fdt, TimerNode, "interrupts", &DataSize); + if ((Data =3D=3D NULL) || + (DataSize !=3D (FdtMaxTimerItem * IntCells * sizeof (UINT32)))) { + // If error or not FdtMaxTimerItem interrupts. + ASSERT (0); + return EFI_ABORTED; + } + + GenericTimerInfo->SecurePL1TimerGSIV =3D + FdtGetInterruptId (&Data[FdtSecureTimerIrq * IntCells]); + GenericTimerInfo->SecurePL1TimerFlags =3D + FdtGetInterruptFlags (&Data[FdtSecureTimerIrq * IntCells]); + GenericTimerInfo->NonSecurePL1TimerGSIV =3D + FdtGetInterruptId (&Data[FdtNonSecureTimerIrq * IntCells]); + GenericTimerInfo->NonSecurePL1TimerFlags =3D + FdtGetInterruptFlags (&Data[FdtNonSecureTimerIrq * IntCells]); + GenericTimerInfo->VirtualTimerGSIV =3D + FdtGetInterruptId (&Data[FdtVirtualTimerIrq * IntCells]); + GenericTimerInfo->VirtualTimerFlags =3D + FdtGetInterruptFlags (&Data[FdtVirtualTimerIrq * IntCells]); + GenericTimerInfo->NonSecurePL2TimerGSIV =3D + FdtGetInterruptId (&Data[FdtHypervisorTimerIrq * IntCells]); + GenericTimerInfo->NonSecurePL2TimerFlags =3D + FdtGetInterruptFlags (&Data[FdtHypervisorTimerIrq * IntCells]); + + if (AlwaysOnTimer) { + GenericTimerInfo->SecurePL1TimerFlags |=3D BIT2; + GenericTimerInfo->NonSecurePL1TimerFlags |=3D BIT2; + GenericTimerInfo->VirtualTimerFlags |=3D BIT2; + GenericTimerInfo->NonSecurePL2TimerFlags |=3D 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 =3D 0xFFFFFFFFFFFFFFFF; + GenericTimerInfo->CounterReadBaseAddress =3D 0xFFFFFFFFFFFFFFFF; + + // For systems not implementing ARMv8.1 VHE, this field is 0. + GenericTimerInfo->VirtualPL2TimerGSIV =3D 0; + GenericTimerInfo->VirtualPL2TimerFlags =3D 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 =3D=3D NULL) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + Fdt =3D FdtParserHandle->Fdt; + Status =3D FdtCountCompatNodeInBranch ( + Fdt, + FdtBranch, + &TimerCompatibleInfo, + &TimerNodeCount + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + if (TimerNodeCount =3D=3D 0) { + return EFI_NOT_FOUND; + } + + // Parse each timer node in the branch. + TimerNode =3D FdtBranch; + for (Index =3D 0; Index < TimerNodeCount; Index++) { + ZeroMem (&GenericTimerInfo, sizeof (CM_ARM_GENERIC_TIMER_INFO)); + + Status =3D FdtGetNextCompatNodeInBranch ( + Fdt, + FdtBranch, + &TimerCompatibleInfo, + &TimerNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + if (Status =3D=3D EFI_NOT_FOUND) { + // Should have found the node. + Status =3D EFI_ABORTED; + } + return Status; + } + + Status =3D TimerNodeParser (Fdt, TimerNode, &GenericTimerInfo); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + // Add the CmObj to the Configuration Manager. + Status =3D 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/Arm= GenericTimerParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Generi= cTimer/ArmGenericTimerParser.h new file mode 100644 index 000000000000..e1d294b3eea9 --- /dev/null +++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGeneric= TimerParser.h @@ -0,0 +1,66 @@ +/** @file + Arm generic timer parser. + + Copyright (c) 2021, ARM Limited. All rights reserved.
+ 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_ --=20 2.17.1