2 * Device tree enumeration DXE driver for ARM Virtual Machines
4 * Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
6 * This program and the accompanying materials are
7 * licensed and made available under the terms and conditions of the BSD License
8 * which accompanies this distribution. The full text of the license may be found at
9 * http://opensource.org/licenses/bsd-license.php
11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/UefiLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/UefiDriverEntryPoint.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/VirtioMmioDeviceLib.h>
24 #include <Library/DevicePathLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/DxeServicesLib.h>
27 #include <Library/HobLib.h>
29 #include <Library/XenIoMmioLib.h>
32 #include <Guid/VirtioMmioTransport.h>
33 #include <Guid/FdtHob.h>
37 VENDOR_DEVICE_PATH Vendor
;
39 EFI_DEVICE_PATH_PROTOCOL End
;
40 } VIRTIO_TRANSPORT_DEVICE_PATH
;
56 STATIC CONST PROPERTY CompatibleProperties
[] = {
57 { PropertyTypeRtc
, "arm,pl031" },
58 { PropertyTypeVirtio
, "virtio,mmio" },
59 { PropertyTypeUart
, "arm,pl011" },
60 { PropertyTypeXen
, "xen,xen" },
61 { PropertyTypeUnknown
, "" }
67 IN CONST CHAR8
*NodeType
,
71 CONST CHAR8
*Compatible
;
72 CONST PROPERTY
*CompatibleProperty
;
75 // A 'compatible' node may contain a sequence of NULL terminated
76 // compatible strings so check each one
78 for (Compatible
= NodeType
; Compatible
< NodeType
+ Size
&& *Compatible
;
79 Compatible
+= 1 + AsciiStrLen (Compatible
)) {
80 for (CompatibleProperty
= CompatibleProperties
; CompatibleProperty
->Compatible
[0]; CompatibleProperty
++) {
81 if (AsciiStrCmp (CompatibleProperty
->Compatible
, Compatible
) == 0) {
82 return CompatibleProperty
->Type
;
86 return PropertyTypeUnknown
;
91 InitializeVirtFdtDxe (
92 IN EFI_HANDLE ImageHandle
,
93 IN EFI_SYSTEM_TABLE
*SystemTable
103 PROPERTY_TYPE PropType
;
105 VIRTIO_TRANSPORT_DEVICE_PATH
*DevicePath
;
109 Hob
= GetFirstGuidHob(&gFdtHobGuid
);
110 if (Hob
== NULL
|| GET_GUID_HOB_DATA_SIZE (Hob
) != sizeof (UINT64
)) {
111 return EFI_NOT_FOUND
;
113 DeviceTreeBase
= (VOID
*)(UINTN
)*(UINT64
*)GET_GUID_HOB_DATA (Hob
);
115 if (fdt_check_header (DeviceTreeBase
) != 0) {
116 DEBUG ((EFI_D_ERROR
, "%a: No DTB found @ 0x%p\n", __FUNCTION__
, DeviceTreeBase
));
117 return EFI_NOT_FOUND
;
120 DEBUG ((EFI_D_INFO
, "%a: DTB @ 0x%p\n", __FUNCTION__
, DeviceTreeBase
));
124 // Now enumerate the nodes and install peripherals that we are interested in,
125 // i.e., GIC, RTC and virtio MMIO nodes
127 for (Prev
= 0;; Prev
= Node
) {
128 Node
= fdt_next_node (DeviceTreeBase
, Prev
, NULL
);
133 Type
= fdt_getprop (DeviceTreeBase
, Node
, "compatible", &Len
);
138 PropType
= GetTypeFromNode (Type
, Len
);
139 if (PropType
== PropertyTypeUnknown
) {
144 // Get the 'reg' property of this node. For now, we will assume
145 // 8 byte quantities for base and size, respectively.
146 // TODO use #cells root properties instead
148 RegProp
= fdt_getprop (DeviceTreeBase
, Node
, "reg", &Len
);
149 ASSERT (RegProp
!= NULL
);
152 case PropertyTypeVirtio
:
155 // Create a unique device path for this transport on the fly
157 RegBase
= fdt64_to_cpu (((UINT64
*)RegProp
)[0]);
158 DevicePath
= (VIRTIO_TRANSPORT_DEVICE_PATH
*)CreateDeviceNode (
159 HARDWARE_DEVICE_PATH
,
161 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH
));
162 if (DevicePath
== NULL
) {
163 DEBUG ((EFI_D_ERROR
, "%a: Out of memory\n", __FUNCTION__
));
167 CopyMem (&DevicePath
->Vendor
.Guid
, &gVirtioMmioTransportGuid
,
169 DevicePath
->PhysBase
= RegBase
;
170 SetDevicePathNodeLength (&DevicePath
->Vendor
,
171 sizeof (*DevicePath
) - sizeof (DevicePath
->End
));
172 SetDevicePathEndNode (&DevicePath
->End
);
175 Status
= gBS
->InstallProtocolInterface (&Handle
,
176 &gEfiDevicePathProtocolGuid
, EFI_NATIVE_INTERFACE
,
178 if (EFI_ERROR (Status
)) {
179 DEBUG ((EFI_D_ERROR
, "%a: Failed to install the EFI_DEVICE_PATH "
180 "protocol on a new handle (Status == %r)\n",
181 __FUNCTION__
, Status
));
182 FreePool (DevicePath
);
186 Status
= VirtioMmioInstallDevice (RegBase
, Handle
);
187 if (EFI_ERROR (Status
)) {
188 DEBUG ((EFI_D_ERROR
, "%a: Failed to install VirtIO transport @ 0x%Lx "
189 "on handle %p (Status == %r)\n", __FUNCTION__
, RegBase
,
192 Status
= gBS
->UninstallProtocolInterface (Handle
,
193 &gEfiDevicePathProtocolGuid
, DevicePath
);
194 ASSERT_EFI_ERROR (Status
);
195 FreePool (DevicePath
);
199 case PropertyTypeRtc
:
202 RegBase
= fdt64_to_cpu (((UINT64
*)RegProp
)[0]);
203 ASSERT (RegBase
< MAX_UINT32
);
205 PcdSet32 (PcdPL031RtcBase
, (UINT32
)RegBase
);
207 DEBUG ((EFI_D_INFO
, "Found PL031 RTC @ 0x%Lx\n", RegBase
));
211 case PropertyTypeXen
:
215 // Retrieve the reg base from this node and wire it up to the
216 // MMIO flavor of the XenBus root device I/O protocol
218 RegBase
= fdt64_to_cpu (((UINT64
*)RegProp
)[0]);
220 Status
= XenIoMmioInstall (&Handle
, RegBase
);
221 if (EFI_ERROR (Status
)) {
222 DEBUG ((EFI_D_ERROR
, "%a: XenIoMmioInstall () failed on a new handle "
223 "(Status == %r)\n", __FUNCTION__
, Status
));
227 DEBUG ((EFI_D_INFO
, "Found Xen node with Grant table @ 0x%Lx\n", RegBase
));
236 if (!FeaturePcdGet (PcdPureAcpiBoot
)) {
238 // Only install the FDT as a configuration table if we want to leave it up
239 // to the OS to decide whether it prefers ACPI over DT.
241 Status
= gBS
->InstallConfigurationTable (&gFdtTableGuid
, DeviceTreeBase
);
242 ASSERT_EFI_ERROR (Status
);
245 // UEFI takes ownership of the RTC hardware, and exposes its functionality
246 // through the UEFI Runtime Services GetTime, SetTime, etc. This means we
247 // need to disable it in the device tree to prevent the OS from attaching its
248 // device driver as well.
250 if ((RtcNode
!= -1) &&
251 fdt_setprop_string (DeviceTreeBase
, RtcNode
, "status",
253 DEBUG ((EFI_D_WARN
, "Failed to set PL031 status to 'disabled'\n"));