]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/VirtFdtDxe/VirtFdtDxe.c
ArmVirtPkg/VirtFdtDxe: drop PCI host bridge handling
[mirror_edk2.git] / ArmVirtPkg / VirtFdtDxe / VirtFdtDxe.c
1 /** @file
2 * Device tree enumeration DXE driver for ARM Virtual Machines
3 *
4 * Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
5 *
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
10 *
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.
13 *
14 **/
15
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>
28 #include <libfdt.h>
29 #include <Library/XenIoMmioLib.h>
30
31 #include <Guid/Fdt.h>
32 #include <Guid/VirtioMmioTransport.h>
33 #include <Guid/FdtHob.h>
34
35 #pragma pack (1)
36 typedef struct {
37 VENDOR_DEVICE_PATH Vendor;
38 UINT64 PhysBase;
39 EFI_DEVICE_PATH_PROTOCOL End;
40 } VIRTIO_TRANSPORT_DEVICE_PATH;
41 #pragma pack ()
42
43 typedef enum {
44 PropertyTypeUnknown,
45 PropertyTypeRtc,
46 PropertyTypeVirtio,
47 PropertyTypeUart,
48 PropertyTypeXen,
49 } PROPERTY_TYPE;
50
51 typedef struct {
52 PROPERTY_TYPE Type;
53 CHAR8 Compatible[32];
54 } PROPERTY;
55
56 STATIC CONST PROPERTY CompatibleProperties[] = {
57 { PropertyTypeRtc, "arm,pl031" },
58 { PropertyTypeVirtio, "virtio,mmio" },
59 { PropertyTypeUart, "arm,pl011" },
60 { PropertyTypeXen, "xen,xen" },
61 { PropertyTypeUnknown, "" }
62 };
63
64 STATIC
65 PROPERTY_TYPE
66 GetTypeFromNode (
67 IN CONST CHAR8 *NodeType,
68 IN UINTN Size
69 )
70 {
71 CONST CHAR8 *Compatible;
72 CONST PROPERTY *CompatibleProperty;
73
74 //
75 // A 'compatible' node may contain a sequence of NULL terminated
76 // compatible strings so check each one
77 //
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;
83 }
84 }
85 }
86 return PropertyTypeUnknown;
87 }
88
89 EFI_STATUS
90 EFIAPI
91 InitializeVirtFdtDxe (
92 IN EFI_HANDLE ImageHandle,
93 IN EFI_SYSTEM_TABLE *SystemTable
94 )
95 {
96 VOID *Hob;
97 VOID *DeviceTreeBase;
98 INT32 Node, Prev;
99 INT32 RtcNode;
100 EFI_STATUS Status;
101 CONST CHAR8 *Type;
102 INT32 Len;
103 PROPERTY_TYPE PropType;
104 CONST VOID *RegProp;
105 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
106 EFI_HANDLE Handle;
107 UINT64 RegBase;
108
109 Hob = GetFirstGuidHob(&gFdtHobGuid);
110 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
111 return EFI_NOT_FOUND;
112 }
113 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
114
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;
118 }
119
120 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
121
122 RtcNode = -1;
123 //
124 // Now enumerate the nodes and install peripherals that we are interested in,
125 // i.e., GIC, RTC and virtio MMIO nodes
126 //
127 for (Prev = 0;; Prev = Node) {
128 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
129 if (Node < 0) {
130 break;
131 }
132
133 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
134 if (Type == NULL) {
135 continue;
136 }
137
138 PropType = GetTypeFromNode (Type, Len);
139 if (PropType == PropertyTypeUnknown) {
140 continue;
141 }
142
143 //
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
147 //
148 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
149 ASSERT (RegProp != NULL);
150
151 switch (PropType) {
152 case PropertyTypeVirtio:
153 ASSERT (Len == 16);
154 //
155 // Create a unique device path for this transport on the fly
156 //
157 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
158 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
159 HARDWARE_DEVICE_PATH,
160 HW_VENDOR_DP,
161 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
162 if (DevicePath == NULL) {
163 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
164 break;
165 }
166
167 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
168 sizeof (EFI_GUID));
169 DevicePath->PhysBase = RegBase;
170 SetDevicePathNodeLength (&DevicePath->Vendor,
171 sizeof (*DevicePath) - sizeof (DevicePath->End));
172 SetDevicePathEndNode (&DevicePath->End);
173
174 Handle = NULL;
175 Status = gBS->InstallProtocolInterface (&Handle,
176 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
177 DevicePath);
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);
183 break;
184 }
185
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,
190 Handle, Status));
191
192 Status = gBS->UninstallProtocolInterface (Handle,
193 &gEfiDevicePathProtocolGuid, DevicePath);
194 ASSERT_EFI_ERROR (Status);
195 FreePool (DevicePath);
196 }
197 break;
198
199 case PropertyTypeRtc:
200 ASSERT (Len == 16);
201
202 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
203 ASSERT (RegBase < MAX_UINT32);
204
205 PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);
206
207 DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));
208 RtcNode = Node;
209 break;
210
211 case PropertyTypeXen:
212 ASSERT (Len == 16);
213
214 //
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
217 //
218 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
219 Handle = NULL;
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));
224 break;
225 }
226
227 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
228
229 break;
230
231 default:
232 break;
233 }
234 }
235
236 if (!FeaturePcdGet (PcdPureAcpiBoot)) {
237 //
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.
240 //
241 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
242 ASSERT_EFI_ERROR (Status);
243
244 //
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.
249 //
250 if ((RtcNode != -1) &&
251 fdt_setprop_string (DeviceTreeBase, RtcNode, "status",
252 "disabled") != 0) {
253 DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));
254 }
255 }
256 return EFI_SUCCESS;
257 }