]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/VirtFdtDxe/VirtFdtDxe.c
ArmVirtPkg/VirtFdtDxe: drop RTC 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 PropertyTypeVirtio,
46 PropertyTypeUart,
47 PropertyTypeXen,
48 } PROPERTY_TYPE;
49
50 typedef struct {
51 PROPERTY_TYPE Type;
52 CHAR8 Compatible[32];
53 } PROPERTY;
54
55 STATIC CONST PROPERTY CompatibleProperties[] = {
56 { PropertyTypeVirtio, "virtio,mmio" },
57 { PropertyTypeUart, "arm,pl011" },
58 { PropertyTypeXen, "xen,xen" },
59 { PropertyTypeUnknown, "" }
60 };
61
62 STATIC
63 PROPERTY_TYPE
64 GetTypeFromNode (
65 IN CONST CHAR8 *NodeType,
66 IN UINTN Size
67 )
68 {
69 CONST CHAR8 *Compatible;
70 CONST PROPERTY *CompatibleProperty;
71
72 //
73 // A 'compatible' node may contain a sequence of NULL terminated
74 // compatible strings so check each one
75 //
76 for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;
77 Compatible += 1 + AsciiStrLen (Compatible)) {
78 for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {
79 if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {
80 return CompatibleProperty->Type;
81 }
82 }
83 }
84 return PropertyTypeUnknown;
85 }
86
87 EFI_STATUS
88 EFIAPI
89 InitializeVirtFdtDxe (
90 IN EFI_HANDLE ImageHandle,
91 IN EFI_SYSTEM_TABLE *SystemTable
92 )
93 {
94 VOID *Hob;
95 VOID *DeviceTreeBase;
96 INT32 Node, Prev;
97 EFI_STATUS Status;
98 CONST CHAR8 *Type;
99 INT32 Len;
100 PROPERTY_TYPE PropType;
101 CONST VOID *RegProp;
102 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
103 EFI_HANDLE Handle;
104 UINT64 RegBase;
105
106 Hob = GetFirstGuidHob(&gFdtHobGuid);
107 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
108 return EFI_NOT_FOUND;
109 }
110 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
111
112 if (fdt_check_header (DeviceTreeBase) != 0) {
113 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
114 return EFI_NOT_FOUND;
115 }
116
117 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
118
119 //
120 // Now enumerate the nodes and install peripherals that we are interested in,
121 // i.e., GIC, RTC and virtio MMIO nodes
122 //
123 for (Prev = 0;; Prev = Node) {
124 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
125 if (Node < 0) {
126 break;
127 }
128
129 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
130 if (Type == NULL) {
131 continue;
132 }
133
134 PropType = GetTypeFromNode (Type, Len);
135 if (PropType == PropertyTypeUnknown) {
136 continue;
137 }
138
139 //
140 // Get the 'reg' property of this node. For now, we will assume
141 // 8 byte quantities for base and size, respectively.
142 // TODO use #cells root properties instead
143 //
144 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
145 ASSERT (RegProp != NULL);
146
147 switch (PropType) {
148 case PropertyTypeVirtio:
149 ASSERT (Len == 16);
150 //
151 // Create a unique device path for this transport on the fly
152 //
153 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
154 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
155 HARDWARE_DEVICE_PATH,
156 HW_VENDOR_DP,
157 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
158 if (DevicePath == NULL) {
159 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
160 break;
161 }
162
163 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
164 sizeof (EFI_GUID));
165 DevicePath->PhysBase = RegBase;
166 SetDevicePathNodeLength (&DevicePath->Vendor,
167 sizeof (*DevicePath) - sizeof (DevicePath->End));
168 SetDevicePathEndNode (&DevicePath->End);
169
170 Handle = NULL;
171 Status = gBS->InstallProtocolInterface (&Handle,
172 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
173 DevicePath);
174 if (EFI_ERROR (Status)) {
175 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
176 "protocol on a new handle (Status == %r)\n",
177 __FUNCTION__, Status));
178 FreePool (DevicePath);
179 break;
180 }
181
182 Status = VirtioMmioInstallDevice (RegBase, Handle);
183 if (EFI_ERROR (Status)) {
184 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
185 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
186 Handle, Status));
187
188 Status = gBS->UninstallProtocolInterface (Handle,
189 &gEfiDevicePathProtocolGuid, DevicePath);
190 ASSERT_EFI_ERROR (Status);
191 FreePool (DevicePath);
192 }
193 break;
194
195 case PropertyTypeXen:
196 ASSERT (Len == 16);
197
198 //
199 // Retrieve the reg base from this node and wire it up to the
200 // MMIO flavor of the XenBus root device I/O protocol
201 //
202 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
203 Handle = NULL;
204 Status = XenIoMmioInstall (&Handle, RegBase);
205 if (EFI_ERROR (Status)) {
206 DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "
207 "(Status == %r)\n", __FUNCTION__, Status));
208 break;
209 }
210
211 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
212
213 break;
214
215 default:
216 break;
217 }
218 }
219
220 if (!FeaturePcdGet (PcdPureAcpiBoot)) {
221 //
222 // Only install the FDT as a configuration table if we want to leave it up
223 // to the OS to decide whether it prefers ACPI over DT.
224 //
225 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
226 ASSERT_EFI_ERROR (Status);
227 }
228
229 return EFI_SUCCESS;
230 }