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