]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/ArmVirtualizationPkg/VirtFdtDxe/VirtFdtDxe.c
ArmVirtualizationPkg/VirtFdtDxe: wire up XenBusDxe to "xen,xen" DT node
[mirror_edk2.git] / ArmPlatformPkg / ArmVirtualizationPkg / VirtFdtDxe / VirtFdtDxe.c
CommitLineData
ad106932
AB
1/** @file\r
2* Device tree enumeration DXE driver for ARM Virtual Machines\r
3*\r
4* Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>\r
5*\r
6* This program and the accompanying materials are\r
7* licensed and made available under the terms and conditions of the BSD License\r
8* which accompanies this distribution. The full text of the license may be found at\r
9* http://opensource.org/licenses/bsd-license.php\r
10*\r
11* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13*\r
14**/\r
15\r
16#include <Library/BaseLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/UefiLib.h>\r
19#include <Library/BaseMemoryLib.h>\r
20#include <Library/UefiDriverEntryPoint.h>\r
21#include <Library/MemoryAllocationLib.h>\r
22#include <Library/UefiBootServicesTableLib.h>\r
23#include <Library/VirtioMmioDeviceLib.h>\r
24#include <Library/DevicePathLib.h>\r
25#include <Library/PcdLib.h>\r
26#include <Library/DxeServicesLib.h>\r
cc667df0 27#include <Library/HobLib.h>\r
ad106932 28#include <libfdt.h>\r
6abe83c3 29#include <Library/XenIoMmioLib.h>\r
ad106932
AB
30\r
31#include <Guid/Fdt.h>\r
73bb8e68 32#include <Guid/VirtioMmioTransport.h>\r
cc667df0 33#include <Guid/FdtHob.h>\r
ad106932
AB
34\r
35#pragma pack (1)\r
36typedef struct {\r
37 VENDOR_DEVICE_PATH Vendor;\r
38 UINT64 PhysBase;\r
39 EFI_DEVICE_PATH_PROTOCOL End;\r
40} VIRTIO_TRANSPORT_DEVICE_PATH;\r
41#pragma pack ()\r
42\r
43typedef enum {\r
44 PropertyTypeUnknown,\r
45 PropertyTypeGic,\r
46 PropertyTypeRtc,\r
47 PropertyTypeVirtio,\r
48 PropertyTypeUart,\r
49 PropertyTypeTimer,\r
50 PropertyTypePsci,\r
ad652d46 51 PropertyTypeFwCfg,\r
65bb13b0 52 PropertyTypePciHost,\r
7b70dabb 53 PropertyTypeGicV3,\r
6abe83c3 54 PropertyTypeXen,\r
ad106932
AB
55} PROPERTY_TYPE;\r
56\r
57typedef struct {\r
58 PROPERTY_TYPE Type;\r
65bb13b0 59 CHAR8 Compatible[32];\r
ad106932
AB
60} PROPERTY;\r
61\r
62STATIC CONST PROPERTY CompatibleProperties[] = {\r
65bb13b0
LE
63 { PropertyTypeGic, "arm,cortex-a15-gic" },\r
64 { PropertyTypeRtc, "arm,pl031" },\r
65 { PropertyTypeVirtio, "virtio,mmio" },\r
66 { PropertyTypeUart, "arm,pl011" },\r
67 { PropertyTypeTimer, "arm,armv7-timer" },\r
68 { PropertyTypeTimer, "arm,armv8-timer" },\r
69 { PropertyTypePsci, "arm,psci-0.2" },\r
70 { PropertyTypeFwCfg, "qemu,fw-cfg-mmio" },\r
71 { PropertyTypePciHost, "pci-host-ecam-generic" },\r
7b70dabb 72 { PropertyTypeGicV3, "arm,gic-v3" },\r
6abe83c3 73 { PropertyTypeXen, "xen,xen" },\r
65bb13b0 74 { PropertyTypeUnknown, "" }\r
ad106932
AB
75};\r
76\r
77typedef struct {\r
78 UINT32 Type;\r
79 UINT32 Number;\r
80 UINT32 Flags;\r
81} INTERRUPT_PROPERTY;\r
82\r
83STATIC\r
84PROPERTY_TYPE\r
85GetTypeFromNode (\r
86 IN CONST CHAR8 *NodeType,\r
87 IN UINTN Size\r
88 )\r
89{\r
90 CONST CHAR8 *Compatible;\r
91 CONST PROPERTY *CompatibleProperty;\r
92\r
93 //\r
94 // A 'compatible' node may contain a sequence of NULL terminated\r
95 // compatible strings so check each one\r
96 //\r
97 for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;\r
98 Compatible += 1 + AsciiStrLen (Compatible)) {\r
99 for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {\r
100 if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {\r
101 return CompatibleProperty->Type;\r
102 }\r
103 }\r
104 }\r
105 return PropertyTypeUnknown;\r
106}\r
107\r
65bb13b0
LE
108//\r
109// We expect the "ranges" property of "pci-host-ecam-generic" to consist of\r
110// records like this.\r
111//\r
112#pragma pack (1)\r
113typedef struct {\r
114 UINT32 Type;\r
115 UINT64 ChildBase;\r
116 UINT64 CpuBase;\r
117 UINT64 Size;\r
118} DTB_PCI_HOST_RANGE_RECORD;\r
119#pragma pack ()\r
120\r
121#define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31\r
122#define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30\r
123#define DTB_PCI_HOST_RANGE_ALIASED BIT29\r
124#define DTB_PCI_HOST_RANGE_MMIO32 BIT25\r
125#define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)\r
126#define DTB_PCI_HOST_RANGE_IO BIT24\r
127#define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)\r
128\r
129/**\r
130 Process the device tree node describing the generic PCI host controller.\r
131\r
132 param[in] DeviceTreeBase Pointer to the device tree.\r
133\r
134 param[in] Node Offset of the device tree node whose "compatible"\r
135 property is "pci-host-ecam-generic".\r
136\r
137 param[in] RegProp Pointer to the "reg" property of Node. The caller\r
138 is responsible for ensuring that the size of the\r
139 property is 4 UINT32 cells.\r
140\r
141 @retval EFI_SUCCESS Parsing successful, properties parsed from Node\r
142 have been stored in dynamic PCDs.\r
143\r
144 @retval EFI_PROTOCOL_ERROR Parsing failed. PCDs are left unchanged.\r
145**/\r
146STATIC\r
147EFI_STATUS\r
148EFIAPI\r
149ProcessPciHost (\r
150 IN CONST VOID *DeviceTreeBase,\r
151 IN INT32 Node,\r
152 IN CONST VOID *RegProp\r
153 )\r
154{\r
155 UINT64 ConfigBase, ConfigSize;\r
156 CONST VOID *Prop;\r
157 INT32 Len;\r
158 UINT32 BusMin, BusMax;\r
159 UINT32 RecordIdx;\r
160 UINT64 IoBase, IoSize, IoTranslation;\r
161 UINT64 MmioBase, MmioSize, MmioTranslation;\r
162\r
163 //\r
164 // Fetch the ECAM window.\r
165 //\r
166 ConfigBase = fdt64_to_cpu (((CONST UINT64 *)RegProp)[0]);\r
167 ConfigSize = fdt64_to_cpu (((CONST UINT64 *)RegProp)[1]);\r
168\r
169 //\r
170 // Fetch the bus range (note: inclusive).\r
171 //\r
172 Prop = fdt_getprop (DeviceTreeBase, Node, "bus-range", &Len);\r
173 if (Prop == NULL || Len != 2 * sizeof(UINT32)) {\r
174 DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n",\r
175 __FUNCTION__));\r
176 return EFI_PROTOCOL_ERROR;\r
177 }\r
178 BusMin = fdt32_to_cpu (((CONST UINT32 *)Prop)[0]);\r
179 BusMax = fdt32_to_cpu (((CONST UINT32 *)Prop)[1]);\r
180\r
181 //\r
182 // Sanity check: the config space must accommodate all 4K register bytes of\r
183 // all 8 functions of all 32 devices of all buses.\r
184 //\r
185 if (BusMax < BusMin || BusMax - BusMin == MAX_UINT32 ||\r
186 DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < BusMax - BusMin + 1) {\r
187 DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n",\r
188 __FUNCTION__));\r
189 return EFI_PROTOCOL_ERROR;\r
190 }\r
191\r
192 //\r
193 // Iterate over "ranges".\r
194 //\r
195 Prop = fdt_getprop (DeviceTreeBase, Node, "ranges", &Len);\r
196 if (Prop == NULL || Len == 0 ||\r
197 Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {\r
198 DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));\r
199 return EFI_PROTOCOL_ERROR;\r
200 }\r
201\r
202 //\r
203 // IoBase, IoTranslation, MmioBase and MmioTranslation are initialized only\r
204 // in order to suppress '-Werror=maybe-uninitialized' warnings *incorrectly*\r
205 // emitted by some gcc versions.\r
206 //\r
207 IoBase = 0;\r
208 IoTranslation = 0;\r
209 MmioBase = 0;\r
210 MmioTranslation = 0;\r
211\r
212 //\r
213 // IoSize and MmioSize are initialized to zero because the logic below\r
214 // requires it.\r
215 //\r
216 IoSize = 0;\r
217 MmioSize = 0;\r
218 for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);\r
219 ++RecordIdx) {\r
220 CONST DTB_PCI_HOST_RANGE_RECORD *Record;\r
221\r
222 Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;\r
223 switch (fdt32_to_cpu (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) {\r
224 case DTB_PCI_HOST_RANGE_IO:\r
225 IoBase = fdt64_to_cpu (Record->ChildBase);\r
226 IoSize = fdt64_to_cpu (Record->Size);\r
227 IoTranslation = fdt64_to_cpu (Record->CpuBase) - IoBase;\r
228 break;\r
229\r
230 case DTB_PCI_HOST_RANGE_MMIO32:\r
231 MmioBase = fdt64_to_cpu (Record->ChildBase);\r
232 MmioSize = fdt64_to_cpu (Record->Size);\r
233 MmioTranslation = fdt64_to_cpu (Record->CpuBase) - MmioBase;\r
234\r
235 if (MmioBase > MAX_UINT32 || MmioSize > MAX_UINT32 ||\r
236 MmioBase + MmioSize > SIZE_4GB) {\r
237 DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__));\r
238 return EFI_PROTOCOL_ERROR;\r
239 }\r
240\r
241 if (MmioTranslation != 0) {\r
242 DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation "\r
243 "0x%Lx\n", __FUNCTION__, MmioTranslation));\r
244 return EFI_UNSUPPORTED;\r
245 }\r
246\r
247 break;\r
248 }\r
249 }\r
250 if (IoSize == 0 || MmioSize == 0) {\r
251 DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__,\r
252 (IoSize == 0) ? "IO" : "MMIO32"));\r
253 return EFI_PROTOCOL_ERROR;\r
254 }\r
255\r
256 PcdSet64 (PcdPciExpressBaseAddress, ConfigBase);\r
257\r
258 PcdSet32 (PcdPciBusMin, BusMin);\r
259 PcdSet32 (PcdPciBusMax, BusMax);\r
260\r
261 PcdSet64 (PcdPciIoBase, IoBase);\r
262 PcdSet64 (PcdPciIoSize, IoSize);\r
263 PcdSet64 (PcdPciIoTranslation, IoTranslation);\r
264\r
265 PcdSet32 (PcdPciMmio32Base, (UINT32)MmioBase);\r
266 PcdSet32 (PcdPciMmio32Size, (UINT32)MmioSize);\r
267\r
268 PcdSetBool (PcdPciDisableBusEnumeration, FALSE);\r
269\r
270 DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] "\r
271 "Io[0x%Lx+0x%Lx)@0x%Lx Mem[0x%Lx+0x%Lx)@0x%Lx\n", __FUNCTION__, ConfigBase,\r
272 ConfigSize, BusMin, BusMax, IoBase, IoSize, IoTranslation, MmioBase,\r
273 MmioSize, MmioTranslation));\r
274 return EFI_SUCCESS;\r
275}\r
276\r
277\r
ad106932
AB
278EFI_STATUS\r
279EFIAPI\r
280InitializeVirtFdtDxe (\r
281 IN EFI_HANDLE ImageHandle,\r
282 IN EFI_SYSTEM_TABLE *SystemTable\r
283 )\r
284{\r
cc667df0 285 VOID *Hob;\r
ad106932
AB
286 VOID *DeviceTreeBase;\r
287 INT32 Node, Prev;\r
288 INT32 RtcNode;\r
289 EFI_STATUS Status;\r
290 CONST CHAR8 *Type;\r
291 INT32 Len;\r
292 PROPERTY_TYPE PropType;\r
293 CONST VOID *RegProp;\r
294 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;\r
295 EFI_HANDLE Handle;\r
296 UINT64 RegBase;\r
7b70dabb 297 UINT64 DistBase, CpuBase, RedistBase;\r
ad106932
AB
298 CONST INTERRUPT_PROPERTY *InterruptProp;\r
299 INT32 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;\r
300 CONST CHAR8 *PsciMethod;\r
ad652d46
LE
301 UINT64 FwCfgSelectorAddress;\r
302 UINT64 FwCfgSelectorSize;\r
303 UINT64 FwCfgDataAddress;\r
304 UINT64 FwCfgDataSize;\r
ad106932 305\r
cc667df0
AB
306 Hob = GetFirstGuidHob(&gFdtHobGuid);\r
307 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {\r
308 return EFI_NOT_FOUND;\r
309 }\r
310 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);\r
ad106932
AB
311\r
312 if (fdt_check_header (DeviceTreeBase) != 0) {\r
313 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));\r
314 return EFI_NOT_FOUND;\r
315 }\r
316\r
317 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);\r
318 ASSERT_EFI_ERROR (Status);\r
319\r
320 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));\r
321\r
322 RtcNode = -1;\r
323 //\r
324 // Now enumerate the nodes and install peripherals that we are interested in,\r
325 // i.e., GIC, RTC and virtio MMIO nodes\r
326 //\r
327 for (Prev = 0;; Prev = Node) {\r
328 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);\r
329 if (Node < 0) {\r
330 break;\r
331 }\r
332\r
333 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);\r
334 if (Type == NULL) {\r
335 continue;\r
336 }\r
337\r
338 PropType = GetTypeFromNode (Type, Len);\r
339 if (PropType == PropertyTypeUnknown) {\r
340 continue;\r
341 }\r
342\r
343 //\r
344 // Get the 'reg' property of this node. For now, we will assume\r
345 // 8 byte quantities for base and size, respectively.\r
346 // TODO use #cells root properties instead\r
347 //\r
348 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);\r
349 ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||\r
350 (PropType == PropertyTypePsci));\r
351\r
352 switch (PropType) {\r
65bb13b0
LE
353 case PropertyTypePciHost:\r
354 ASSERT (Len == 2 * sizeof (UINT64));\r
355 Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);\r
356 ASSERT_EFI_ERROR (Status);\r
357 break;\r
358\r
ad652d46
LE
359 case PropertyTypeFwCfg:\r
360 ASSERT (Len == 2 * sizeof (UINT64));\r
361\r
362 FwCfgDataAddress = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
363 FwCfgDataSize = 8;\r
364 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;\r
365 FwCfgSelectorSize = 2;\r
366\r
367 //\r
368 // The following ASSERT()s express\r
369 //\r
370 // Address + Size - 1 <= MAX_UINTN\r
371 //\r
372 // for both registers, that is, that the last byte in each MMIO range is\r
373 // expressible as a MAX_UINTN. The form below is mathematically\r
374 // equivalent, and it also prevents any unsigned overflow before the\r
375 // comparison.\r
376 //\r
377 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);\r
378 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);\r
379\r
380 PcdSet64 (PcdFwCfgSelectorAddress, FwCfgSelectorAddress);\r
381 PcdSet64 (PcdFwCfgDataAddress, FwCfgDataAddress);\r
382\r
383 DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,\r
384 FwCfgDataAddress));\r
385 break;\r
386\r
ad106932
AB
387 case PropertyTypeVirtio:\r
388 ASSERT (Len == 16);\r
389 //\r
390 // Create a unique device path for this transport on the fly\r
391 //\r
392 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
393 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (\r
394 HARDWARE_DEVICE_PATH,\r
395 HW_VENDOR_DP,\r
396 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));\r
397 if (DevicePath == NULL) {\r
398 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));\r
399 break;\r
400 }\r
401\r
73bb8e68
LE
402 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,\r
403 sizeof (EFI_GUID));\r
ad106932
AB
404 DevicePath->PhysBase = RegBase;\r
405 SetDevicePathNodeLength (&DevicePath->Vendor,\r
406 sizeof (*DevicePath) - sizeof (DevicePath->End));\r
407 SetDevicePathEndNode (&DevicePath->End);\r
408\r
409 Handle = NULL;\r
410 Status = gBS->InstallProtocolInterface (&Handle,\r
411 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,\r
412 DevicePath);\r
413 if (EFI_ERROR (Status)) {\r
414 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "\r
415 "protocol on a new handle (Status == %r)\n",\r
416 __FUNCTION__, Status));\r
417 FreePool (DevicePath);\r
418 break;\r
419 }\r
420\r
421 Status = VirtioMmioInstallDevice (RegBase, Handle);\r
422 if (EFI_ERROR (Status)) {\r
423 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "\r
424 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,\r
425 Handle, Status));\r
426\r
427 Status = gBS->UninstallProtocolInterface (Handle,\r
428 &gEfiDevicePathProtocolGuid, DevicePath);\r
429 ASSERT_EFI_ERROR (Status);\r
430 FreePool (DevicePath);\r
431 }\r
432 break;\r
433\r
434 case PropertyTypeGic:\r
435 ASSERT (Len == 32);\r
436\r
437 DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
438 CpuBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);\r
439 ASSERT (DistBase < MAX_UINT32);\r
440 ASSERT (CpuBase < MAX_UINT32);\r
441\r
442 PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);\r
443 PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);\r
444\r
445 DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));\r
446 break;\r
447\r
7b70dabb
AB
448 case PropertyTypeGicV3:\r
449 //\r
450 // The GIC v3 DT binding describes a series of at least 3 physical (base\r
451 // addresses, size) pairs: the distributor interface (GICD), at least one\r
452 // redistributor region (GICR) containing dedicated redistributor\r
453 // interfaces for all individual CPUs, and the CPU interface (GICC).\r
454 // Under virtualization, we assume that the first redistributor region\r
455 // listed covers the boot CPU. Also, our GICv3 driver only supports the\r
456 // system register CPU interface, so we can safely ignore the MMIO version\r
457 // which is listed after the sequence of redistributor interfaces.\r
458 // This means we are only interested in the first two memory regions\r
459 // supplied, and ignore everything else.\r
460 //\r
461 ASSERT (Len >= 32);\r
462\r
463 // RegProp[0..1] == { GICD base, GICD size }\r
464 DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
465 ASSERT (DistBase < MAX_UINT32);\r
466\r
467 // RegProp[2..3] == { GICR base, GICR size }\r
468 RedistBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);\r
469 ASSERT (RedistBase < MAX_UINT32);\r
470\r
471 PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);\r
472 PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);\r
473\r
474 DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",\r
475 DistBase, RedistBase));\r
476 break;\r
477\r
ad106932
AB
478 case PropertyTypeRtc:\r
479 ASSERT (Len == 16);\r
480\r
481 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
482 ASSERT (RegBase < MAX_UINT32);\r
483\r
484 PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);\r
485\r
486 DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));\r
487 RtcNode = Node;\r
488 break;\r
489\r
490 case PropertyTypeTimer:\r
491 //\r
492 // - interrupts : Interrupt list for secure, non-secure, virtual and\r
493 // hypervisor timers, in that order.\r
494 //\r
495 InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);\r
967efdcd 496 ASSERT (Len == 36 || Len == 48);\r
ad106932
AB
497\r
498 SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)\r
499 + (InterruptProp[0].Type ? 16 : 0);\r
500 IntrNum = fdt32_to_cpu (InterruptProp[1].Number)\r
501 + (InterruptProp[1].Type ? 16 : 0);\r
502 VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)\r
503 + (InterruptProp[2].Type ? 16 : 0);\r
967efdcd
AB
504 HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)\r
505 + (InterruptProp[3].Type ? 16 : 0);\r
ad106932
AB
506\r
507 DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",\r
508 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));\r
509\r
510 PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);\r
511 PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);\r
512 PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);\r
513 PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);\r
514 break;\r
515\r
516 case PropertyTypePsci:\r
517 PsciMethod = fdt_getprop (DeviceTreeBase, Node, "method", &Len);\r
518\r
519 if (PsciMethod && AsciiStrnCmp (PsciMethod, "hvc", 3) == 0) {\r
520 PcdSet32 (PcdArmPsciMethod, 1);\r
521 } else if (PsciMethod && AsciiStrnCmp (PsciMethod, "smc", 3) == 0) {\r
522 PcdSet32 (PcdArmPsciMethod, 2);\r
523 } else {\r
524 DEBUG ((EFI_D_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,\r
525 PsciMethod));\r
526 }\r
527 break;\r
528\r
6abe83c3
AB
529 case PropertyTypeXen:\r
530 ASSERT (Len == 16);\r
531\r
532 //\r
533 // Retrieve the reg base from this node and wire it up to the\r
534 // MMIO flavor of the XenBus root device I/O protocol\r
535 //\r
536 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
537 Handle = NULL;\r
538 Status = XenIoMmioInstall (&Handle, RegBase);\r
539 if (EFI_ERROR (Status)) {\r
540 DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "\r
541 "(Status == %r)\n", __FUNCTION__, Status));\r
542 break;\r
543 }\r
544\r
545 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));\r
546\r
547 break;\r
548\r
ad106932
AB
549 default:\r
550 break;\r
551 }\r
552 }\r
553\r
554 //\r
555 // UEFI takes ownership of the RTC hardware, and exposes its functionality\r
556 // through the UEFI Runtime Services GetTime, SetTime, etc. This means we\r
557 // need to disable it in the device tree to prevent the OS from attaching its\r
558 // device driver as well.\r
559 //\r
560 if ((RtcNode != -1) &&\r
561 fdt_setprop_string (DeviceTreeBase, RtcNode, "status",\r
562 "disabled") != 0) {\r
563 DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));\r
564 }\r
565 return EFI_SUCCESS;\r
566}\r