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