]> git.proxmox.com Git - mirror_edk2.git/commitdiff
DynamicTablesPkg: FdtHwInfoParser: Add FDT utility functions
authorPierre Gondois <Pierre.Gondois@arm.com>
Thu, 9 Dec 2021 09:31:56 +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 FdtHwInfoParser parses a platform Device Tree and populates
the Platform Information repository with Configuration Manager
objects.

Therefore, add a set of helper functions to simplify parsing of
the platform Device Tree.

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c [new file with mode: 0644]
DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h [new file with mode: 0644]

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c
new file mode 100644 (file)
index 0000000..5314cf3
--- /dev/null
@@ -0,0 +1,923 @@
+/** @file\r
+  Flattened device tree utility.\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
+  - Device tree Specification - Release v0.3\r
+  - linux/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml\r
+  - linux//Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml\r
+**/\r
+\r
+#include <FdtHwInfoParserInclude.h>\r
+#include "FdtUtility.h"\r
+\r
+/** Get the interrupt Id of an interrupt described in a fdt.\r
+\r
+  Data must describe a GIC interrupt. A GIC interrupt is on at least\r
+  3 UINT32 cells.\r
+  This function DOES NOT SUPPORT extended SPI range and extended PPI range.\r
+\r
+  @param [in]  Data   Pointer to the first cell of an "interrupts" property.\r
+\r
+  @retval  The interrupt id.\r
+**/\r
+UINT32\r
+EFIAPI\r
+FdtGetInterruptId (\r
+  UINT32 CONST  *Data\r
+  )\r
+{\r
+  UINT32  IrqType;\r
+  UINT32  IrqId;\r
+\r
+  ASSERT (Data != NULL);\r
+\r
+  IrqType = fdt32_to_cpu (Data[IRQ_TYPE_OFFSET]);\r
+  IrqId   = fdt32_to_cpu (Data[IRQ_NUMBER_OFFSET]);\r
+\r
+  switch (IrqType) {\r
+    case DT_SPI_IRQ:\r
+      IrqId += SPI_OFFSET;\r
+      break;\r
+\r
+    case DT_PPI_IRQ:\r
+      IrqId += PPI_OFFSET;\r
+      break;\r
+\r
+    default:\r
+      ASSERT (0);\r
+      IrqId = 0;\r
+  }\r
+\r
+  return IrqId;\r
+}\r
+\r
+/** Get the ACPI interrupt flags of an interrupt described in a fdt.\r
+\r
+  Data must describe a GIC interrupt. A GIC interrupt is on at least\r
+  3 UINT32 cells.\r
+\r
+  PPI interrupt cpu mask on bits [15:8] are ignored.\r
+\r
+  @param [in]  Data   Pointer to the first cell of an "interrupts" property.\r
+\r
+  @retval  The interrupt flags (for ACPI).\r
+**/\r
+UINT32\r
+EFIAPI\r
+FdtGetInterruptFlags (\r
+  UINT32 CONST  *Data\r
+  )\r
+{\r
+  UINT32  IrqFlags;\r
+  UINT32  AcpiIrqFlags;\r
+\r
+  ASSERT (Data != NULL);\r
+\r
+  IrqFlags = fdt32_to_cpu (Data[IRQ_FLAGS_OFFSET]);\r
+\r
+  AcpiIrqFlags  = DT_IRQ_IS_EDGE_TRIGGERED (IrqFlags) ? BIT0 : 0;\r
+  AcpiIrqFlags |= DT_IRQ_IS_ACTIVE_LOW (IrqFlags) ? BIT1 : 0;\r
+\r
+  return AcpiIrqFlags;\r
+}\r
+\r
+/** Check whether a node has the input name.\r
+\r
+  @param [in]  Fdt          Pointer to a Flattened Device Tree.\r
+  @param [in]  Node         Offset of the node to check the name.\r
+  @param [in]  SearchName   Node name to search.\r
+                            This is a NULL terminated string.\r
+\r
+  @retval True    The node has the input name.\r
+  @retval FALSE   Otherwise, or error.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+FdtNodeHasName (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  Node,\r
+  IN  CONST VOID   *SearchName\r
+  )\r
+{\r
+  CONST CHAR8  *NodeName;\r
+  UINT32       Length;\r
+\r
+  if ((Fdt == NULL) ||\r
+      (SearchName == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return FALSE;\r
+  }\r
+\r
+  // Always compare the whole string. Don't stop at the "@" char.\r
+  Length = (UINT32)AsciiStrLen (SearchName);\r
+\r
+  // Get the address of the node name.\r
+  NodeName = fdt_offset_ptr (Fdt, Node + FDT_TAGSIZE, Length + 1);\r
+  if (NodeName == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  // SearchName must be longer than the node name.\r
+  if (Length > AsciiStrLen (NodeName)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (AsciiStrnCmp (NodeName, SearchName, Length) != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  // The name matches perfectly, or\r
+  // the node name is XXX@addr and the XXX matches.\r
+  if ((NodeName[Length] == '\0') ||\r
+      (NodeName[Length] == '@'))\r
+  {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/** Iterate through the list of strings in the Context,\r
+    and check whether at least one string is matching the\r
+    "compatible" property of the node.\r
+\r
+  @param [in]  Fdt          Pointer to a Flattened Device Tree.\r
+  @param [in]  Node         Offset of the node to operate the check on.\r
+  @param [in]  CompatInfo   COMPATIBILITY_INFO containing the list of compatible\r
+                            strings to compare with the "compatible" property\r
+                            of the node.\r
+\r
+  @retval TRUE    At least one string matched, the node is compatible.\r
+  @retval FALSE   Otherwise, or error.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+FdtNodeIsCompatible (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  Node,\r
+  IN  CONST VOID   *CompatInfo\r
+  )\r
+{\r
+  UINT32                   Index;\r
+  CONST COMPATIBILITY_STR  *CompatibleTable;\r
+  UINT32                   Count;\r
+  CONST VOID               *Prop;\r
+  INT32                    PropLen;\r
+\r
+  if ((Fdt == NULL) ||\r
+      (CompatInfo == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return FALSE;\r
+  }\r
+\r
+  Count           = ((COMPATIBILITY_INFO *)CompatInfo)->Count;\r
+  CompatibleTable = ((COMPATIBILITY_INFO *)CompatInfo)->CompatTable;\r
+\r
+  // Get the "compatible" property.\r
+  Prop = fdt_getprop (Fdt, Node, "compatible", &PropLen);\r
+  if ((Prop == NULL) || (PropLen < 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    if (fdt_stringlist_contains (\r
+          Prop,\r
+          PropLen,\r
+          CompatibleTable[Index].CompatStr\r
+          ))\r
+    {\r
+      return TRUE;\r
+    }\r
+  } // for\r
+\r
+  return FALSE;\r
+}\r
+\r
+/** Check whether a node has a property.\r
+\r
+  @param [in]  Fdt          Pointer to a Flattened Device Tree.\r
+  @param [in]  Node         Offset of the node to operate the check on.\r
+  @param [in]  PropertyName Name of the property to search.\r
+                            This is a NULL terminated string.\r
+\r
+  @retval True    The node has the property.\r
+  @retval FALSE   Otherwise, or error.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+FdtNodeHasProperty (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  Node,\r
+  IN  CONST VOID   *PropertyName\r
+  )\r
+{\r
+  INT32       Size;\r
+  CONST VOID  *Prop;\r
+\r
+  if ((Fdt == NULL) ||\r
+      (PropertyName == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return FALSE;\r
+  }\r
+\r
+  Prop = fdt_getprop (Fdt, Node, PropertyName, &Size);\r
+  if ((Prop == NULL) || (Size < 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/** Get the next node in the whole DT fulfilling a condition.\r
+\r
+  The condition to fulfill is checked by the NodeChecker function.\r
+  Context is passed to NodeChecker.\r
+\r
+  The Device tree is traversed in a depth-first search, starting from Node.\r
+  The input Node is skipped.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in, out]  Node        At entry: Node offset to start the search.\r
+                                          This first node is skipped.\r
+                                          Write (-1) to search the whole tree.\r
+                                At exit:  If success, contains the offset of\r
+                                          the next node fulfilling the\r
+                                          condition.\r
+  @param [in, out]  Depth       Depth is incremented/decremented of the depth\r
+                                difference between the input Node and the\r
+                                output Node.\r
+                                E.g.: If the output Node is a child node\r
+                                of the input Node, contains (+1).\r
+  @param [in]  NodeChecker      Function called to check if the condition\r
+                                is fulfilled.\r
+  @param [in]  Context          Context for the NodeChecker.\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           No matching node found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetNextCondNode (\r
+  IN      CONST VOID               *Fdt,\r
+  IN OUT        INT32              *Node,\r
+  IN OUT        INT32              *Depth,\r
+  IN            NODE_CHECKER_FUNC  NodeChecker,\r
+  IN      CONST VOID               *Context\r
+  )\r
+{\r
+  INT32  CurrNode;\r
+\r
+  if ((Fdt == NULL)   ||\r
+      (Node == NULL)  ||\r
+      (Depth == NULL) ||\r
+      (NodeChecker == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CurrNode = *Node;\r
+  do {\r
+    CurrNode = fdt_next_node (Fdt, CurrNode, Depth);\r
+    if ((CurrNode == -FDT_ERR_NOTFOUND) ||\r
+        (*Depth < 0))\r
+    {\r
+      // End of the tree, no matching node found.\r
+      return EFI_NOT_FOUND;\r
+    } else if (CurrNode < 0) {\r
+      // An error occurred.\r
+      ASSERT (0);\r
+      return EFI_ABORTED;\r
+    }\r
+  } while (!NodeChecker (Fdt, CurrNode, Context));\r
+\r
+  // Matching node found.\r
+  *Node = CurrNode;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/** Get the next node in a branch fulfilling a condition.\r
+\r
+  The condition to fulfill is checked by the NodeChecker function.\r
+  Context is passed to NodeChecker.\r
+\r
+  The Device tree is traversed in a depth-first search, starting from Node.\r
+  The input Node is skipped.\r
+\r
+  @param [in]       Fdt             Pointer to a Flattened Device Tree.\r
+  @param [in]       FdtBranch       Only search in the sub-nodes of this\r
+                                    branch.\r
+                                    Write (-1) to search the whole tree.\r
+  @param [in]       NodeChecker     Function called to check if the condition\r
+                                    is fulfilled.\r
+  @param [in]       Context         Context for the NodeChecker.\r
+  @param [in, out]  Node            At entry: Node offset to start the search.\r
+                                         This first node is skipped.\r
+                                         Write (-1) to search the whole tree.\r
+                                    At exit:  If success, contains the offset\r
+                                         of the next node in the branch\r
+                                         fulfilling the condition.\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           No matching node found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetNextCondNodeInBranch (\r
+  IN      CONST VOID               *Fdt,\r
+  IN            INT32              FdtBranch,\r
+  IN            NODE_CHECKER_FUNC  NodeChecker,\r
+  IN      CONST VOID               *Context,\r
+  IN OUT        INT32              *Node\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  INT32       CurrNode;\r
+  INT32       Depth;\r
+\r
+  if ((Fdt == NULL)   ||\r
+      (Node == NULL)  ||\r
+      (NodeChecker == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CurrNode = FdtBranch;\r
+  Depth    = 0;\r
+\r
+  // First, check the Node is in the sub-nodes of the branch.\r
+  // This allows to find the relative depth of Node in the branch.\r
+  if (CurrNode != *Node) {\r
+    for (CurrNode = fdt_next_node (Fdt, CurrNode, &Depth);\r
+         (CurrNode >= 0) && (Depth > 0);\r
+         CurrNode = fdt_next_node (Fdt, CurrNode, &Depth))\r
+    {\r
+      if (CurrNode == *Node) {\r
+        // Node found.\r
+        break;\r
+      }\r
+    } // for\r
+\r
+    if ((CurrNode < 0) || (Depth <= 0)) {\r
+      // Node is not a node in the branch, or an error occurred.\r
+      ASSERT (0);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  // Get the next node in the tree fulfilling the condition,\r
+  // in any branch.\r
+  Status = FdtGetNextCondNode (\r
+             Fdt,\r
+             Node,\r
+             &Depth,\r
+             NodeChecker,\r
+             Context\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (Status == EFI_NOT_FOUND);\r
+    return Status;\r
+  }\r
+\r
+  if (Depth <= 0) {\r
+    // The node found is not in the right branch.\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/** Get the next node in a branch having a matching name.\r
+\r
+  The Device tree is traversed in a depth-first search, starting from Node.\r
+  The input Node is skipped.\r
+\r
+  @param [in]       Fdt         Pointer to a Flattened Device Tree.\r
+  @param [in]       FdtBranch   Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]       NodeName    The node name to search.\r
+                                This is a NULL terminated string.\r
+  @param [in, out]  Node        At entry: Node offset to start the search.\r
+                                          This first node is skipped.\r
+                                          Write (-1) to search the whole tree.\r
+                                At exit:  If success, contains the offset of\r
+                                          the next node in the branch\r
+                                          having a matching name.\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           No matching node found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetNextNamedNodeInBranch (\r
+  IN      CONST VOID   *Fdt,\r
+  IN            INT32  FdtBranch,\r
+  IN      CONST CHAR8  *NodeName,\r
+  IN OUT        INT32  *Node\r
+  )\r
+{\r
+  return FdtGetNextCondNodeInBranch (\r
+           Fdt,\r
+           FdtBranch,\r
+           FdtNodeHasName,\r
+           NodeName,\r
+           Node\r
+           );\r
+}\r
+\r
+/** Get the next node in a branch with at least one compatible property.\r
+\r
+  The Device tree is traversed in a depth-first search, starting from Node.\r
+  The input Node is skipped.\r
+\r
+  @param [in]       Fdt         Pointer to a Flattened Device Tree.\r
+  @param [in]       FdtBranch   Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  CompatNamesInfo  Table of compatible strings to compare with\r
+                                the compatible property of the node.\r
+  @param [in, out]  Node        At entry: Node offset to start the search.\r
+                                          This first node is skipped.\r
+                                          Write (-1) to search the whole tree.\r
+                                At exit:  If success, contains the offset of\r
+                                          the next node in the branch\r
+                                          being compatible.\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           No matching node found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetNextCompatNodeInBranch (\r
+  IN      CONST VOID                *Fdt,\r
+  IN            INT32               FdtBranch,\r
+  IN      CONST COMPATIBILITY_INFO  *CompatNamesInfo,\r
+  IN OUT        INT32               *Node\r
+  )\r
+{\r
+  return FdtGetNextCondNodeInBranch (\r
+           Fdt,\r
+           FdtBranch,\r
+           FdtNodeIsCompatible,\r
+           (CONST VOID *)CompatNamesInfo,\r
+           Node\r
+           );\r
+}\r
+\r
+/** Get the next node in a branch having the PropName property.\r
+\r
+  The Device tree is traversed in a depth-first search, starting from Node.\r
+  The input Node is skipped.\r
+\r
+  @param [in]       Fdt         Pointer to a Flattened Device Tree.\r
+  @param [in]       FdtBranch   Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]       PropName    Name of the property to search.\r
+                                This is a NULL terminated string.\r
+  @param [in, out]  Node        At entry: Node offset to start the search.\r
+                                          This first node is skipped.\r
+                                          Write (-1) to search the whole tree.\r
+                                At exit:  If success, contains the offset of\r
+                                          the next node in the branch\r
+                                          being compatible.\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           No matching node found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetNextPropNodeInBranch (\r
+  IN      CONST VOID   *Fdt,\r
+  IN            INT32  FdtBranch,\r
+  IN      CONST CHAR8  *PropName,\r
+  IN OUT        INT32  *Node\r
+  )\r
+{\r
+  return FdtGetNextCondNodeInBranch (\r
+           Fdt,\r
+           FdtBranch,\r
+           FdtNodeHasProperty,\r
+           (CONST VOID *)PropName,\r
+           Node\r
+           );\r
+}\r
+\r
+/** Count the number of Device Tree nodes fulfilling a condition\r
+    in a Device Tree branch.\r
+\r
+  The condition to fulfill is checked by the NodeChecker function.\r
+  Context is passed to NodeChecker.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  FdtBranch        Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  NodeChecker      Function called to check the condition is\r
+                                fulfilled.\r
+  @param [in]  Context          Context for the NodeChecker.\r
+  @param [out] NodeCount        If success, contains the count of nodes\r
+                                fulfilling the condition.\r
+                                Can be 0.\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
+FdtCountCondNodeInBranch (\r
+  IN  CONST VOID               *Fdt,\r
+  IN        INT32              FdtBranch,\r
+  IN        NODE_CHECKER_FUNC  NodeChecker,\r
+  IN  CONST VOID               *Context,\r
+  OUT       UINT32             *NodeCount\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  INT32       CurrNode;\r
+\r
+  if ((Fdt == NULL)         ||\r
+      (NodeChecker == NULL) ||\r
+      (NodeCount == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *NodeCount = 0;\r
+  CurrNode   = FdtBranch;\r
+  while (TRUE) {\r
+    Status = FdtGetNextCondNodeInBranch (\r
+               Fdt,\r
+               FdtBranch,\r
+               NodeChecker,\r
+               Context,\r
+               &CurrNode\r
+               );\r
+    if (EFI_ERROR (Status)  &&\r
+        (Status != EFI_NOT_FOUND))\r
+    {\r
+      ASSERT (0);\r
+      return Status;\r
+    } else if (Status == EFI_NOT_FOUND) {\r
+      break;\r
+    }\r
+\r
+    (*NodeCount)++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/** Count the number of nodes in a branch with the input name.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  FdtBranch        Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  NodeName         Node name to search.\r
+                                This is a NULL terminated string.\r
+  @param [out] NodeCount        If success, contains the count of nodes\r
+                                fulfilling the condition.\r
+                                Can be 0.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtCountNamedNodeInBranch (\r
+  IN  CONST VOID    *Fdt,\r
+  IN        INT32   FdtBranch,\r
+  IN  CONST CHAR8   *NodeName,\r
+  OUT       UINT32  *NodeCount\r
+  )\r
+{\r
+  return FdtCountCondNodeInBranch (\r
+           Fdt,\r
+           FdtBranch,\r
+           FdtNodeHasName,\r
+           NodeName,\r
+           NodeCount\r
+           );\r
+}\r
+\r
+/** Count the number of nodes in a branch with at least\r
+    one compatible property.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  FdtBranch        Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  CompatNamesInfo  Table of compatible strings to\r
+                                compare with the compatible property\r
+                                of the node.\r
+  @param [out] NodeCount        If success, contains the count of nodes\r
+                                fulfilling the condition.\r
+                                Can be 0.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtCountCompatNodeInBranch (\r
+  IN  CONST VOID                *Fdt,\r
+  IN        INT32               FdtBranch,\r
+  IN  CONST COMPATIBILITY_INFO  *CompatNamesInfo,\r
+  OUT       UINT32              *NodeCount\r
+  )\r
+{\r
+  return FdtCountCondNodeInBranch (\r
+           Fdt,\r
+           FdtBranch,\r
+           FdtNodeIsCompatible,\r
+           CompatNamesInfo,\r
+           NodeCount\r
+           );\r
+}\r
+\r
+/** Count the number of nodes in a branch having the PropName property.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  FdtBranch        Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  PropName         Name of the property to search.\r
+                                This is a NULL terminated string.\r
+  @param [out] NodeCount        If success, contains the count of nodes\r
+                                fulfilling the condition.\r
+                                Can be 0.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtCountPropNodeInBranch (\r
+  IN  CONST VOID    *Fdt,\r
+  IN        INT32   FdtBranch,\r
+  IN  CONST CHAR8   *PropName,\r
+  OUT       UINT32  *NodeCount\r
+  )\r
+{\r
+  return FdtCountCondNodeInBranch (\r
+           Fdt,\r
+           FdtBranch,\r
+           FdtNodeHasProperty,\r
+           PropName,\r
+           NodeCount\r
+           );\r
+}\r
+\r
+/** Get the interrupt-controller node handling the interrupts of\r
+    the input node.\r
+\r
+  To do this, recursively search a node with either the "interrupt-controller"\r
+  or the "interrupt-parent" property in the parents of Node.\r
+\r
+  Devicetree Specification, Release v0.3,\r
+  2.4.1 "Properties for Interrupt Generating Devices":\r
+    Because the hierarchy of the nodes in the interrupt tree\r
+    might not match the devicetree, the interrupt-parent\r
+    property is available to make the definition of an\r
+    interrupt parent explicit. The value is the phandle to the\r
+    interrupt parent. If this property is missing from a\r
+    device, its interrupt parent is assumed to be its devicetree\r
+    parent.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  Node             Offset of the node to start the search.\r
+  @param [out] IntcNode         If success, contains the offset of the\r
+                                interrupt-controller node.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+  @retval EFI_NOT_FOUND           No interrupt-controller node found.\r
+  @retval EFI_ABORTED             An error occurred.\r
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetIntcParentNode (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  Node,\r
+  OUT       INT32  *IntcNode\r
+  )\r
+{\r
+  CONST UINT32  *PHandle;\r
+  INT32         Size;\r
+  CONST VOID    *Prop;\r
+\r
+  if ((Fdt == NULL) ||\r
+      (IntcNode == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  while (TRUE) {\r
+    // Check whether the node has the "interrupt-controller" property.\r
+    Prop = fdt_getprop (Fdt, Node, "interrupt-controller", &Size);\r
+    if ((Prop != NULL) && (Size >= 0)) {\r
+      // The interrupt-controller has been found.\r
+      *IntcNode = Node;\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      // Check whether the node has the "interrupt-parent" property.\r
+      PHandle = fdt_getprop (Fdt, Node, "interrupt-parent", &Size);\r
+      if ((PHandle != NULL) && (Size == sizeof (UINT32))) {\r
+        // The phandle of the interrupt-controller has been found.\r
+        // Search the node having this phandle and return it.\r
+        Node = fdt_node_offset_by_phandle (Fdt, fdt32_to_cpu (*PHandle));\r
+        if (Node < 0) {\r
+          ASSERT (0);\r
+          return EFI_ABORTED;\r
+        }\r
+\r
+        *IntcNode = Node;\r
+        return EFI_SUCCESS;\r
+      } else if (Size != -FDT_ERR_NOTFOUND) {\r
+        ASSERT (0);\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    if (Node == 0) {\r
+      // We are at the root of the tree. Not parent available.\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    // Get the parent of the node.\r
+    Node = fdt_parent_offset (Fdt, Node);\r
+    if (Node < 0) {\r
+      // An error occurred.\r
+      ASSERT (0);\r
+      return EFI_ABORTED;\r
+    }\r
+  } // while\r
+}\r
+\r
+/** Get the "interrupt-cells" property value of the node.\r
+\r
+  The "interrupts" property requires to know the number of cells used\r
+  to encode an interrupt. This information is stored in the\r
+  interrupt-controller of the input Node.\r
+\r
+  @param [in]  Fdt          Pointer to a Flattened Device Tree (Fdt).\r
+  @param [in]  IntcNode     Offset of an interrupt-controller node.\r
+  @param [out] IntCells     If success, contains the "interrupt-cells"\r
+                            property of the IntcNode.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+  @retval EFI_UNSUPPORTED         Unsupported.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetInterruptCellsInfo (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  IntcNode,\r
+  OUT       INT32  *IntCells\r
+  )\r
+{\r
+  CONST UINT32  *Data;\r
+  INT32         Size;\r
+\r
+  if ((Fdt == NULL) ||\r
+      (IntCells == NULL))\r
+  {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Data = fdt_getprop (Fdt, IntcNode, "#interrupt-cells", &Size);\r
+  if ((Data == NULL) || (Size != sizeof (UINT32))) {\r
+    // If error or not on one UINT32 cell.\r
+    ASSERT (0);\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  *IntCells = fdt32_to_cpu (*Data);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/** Get the "#address-cells" and/or "#size-cells" property of the node.\r
+\r
+  According to the Device Tree specification, s2.3.5 "#address-cells and\r
+  #size-cells":\r
+  "If missing, a client program should assume a default value of 2 for\r
+  #address-cells, and a value of 1 for #size-cells."\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  Node             Offset of the node having to get the\r
+                                "#address-cells" and "#size-cells"\r
+                                properties from.\r
+  @param [out] AddressCells     If success, number of address-cells.\r
+                                If the property is not available,\r
+                                default value is 2.\r
+  @param [out] SizeCells        If success, number of size-cells.\r
+                                If the property is not available,\r
+                                default value is 1.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtGetAddressInfo (\r
+  IN  CONST VOID *Fdt,\r
+  IN        INT32 Node,\r
+  OUT       INT32 *AddressCells, OPTIONAL\r
+  OUT       INT32     *SizeCells       OPTIONAL\r
+  )\r
+{\r
+  if (Fdt == NULL) {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (AddressCells != NULL) {\r
+    *AddressCells = fdt_address_cells (Fdt, Node);\r
+    if (*AddressCells < 0) {\r
+      ASSERT (0);\r
+      return EFI_ABORTED;\r
+    }\r
+  }\r
+\r
+  if (SizeCells != NULL) {\r
+    *SizeCells = fdt_size_cells (Fdt, Node);\r
+    if (*SizeCells < 0) {\r
+      ASSERT (0);\r
+      return EFI_ABORTED;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/** Get the "#address-cells" and/or "#size-cells" property of the parent node.\r
+\r
+  According to the Device Tree specification, s2.3.5 "#address-cells and\r
+  #size-cells":\r
+  "If missing, a client program should assume a default value of 2 for\r
+  #address-cells, and a value of 1 for #size-cells."\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  Node             Offset of the node having to get the\r
+                                "#address-cells" and "#size-cells"\r
+                                properties from its parent.\r
+  @param [out] AddressCells     If success, number of address-cells.\r
+                                If the property is not available,\r
+                                default value is 2.\r
+  @param [out] SizeCells        If success, number of size-cells.\r
+                                If the property is not available,\r
+                                default value is 1.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtGetParentAddressInfo (\r
+  IN  CONST VOID *Fdt,\r
+  IN        INT32 Node,\r
+  OUT       INT32 *AddressCells, OPTIONAL\r
+  OUT       INT32     *SizeCells       OPTIONAL\r
+  )\r
+{\r
+  if (Fdt == NULL) {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Node = fdt_parent_offset (Fdt, Node);\r
+  if (Node < 0) {\r
+    // End of the tree, or an error occurred.\r
+    ASSERT (0);\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return FdtGetAddressInfo (Fdt, Node, AddressCells, SizeCells);\r
+}\r
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h
new file mode 100644 (file)
index 0000000..f2f4256
--- /dev/null
@@ -0,0 +1,458 @@
+/** @file\r
+  Flattened device tree utility.\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
+  - Device tree Specification - Release v0.3\r
+  - linux/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml\r
+  - linux//Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml\r
+**/\r
+\r
+#ifndef FDT_UTILITY_H_\r
+#define FDT_UTILITY_H_\r
+\r
+/** Get the offset of an address in a "reg" Device Tree property.\r
+\r
+  In a Device Tree, the "reg" property stores address/size couples.\r
+  They are stored on N 32-bits cells.\r
+  Based on the value of the #address-cells, the #size-cells and the\r
+  index in the "reg" property, compute the number of 32-bits cells\r
+  to skip.\r
+\r
+  @param [in]  Index        Index in the reg property.\r
+  @param [in]  AddrCells    Number of cells used to store an address.\r
+  @param [in]  SizeCells    Number of cells used to store the size of\r
+                            an address.\r
+\r
+  @retval  Number of 32-bits cells to skip to access the address.\r
+*/\r
+#define GET_DT_REG_ADDRESS_OFFSET(Index, AddrCells, SizeCells)  (           \\r
+          (Index) * ((AddrCells) + (SizeCells))                             \\r
+          )\r
+\r
+/** Get the offset of an address size in a "reg" Device Tree property.\r
+\r
+  In a Device Tree, the "reg" property stores address/size couples.\r
+  They are stored on N 32-bits cells.\r
+  Based on the value of the #address-cells, the #size-cells and the\r
+  index in the "reg" property, compute the number of 32-bits cells\r
+  to skip.\r
+\r
+  @param [in]  Index        Index in the reg property.\r
+  @param [in]  AddrCells    Number of cells used to store an address.\r
+  @param [in]  SizeCells    Number of cells used to store the size of\r
+                            an address.\r
+\r
+  @retval  Number of 32-bits cells to skip to access the address size.\r
+*/\r
+#define GET_DT_REG_SIZE_OFFSET(Index, AddrCells, SizeCells)  (              \\r
+          GET_DT_REG_ADDRESS_OFFSET ((Index), (AddrCells), (SizeCells)) +   \\r
+          (SizeCells)                                                       \\r
+          )\r
+\r
+/// Maximum string length for compatible names.\r
+#define COMPATIBLE_STR_LEN  (32U)\r
+\r
+/// Interrupt macros\r
+#define PPI_OFFSET  (16U)\r
+#define SPI_OFFSET  (32U)\r
+#define DT_PPI_IRQ  (1U)\r
+#define DT_SPI_IRQ  (0U)\r
+#define DT_IRQ_IS_EDGE_TRIGGERED(x)  ((((x) & (BIT0 | BIT2)) != 0))\r
+#define DT_IRQ_IS_ACTIVE_LOW(x)      ((((x) & (BIT1 | BIT3)) != 0))\r
+#define IRQ_TYPE_OFFSET    (0U)\r
+#define IRQ_NUMBER_OFFSET  (1U)\r
+#define IRQ_FLAGS_OFFSET   (2U)\r
+\r
+/** Get the interrupt Id of an interrupt described in a fdt.\r
+\r
+  Data must describe a GIC interrupt. A GIC interrupt is on at least\r
+  3 UINT32 cells.\r
+  This function DOES NOT SUPPORT extended SPI range and extended PPI range.\r
+\r
+  @param [in]  Data   Pointer to the first cell of an "interrupts" property.\r
+\r
+  @retval  The interrupt id.\r
+**/\r
+UINT32\r
+EFIAPI\r
+FdtGetInterruptId (\r
+  UINT32 CONST  *Data\r
+  );\r
+\r
+/** Get the ACPI interrupt flags of an interrupt described in a fdt.\r
+\r
+  Data must describe a GIC interrupt. A GIC interrupt is on at least\r
+  3 UINT32 cells.\r
+\r
+  @param [in]  Data   Pointer to the first cell of an "interrupts" property.\r
+\r
+  @retval  The interrupt flags (for ACPI).\r
+**/\r
+UINT32\r
+EFIAPI\r
+FdtGetInterruptFlags (\r
+  UINT32 CONST  *Data\r
+  );\r
+\r
+/** A structure describing a compatibility string.\r
+*/\r
+typedef struct CompatStr {\r
+  CONST CHAR8    CompatStr[COMPATIBLE_STR_LEN];\r
+} COMPATIBILITY_STR;\r
+\r
+/** Structure containing a list of compatible names and their count.\r
+*/\r
+typedef struct CompatibilityInfo {\r
+  /// Count of entries in the NAME_TABLE.\r
+  UINT32                     Count;\r
+\r
+  /// Pointer to a table storing the names.\r
+  CONST COMPATIBILITY_STR    *CompatTable;\r
+} COMPATIBILITY_INFO;\r
+\r
+/** Operate a check on a Device Tree node.\r
+\r
+  @param [in]  Fdt          Pointer to a Flattened Device Tree.\r
+  @param [in]  NodeOffset   Offset of the node to compare input string.\r
+  @param [in]  Context      Context to operate the check on the node.\r
+\r
+  @retval True    The check is correct.\r
+  @retval FALSE   Otherwise, or error.\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *NODE_CHECKER_FUNC)(\r
+  IN  CONST VOID    *Fdt,\r
+  IN        INT32     NodeOffset,\r
+  IN  CONST VOID    *Context\r
+  );\r
+\r
+/** Iterate through the list of strings in the Context,\r
+    and check whether at least one string is matching the\r
+    "compatible" property of the node.\r
+\r
+  @param [in]  Fdt          Pointer to a Flattened Device Tree.\r
+  @param [in]  Node         Offset of the node to operate the check on.\r
+  @param [in]  CompatInfo   COMPATIBILITY_INFO containing the list of compatible\r
+                            strings to compare with the "compatible" property\r
+                            of the node.\r
+\r
+  @retval TRUE    At least one string matched, the node is compatible.\r
+  @retval FALSE   Otherwise, or error.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+FdtNodeIsCompatible (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  Node,\r
+  IN  CONST VOID   *CompatInfo\r
+  );\r
+\r
+/** Check whether a node has a property.\r
+\r
+  @param [in]  Fdt          Pointer to a Flattened Device Tree.\r
+  @param [in]  Node         Offset of the node to operate the check on.\r
+  @param [in]  PropertyName Name of the property to search.\r
+                            This is a NULL terminated string.\r
+\r
+  @retval True    The node has the property.\r
+  @retval FALSE   Otherwise, or error.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+FdtNodeHasProperty (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  Node,\r
+  IN  CONST VOID   *PropertyName\r
+  );\r
+\r
+/** Get the next node in a branch having a matching name.\r
+\r
+  The Device tree is traversed in a depth-first search, starting from Node.\r
+  The input Node is skipped.\r
+\r
+  @param [in]       Fdt         Pointer to a Flattened Device Tree.\r
+  @param [in]       FdtBranch   Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]       NodeName    The node name to search.\r
+                                This is a NULL terminated string.\r
+  @param [in, out]  Node        At entry: Node offset to start the search.\r
+                                          This first node is skipped.\r
+                                          Write (-1) to search the whole tree.\r
+                                At exit:  If success, contains the offset of\r
+                                          the next node in the branch\r
+                                          having a matching name.\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           No matching node found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetNextNamedNodeInBranch (\r
+  IN      CONST VOID   *Fdt,\r
+  IN            INT32  FdtBranch,\r
+  IN      CONST CHAR8  *NodeName,\r
+  IN OUT        INT32  *Node\r
+  );\r
+\r
+/** Get the next node in a branch with at least one compatible property.\r
+\r
+  The Device tree is traversed in a depth-first search, starting from Node.\r
+  The input Node is skipped.\r
+\r
+  @param [in]       Fdt         Pointer to a Flattened Device Tree.\r
+  @param [in]       FdtBranch   Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  CompatNamesInfo  Table of compatible strings to compare with\r
+                                the compatible property of the node.\r
+  @param [in, out]  Node        At entry: Node offset to start the search.\r
+                                          This first node is skipped.\r
+                                          Write (-1) to search the whole tree.\r
+                                At exit:  If success, contains the offset of\r
+                                          the next node in the branch\r
+                                          being compatible.\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           No matching node found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetNextCompatNodeInBranch (\r
+  IN      CONST VOID                *Fdt,\r
+  IN            INT32               FdtBranch,\r
+  IN      CONST COMPATIBILITY_INFO  *CompatNamesInfo,\r
+  IN OUT        INT32               *Node\r
+  );\r
+\r
+/** Get the next node in a branch having the PropName property.\r
+\r
+  The Device tree is traversed in a depth-first search, starting from Node.\r
+  The input Node is skipped.\r
+\r
+  @param [in]       Fdt         Pointer to a Flattened Device Tree.\r
+  @param [in]       FdtBranch   Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]       PropName    Name of the property to search.\r
+                                This is a NULL terminated string.\r
+  @param [in, out]  Node        At entry: Node offset to start the search.\r
+                                          This first node is skipped.\r
+                                          Write (-1) to search the whole tree.\r
+                                At exit:  If success, contains the offset of\r
+                                          the next node in the branch\r
+                                          being compatible.\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           No matching node found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetNextPropNodeInBranch (\r
+  IN      CONST VOID   *Fdt,\r
+  IN            INT32  FdtBranch,\r
+  IN      CONST CHAR8  *PropName,\r
+  IN OUT        INT32  *Node\r
+  );\r
+\r
+/** Count the number of nodes in a branch with the input name.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  FdtBranch        Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  NodeName         Node name to search.\r
+                                This is a NULL terminated string.\r
+  @param [out] NodeCount        If success, contains the count of nodes\r
+                                fulfilling the condition.\r
+                                Can be 0.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtCountNamedNodeInBranch (\r
+  IN  CONST VOID    *Fdt,\r
+  IN        INT32   FdtBranch,\r
+  IN  CONST CHAR8   *NodeName,\r
+  OUT       UINT32  *NodeCount\r
+  );\r
+\r
+/** Count the number of nodes in a branch with at least\r
+    one compatible property.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  FdtBranch        Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  CompatibleTable  Table of compatible strings to\r
+                                compare with the compatible property\r
+                                of the node.\r
+  @param [out] NodeCount        If success, contains the count of nodes\r
+                                fulfilling the condition.\r
+                                Can be 0.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtCountCompatNodeInBranch (\r
+  IN  CONST VOID                *Fdt,\r
+  IN        INT32               FdtBranch,\r
+  IN  CONST COMPATIBILITY_INFO  *CompatNamesInfo,\r
+  OUT       UINT32              *NodeCount\r
+  );\r
+\r
+/** Count the number of nodes in a branch having the PropName property.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  FdtBranch        Only search in the sub-nodes of this branch.\r
+                                Write (-1) to search the whole tree.\r
+  @param [in]  PropName         Name of the property to search.\r
+                                This is a NULL terminated string.\r
+  @param [out] NodeCount        If success, contains the count of nodes\r
+                                fulfilling the condition.\r
+                                Can be 0.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtCountPropNodeInBranch (\r
+  IN  CONST VOID    *Fdt,\r
+  IN        INT32   FdtBranch,\r
+  IN  CONST CHAR8   *PropName,\r
+  OUT       UINT32  *NodeCount\r
+  );\r
+\r
+/** Get the interrupt-controller node handling the interrupts of\r
+    the input node.\r
+\r
+  To do this, recursively search a node with either the "interrupt-controller"\r
+  or the "interrupt-parent" property in the parents of Node.\r
+\r
+  Devicetree Specification, Release v0.3,\r
+  2.4.1 "Properties for Interrupt Generating Devices":\r
+    Because the hierarchy of the nodes in the interrupt tree\r
+    might not match the devicetree, the interrupt-parent\r
+    property is available to make the definition of an\r
+    interrupt parent explicit. The value is the phandle to the\r
+    interrupt parent. If this property is missing from a\r
+    device, its interrupt parent is assumed to be its devicetree\r
+    parent.\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  Node             Offset of the node to start the search.\r
+  @param [out] IntcNode         If success, contains the offset of the\r
+                                interrupt-controller node.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+  @retval EFI_NOT_FOUND           No interrupt-controller node found.\r
+  @retval EFI_ABORTED             An error occurred.\r
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetIntcParentNode (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  Node,\r
+  OUT       INT32  *IntcNode\r
+  );\r
+\r
+/** Get the "interrupt-cells" property value of the node.\r
+\r
+  The "interrupts" property requires to know the number of cells used\r
+  to encode an interrupt. This information is stored in the\r
+  interrupt-controller of the input Node.\r
+\r
+  @param [in]  Fdt          Pointer to a Flattened Device Tree (Fdt).\r
+  @param [in]  IntcNode     Offset of an interrupt-controller node.\r
+  @param [out] IntCells     If success, contains the "interrupt-cells"\r
+                            property of the IntcNode.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+  @retval EFI_UNSUPPORTED         Unsupported.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FdtGetInterruptCellsInfo (\r
+  IN  CONST VOID   *Fdt,\r
+  IN        INT32  IntcNode,\r
+  OUT       INT32  *InterruptCells\r
+  );\r
+\r
+/** Get the "#address-cells" and/or "#size-cells" property of the node.\r
+\r
+  According to the Device Tree specification, s2.3.5 "#address-cells and\r
+  #size-cells":\r
+  "If missing, a client program should assume a default value of 2 for\r
+  #address-cells, and a value of 1 for #size-cells."\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  Node             Offset of the node having to get the\r
+                                "#address-cells" and "#size-cells"\r
+                                properties from.\r
+  @param [out] AddressCells     If success, number of address-cells.\r
+                                If the property is not available,\r
+                                default value is 2.\r
+  @param [out] SizeCells        If success, number of size-cells.\r
+                                If the property is not available,\r
+                                default value is 1.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtGetAddressInfo (\r
+  IN  CONST VOID *Fdt,\r
+  IN        INT32 Node,\r
+  OUT       INT32 *AddressCells, OPTIONAL\r
+  OUT       INT32     *SizeCells       OPTIONAL\r
+  );\r
+\r
+/** Get the "#address-cells" and/or "#size-cells" property of the parent node.\r
+\r
+  According to the Device Tree specification, s2.3.5 "#address-cells and\r
+  #size-cells":\r
+  "If missing, a client program should assume a default value of 2 for\r
+  #address-cells, and a value of 1 for #size-cells."\r
+\r
+  @param [in]  Fdt              Pointer to a Flattened Device Tree.\r
+  @param [in]  Node             Offset of the node having to get the\r
+                                "#address-cells" and "#size-cells"\r
+                                properties from its parent.\r
+  @param [out] AddressCells     If success, number of address-cells.\r
+                                If the property is not available,\r
+                                default value is 2.\r
+  @param [out] SizeCells        If success, number of size-cells.\r
+                                If the property is not available,\r
+                                default value is 1.\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
+EFI_STATUS\r
+EFIAPI\r
+FdtGetParentAddressInfo (\r
+  IN  CONST VOID *Fdt,\r
+  IN        INT32 Node,\r
+  OUT       INT32 *AddressCells, OPTIONAL\r
+  OUT       INT32     *SizeCells       OPTIONAL\r
+  );\r
+\r
+#endif // FDT_UTILITY_H_\r