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