]> git.proxmox.com Git - mirror_edk2.git/commitdiff
DynamicTablesPkg: FdtHwInfoParser: Generic Timer Parser
authorPierre Gondois <Pierre.Gondois@arm.com>
Thu, 9 Dec 2021 09:31:58 +0000 (10:31 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Tue, 14 Dec 2021 16:07:00 +0000 (16:07 +0000)
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>
DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c [new file with mode: 0644]
DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h [new file with mode: 0644]

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c
new file mode 100644 (file)
index 0000000..988a812
--- /dev/null
@@ -0,0 +1,258 @@
+/** @file\r
+  Arm generic timer parser.\r
+\r
+  Copyright (c) 2021, ARM Limited. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+  @par Reference(s):\r
+  - linux/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml\r
+**/\r
+\r
+#include "FdtHwInfoParser.h"\r
+#include "CmObjectDescUtility.h"\r
+#include "GenericTimer/ArmGenericTimerParser.h"\r
+#include "Gic/ArmGicDispatcher.h"\r
+\r
+/** List of "compatible" property values for timer nodes.\r
+\r
+  Other "compatible" values are not supported by this module.\r
+*/\r
+STATIC CONST COMPATIBILITY_STR  TimerCompatibleStr[] = {\r
+  { "arm,armv7-timer" },\r
+  { "arm,armv8-timer" }\r
+};\r
+\r
+/** Timer compatiblity information.\r
+*/\r
+STATIC CONST COMPATIBILITY_INFO  TimerCompatibleInfo = {\r
+  ARRAY_SIZE (TimerCompatibleStr),\r
+  TimerCompatibleStr\r
+};\r
+\r
+/** Parse a timer node.\r
+\r
+  @param [in]  Fdt                Pointer to a Flattened Device Tree (Fdt).\r
+  @param [in]  TimerNode          Offset of a timer node.\r
+  @param [in]  GenericTimerInfo   The CM_ARM_BOOT_ARCH_INFO to populate.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+  @retval EFI_ABORTED             An error occurred.\r
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+TimerNodeParser (\r
+  IN  CONST VOID                       *Fdt,\r
+  IN        INT32                      TimerNode,\r
+  IN        CM_ARM_GENERIC_TIMER_INFO  *GenericTimerInfo\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  CONST UINT32  *Data;\r
+  INT32         IntcNode;\r
+  UINT32        GicVersion;\r
+  INT32         DataSize;\r
+  INT32         IntCells;\r
+  BOOLEAN       AlwaysOnTimer;\r
+\r
+  if ((Fdt == NULL) ||\r
+      (GenericTimerInfo == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Data = fdt_getprop (Fdt, TimerNode, "always-on", &DataSize);\r
+  if ((Data == NULL) || (DataSize < 0)) {\r
+    AlwaysOnTimer = FALSE;\r
+  } else {\r
+    AlwaysOnTimer = TRUE;\r
+  }\r
+\r
+  // Get the associated interrupt-controller.\r
+  Status = FdtGetIntcParentNode (Fdt, TimerNode, &IntcNode);\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (0);\r
+    return Status;\r
+  }\r
+\r
+  // Check that the interrupt-controller node is a Gic.\r
+  Status = GetGicVersion (Fdt, IntcNode, &GicVersion);\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (0);\r
+    return Status;\r
+  }\r
+\r
+  // Get the number of cells used to encode an interrupt.\r
+  Status = FdtGetInterruptCellsInfo (Fdt, IntcNode, &IntCells);\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (0);\r
+    if (Status == EFI_NOT_FOUND) {\r
+      // Should have found the node.\r
+      Status = EFI_ABORTED;\r
+    }\r
+\r
+    return Status;\r
+  }\r
+\r
+  Data = fdt_getprop (Fdt, TimerNode, "interrupts", &DataSize);\r
+  if ((Data == NULL) ||\r
+      (DataSize != (FdtMaxTimerItem * IntCells * sizeof (UINT32))))\r
+  {\r
+    // If error or not FdtMaxTimerItem interrupts.\r
+    ASSERT (0);\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  GenericTimerInfo->SecurePL1TimerGSIV =\r
+    FdtGetInterruptId (&Data[FdtSecureTimerIrq * IntCells]);\r
+  GenericTimerInfo->SecurePL1TimerFlags =\r
+    FdtGetInterruptFlags (&Data[FdtSecureTimerIrq * IntCells]);\r
+  GenericTimerInfo->NonSecurePL1TimerGSIV =\r
+    FdtGetInterruptId (&Data[FdtNonSecureTimerIrq * IntCells]);\r
+  GenericTimerInfo->NonSecurePL1TimerFlags =\r
+    FdtGetInterruptFlags (&Data[FdtNonSecureTimerIrq * IntCells]);\r
+  GenericTimerInfo->VirtualTimerGSIV =\r
+    FdtGetInterruptId (&Data[FdtVirtualTimerIrq * IntCells]);\r
+  GenericTimerInfo->VirtualTimerFlags =\r
+    FdtGetInterruptFlags (&Data[FdtVirtualTimerIrq * IntCells]);\r
+  GenericTimerInfo->NonSecurePL2TimerGSIV =\r
+    FdtGetInterruptId (&Data[FdtHypervisorTimerIrq * IntCells]);\r
+  GenericTimerInfo->NonSecurePL2TimerFlags =\r
+    FdtGetInterruptFlags (&Data[FdtHypervisorTimerIrq * IntCells]);\r
+\r
+  if (AlwaysOnTimer) {\r
+    GenericTimerInfo->SecurePL1TimerFlags    |= BIT2;\r
+    GenericTimerInfo->NonSecurePL1TimerFlags |= BIT2;\r
+    GenericTimerInfo->VirtualTimerFlags      |= BIT2;\r
+    GenericTimerInfo->NonSecurePL2TimerFlags |= BIT2;\r
+  }\r
+\r
+  // Setup default values\r
+  // The CntControlBase & CntReadBase Physical Address are optional if\r
+  // the system implements EL3 (Security Extensions). So, initialise\r
+  // these to their default value.\r
+  GenericTimerInfo->CounterControlBaseAddress = 0xFFFFFFFFFFFFFFFF;\r
+  GenericTimerInfo->CounterReadBaseAddress    = 0xFFFFFFFFFFFFFFFF;\r
+\r
+  // For systems not implementing ARMv8.1 VHE, this field is 0.\r
+  GenericTimerInfo->VirtualPL2TimerGSIV  = 0;\r
+  GenericTimerInfo->VirtualPL2TimerFlags = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/** CM_ARM_GENERIC_TIMER_INFO parser function.\r
+\r
+  The following structure is populated:\r
+  typedef struct CmArmGenericTimerInfo {\r
+    UINT64  CounterControlBaseAddress;        // {default}\r
+    UINT64  CounterReadBaseAddress;           // {default}\r
+    UINT32  SecurePL1TimerGSIV;               // {Populated}\r
+    UINT32  SecurePL1TimerFlags;              // {Populated}\r
+    UINT32  NonSecurePL1TimerGSIV;            // {Populated}\r
+    UINT32  NonSecurePL1TimerFlags;           // {Populated}\r
+    UINT32  VirtualTimerGSIV;                 // {Populated}\r
+    UINT32  VirtualTimerFlags;                // {Populated}\r
+    UINT32  NonSecurePL2TimerGSIV;            // {Populated}\r
+    UINT32  NonSecurePL2TimerFlags;           // {Populated}\r
+    UINT32  VirtualPL2TimerGSIV;              // {default}\r
+    UINT32  VirtualPL2TimerFlags;             // {default}\r
+  } CM_ARM_GENERIC_TIMER_INFO;\r
+\r
+  A parser parses a Device Tree to populate a specific CmObj type. None,\r
+  one or many CmObj can be created by the parser.\r
+  The created CmObj are then handed to the parser's caller through the\r
+  HW_INFO_ADD_OBJECT interface.\r
+  This can also be a dispatcher. I.e. a function that not parsing a\r
+  Device Tree but calling other parsers.\r
+\r
+  @param [in]  FdtParserHandle A handle to the parser instance.\r
+  @param [in]  FdtBranch       When searching for DT node name, restrict\r
+                               the search to this Device Tree branch.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+  @retval EFI_ABORTED             An error occurred.\r
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+  @retval EFI_NOT_FOUND           Not found.\r
+  @retval EFI_UNSUPPORTED         Unsupported.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArmGenericTimerInfoParser (\r
+  IN  CONST FDT_HW_INFO_PARSER_HANDLE  FdtParserHandle,\r
+  IN        INT32                      FdtBranch\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINT32                     Index;\r
+  INT32                      TimerNode;\r
+  UINT32                     TimerNodeCount;\r
+  CM_ARM_GENERIC_TIMER_INFO  GenericTimerInfo;\r
+  VOID                       *Fdt;\r
+\r
+  if (FdtParserHandle == NULL) {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Fdt    = FdtParserHandle->Fdt;\r
+  Status = FdtCountCompatNodeInBranch (\r
+             Fdt,\r
+             FdtBranch,\r
+             &TimerCompatibleInfo,\r
+             &TimerNodeCount\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (0);\r
+    return Status;\r
+  }\r
+\r
+  if (TimerNodeCount == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  // Parse each timer node in the branch.\r
+  TimerNode = FdtBranch;\r
+  for (Index = 0; Index < TimerNodeCount; Index++) {\r
+    ZeroMem (&GenericTimerInfo, sizeof (CM_ARM_GENERIC_TIMER_INFO));\r
+\r
+    Status = FdtGetNextCompatNodeInBranch (\r
+               Fdt,\r
+               FdtBranch,\r
+               &TimerCompatibleInfo,\r
+               &TimerNode\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      ASSERT (0);\r
+      if (Status == EFI_NOT_FOUND) {\r
+        // Should have found the node.\r
+        Status = EFI_ABORTED;\r
+      }\r
+\r
+      return Status;\r
+    }\r
+\r
+    Status = TimerNodeParser (Fdt, TimerNode, &GenericTimerInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      ASSERT (0);\r
+      return Status;\r
+    }\r
+\r
+    // Add the CmObj to the Configuration Manager.\r
+    Status = AddSingleCmObj (\r
+               FdtParserHandle,\r
+               CREATE_CM_ARM_OBJECT_ID (EArmObjGenericTimerInfo),\r
+               &GenericTimerInfo,\r
+               sizeof (CM_ARM_GENERIC_TIMER_INFO),\r
+               NULL\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      ASSERT (0);\r
+      return Status;\r
+    }\r
+  } // for\r
+\r
+  return Status;\r
+}\r
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h
new file mode 100644 (file)
index 0000000..d7fa278
--- /dev/null
@@ -0,0 +1,66 @@
+/** @file\r
+  Arm generic timer parser.\r
+\r
+  Copyright (c) 2021, ARM Limited. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+  @par Reference(s):\r
+  - linux/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml\r
+**/\r
+\r
+#ifndef ARM_GENERIC_TIMER_PARSER_H_\r
+#define ARM_GENERIC_TIMER_PARSER_H_\r
+\r
+/** An enum listing the FDT interrupt items.\r
+*/\r
+typedef enum FdtTimerInterruptItems {\r
+  FdtSecureTimerIrq,      ///< Secure timer IRQ\r
+  FdtNonSecureTimerIrq,   ///< Non-secure timer IRQ\r
+  FdtVirtualTimerIrq,     ///< Virtual timer IRQ\r
+  FdtHypervisorTimerIrq,  ///< Hypervisor timer IRQ\r
+  FdtMaxTimerItem         ///< Max timer item\r
+} FDT_TIMER_INTERRUPT_ITEMS;\r
+\r
+/** CM_ARM_BOOT_ARCH_INFO parser function.\r
+\r
+  The following structure is populated:\r
+  typedef struct CmArmGenericTimerInfo {\r
+    UINT64  CounterControlBaseAddress;        // {default}\r
+    UINT64  CounterReadBaseAddress;           // {default}\r
+    UINT32  SecurePL1TimerGSIV;               // {Populated}\r
+    UINT32  SecurePL1TimerFlags;              // {Populated}\r
+    UINT32  NonSecurePL1TimerGSIV;            // {Populated}\r
+    UINT32  NonSecurePL1TimerFlags;           // {Populated}\r
+    UINT32  VirtualTimerGSIV;                 // {Populated}\r
+    UINT32  VirtualTimerFlags;                // {Populated}\r
+    UINT32  NonSecurePL2TimerGSIV;            // {Populated}\r
+    UINT32  NonSecurePL2TimerFlags;           // {Populated}\r
+    UINT32  VirtualPL2TimerGSIV;              // {default}\r
+    UINT32  VirtualPL2TimerFlags;             // {default}\r
+  } CM_ARM_GENERIC_TIMER_INFO;\r
+\r
+  A parser parses a Device Tree to populate a specific CmObj type. None,\r
+  one or many CmObj can be created by the parser.\r
+  The created CmObj are then handed to the parser's caller through the\r
+  HW_INFO_ADD_OBJECT interface.\r
+  This can also be a dispatcher. I.e. a function that not parsing a\r
+  Device Tree but calling other parsers.\r
+\r
+  @param [in]  FdtParserHandle A handle to the parser instance.\r
+  @param [in]  FdtBranch       When searching for DT node name, restrict\r
+                               the search to this Device Tree branch.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+  @retval EFI_ABORTED             An error occurred.\r
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+  @retval EFI_NOT_FOUND           Not found.\r
+  @retval EFI_UNSUPPORTED         Unsupported.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArmGenericTimerInfoParser (\r
+  IN  CONST FDT_HW_INFO_PARSER_HANDLE  FdtParserHandle,\r
+  IN        INT32                      FdtBranch\r
+  );\r
+\r
+#endif // ARM_GENERIC_TIMER_PARSER_H_\r