diff mbox

[Linaro-uefi,v2] Platforms/AMD: implement DtPlatformDtbLoaderLib

Message ID 20170407085932.2765-1-ard.biesheuvel@linaro.org
State Accepted
Commit 549704d61d83e4c87dbb75c4d354b215389e478b
Headers show

Commit Message

Ard Biesheuvel April 7, 2017, 8:59 a.m. UTC
In order to be able to switch to the generic DtPlatformDxe driver,
implement the glue library that loads it and prepares it based on
the properties of the actual hardware.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c   | 481 ++++++++++++++++++++
 Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf |  64 +++
 2 files changed, 545 insertions(+)

Comments

Ard Biesheuvel April 7, 2017, 9:03 a.m. UTC | #1
On 7 April 2017 at 09:59, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> In order to be able to switch to the generic DtPlatformDxe driver,
> implement the glue library that loads it and prepares it based on
> the properties of the actual hardware.
>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---

v2: whitespace changes mostly, and fixed the IsRevB1 test to use SOCid defines

>  Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c   | 481 ++++++++++++++++++++
>  Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf |  64 +++
>  2 files changed, 545 insertions(+)
>
> diff --git a/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c
> new file mode 100644
> index 000000000000..b18caf19985b
> --- /dev/null
> +++ b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c
> @@ -0,0 +1,481 @@
> +/** @file
> +*
> +*  Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> +*
> +*  This program and the accompanying materials
> +*  are licensed and made available under the terms and conditions of the BSD License
> +*  which accompanies this distribution.  The full text of the license may be found at
> +*  http://opensource.org/licenses/bsd-license.php
> +*
> +*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +*
> +**/
> +
> +#include <PiDxe.h>
> +
> +#include <Guid/ArmMpCoreInfo.h>
> +
> +#include <libfdt.h>
> +#include <Library/ArmLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DxeServicesLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include <Protocol/AmdMpCoreInfo.h>
> +
> +#define PMU_INT_FLAG_SPI        0
> +#define PMU_INT_TYPE_HIGH_LEVEL 4
> +
> +//
> +// PMU interrupts per core
> +//
> +#pragma pack(push, 1)
> +typedef struct {
> +  UINT32 Flag;          // 0 == SPI
> +  UINT32 IntId;         // GSIV == IntId+32
> +  UINT32 Type;          // 4 == Level-Sensitive, Active-High
> +} PMU_INTERRUPT;
> +#pragma pack(pop)
> +
> +STATIC
> +BOOLEAN
> +ClusterInRange (
> +  IN ARM_CORE_INFO  *ArmCoreInfoTable,
> +  IN UINTN          ClusterId,
> +  IN UINTN          LowIndex,
> +  IN UINTN          HighIndex
> +  )
> +{
> +  do {
> +    if (ClusterId == ArmCoreInfoTable[LowIndex].ClusterId)
> +      return TRUE;
> +  } while (++LowIndex <= HighIndex);
> +
> +  return FALSE;
> +}
> +
> +
> +STATIC
> +UINTN
> +NumberOfCoresInCluster (
> +  IN ARM_CORE_INFO  *ArmCoreInfoTable,
> +  IN UINTN          NumberOfEntries,
> +  IN UINTN          ClusterId
> +  )
> +{
> +  UINTN Index, Cores;
> +
> +  Cores = 0;
> +  for (Index = 0; Index < NumberOfEntries; ++Index) {
> +    if (ClusterId == ArmCoreInfoTable[Index].ClusterId)
> +      ++Cores;
> +  }
> +
> +  return Cores;
> +}
> +
> +
> +STATIC
> +UINTN
> +NumberOfClustersInTable (
> +  IN ARM_CORE_INFO  *ArmCoreInfoTable,
> +  IN UINTN          NumberOfEntries
> +  )
> +{
> +  UINTN Index, Cores, Clusters, ClusterId;
> +
> +  Index = 0;
> +  Clusters = 0;
> +  Cores = NumberOfEntries;
> +  while (Cores) {
> +     ++Clusters;
> +     ClusterId = ArmCoreInfoTable[Index].ClusterId;
> +     Cores -= NumberOfCoresInCluster (ArmCoreInfoTable,
> +                                      NumberOfEntries,
> +                                      ClusterId);
> +     if (Cores) {
> +       do {
> +         ++Index;
> +       } while (ClusterInRange (ArmCoreInfoTable,
> +                                ArmCoreInfoTable[Index].ClusterId,
> +                                0, Index-1));
> +     }
> +  }
> +
> +  return Clusters;
> +}
> +
> +
> +STATIC
> +INT32
> +fdt_alloc_phandle (
> +  IN VOID     *Fdt
> +  )
> +{
> +  INT32    Offset;
> +  INT32    Phandle;
> +
> +  Phandle = 0;
> +
> +  for (Offset = fdt_next_node (Fdt, -1, NULL); Offset >= 0;
> +       Offset = fdt_next_node (Fdt, Offset, NULL)) {
> +       Phandle = MAX (Phandle, fdt_get_phandle (Fdt, Offset));
> +  }
> +
> +  return Phandle + 1;
> +}
> +
> +STATIC
> +VOID
> +SetDeviceStatus (
> +  IN VOID           *Fdt,
> +  IN CONST CHAR8    *Device,
> +  IN BOOLEAN        Enable
> +  )
> +{
> +  INT32     Node;
> +  INT32     SubNode;
> +  INT32     Rc;
> +
> +  Node = fdt_subnode_offset (Fdt, 0, "smb");
> +  if (Node >= 0) {
> +    SubNode = fdt_subnode_offset (Fdt, Node, Device);
> +    if (SubNode >= 0) {
> +      Rc = fdt_setprop_string (Fdt, SubNode, "status",
> +             Enable ? "okay" : "disabled");
> +      if (Rc) {
> +        DEBUG ((DEBUG_ERROR,
> +          "%a: Could not set 'status' property for '%a' node\n",
> +          __FUNCTION__, Device));
> +      }
> +    }
> +  }
> +}
> +
> +#if DO_XGBE
> +
> +#define MAC_ADDRESS_BYTES       6
> +
> +STATIC
> +VOID
> +SetMacAddress (
> +  IN VOID           *Fdt,
> +  IN CONST CHAR8    *Device,
> +  IN UINT64         MacAddress
> +  )
> +{
> +  INT32     Node;
> +  INT32     SubNode;
> +  INT32     Rc;
> +
> +  Node = fdt_subnode_offset (Fdt, 0, "smb");
> +  if (Node >= 0) {
> +    SubNode = fdt_subnode_offset (Fdt, Node, Device);
> +    if (SubNode >= 0) {
> +      Rc = fdt_setprop (Fdt, SubNode, "mac-address", (VOID *)&MacAddress,
> +             MAC_ADDRESS_BYTES);
> +      if (Rc) {
> +        DEBUG ((DEBUG_ERROR,
> +          "%a: Could not set 'mac-address' property for '%a' node\n",
> +          __FUNCTION__, Device));
> +      }
> +    }
> +  }
> +}
> +
> +#endif
> +
> +#define STYX_SOC_VERSION_MASK    0xFFF
> +#define STYX_SOC_VERSION_A0      0x000
> +#define STYX_SOC_VERSION_B0      0x010
> +#define STYX_SOC_VERSION_B1      0x011
> +
> +STATIC
> +VOID
> +SetSocIdStatus (
> +  IN VOID       *Fdt
> +  )
> +{
> +  UINT32        SocId;
> +  BOOLEAN       IsRevB1;
> +
> +  SocId = PcdGet32 (PcdSocCpuId);
> +  IsRevB1 = (SocId & STYX_SOC_VERSION_MASK) >= STYX_SOC_VERSION_B1;
> +
> +  SetDeviceStatus (Fdt, "sata@e0d00000",
> +    IsRevB1 && FixedPcdGet8 (PcdSata1PortCount) > 0);
> +  SetDeviceStatus (Fdt, "gpio@e0020000", IsRevB1);
> +  SetDeviceStatus (Fdt, "gpio@e0030000", IsRevB1);
> +  SetDeviceStatus (Fdt, "gwdt@e0bb0000", IsRevB1);
> +#if DO_KCS
> +  SetDeviceStatus (Fdt, "kcs@e0010000", IsRevB1);
> +#else
> +  SetDeviceStatus (Fdt, "kcs@e0010000", FALSE);
> +#endif
> +}
> +
> +STATIC
> +VOID
> +SetXgbeStatus (
> +  IN VOID       *Fdt
> +  )
> +{
> +#if DO_XGBE
> +  SetDeviceStatus (Fdt, "xgmac@e0700000", TRUE);
> +  SetDeviceStatus (Fdt, "phy@e1240800", TRUE);
> +  SetDeviceStatus (Fdt, "xgmac@e0900000", TRUE);
> +  SetDeviceStatus (Fdt, "phy@e1240c00", TRUE);
> +
> +  SetMacAddress (Fdt, "xgmac@e0700000", PcdGet64 (PcdEthMacA));
> +  SetMacAddress (Fdt, "xgmac@e0900000", PcdGet64 (PcdEthMacB));
> +#else
> +  SetDeviceStatus (Fdt, "xgmac@e0700000", FALSE);
> +  SetDeviceStatus (Fdt, "phy@e1240800", FALSE);
> +  SetDeviceStatus (Fdt, "xgmac@e0900000", FALSE);
> +  SetDeviceStatus (Fdt, "phy@e1240c00", FALSE);
> +#endif
> +}
> +
> +
> +STATIC
> +EFI_STATUS
> +PrepareFdt (
> +  IN OUT VOID                 *Fdt,
> +  IN     UINTN                FdtSize
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  INT32                       Node;
> +  INT32                       CpuNode;
> +  UINTN                       Index;
> +  ARM_CORE_INFO               *ArmCoreInfoTable;
> +  UINTN                       ArmCoreCount;
> +  INT32                       MapNode;
> +  INT32                       ClusterNode;
> +  INT32                       PmuNode;
> +  PMU_INTERRUPT               PmuInt;
> +  INT32                       Phandle[NUM_CORES];
> +  UINT32                      ClusterIndex;
> +  UINT32                      CoreIndex;
> +  UINT32                      ClusterCount;
> +  UINT32                      CoresInCluster;
> +  UINT32                      ClusterId;
> +  UINTN                       MpId;
> +  CHAR8                       Name[10];
> +  AMD_MP_CORE_INFO_PROTOCOL   *AmdMpCoreInfoProtocol;
> +
> +  //
> +  // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms.
> +  //
> +  // For 'cpus' and 'cpu' device tree nodes bindings, refer to this file
> +  // in the kernel documentation:
> +  // Documentation/devicetree/bindings/arm/cpus.txt
> +  //
> +  Status = gBS->LocateProtocol (
> +                  &gAmdMpCoreInfoProtocolGuid,
> +                  NULL,
> +                  (VOID **)&AmdMpCoreInfoProtocol
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  // Get pointer to ARM core info table
> +  ArmCoreInfoTable = AmdMpCoreInfoProtocol->GetArmCoreInfoTable (&ArmCoreCount);
> +  ASSERT (ArmCoreInfoTable != NULL);
> +  ASSERT (ArmCoreCount <= NUM_CORES);
> +
> +  // Get Id from primary CPU
> +  MpId = (UINTN)ArmReadMpidr ();
> +
> +  // Create /pmu node
> +  PmuNode = fdt_add_subnode(Fdt, 0, "pmu");
> +  if (PmuNode >= 0) {
> +    fdt_setprop_string (Fdt, PmuNode, "compatible", "arm,armv8-pmuv3");
> +
> +    // append PMU interrupts
> +    for (Index = 0; Index < ArmCoreCount; Index++) {
> +      MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId,
> +                              ArmCoreInfoTable[Index].CoreId);
> +
> +      Status = AmdMpCoreInfoProtocol->GetPmuSpiFromMpId (MpId, &PmuInt.IntId);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR,
> +          "FDT: Error getting PMU interrupt for MpId '0x%x'\n", MpId));
> +        return Status;
> +      }
> +
> +      PmuInt.Flag = cpu_to_fdt32 (PMU_INT_FLAG_SPI);
> +      PmuInt.IntId = cpu_to_fdt32 (PmuInt.IntId);
> +      PmuInt.Type = cpu_to_fdt32 (PMU_INT_TYPE_HIGH_LEVEL);
> +      fdt_appendprop (Fdt, PmuNode, "interrupts", &PmuInt, sizeof(PmuInt));
> +    }
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "FDT: Error creating 'pmu' node\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Create /cpus noide
> +  Node = fdt_add_subnode (Fdt, 0, "cpus");
> +  if (Node >= 0) {
> +    // Configure the 'cpus' node
> +    fdt_setprop_string (Fdt, Node, "name", "cpus");
> +    fdt_setprop_cell (Fdt, Node, "#address-cells", sizeof (UINTN) / 4);
> +    fdt_setprop_cell (Fdt, Node, "#size-cells", 0);
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "FDT: Error creating 'cpus' node\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Walk the processor table in reverse order for proper listing in FDT
> +  //
> +  Index = ArmCoreCount;
> +  while (Index--) {
> +    // Create 'cpu' node
> +    AsciiSPrint (Name, sizeof (Name), "CPU%d", Index);
> +    CpuNode = fdt_add_subnode (Fdt, Node, Name);
> +    if (CpuNode < 0) {
> +      DEBUG ((DEBUG_ERROR, "FDT: Error on creating '%a' node\n", Name));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    Phandle[Index] = fdt_alloc_phandle (Fdt);
> +    fdt_setprop_cell (Fdt, CpuNode, "phandle", Phandle[Index]);
> +    fdt_setprop_cell (Fdt, CpuNode, "linux,phandle", Phandle[Index]);
> +
> +    fdt_setprop_string (Fdt, CpuNode, "enable-method", "psci");
> +
> +    MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId,
> +                            ArmCoreInfoTable[Index].CoreId);
> +    MpId = cpu_to_fdt64 (MpId);
> +    fdt_setprop (Fdt, CpuNode, "reg", &MpId, sizeof (MpId));
> +    fdt_setprop_string (Fdt, CpuNode, "compatible", "arm,armv8");
> +    fdt_setprop_string (Fdt, CpuNode, "device_type", "cpu");
> +  }
> +
> +  // Create /cpu-map node
> +  MapNode = fdt_add_subnode (Fdt, Node, "cpu-map");
> +  if (MapNode >= 0) {
> +    ClusterIndex = ArmCoreCount - 1;
> +    ClusterCount = NumberOfClustersInTable (ArmCoreInfoTable,
> +                                            ArmCoreCount);
> +    while (ClusterCount--) {
> +      // Create 'cluster' node
> +      AsciiSPrint (Name, sizeof (Name), "cluster%d", ClusterCount);
> +      ClusterNode = fdt_add_subnode (Fdt, MapNode, Name);
> +      if (ClusterNode < 0) {
> +        DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name));
> +        return EFI_INVALID_PARAMETER;
> +      }
> +
> +      ClusterId = ArmCoreInfoTable[ClusterIndex].ClusterId;
> +      CoreIndex = ClusterIndex;
> +      CoresInCluster = NumberOfCoresInCluster (ArmCoreInfoTable,
> +                                               ArmCoreCount,
> +                                               ClusterId);
> +      while (CoresInCluster--) {
> +        // Create 'core' node
> +        AsciiSPrint (Name, sizeof (Name), "core%d", CoresInCluster);
> +        CpuNode = fdt_add_subnode (Fdt, ClusterNode, Name);
> +        if (CpuNode < 0) {
> +          DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name));
> +          return EFI_INVALID_PARAMETER;
> +        }
> +        fdt_setprop_cell (Fdt, CpuNode, "cpu", Phandle[CoreIndex]);
> +
> +        // iterate to next core in cluster
> +        if (CoresInCluster) {
> +          do {
> +             --CoreIndex;
> +          } while (ClusterId != ArmCoreInfoTable[CoreIndex].ClusterId);
> +        }
> +      }
> +
> +      // iterate to next cluster
> +      if (ClusterCount) {
> +        do {
> +           --ClusterIndex;
> +        } while (ClusterInRange (ArmCoreInfoTable,
> +                                 ArmCoreInfoTable[ClusterIndex].ClusterId,
> +                                 ClusterIndex + 1,
> +                                 ArmCoreCount - 1));
> +      }
> +    }
> +  } else {
> +    DEBUG ((DEBUG_ERROR,"FDT: Error creating 'cpu-map' node\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SetSocIdStatus (Fdt);
> +  SetXgbeStatus (Fdt);
> +
> +  // Update the real size of the Device Tree
> +  fdt_pack (Fdt);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +  Return a pool allocated copy of the DTB image that is appropriate for
> +  booting the current platform via DT.
> +
> +  @param[out]   Dtb                   Pointer to the DTB copy
> +  @param[out]   DtbSize               Size of the DTB copy
> +
> +  @retval       EFI_SUCCESS           Operation completed successfully
> +  @retval       EFI_NOT_FOUND         No suitable DTB image could be located
> +  @retval       EFI_OUT_OF_RESOURCES  No pool memory available
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DtPlatformLoadDtb (
> +  OUT   VOID        **Dtb,
> +  OUT   UINTN       *DtbSize
> +  )
> +{
> +  EFI_STATUS      Status;
> +  VOID            *OrigDtb;
> +  VOID            *CopyDtb;
> +  UINTN           OrigDtbSize;
> +  UINTN           CopyDtbSize;
> +  INT32           Error;
> +
> +  Status = GetSectionFromAnyFv (&gDtPlatformDefaultDtbFileGuid,
> +             EFI_SECTION_RAW, 0, &OrigDtb, &OrigDtbSize);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Allocate space for the DTB: add a page of slack space to make some room
> +  // for our modifications.
> +  //
> +  CopyDtbSize = OrigDtbSize + EFI_PAGE_SIZE;
> +  CopyDtb = AllocatePool (CopyDtbSize);
> +  if (CopyDtb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Error = fdt_open_into (OrigDtb, CopyDtb, CopyDtbSize);
> +  if (Error != 0) {
> +    //
> +    // fdt_open_into() validates the DTB header, so if it fails, the template
> +    // is most likely invalid.
> +    //
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Status = PrepareFdt (CopyDtb, CopyDtbSize);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  *Dtb = CopyDtb;
> +  *DtbSize = CopyDtbSize;
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf
> new file mode 100644
> index 000000000000..f5ba5f1d1335
> --- /dev/null
> +++ b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf
> @@ -0,0 +1,64 @@
> +/** @file
> +*
> +*  Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> +*
> +*  This program and the accompanying materials
> +*  are licensed and made available under the terms and conditions of the BSD License
> +*  which accompanies this distribution.  The full text of the license may be found at
> +*  http://opensource.org/licenses/bsd-license.php
> +*
> +*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +*
> +**/
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010019
> +  BASE_NAME                      = StyxDtbLoaderLib
> +  FILE_GUID                      = 3874890c-2917-46a6-8711-8fcaee92260a
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = DtPlatformDtbLoaderLib|DXE_DRIVER
> +
> +[Sources]
> +  StyxDtbLoaderLib.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  MdePkg/MdePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  AmdModulePkg/AmdModulePkg.dec
> +  OpenPlatformPkg/Platforms/AMD/Styx/AmdStyx.dec
> +
> +[LibraryClasses]
> +  ArmLib
> +  BaseLib
> +  DebugLib
> +  DxeServicesLib
> +  FdtLib
> +  MemoryAllocationLib
> +  PrintLib
> +  UefiBootServicesTableLib
> +
> +[Pcd]
> +  gAmdStyxTokenSpaceGuid.PcdStyxFdt
> +  gAmdStyxTokenSpaceGuid.PcdSocCpuId
> +  gAmdStyxTokenSpaceGuid.PcdEthMacA
> +  gAmdStyxTokenSpaceGuid.PcdEthMacB
> +  gArmTokenSpaceGuid.PcdSystemMemoryBase
> +
> +[FixedPcd]
> +  gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset
> +  gArmTokenSpaceGuid.PcdArmLinuxFdtAlignment
> +  gAmdStyxTokenSpaceGuid.PcdPsciOsSupport
> +  gAmdStyxTokenSpaceGuid.PcdTrustedFWSupport
> +  gAmdStyxTokenSpaceGuid.PcdSata1PortCount
> +
> +[Guids]
> +  gDtPlatformDefaultDtbFileGuid
> +
> +[Protocols]
> +  gAmdMpCoreInfoProtocolGuid         ## CONSUMED
> +
> +[Depex]
> +  gAmdMpCoreInfoProtocolGuid
> --
> 2.9.3
>
Leif Lindholm April 7, 2017, 9:48 a.m. UTC | #2
On Fri, Apr 07, 2017 at 09:59:32AM +0100, Ard Biesheuvel wrote:
> In order to be able to switch to the generic DtPlatformDxe driver,
> implement the glue library that loads it and prepares it based on
> the properties of the actual hardware.
> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

I may have left my glasses at home today, but as far as I can see, all
that I asked for has been addressed, so:

Revie_we_d-by: Leif Lindholm <leif.lindholm@linaro.org>

(sneeks off to do some emacs scripting)

> ---
>  Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c   | 481 ++++++++++++++++++++
>  Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf |  64 +++
>  2 files changed, 545 insertions(+)
> 
> diff --git a/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c
> new file mode 100644
> index 000000000000..b18caf19985b
> --- /dev/null
> +++ b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c
> @@ -0,0 +1,481 @@
> +/** @file
> +*
> +*  Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> +*
> +*  This program and the accompanying materials
> +*  are licensed and made available under the terms and conditions of the BSD License
> +*  which accompanies this distribution.  The full text of the license may be found at
> +*  http://opensource.org/licenses/bsd-license.php
> +*
> +*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +*
> +**/
> +
> +#include <PiDxe.h>
> +
> +#include <Guid/ArmMpCoreInfo.h>
> +
> +#include <libfdt.h>
> +#include <Library/ArmLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DxeServicesLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include <Protocol/AmdMpCoreInfo.h>
> +
> +#define PMU_INT_FLAG_SPI        0
> +#define PMU_INT_TYPE_HIGH_LEVEL 4
> +
> +//
> +// PMU interrupts per core
> +//
> +#pragma pack(push, 1)
> +typedef struct {
> +  UINT32 Flag;          // 0 == SPI
> +  UINT32 IntId;         // GSIV == IntId+32
> +  UINT32 Type;          // 4 == Level-Sensitive, Active-High
> +} PMU_INTERRUPT;
> +#pragma pack(pop)
> +
> +STATIC
> +BOOLEAN
> +ClusterInRange (
> +  IN ARM_CORE_INFO  *ArmCoreInfoTable,
> +  IN UINTN          ClusterId,
> +  IN UINTN          LowIndex,
> +  IN UINTN          HighIndex
> +  )
> +{
> +  do {
> +    if (ClusterId == ArmCoreInfoTable[LowIndex].ClusterId)
> +      return TRUE;
> +  } while (++LowIndex <= HighIndex);
> +
> +  return FALSE;
> +}
> +
> +
> +STATIC
> +UINTN
> +NumberOfCoresInCluster (
> +  IN ARM_CORE_INFO  *ArmCoreInfoTable,
> +  IN UINTN          NumberOfEntries,
> +  IN UINTN          ClusterId
> +  )
> +{
> +  UINTN Index, Cores;
> +
> +  Cores = 0;
> +  for (Index = 0; Index < NumberOfEntries; ++Index) {
> +    if (ClusterId == ArmCoreInfoTable[Index].ClusterId)
> +      ++Cores;
> +  }
> +
> +  return Cores;
> +}
> +
> +
> +STATIC
> +UINTN
> +NumberOfClustersInTable (
> +  IN ARM_CORE_INFO  *ArmCoreInfoTable,
> +  IN UINTN          NumberOfEntries
> +  )
> +{
> +  UINTN Index, Cores, Clusters, ClusterId;
> +
> +  Index = 0;
> +  Clusters = 0;
> +  Cores = NumberOfEntries;
> +  while (Cores) {
> +     ++Clusters;
> +     ClusterId = ArmCoreInfoTable[Index].ClusterId;
> +     Cores -= NumberOfCoresInCluster (ArmCoreInfoTable,
> +                                      NumberOfEntries,
> +                                      ClusterId);
> +     if (Cores) {
> +       do {
> +         ++Index;
> +       } while (ClusterInRange (ArmCoreInfoTable,
> +                                ArmCoreInfoTable[Index].ClusterId,
> +                                0, Index-1));
> +     }
> +  }
> +
> +  return Clusters;
> +}
> +
> +
> +STATIC
> +INT32
> +fdt_alloc_phandle (
> +  IN VOID     *Fdt
> +  )
> +{
> +  INT32    Offset;
> +  INT32    Phandle;
> +
> +  Phandle = 0;
> +
> +  for (Offset = fdt_next_node (Fdt, -1, NULL); Offset >= 0;
> +       Offset = fdt_next_node (Fdt, Offset, NULL)) {
> +       Phandle = MAX (Phandle, fdt_get_phandle (Fdt, Offset));
> +  }
> +
> +  return Phandle + 1;
> +}
> +
> +STATIC
> +VOID
> +SetDeviceStatus (
> +  IN VOID           *Fdt,
> +  IN CONST CHAR8    *Device,
> +  IN BOOLEAN        Enable
> +  )
> +{
> +  INT32     Node;
> +  INT32     SubNode;
> +  INT32     Rc;
> +
> +  Node = fdt_subnode_offset (Fdt, 0, "smb");
> +  if (Node >= 0) {
> +    SubNode = fdt_subnode_offset (Fdt, Node, Device);
> +    if (SubNode >= 0) {
> +      Rc = fdt_setprop_string (Fdt, SubNode, "status",
> +             Enable ? "okay" : "disabled");
> +      if (Rc) {
> +        DEBUG ((DEBUG_ERROR,
> +          "%a: Could not set 'status' property for '%a' node\n",
> +          __FUNCTION__, Device));
> +      }
> +    }
> +  }
> +}
> +
> +#if DO_XGBE
> +
> +#define MAC_ADDRESS_BYTES       6
> +
> +STATIC
> +VOID
> +SetMacAddress (
> +  IN VOID           *Fdt,
> +  IN CONST CHAR8    *Device,
> +  IN UINT64         MacAddress
> +  )
> +{
> +  INT32     Node;
> +  INT32     SubNode;
> +  INT32     Rc;
> +
> +  Node = fdt_subnode_offset (Fdt, 0, "smb");
> +  if (Node >= 0) {
> +    SubNode = fdt_subnode_offset (Fdt, Node, Device);
> +    if (SubNode >= 0) {
> +      Rc = fdt_setprop (Fdt, SubNode, "mac-address", (VOID *)&MacAddress,
> +             MAC_ADDRESS_BYTES);
> +      if (Rc) {
> +        DEBUG ((DEBUG_ERROR,
> +          "%a: Could not set 'mac-address' property for '%a' node\n",
> +          __FUNCTION__, Device));
> +      }
> +    }
> +  }
> +}
> +
> +#endif
> +
> +#define STYX_SOC_VERSION_MASK    0xFFF
> +#define STYX_SOC_VERSION_A0      0x000
> +#define STYX_SOC_VERSION_B0      0x010
> +#define STYX_SOC_VERSION_B1      0x011
> +
> +STATIC
> +VOID
> +SetSocIdStatus (
> +  IN VOID       *Fdt
> +  )
> +{
> +  UINT32        SocId;
> +  BOOLEAN       IsRevB1;
> +
> +  SocId = PcdGet32 (PcdSocCpuId);
> +  IsRevB1 = (SocId & STYX_SOC_VERSION_MASK) >= STYX_SOC_VERSION_B1;
> +
> +  SetDeviceStatus (Fdt, "sata@e0d00000",
> +    IsRevB1 && FixedPcdGet8 (PcdSata1PortCount) > 0);
> +  SetDeviceStatus (Fdt, "gpio@e0020000", IsRevB1);
> +  SetDeviceStatus (Fdt, "gpio@e0030000", IsRevB1);
> +  SetDeviceStatus (Fdt, "gwdt@e0bb0000", IsRevB1);
> +#if DO_KCS
> +  SetDeviceStatus (Fdt, "kcs@e0010000", IsRevB1);
> +#else
> +  SetDeviceStatus (Fdt, "kcs@e0010000", FALSE);
> +#endif
> +}
> +
> +STATIC
> +VOID
> +SetXgbeStatus (
> +  IN VOID       *Fdt
> +  )
> +{
> +#if DO_XGBE
> +  SetDeviceStatus (Fdt, "xgmac@e0700000", TRUE);
> +  SetDeviceStatus (Fdt, "phy@e1240800", TRUE);
> +  SetDeviceStatus (Fdt, "xgmac@e0900000", TRUE);
> +  SetDeviceStatus (Fdt, "phy@e1240c00", TRUE);
> +
> +  SetMacAddress (Fdt, "xgmac@e0700000", PcdGet64 (PcdEthMacA));
> +  SetMacAddress (Fdt, "xgmac@e0900000", PcdGet64 (PcdEthMacB));
> +#else
> +  SetDeviceStatus (Fdt, "xgmac@e0700000", FALSE);
> +  SetDeviceStatus (Fdt, "phy@e1240800", FALSE);
> +  SetDeviceStatus (Fdt, "xgmac@e0900000", FALSE);
> +  SetDeviceStatus (Fdt, "phy@e1240c00", FALSE);
> +#endif
> +}
> +
> +
> +STATIC
> +EFI_STATUS
> +PrepareFdt (
> +  IN OUT VOID                 *Fdt,
> +  IN     UINTN                FdtSize
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  INT32                       Node;
> +  INT32                       CpuNode;
> +  UINTN                       Index;
> +  ARM_CORE_INFO               *ArmCoreInfoTable;
> +  UINTN                       ArmCoreCount;
> +  INT32                       MapNode;
> +  INT32                       ClusterNode;
> +  INT32                       PmuNode;
> +  PMU_INTERRUPT               PmuInt;
> +  INT32                       Phandle[NUM_CORES];
> +  UINT32                      ClusterIndex;
> +  UINT32                      CoreIndex;
> +  UINT32                      ClusterCount;
> +  UINT32                      CoresInCluster;
> +  UINT32                      ClusterId;
> +  UINTN                       MpId;
> +  CHAR8                       Name[10];
> +  AMD_MP_CORE_INFO_PROTOCOL   *AmdMpCoreInfoProtocol;
> +
> +  //
> +  // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms.
> +  //
> +  // For 'cpus' and 'cpu' device tree nodes bindings, refer to this file
> +  // in the kernel documentation:
> +  // Documentation/devicetree/bindings/arm/cpus.txt
> +  //
> +  Status = gBS->LocateProtocol (
> +                  &gAmdMpCoreInfoProtocolGuid,
> +                  NULL,
> +                  (VOID **)&AmdMpCoreInfoProtocol
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  // Get pointer to ARM core info table
> +  ArmCoreInfoTable = AmdMpCoreInfoProtocol->GetArmCoreInfoTable (&ArmCoreCount);
> +  ASSERT (ArmCoreInfoTable != NULL);
> +  ASSERT (ArmCoreCount <= NUM_CORES);
> +
> +  // Get Id from primary CPU
> +  MpId = (UINTN)ArmReadMpidr ();
> +
> +  // Create /pmu node
> +  PmuNode = fdt_add_subnode(Fdt, 0, "pmu");
> +  if (PmuNode >= 0) {
> +    fdt_setprop_string (Fdt, PmuNode, "compatible", "arm,armv8-pmuv3");
> +
> +    // append PMU interrupts
> +    for (Index = 0; Index < ArmCoreCount; Index++) {
> +      MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId,
> +                              ArmCoreInfoTable[Index].CoreId);
> +
> +      Status = AmdMpCoreInfoProtocol->GetPmuSpiFromMpId (MpId, &PmuInt.IntId);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR,
> +          "FDT: Error getting PMU interrupt for MpId '0x%x'\n", MpId));
> +        return Status;
> +      }
> +
> +      PmuInt.Flag = cpu_to_fdt32 (PMU_INT_FLAG_SPI);
> +      PmuInt.IntId = cpu_to_fdt32 (PmuInt.IntId);
> +      PmuInt.Type = cpu_to_fdt32 (PMU_INT_TYPE_HIGH_LEVEL);
> +      fdt_appendprop (Fdt, PmuNode, "interrupts", &PmuInt, sizeof(PmuInt));
> +    }
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "FDT: Error creating 'pmu' node\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Create /cpus noide
> +  Node = fdt_add_subnode (Fdt, 0, "cpus");
> +  if (Node >= 0) {
> +    // Configure the 'cpus' node
> +    fdt_setprop_string (Fdt, Node, "name", "cpus");
> +    fdt_setprop_cell (Fdt, Node, "#address-cells", sizeof (UINTN) / 4);
> +    fdt_setprop_cell (Fdt, Node, "#size-cells", 0);
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "FDT: Error creating 'cpus' node\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Walk the processor table in reverse order for proper listing in FDT
> +  //
> +  Index = ArmCoreCount;
> +  while (Index--) {
> +    // Create 'cpu' node
> +    AsciiSPrint (Name, sizeof (Name), "CPU%d", Index);
> +    CpuNode = fdt_add_subnode (Fdt, Node, Name);
> +    if (CpuNode < 0) {
> +      DEBUG ((DEBUG_ERROR, "FDT: Error on creating '%a' node\n", Name));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    Phandle[Index] = fdt_alloc_phandle (Fdt);
> +    fdt_setprop_cell (Fdt, CpuNode, "phandle", Phandle[Index]);
> +    fdt_setprop_cell (Fdt, CpuNode, "linux,phandle", Phandle[Index]);
> +
> +    fdt_setprop_string (Fdt, CpuNode, "enable-method", "psci");
> +
> +    MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId,
> +                            ArmCoreInfoTable[Index].CoreId);
> +    MpId = cpu_to_fdt64 (MpId);
> +    fdt_setprop (Fdt, CpuNode, "reg", &MpId, sizeof (MpId));
> +    fdt_setprop_string (Fdt, CpuNode, "compatible", "arm,armv8");
> +    fdt_setprop_string (Fdt, CpuNode, "device_type", "cpu");
> +  }
> +
> +  // Create /cpu-map node
> +  MapNode = fdt_add_subnode (Fdt, Node, "cpu-map");
> +  if (MapNode >= 0) {
> +    ClusterIndex = ArmCoreCount - 1;
> +    ClusterCount = NumberOfClustersInTable (ArmCoreInfoTable,
> +                                            ArmCoreCount);
> +    while (ClusterCount--) {
> +      // Create 'cluster' node
> +      AsciiSPrint (Name, sizeof (Name), "cluster%d", ClusterCount);
> +      ClusterNode = fdt_add_subnode (Fdt, MapNode, Name);
> +      if (ClusterNode < 0) {
> +        DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name));
> +        return EFI_INVALID_PARAMETER;
> +      }
> +
> +      ClusterId = ArmCoreInfoTable[ClusterIndex].ClusterId;
> +      CoreIndex = ClusterIndex;
> +      CoresInCluster = NumberOfCoresInCluster (ArmCoreInfoTable,
> +                                               ArmCoreCount,
> +                                               ClusterId);
> +      while (CoresInCluster--) {
> +        // Create 'core' node
> +        AsciiSPrint (Name, sizeof (Name), "core%d", CoresInCluster);
> +        CpuNode = fdt_add_subnode (Fdt, ClusterNode, Name);
> +        if (CpuNode < 0) {
> +          DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name));
> +          return EFI_INVALID_PARAMETER;
> +        }
> +        fdt_setprop_cell (Fdt, CpuNode, "cpu", Phandle[CoreIndex]);
> +
> +        // iterate to next core in cluster
> +        if (CoresInCluster) {
> +          do {
> +             --CoreIndex;
> +          } while (ClusterId != ArmCoreInfoTable[CoreIndex].ClusterId);
> +        }
> +      }
> +
> +      // iterate to next cluster
> +      if (ClusterCount) {
> +        do {
> +           --ClusterIndex;
> +        } while (ClusterInRange (ArmCoreInfoTable,
> +                                 ArmCoreInfoTable[ClusterIndex].ClusterId,
> +                                 ClusterIndex + 1,
> +                                 ArmCoreCount - 1));
> +      }
> +    }
> +  } else {
> +    DEBUG ((DEBUG_ERROR,"FDT: Error creating 'cpu-map' node\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SetSocIdStatus (Fdt);
> +  SetXgbeStatus (Fdt);
> +
> +  // Update the real size of the Device Tree
> +  fdt_pack (Fdt);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +  Return a pool allocated copy of the DTB image that is appropriate for
> +  booting the current platform via DT.
> +
> +  @param[out]   Dtb                   Pointer to the DTB copy
> +  @param[out]   DtbSize               Size of the DTB copy
> +
> +  @retval       EFI_SUCCESS           Operation completed successfully
> +  @retval       EFI_NOT_FOUND         No suitable DTB image could be located
> +  @retval       EFI_OUT_OF_RESOURCES  No pool memory available
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DtPlatformLoadDtb (
> +  OUT   VOID        **Dtb,
> +  OUT   UINTN       *DtbSize
> +  )
> +{
> +  EFI_STATUS      Status;
> +  VOID            *OrigDtb;
> +  VOID            *CopyDtb;
> +  UINTN           OrigDtbSize;
> +  UINTN           CopyDtbSize;
> +  INT32           Error;
> +
> +  Status = GetSectionFromAnyFv (&gDtPlatformDefaultDtbFileGuid,
> +             EFI_SECTION_RAW, 0, &OrigDtb, &OrigDtbSize);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Allocate space for the DTB: add a page of slack space to make some room
> +  // for our modifications.
> +  //
> +  CopyDtbSize = OrigDtbSize + EFI_PAGE_SIZE;
> +  CopyDtb = AllocatePool (CopyDtbSize);
> +  if (CopyDtb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Error = fdt_open_into (OrigDtb, CopyDtb, CopyDtbSize);
> +  if (Error != 0) {
> +    //
> +    // fdt_open_into() validates the DTB header, so if it fails, the template
> +    // is most likely invalid.
> +    //
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Status = PrepareFdt (CopyDtb, CopyDtbSize);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  *Dtb = CopyDtb;
> +  *DtbSize = CopyDtbSize;
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf
> new file mode 100644
> index 000000000000..f5ba5f1d1335
> --- /dev/null
> +++ b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf
> @@ -0,0 +1,64 @@
> +/** @file
> +*
> +*  Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> +*
> +*  This program and the accompanying materials
> +*  are licensed and made available under the terms and conditions of the BSD License
> +*  which accompanies this distribution.  The full text of the license may be found at
> +*  http://opensource.org/licenses/bsd-license.php
> +*
> +*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +*
> +**/
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010019
> +  BASE_NAME                      = StyxDtbLoaderLib
> +  FILE_GUID                      = 3874890c-2917-46a6-8711-8fcaee92260a
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = DtPlatformDtbLoaderLib|DXE_DRIVER
> +
> +[Sources]
> +  StyxDtbLoaderLib.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  MdePkg/MdePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  AmdModulePkg/AmdModulePkg.dec
> +  OpenPlatformPkg/Platforms/AMD/Styx/AmdStyx.dec
> +
> +[LibraryClasses]
> +  ArmLib
> +  BaseLib
> +  DebugLib
> +  DxeServicesLib
> +  FdtLib
> +  MemoryAllocationLib
> +  PrintLib
> +  UefiBootServicesTableLib
> +
> +[Pcd]
> +  gAmdStyxTokenSpaceGuid.PcdStyxFdt
> +  gAmdStyxTokenSpaceGuid.PcdSocCpuId
> +  gAmdStyxTokenSpaceGuid.PcdEthMacA
> +  gAmdStyxTokenSpaceGuid.PcdEthMacB
> +  gArmTokenSpaceGuid.PcdSystemMemoryBase
> +
> +[FixedPcd]
> +  gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset
> +  gArmTokenSpaceGuid.PcdArmLinuxFdtAlignment
> +  gAmdStyxTokenSpaceGuid.PcdPsciOsSupport
> +  gAmdStyxTokenSpaceGuid.PcdTrustedFWSupport
> +  gAmdStyxTokenSpaceGuid.PcdSata1PortCount
> +
> +[Guids]
> +  gDtPlatformDefaultDtbFileGuid
> +
> +[Protocols]
> +  gAmdMpCoreInfoProtocolGuid         ## CONSUMED
> +
> +[Depex]
> +  gAmdMpCoreInfoProtocolGuid
> -- 
> 2.9.3
>
Ard Biesheuvel April 7, 2017, 10:26 a.m. UTC | #3
On 7 April 2017 at 10:48, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Fri, Apr 07, 2017 at 09:59:32AM +0100, Ard Biesheuvel wrote:
>> In order to be able to switch to the generic DtPlatformDxe driver,
>> implement the glue library that loads it and prepares it based on
>> the properties of the actual hardware.
>>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>
> I may have left my glasses at home today, but as far as I can see, all
> that I asked for has been addressed, so:
>
> Revie_we_d-by: Leif Lindholm <leif.lindholm@linaro.org>
>


Thanks. I pushed this one, and the next one that moves Overdrive to it.

Alan, could you let me know whether you are ok with changing Overdrive
1000 as well?
Alan Ott April 7, 2017, 4:42 p.m. UTC | #4
On 04/07/2017 06:26 AM, Ard Biesheuvel wrote:
> On 7 April 2017 at 10:48, Leif Lindholm <leif.lindholm@linaro.org> wrote:
>> On Fri, Apr 07, 2017 at 09:59:32AM +0100, Ard Biesheuvel wrote:
>>> In order to be able to switch to the generic DtPlatformDxe driver,
>>> implement the glue library that loads it and prepares it based on
>>> the properties of the actual hardware.
>>>
>>> Contributed-under: TianoCore Contribution Agreement 1.0
>>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> I may have left my glasses at home today, but as far as I can see, all
>> that I asked for has been addressed, so:
>>
>> Revie_we_d-by: Leif Lindholm <leif.lindholm@linaro.org>
>>
>
> Thanks. I pushed this one, and the next one that moves Overdrive to it.
>
> Alan, could you let me know whether you are ok with changing Overdrive
> 1000 as well?

I haven't tested it here yet, but they're close enough to being the 
same. I can test it today.

Alan.
diff mbox

Patch

diff --git a/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c
new file mode 100644
index 000000000000..b18caf19985b
--- /dev/null
+++ b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.c
@@ -0,0 +1,481 @@ 
+/** @file
+*
+*  Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/ArmMpCoreInfo.h>
+
+#include <libfdt.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/AmdMpCoreInfo.h>
+
+#define PMU_INT_FLAG_SPI        0
+#define PMU_INT_TYPE_HIGH_LEVEL 4
+
+//
+// PMU interrupts per core
+//
+#pragma pack(push, 1)
+typedef struct {
+  UINT32 Flag;          // 0 == SPI
+  UINT32 IntId;         // GSIV == IntId+32
+  UINT32 Type;          // 4 == Level-Sensitive, Active-High
+} PMU_INTERRUPT;
+#pragma pack(pop)
+
+STATIC
+BOOLEAN
+ClusterInRange (
+  IN ARM_CORE_INFO  *ArmCoreInfoTable,
+  IN UINTN          ClusterId,
+  IN UINTN          LowIndex,
+  IN UINTN          HighIndex
+  )
+{
+  do {
+    if (ClusterId == ArmCoreInfoTable[LowIndex].ClusterId)
+      return TRUE;
+  } while (++LowIndex <= HighIndex);
+
+  return FALSE;
+}
+
+
+STATIC
+UINTN
+NumberOfCoresInCluster (
+  IN ARM_CORE_INFO  *ArmCoreInfoTable,
+  IN UINTN          NumberOfEntries,
+  IN UINTN          ClusterId
+  )
+{
+  UINTN Index, Cores;
+
+  Cores = 0;
+  for (Index = 0; Index < NumberOfEntries; ++Index) {
+    if (ClusterId == ArmCoreInfoTable[Index].ClusterId)
+      ++Cores;
+  }
+
+  return Cores;
+}
+
+
+STATIC
+UINTN
+NumberOfClustersInTable (
+  IN ARM_CORE_INFO  *ArmCoreInfoTable,
+  IN UINTN          NumberOfEntries
+  )
+{
+  UINTN Index, Cores, Clusters, ClusterId;
+
+  Index = 0;
+  Clusters = 0;
+  Cores = NumberOfEntries;
+  while (Cores) {
+     ++Clusters;
+     ClusterId = ArmCoreInfoTable[Index].ClusterId;
+     Cores -= NumberOfCoresInCluster (ArmCoreInfoTable,
+                                      NumberOfEntries,
+                                      ClusterId);
+     if (Cores) {
+       do {
+         ++Index;
+       } while (ClusterInRange (ArmCoreInfoTable,
+                                ArmCoreInfoTable[Index].ClusterId,
+                                0, Index-1));
+     }
+  }
+
+  return Clusters;
+}
+
+
+STATIC
+INT32
+fdt_alloc_phandle (
+  IN VOID     *Fdt
+  )
+{
+  INT32    Offset;
+  INT32    Phandle;
+
+  Phandle = 0;
+
+  for (Offset = fdt_next_node (Fdt, -1, NULL); Offset >= 0;
+       Offset = fdt_next_node (Fdt, Offset, NULL)) {
+       Phandle = MAX (Phandle, fdt_get_phandle (Fdt, Offset));
+  }
+
+  return Phandle + 1;
+}
+
+STATIC
+VOID
+SetDeviceStatus (
+  IN VOID           *Fdt,
+  IN CONST CHAR8    *Device,
+  IN BOOLEAN        Enable
+  )
+{
+  INT32     Node;
+  INT32     SubNode;
+  INT32     Rc;
+
+  Node = fdt_subnode_offset (Fdt, 0, "smb");
+  if (Node >= 0) {
+    SubNode = fdt_subnode_offset (Fdt, Node, Device);
+    if (SubNode >= 0) {
+      Rc = fdt_setprop_string (Fdt, SubNode, "status",
+             Enable ? "okay" : "disabled");
+      if (Rc) {
+        DEBUG ((DEBUG_ERROR,
+          "%a: Could not set 'status' property for '%a' node\n",
+          __FUNCTION__, Device));
+      }
+    }
+  }
+}
+
+#if DO_XGBE
+
+#define MAC_ADDRESS_BYTES       6
+
+STATIC
+VOID
+SetMacAddress (
+  IN VOID           *Fdt,
+  IN CONST CHAR8    *Device,
+  IN UINT64         MacAddress
+  )
+{
+  INT32     Node;
+  INT32     SubNode;
+  INT32     Rc;
+
+  Node = fdt_subnode_offset (Fdt, 0, "smb");
+  if (Node >= 0) {
+    SubNode = fdt_subnode_offset (Fdt, Node, Device);
+    if (SubNode >= 0) {
+      Rc = fdt_setprop (Fdt, SubNode, "mac-address", (VOID *)&MacAddress,
+             MAC_ADDRESS_BYTES);
+      if (Rc) {
+        DEBUG ((DEBUG_ERROR,
+          "%a: Could not set 'mac-address' property for '%a' node\n",
+          __FUNCTION__, Device));
+      }
+    }
+  }
+}
+
+#endif
+
+#define STYX_SOC_VERSION_MASK    0xFFF
+#define STYX_SOC_VERSION_A0      0x000
+#define STYX_SOC_VERSION_B0      0x010
+#define STYX_SOC_VERSION_B1      0x011
+
+STATIC
+VOID
+SetSocIdStatus (
+  IN VOID       *Fdt
+  )
+{
+  UINT32        SocId;
+  BOOLEAN       IsRevB1;
+
+  SocId = PcdGet32 (PcdSocCpuId);
+  IsRevB1 = (SocId & STYX_SOC_VERSION_MASK) >= STYX_SOC_VERSION_B1;
+
+  SetDeviceStatus (Fdt, "sata@e0d00000",
+    IsRevB1 && FixedPcdGet8 (PcdSata1PortCount) > 0);
+  SetDeviceStatus (Fdt, "gpio@e0020000", IsRevB1);
+  SetDeviceStatus (Fdt, "gpio@e0030000", IsRevB1);
+  SetDeviceStatus (Fdt, "gwdt@e0bb0000", IsRevB1);
+#if DO_KCS
+  SetDeviceStatus (Fdt, "kcs@e0010000", IsRevB1);
+#else
+  SetDeviceStatus (Fdt, "kcs@e0010000", FALSE);
+#endif
+}
+
+STATIC
+VOID
+SetXgbeStatus (
+  IN VOID       *Fdt
+  )
+{
+#if DO_XGBE
+  SetDeviceStatus (Fdt, "xgmac@e0700000", TRUE);
+  SetDeviceStatus (Fdt, "phy@e1240800", TRUE);
+  SetDeviceStatus (Fdt, "xgmac@e0900000", TRUE);
+  SetDeviceStatus (Fdt, "phy@e1240c00", TRUE);
+
+  SetMacAddress (Fdt, "xgmac@e0700000", PcdGet64 (PcdEthMacA));
+  SetMacAddress (Fdt, "xgmac@e0900000", PcdGet64 (PcdEthMacB));
+#else
+  SetDeviceStatus (Fdt, "xgmac@e0700000", FALSE);
+  SetDeviceStatus (Fdt, "phy@e1240800", FALSE);
+  SetDeviceStatus (Fdt, "xgmac@e0900000", FALSE);
+  SetDeviceStatus (Fdt, "phy@e1240c00", FALSE);
+#endif
+}
+
+
+STATIC
+EFI_STATUS
+PrepareFdt (
+  IN OUT VOID                 *Fdt,
+  IN     UINTN                FdtSize
+  )
+{
+  EFI_STATUS                  Status;
+  INT32                       Node;
+  INT32                       CpuNode;
+  UINTN                       Index;
+  ARM_CORE_INFO               *ArmCoreInfoTable;
+  UINTN                       ArmCoreCount;
+  INT32                       MapNode;
+  INT32                       ClusterNode;
+  INT32                       PmuNode;
+  PMU_INTERRUPT               PmuInt;
+  INT32                       Phandle[NUM_CORES];
+  UINT32                      ClusterIndex;
+  UINT32                      CoreIndex;
+  UINT32                      ClusterCount;
+  UINT32                      CoresInCluster;
+  UINT32                      ClusterId;
+  UINTN                       MpId;
+  CHAR8                       Name[10];
+  AMD_MP_CORE_INFO_PROTOCOL   *AmdMpCoreInfoProtocol;
+
+  //
+  // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms.
+  //
+  // For 'cpus' and 'cpu' device tree nodes bindings, refer to this file
+  // in the kernel documentation:
+  // Documentation/devicetree/bindings/arm/cpus.txt
+  //
+  Status = gBS->LocateProtocol (
+                  &gAmdMpCoreInfoProtocolGuid,
+                  NULL,
+                  (VOID **)&AmdMpCoreInfoProtocol
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  // Get pointer to ARM core info table
+  ArmCoreInfoTable = AmdMpCoreInfoProtocol->GetArmCoreInfoTable (&ArmCoreCount);
+  ASSERT (ArmCoreInfoTable != NULL);
+  ASSERT (ArmCoreCount <= NUM_CORES);
+
+  // Get Id from primary CPU
+  MpId = (UINTN)ArmReadMpidr ();
+
+  // Create /pmu node
+  PmuNode = fdt_add_subnode(Fdt, 0, "pmu");
+  if (PmuNode >= 0) {
+    fdt_setprop_string (Fdt, PmuNode, "compatible", "arm,armv8-pmuv3");
+
+    // append PMU interrupts
+    for (Index = 0; Index < ArmCoreCount; Index++) {
+      MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId,
+                              ArmCoreInfoTable[Index].CoreId);
+
+      Status = AmdMpCoreInfoProtocol->GetPmuSpiFromMpId (MpId, &PmuInt.IntId);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR,
+          "FDT: Error getting PMU interrupt for MpId '0x%x'\n", MpId));
+        return Status;
+      }
+
+      PmuInt.Flag = cpu_to_fdt32 (PMU_INT_FLAG_SPI);
+      PmuInt.IntId = cpu_to_fdt32 (PmuInt.IntId);
+      PmuInt.Type = cpu_to_fdt32 (PMU_INT_TYPE_HIGH_LEVEL);
+      fdt_appendprop (Fdt, PmuNode, "interrupts", &PmuInt, sizeof(PmuInt));
+    }
+  } else {
+    DEBUG ((DEBUG_ERROR, "FDT: Error creating 'pmu' node\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Create /cpus noide
+  Node = fdt_add_subnode (Fdt, 0, "cpus");
+  if (Node >= 0) {
+    // Configure the 'cpus' node
+    fdt_setprop_string (Fdt, Node, "name", "cpus");
+    fdt_setprop_cell (Fdt, Node, "#address-cells", sizeof (UINTN) / 4);
+    fdt_setprop_cell (Fdt, Node, "#size-cells", 0);
+  } else {
+    DEBUG ((DEBUG_ERROR, "FDT: Error creating 'cpus' node\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Walk the processor table in reverse order for proper listing in FDT
+  //
+  Index = ArmCoreCount;
+  while (Index--) {
+    // Create 'cpu' node
+    AsciiSPrint (Name, sizeof (Name), "CPU%d", Index);
+    CpuNode = fdt_add_subnode (Fdt, Node, Name);
+    if (CpuNode < 0) {
+      DEBUG ((DEBUG_ERROR, "FDT: Error on creating '%a' node\n", Name));
+      return EFI_INVALID_PARAMETER;
+    }
+    Phandle[Index] = fdt_alloc_phandle (Fdt);
+    fdt_setprop_cell (Fdt, CpuNode, "phandle", Phandle[Index]);
+    fdt_setprop_cell (Fdt, CpuNode, "linux,phandle", Phandle[Index]);
+
+    fdt_setprop_string (Fdt, CpuNode, "enable-method", "psci");
+
+    MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId,
+                            ArmCoreInfoTable[Index].CoreId);
+    MpId = cpu_to_fdt64 (MpId);
+    fdt_setprop (Fdt, CpuNode, "reg", &MpId, sizeof (MpId));
+    fdt_setprop_string (Fdt, CpuNode, "compatible", "arm,armv8");
+    fdt_setprop_string (Fdt, CpuNode, "device_type", "cpu");
+  }
+
+  // Create /cpu-map node
+  MapNode = fdt_add_subnode (Fdt, Node, "cpu-map");
+  if (MapNode >= 0) {
+    ClusterIndex = ArmCoreCount - 1;
+    ClusterCount = NumberOfClustersInTable (ArmCoreInfoTable,
+                                            ArmCoreCount);
+    while (ClusterCount--) {
+      // Create 'cluster' node
+      AsciiSPrint (Name, sizeof (Name), "cluster%d", ClusterCount);
+      ClusterNode = fdt_add_subnode (Fdt, MapNode, Name);
+      if (ClusterNode < 0) {
+        DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name));
+        return EFI_INVALID_PARAMETER;
+      }
+
+      ClusterId = ArmCoreInfoTable[ClusterIndex].ClusterId;
+      CoreIndex = ClusterIndex;
+      CoresInCluster = NumberOfCoresInCluster (ArmCoreInfoTable,
+                                               ArmCoreCount,
+                                               ClusterId);
+      while (CoresInCluster--) {
+        // Create 'core' node
+        AsciiSPrint (Name, sizeof (Name), "core%d", CoresInCluster);
+        CpuNode = fdt_add_subnode (Fdt, ClusterNode, Name);
+        if (CpuNode < 0) {
+          DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name));
+          return EFI_INVALID_PARAMETER;
+        }
+        fdt_setprop_cell (Fdt, CpuNode, "cpu", Phandle[CoreIndex]);
+
+        // iterate to next core in cluster
+        if (CoresInCluster) {
+          do {
+             --CoreIndex;
+          } while (ClusterId != ArmCoreInfoTable[CoreIndex].ClusterId);
+        }
+      }
+
+      // iterate to next cluster
+      if (ClusterCount) {
+        do {
+           --ClusterIndex;
+        } while (ClusterInRange (ArmCoreInfoTable,
+                                 ArmCoreInfoTable[ClusterIndex].ClusterId,
+                                 ClusterIndex + 1,
+                                 ArmCoreCount - 1));
+      }
+    }
+  } else {
+    DEBUG ((DEBUG_ERROR,"FDT: Error creating 'cpu-map' node\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SetSocIdStatus (Fdt);
+  SetXgbeStatus (Fdt);
+
+  // Update the real size of the Device Tree
+  fdt_pack (Fdt);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Return a pool allocated copy of the DTB image that is appropriate for
+  booting the current platform via DT.
+
+  @param[out]   Dtb                   Pointer to the DTB copy
+  @param[out]   DtbSize               Size of the DTB copy
+
+  @retval       EFI_SUCCESS           Operation completed successfully
+  @retval       EFI_NOT_FOUND         No suitable DTB image could be located
+  @retval       EFI_OUT_OF_RESOURCES  No pool memory available
+
+**/
+EFI_STATUS
+EFIAPI
+DtPlatformLoadDtb (
+  OUT   VOID        **Dtb,
+  OUT   UINTN       *DtbSize
+  )
+{
+  EFI_STATUS      Status;
+  VOID            *OrigDtb;
+  VOID            *CopyDtb;
+  UINTN           OrigDtbSize;
+  UINTN           CopyDtbSize;
+  INT32           Error;
+
+  Status = GetSectionFromAnyFv (&gDtPlatformDefaultDtbFileGuid,
+             EFI_SECTION_RAW, 0, &OrigDtb, &OrigDtbSize);
+  if (EFI_ERROR (Status)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Allocate space for the DTB: add a page of slack space to make some room
+  // for our modifications.
+  //
+  CopyDtbSize = OrigDtbSize + EFI_PAGE_SIZE;
+  CopyDtb = AllocatePool (CopyDtbSize);
+  if (CopyDtb == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Error = fdt_open_into (OrigDtb, CopyDtb, CopyDtbSize);
+  if (Error != 0) {
+    //
+    // fdt_open_into() validates the DTB header, so if it fails, the template
+    // is most likely invalid.
+    //
+    return EFI_NOT_FOUND;
+  }
+
+  Status = PrepareFdt (CopyDtb, CopyDtbSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  *Dtb = CopyDtb;
+  *DtbSize = CopyDtbSize;
+
+  return EFI_SUCCESS;
+}
diff --git a/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf
new file mode 100644
index 000000000000..f5ba5f1d1335
--- /dev/null
+++ b/Platforms/AMD/Styx/Library/StyxDtbLoaderLib/StyxDtbLoaderLib.inf
@@ -0,0 +1,64 @@ 
+/** @file
+*
+*  Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = StyxDtbLoaderLib
+  FILE_GUID                      = 3874890c-2917-46a6-8711-8fcaee92260a
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = DtPlatformDtbLoaderLib|DXE_DRIVER
+
+[Sources]
+  StyxDtbLoaderLib.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  AmdModulePkg/AmdModulePkg.dec
+  OpenPlatformPkg/Platforms/AMD/Styx/AmdStyx.dec
+
+[LibraryClasses]
+  ArmLib
+  BaseLib
+  DebugLib
+  DxeServicesLib
+  FdtLib
+  MemoryAllocationLib
+  PrintLib
+  UefiBootServicesTableLib
+
+[Pcd]
+  gAmdStyxTokenSpaceGuid.PcdStyxFdt
+  gAmdStyxTokenSpaceGuid.PcdSocCpuId
+  gAmdStyxTokenSpaceGuid.PcdEthMacA
+  gAmdStyxTokenSpaceGuid.PcdEthMacB
+  gArmTokenSpaceGuid.PcdSystemMemoryBase
+
+[FixedPcd]
+  gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset
+  gArmTokenSpaceGuid.PcdArmLinuxFdtAlignment
+  gAmdStyxTokenSpaceGuid.PcdPsciOsSupport
+  gAmdStyxTokenSpaceGuid.PcdTrustedFWSupport
+  gAmdStyxTokenSpaceGuid.PcdSata1PortCount
+
+[Guids]
+  gDtPlatformDefaultDtbFileGuid
+
+[Protocols]
+  gAmdMpCoreInfoProtocolGuid         ## CONSUMED
+
+[Depex]
+  gAmdMpCoreInfoProtocolGuid