1ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel/** @file
2ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*  Device tree enumeration DXE driver for ARM Virtual Machines
3ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*
4ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*  Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
5ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*
6ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*  This program and the accompanying materials are
7ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*  licensed and made available under the terms and conditions of the BSD License
8ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*  which accompanies this distribution.  The full text of the license may be found at
9ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*  http://opensource.org/licenses/bsd-license.php
10ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*
11ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel*
14ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel**/
15ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
16ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/BaseLib.h>
17ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/DebugLib.h>
18ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/UefiLib.h>
19ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/BaseMemoryLib.h>
20ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/UefiDriverEntryPoint.h>
21ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/MemoryAllocationLib.h>
22ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/UefiBootServicesTableLib.h>
23ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/VirtioMmioDeviceLib.h>
24ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/DevicePathLib.h>
25ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/PcdLib.h>
26ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Library/DxeServicesLib.h>
27cc667df08ae8208865744465eafa446b39b2805dArd Biesheuvel#include <Library/HobLib.h>
28ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <libfdt.h>
296abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel#include <Library/XenIoMmioLib.h>
30ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
31ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#include <Guid/Fdt.h>
3273bb8e6895080f07ece26b0db0f50048713c2b93Laszlo Ersek#include <Guid/VirtioMmioTransport.h>
33cc667df08ae8208865744465eafa446b39b2805dArd Biesheuvel#include <Guid/FdtHob.h>
34ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
35ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#pragma pack (1)
36ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuveltypedef struct {
37ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  VENDOR_DEVICE_PATH                  Vendor;
38ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  UINT64                              PhysBase;
39ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  EFI_DEVICE_PATH_PROTOCOL            End;
40ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel} VIRTIO_TRANSPORT_DEVICE_PATH;
41ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel#pragma pack ()
42ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
43ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuveltypedef enum {
44ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PropertyTypeUnknown,
45ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PropertyTypeGic,
46ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PropertyTypeRtc,
47ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PropertyTypeVirtio,
48ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PropertyTypeUart,
49ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PropertyTypeTimer,
50ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PropertyTypePsci,
51ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek  PropertyTypeFwCfg,
5265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PropertyTypePciHost,
537b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel  PropertyTypeGicV3,
546abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel  PropertyTypeXen,
55ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel} PROPERTY_TYPE;
56ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
57ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuveltypedef struct {
58ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PROPERTY_TYPE Type;
5965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  CHAR8         Compatible[32];
60ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel} PROPERTY;
61ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
62ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard BiesheuvelSTATIC CONST PROPERTY CompatibleProperties[] = {
6365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypeGic,     "arm,cortex-a15-gic"    },
6465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypeRtc,     "arm,pl031"             },
6565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypeVirtio,  "virtio,mmio"           },
6665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypeUart,    "arm,pl011"             },
6765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypeTimer,   "arm,armv7-timer"       },
6865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypeTimer,   "arm,armv8-timer"       },
6965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypePsci,    "arm,psci-0.2"          },
7065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypeFwCfg,   "qemu,fw-cfg-mmio"      },
7165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypePciHost, "pci-host-ecam-generic" },
727b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel  { PropertyTypeGicV3,   "arm,gic-v3"            },
736abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel  { PropertyTypeXen,     "xen,xen"               },
7465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  { PropertyTypeUnknown, ""                      }
75ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel};
76ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
77ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuveltypedef struct {
78ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  UINT32  Type;
79ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  UINT32  Number;
80ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  UINT32  Flags;
81ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel} INTERRUPT_PROPERTY;
82ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
83ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard BiesheuvelSTATIC
84ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard BiesheuvelPROPERTY_TYPE
85ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard BiesheuvelGetTypeFromNode (
86ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  IN CONST CHAR8 *NodeType,
87ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  IN UINTN       Size
88ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  )
89ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel{
90ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  CONST CHAR8    *Compatible;
91ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  CONST PROPERTY *CompatibleProperty;
92ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
93ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  //
94ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  // A 'compatible' node may contain a sequence of NULL terminated
95ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  // compatible strings so check each one
96ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  //
97ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;
98ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel       Compatible += 1 + AsciiStrLen (Compatible)) {
99ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {
100ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {
101ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        return CompatibleProperty->Type;
102ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      }
103ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    }
104ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  }
105ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  return PropertyTypeUnknown;
106ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel}
107ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
10865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek//
10965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek// We expect the "ranges" property of "pci-host-ecam-generic" to consist of
11065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek// records like this.
11165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek//
11265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#pragma pack (1)
11365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersektypedef struct {
11465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT32 Type;
11565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT64 ChildBase;
11665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT64 CpuBase;
11765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT64 Size;
11865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek} DTB_PCI_HOST_RANGE_RECORD;
11965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#pragma pack ()
12065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
12165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#define DTB_PCI_HOST_RANGE_RELOCATABLE  BIT31
12265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
12365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#define DTB_PCI_HOST_RANGE_ALIASED      BIT29
12465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#define DTB_PCI_HOST_RANGE_MMIO32       BIT25
12565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#define DTB_PCI_HOST_RANGE_MMIO64       (BIT25 | BIT24)
12665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#define DTB_PCI_HOST_RANGE_IO           BIT24
12765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek#define DTB_PCI_HOST_RANGE_TYPEMASK     (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
12865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
12965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek/**
13065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  Process the device tree node describing the generic PCI host controller.
13165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
13265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  param[in] DeviceTreeBase  Pointer to the device tree.
13365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
13465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  param[in] Node            Offset of the device tree node whose "compatible"
13565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek                            property is "pci-host-ecam-generic".
13665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
13765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  param[in] RegProp         Pointer to the "reg" property of Node. The caller
13865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek                            is responsible for ensuring that the size of the
13965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek                            property is 4 UINT32 cells.
14065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
14165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  @retval EFI_SUCCESS         Parsing successful, properties parsed from Node
14265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek                              have been stored in dynamic PCDs.
14365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
14465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  @retval EFI_PROTOCOL_ERROR  Parsing failed. PCDs are left unchanged.
14565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek**/
14665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo ErsekSTATIC
14765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo ErsekEFI_STATUS
14865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo ErsekEFIAPI
14965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo ErsekProcessPciHost (
15065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  IN CONST VOID *DeviceTreeBase,
15165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  IN INT32      Node,
15265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  IN CONST VOID *RegProp
15365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  )
15465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek{
15565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT64     ConfigBase, ConfigSize;
15665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  CONST VOID *Prop;
15765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  INT32      Len;
15865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT32     BusMin, BusMax;
15965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT32     RecordIdx;
16065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT64     IoBase, IoSize, IoTranslation;
16165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  UINT64     MmioBase, MmioSize, MmioTranslation;
16265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
16365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
16465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // Fetch the ECAM window.
16565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
16665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  ConfigBase = fdt64_to_cpu (((CONST UINT64 *)RegProp)[0]);
16765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  ConfigSize = fdt64_to_cpu (((CONST UINT64 *)RegProp)[1]);
16865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
16965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
17065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // Fetch the bus range (note: inclusive).
17165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
17265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  Prop = fdt_getprop (DeviceTreeBase, Node, "bus-range", &Len);
17365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  if (Prop == NULL || Len != 2 * sizeof(UINT32)) {
17465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n",
17565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      __FUNCTION__));
17665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    return EFI_PROTOCOL_ERROR;
17765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  }
17865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  BusMin = fdt32_to_cpu (((CONST UINT32 *)Prop)[0]);
17965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  BusMax = fdt32_to_cpu (((CONST UINT32 *)Prop)[1]);
18065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
18165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
18265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // Sanity check: the config space must accommodate all 4K register bytes of
18365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // all 8 functions of all 32 devices of all buses.
18465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
18565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  if (BusMax < BusMin || BusMax - BusMin == MAX_UINT32 ||
18665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < BusMax - BusMin + 1) {
18765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n",
18865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      __FUNCTION__));
18965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    return EFI_PROTOCOL_ERROR;
19065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  }
19165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
19265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
19365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // Iterate over "ranges".
19465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
19565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  Prop = fdt_getprop (DeviceTreeBase, Node, "ranges", &Len);
19665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  if (Prop == NULL || Len == 0 ||
19765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {
19865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));
19965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    return EFI_PROTOCOL_ERROR;
20065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  }
20165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
20265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
20365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // IoBase, IoTranslation, MmioBase and MmioTranslation are initialized only
20465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // in order to suppress '-Werror=maybe-uninitialized' warnings *incorrectly*
20565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // emitted by some gcc versions.
20665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
20765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  IoBase = 0;
20865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  IoTranslation = 0;
20965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  MmioBase = 0;
21065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  MmioTranslation = 0;
21165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
21265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
21365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // IoSize and MmioSize are initialized to zero because the logic below
21465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  // requires it.
21565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  //
21665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  IoSize = 0;
21765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  MmioSize = 0;
21865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);
21965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek       ++RecordIdx) {
22065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    CONST DTB_PCI_HOST_RANGE_RECORD *Record;
22165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
22265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;
22365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    switch (fdt32_to_cpu (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) {
22465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    case DTB_PCI_HOST_RANGE_IO:
22565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      IoBase = fdt64_to_cpu (Record->ChildBase);
22665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      IoSize = fdt64_to_cpu (Record->Size);
22765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      IoTranslation = fdt64_to_cpu (Record->CpuBase) - IoBase;
22865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      break;
22965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
23065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    case DTB_PCI_HOST_RANGE_MMIO32:
23165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      MmioBase = fdt64_to_cpu (Record->ChildBase);
23265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      MmioSize = fdt64_to_cpu (Record->Size);
23365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      MmioTranslation = fdt64_to_cpu (Record->CpuBase) - MmioBase;
23465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
23565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      if (MmioBase > MAX_UINT32 || MmioSize > MAX_UINT32 ||
23665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek          MmioBase + MmioSize > SIZE_4GB) {
23765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek        DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__));
23865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek        return EFI_PROTOCOL_ERROR;
23965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      }
24065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
24165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      if (MmioTranslation != 0) {
24265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek        DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation "
24365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek          "0x%Lx\n", __FUNCTION__, MmioTranslation));
24465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek        return EFI_UNSUPPORTED;
24565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      }
24665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
24765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      break;
24865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    }
24965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  }
25065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  if (IoSize == 0 || MmioSize == 0) {
25165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__,
25265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      (IoSize == 0) ? "IO" : "MMIO32"));
25365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    return EFI_PROTOCOL_ERROR;
25465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  }
25565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
25665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSet64 (PcdPciExpressBaseAddress, ConfigBase);
25765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
25865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSet32 (PcdPciBusMin, BusMin);
25965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSet32 (PcdPciBusMax, BusMax);
26065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
26165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSet64 (PcdPciIoBase,        IoBase);
26265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSet64 (PcdPciIoSize,        IoSize);
26365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSet64 (PcdPciIoTranslation, IoTranslation);
26465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
26565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSet32 (PcdPciMmio32Base, (UINT32)MmioBase);
26665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSet32 (PcdPciMmio32Size, (UINT32)MmioSize);
26765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
26865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  PcdSetBool (PcdPciDisableBusEnumeration, FALSE);
26965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
27065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] "
27165bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    "Io[0x%Lx+0x%Lx)@0x%Lx Mem[0x%Lx+0x%Lx)@0x%Lx\n", __FUNCTION__, ConfigBase,
27265bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    ConfigSize, BusMin, BusMax, IoBase, IoSize, IoTranslation, MmioBase,
27365bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    MmioSize, MmioTranslation));
27465bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek  return EFI_SUCCESS;
27565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek}
27665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
27765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
278ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard BiesheuvelEFI_STATUS
279ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard BiesheuvelEFIAPI
280ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard BiesheuvelInitializeVirtFdtDxe (
281ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  IN EFI_HANDLE           ImageHandle,
282ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  IN EFI_SYSTEM_TABLE     *SystemTable
283ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  )
284ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel{
285cc667df08ae8208865744465eafa446b39b2805dArd Biesheuvel  VOID                           *Hob;
286ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  VOID                           *DeviceTreeBase;
287ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  INT32                          Node, Prev;
288ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  INT32                          RtcNode;
289ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  EFI_STATUS                     Status;
290ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  CONST CHAR8                    *Type;
291ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  INT32                          Len;
292ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  PROPERTY_TYPE                  PropType;
293ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  CONST VOID                     *RegProp;
294ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  VIRTIO_TRANSPORT_DEVICE_PATH   *DevicePath;
295ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  EFI_HANDLE                     Handle;
296ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  UINT64                         RegBase;
2977b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel  UINT64                         DistBase, CpuBase, RedistBase;
298ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  CONST INTERRUPT_PROPERTY       *InterruptProp;
299ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  INT32                          SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;
300ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  CONST CHAR8                    *PsciMethod;
301ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek  UINT64                         FwCfgSelectorAddress;
302ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek  UINT64                         FwCfgSelectorSize;
303ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek  UINT64                         FwCfgDataAddress;
304ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek  UINT64                         FwCfgDataSize;
30550b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek  UINT64                         FwCfgDmaAddress;
30650b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek  UINT64                         FwCfgDmaSize;
307ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
308cc667df08ae8208865744465eafa446b39b2805dArd Biesheuvel  Hob = GetFirstGuidHob(&gFdtHobGuid);
309cc667df08ae8208865744465eafa446b39b2805dArd Biesheuvel  if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
310cc667df08ae8208865744465eafa446b39b2805dArd Biesheuvel    return EFI_NOT_FOUND;
311cc667df08ae8208865744465eafa446b39b2805dArd Biesheuvel  }
312cc667df08ae8208865744465eafa446b39b2805dArd Biesheuvel  DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
313ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
314ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  if (fdt_check_header (DeviceTreeBase) != 0) {
315ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
316ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    return EFI_NOT_FOUND;
317ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  }
318ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
319ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
320ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  ASSERT_EFI_ERROR (Status);
321ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
322ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
323ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
324ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  RtcNode = -1;
325ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  //
326ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  // Now enumerate the nodes and install peripherals that we are interested in,
327ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  // i.e., GIC, RTC and virtio MMIO nodes
328ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  //
329ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  for (Prev = 0;; Prev = Node) {
330ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
331ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    if (Node < 0) {
332ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      break;
333ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    }
334ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
335ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
336ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    if (Type == NULL) {
337ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      continue;
338ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    }
339ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
340ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    PropType = GetTypeFromNode (Type, Len);
341ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    if (PropType == PropertyTypeUnknown) {
342ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      continue;
343ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    }
344ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
345ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    //
346ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    // Get the 'reg' property of this node. For now, we will assume
347ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    // 8 byte quantities for base and size, respectively.
348ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    // TODO use #cells root properties instead
349ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    //
350ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
351ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||
352ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      (PropType == PropertyTypePsci));
353ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
354ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    switch (PropType) {
35565bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek    case PropertyTypePciHost:
35665bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      ASSERT (Len == 2 * sizeof (UINT64));
35765bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);
35865bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      ASSERT_EFI_ERROR (Status);
35965bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek      break;
36065bb13b0fd7feed90ca45ea5333490a3f35e24abLaszlo Ersek
361ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek    case PropertyTypeFwCfg:
362ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      ASSERT (Len == 2 * sizeof (UINT64));
363ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek
364ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      FwCfgDataAddress     = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
365ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      FwCfgDataSize        = 8;
366ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
367ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      FwCfgSelectorSize    = 2;
368ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek
369ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      //
370ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      // The following ASSERT()s express
371ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      //
372ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      //   Address + Size - 1 <= MAX_UINTN
373ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      //
374ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      // for both registers, that is, that the last byte in each MMIO range is
375ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      // expressible as a MAX_UINTN. The form below is mathematically
376ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      // equivalent, and it also prevents any unsigned overflow before the
377ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      // comparison.
378ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      //
379ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
380ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      ASSERT (FwCfgDataAddress     <= MAX_UINTN - FwCfgDataSize     + 1);
381ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek
382ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      PcdSet64 (PcdFwCfgSelectorAddress, FwCfgSelectorAddress);
383ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      PcdSet64 (PcdFwCfgDataAddress,     FwCfgDataAddress);
384ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek
385ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,
386ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek        FwCfgDataAddress));
38750b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek
38850b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek      if (fdt64_to_cpu (((UINT64 *)RegProp)[1]) >= 0x18) {
38950b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek        FwCfgDmaAddress = FwCfgDataAddress + 0x10;
39050b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek        FwCfgDmaSize    = 0x08;
39150b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek
39250b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek        //
39350b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek        // See explanation above.
39450b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek        //
39550b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek        ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);
39650b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek
39750b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek        PcdSet64 (PcdFwCfgDmaAddress, FwCfgDmaAddress);
39850b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek        DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));
39950b91449a3a073af3a7c87af83002016e7e34cc4Laszlo Ersek      }
400ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek      break;
401ad652d46941c6a1e0f828cb084fb6829c3abb68dLaszlo Ersek
402ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    case PropertyTypeVirtio:
403ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      ASSERT (Len == 16);
404ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      //
405ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      // Create a unique device path for this transport on the fly
406ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      //
407ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
408ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
409ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                                    HARDWARE_DEVICE_PATH,
410ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                                    HW_VENDOR_DP,
411ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                                    sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
412ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      if (DevicePath == NULL) {
413ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
414ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        break;
415ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      }
416ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
41773bb8e6895080f07ece26b0db0f50048713c2b93Laszlo Ersek      CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
41873bb8e6895080f07ece26b0db0f50048713c2b93Laszlo Ersek        sizeof (EFI_GUID));
419ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      DevicePath->PhysBase = RegBase;
420ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      SetDevicePathNodeLength (&DevicePath->Vendor,
421ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                               sizeof (*DevicePath) - sizeof (DevicePath->End));
422ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      SetDevicePathEndNode (&DevicePath->End);
423ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
424ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      Handle = NULL;
425ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      Status = gBS->InstallProtocolInterface (&Handle,
426ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                     &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
427ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                     DevicePath);
428ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      if (EFI_ERROR (Status)) {
429ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
430ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel          "protocol on a new handle (Status == %r)\n",
431ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel          __FUNCTION__, Status));
432ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        FreePool (DevicePath);
433ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        break;
434ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      }
435ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
436ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      Status = VirtioMmioInstallDevice (RegBase, Handle);
437ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      if (EFI_ERROR (Status)) {
438ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
439ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel          "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
440ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel          Handle, Status));
441ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
442ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        Status = gBS->UninstallProtocolInterface (Handle,
443ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                        &gEfiDevicePathProtocolGuid, DevicePath);
444ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        ASSERT_EFI_ERROR (Status);
445ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        FreePool (DevicePath);
446ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      }
447ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      break;
448ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
449ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    case PropertyTypeGic:
450ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      ASSERT (Len == 32);
451ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
452ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
453ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      CpuBase  = fdt64_to_cpu (((UINT64 *)RegProp)[2]);
454ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      ASSERT (DistBase < MAX_UINT32);
455ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      ASSERT (CpuBase < MAX_UINT32);
456ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
457ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
458ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);
459ae26410e285bf0320252f99fe25055d467f86824Ard Biesheuvel      PcdSet32 (PcdArmGicRevision, 2);
460ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
461ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));
462ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      break;
463ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
4647b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel    case PropertyTypeGicV3:
4657b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      //
4667b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // The GIC v3 DT binding describes a series of at least 3 physical (base
4677b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // addresses, size) pairs: the distributor interface (GICD), at least one
4687b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // redistributor region (GICR) containing dedicated redistributor
4697b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // interfaces for all individual CPUs, and the CPU interface (GICC).
4707b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // Under virtualization, we assume that the first redistributor region
4717b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // listed covers the boot CPU. Also, our GICv3 driver only supports the
4727b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // system register CPU interface, so we can safely ignore the MMIO version
4737b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // which is listed after the sequence of redistributor interfaces.
4747b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // This means we are only interested in the first two memory regions
4757b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // supplied, and ignore everything else.
4767b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      //
4777b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      ASSERT (Len >= 32);
4787b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel
4797b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // RegProp[0..1] == { GICD base, GICD size }
4807b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
4817b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      ASSERT (DistBase < MAX_UINT32);
4827b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel
4837b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      // RegProp[2..3] == { GICR base, GICR size }
4847b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      RedistBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);
4857b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      ASSERT (RedistBase < MAX_UINT32);
4867b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel
4877b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
4887b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);
489ae26410e285bf0320252f99fe25055d467f86824Ard Biesheuvel      PcdSet32 (PcdArmGicRevision, 3);
4907b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel
4917b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",
4927b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel        DistBase, RedistBase));
4937b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel      break;
4947b70dabbb2d8dd22afbb14defbb9ce5b9cb8b4c7Ard Biesheuvel
495ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    case PropertyTypeRtc:
496ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      ASSERT (Len == 16);
497ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
498ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
499ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      ASSERT (RegBase < MAX_UINT32);
500ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
501ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);
502ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
503ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));
504ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      RtcNode = Node;
505ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      break;
506ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
507ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    case PropertyTypeTimer:
508ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      //
509ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      // - interrupts : Interrupt list for secure, non-secure, virtual and
510ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      //  hypervisor timers, in that order.
511ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      //
512ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);
513967efdcdc3a3a22550563acb9ec77f565b3dbee0Ard Biesheuvel      ASSERT (Len == 36 || Len == 48);
514ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
515ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)
516ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                   + (InterruptProp[0].Type ? 16 : 0);
517ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      IntrNum = fdt32_to_cpu (InterruptProp[1].Number)
518ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                + (InterruptProp[1].Type ? 16 : 0);
519ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)
520ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel                    + (InterruptProp[2].Type ? 16 : 0);
521967efdcdc3a3a22550563acb9ec77f565b3dbee0Ard Biesheuvel      HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)
522967efdcdc3a3a22550563acb9ec77f565b3dbee0Ard Biesheuvel                                  + (InterruptProp[3].Type ? 16 : 0);
523ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
524ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",
525ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));
526ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
527ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);
528ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);
529ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);
530ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);
531ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      break;
532ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
533ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    case PropertyTypePsci:
534ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      PsciMethod = fdt_getprop (DeviceTreeBase, Node, "method", &Len);
535ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
536ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      if (PsciMethod && AsciiStrnCmp (PsciMethod, "hvc", 3) == 0) {
537ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        PcdSet32 (PcdArmPsciMethod, 1);
538ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      } else if (PsciMethod && AsciiStrnCmp (PsciMethod, "smc", 3) == 0) {
539ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        PcdSet32 (PcdArmPsciMethod, 2);
540ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      } else {
541ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        DEBUG ((EFI_D_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,
542ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel          PsciMethod));
543ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      }
544ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      break;
545ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
5466abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel    case PropertyTypeXen:
5476abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      ASSERT (Len == 16);
5486abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel
5496abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      //
5506abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      // Retrieve the reg base from this node and wire it up to the
5516abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      // MMIO flavor of the XenBus root device I/O protocol
5526abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      //
5536abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
5546abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      Handle = NULL;
5556abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      Status = XenIoMmioInstall (&Handle, RegBase);
5566abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      if (EFI_ERROR (Status)) {
5576abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel        DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "
5586abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel          "(Status == %r)\n", __FUNCTION__, Status));
5596abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel        break;
5606abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      }
5616abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel
5626abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
5636abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel
5646abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel      break;
5656abe83c3c884f86bd423d6155eb1b7f6d2833fd9Ard Biesheuvel
566ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    default:
567ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      break;
568ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    }
569ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  }
570ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel
571ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  //
572ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  // UEFI takes ownership of the RTC hardware, and exposes its functionality
573ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  // through the UEFI Runtime Services GetTime, SetTime, etc. This means we
574ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  // need to disable it in the device tree to prevent the OS from attaching its
575ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  // device driver as well.
576ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  //
577ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  if ((RtcNode != -1) &&
578ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel      fdt_setprop_string (DeviceTreeBase, RtcNode, "status",
579ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel        "disabled") != 0) {
580ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel    DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));
581ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  }
582ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel  return EFI_SUCCESS;
583ad10693231b9bc5ba7bab0f20ce1bf8d8f868c52Ard Biesheuvel}
584