]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/VirtFdtDxe/VirtFdtDxe.c
ShellPkg/mm: Fix the help message to align to implementation and spec
[mirror_edk2.git] / ArmVirtPkg / 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
50b91449
LE
305 UINT64 FwCfgDmaAddress;\r
306 UINT64 FwCfgDmaSize;\r
ad106932 307\r
cc667df0
AB
308 Hob = GetFirstGuidHob(&gFdtHobGuid);\r
309 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {\r
310 return EFI_NOT_FOUND;\r
311 }\r
312 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);\r
ad106932
AB
313\r
314 if (fdt_check_header (DeviceTreeBase) != 0) {\r
315 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));\r
316 return EFI_NOT_FOUND;\r
317 }\r
318\r
319 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);\r
320 ASSERT_EFI_ERROR (Status);\r
321\r
322 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));\r
323\r
324 RtcNode = -1;\r
325 //\r
326 // Now enumerate the nodes and install peripherals that we are interested in,\r
327 // i.e., GIC, RTC and virtio MMIO nodes\r
328 //\r
329 for (Prev = 0;; Prev = Node) {\r
330 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);\r
331 if (Node < 0) {\r
332 break;\r
333 }\r
334\r
335 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);\r
336 if (Type == NULL) {\r
337 continue;\r
338 }\r
339\r
340 PropType = GetTypeFromNode (Type, Len);\r
341 if (PropType == PropertyTypeUnknown) {\r
342 continue;\r
343 }\r
344\r
345 //\r
346 // Get the 'reg' property of this node. For now, we will assume\r
347 // 8 byte quantities for base and size, respectively.\r
348 // TODO use #cells root properties instead\r
349 //\r
350 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);\r
351 ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||\r
352 (PropType == PropertyTypePsci));\r
353\r
354 switch (PropType) {\r
65bb13b0
LE
355 case PropertyTypePciHost:\r
356 ASSERT (Len == 2 * sizeof (UINT64));\r
357 Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);\r
358 ASSERT_EFI_ERROR (Status);\r
359 break;\r
360\r
ad652d46
LE
361 case PropertyTypeFwCfg:\r
362 ASSERT (Len == 2 * sizeof (UINT64));\r
363\r
364 FwCfgDataAddress = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
365 FwCfgDataSize = 8;\r
366 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;\r
367 FwCfgSelectorSize = 2;\r
368\r
369 //\r
370 // The following ASSERT()s express\r
371 //\r
372 // Address + Size - 1 <= MAX_UINTN\r
373 //\r
374 // for both registers, that is, that the last byte in each MMIO range is\r
375 // expressible as a MAX_UINTN. The form below is mathematically\r
376 // equivalent, and it also prevents any unsigned overflow before the\r
377 // comparison.\r
378 //\r
379 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);\r
380 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);\r
381\r
382 PcdSet64 (PcdFwCfgSelectorAddress, FwCfgSelectorAddress);\r
383 PcdSet64 (PcdFwCfgDataAddress, FwCfgDataAddress);\r
384\r
385 DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,\r
386 FwCfgDataAddress));\r
50b91449
LE
387\r
388 if (fdt64_to_cpu (((UINT64 *)RegProp)[1]) >= 0x18) {\r
389 FwCfgDmaAddress = FwCfgDataAddress + 0x10;\r
390 FwCfgDmaSize = 0x08;\r
391\r
392 //\r
393 // See explanation above.\r
394 //\r
395 ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);\r
396\r
397 PcdSet64 (PcdFwCfgDmaAddress, FwCfgDmaAddress);\r
398 DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));\r
399 }\r
ad652d46
LE
400 break;\r
401\r
ad106932
AB
402 case PropertyTypeVirtio:\r
403 ASSERT (Len == 16);\r
404 //\r
405 // Create a unique device path for this transport on the fly\r
406 //\r
407 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
408 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (\r
409 HARDWARE_DEVICE_PATH,\r
410 HW_VENDOR_DP,\r
411 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));\r
412 if (DevicePath == NULL) {\r
413 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));\r
414 break;\r
415 }\r
416\r
73bb8e68
LE
417 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,\r
418 sizeof (EFI_GUID));\r
ad106932
AB
419 DevicePath->PhysBase = RegBase;\r
420 SetDevicePathNodeLength (&DevicePath->Vendor,\r
421 sizeof (*DevicePath) - sizeof (DevicePath->End));\r
422 SetDevicePathEndNode (&DevicePath->End);\r
423\r
424 Handle = NULL;\r
425 Status = gBS->InstallProtocolInterface (&Handle,\r
426 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,\r
427 DevicePath);\r
428 if (EFI_ERROR (Status)) {\r
429 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "\r
430 "protocol on a new handle (Status == %r)\n",\r
431 __FUNCTION__, Status));\r
432 FreePool (DevicePath);\r
433 break;\r
434 }\r
435\r
436 Status = VirtioMmioInstallDevice (RegBase, Handle);\r
437 if (EFI_ERROR (Status)) {\r
438 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "\r
439 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,\r
440 Handle, Status));\r
441\r
442 Status = gBS->UninstallProtocolInterface (Handle,\r
443 &gEfiDevicePathProtocolGuid, DevicePath);\r
444 ASSERT_EFI_ERROR (Status);\r
445 FreePool (DevicePath);\r
446 }\r
447 break;\r
448\r
449 case PropertyTypeGic:\r
450 ASSERT (Len == 32);\r
451\r
452 DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
453 CpuBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);\r
454 ASSERT (DistBase < MAX_UINT32);\r
455 ASSERT (CpuBase < MAX_UINT32);\r
456\r
457 PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);\r
458 PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);\r
ae26410e 459 PcdSet32 (PcdArmGicRevision, 2);\r
ad106932
AB
460\r
461 DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));\r
462 break;\r
463\r
7b70dabb
AB
464 case PropertyTypeGicV3:\r
465 //\r
466 // The GIC v3 DT binding describes a series of at least 3 physical (base\r
467 // addresses, size) pairs: the distributor interface (GICD), at least one\r
468 // redistributor region (GICR) containing dedicated redistributor\r
469 // interfaces for all individual CPUs, and the CPU interface (GICC).\r
470 // Under virtualization, we assume that the first redistributor region\r
471 // listed covers the boot CPU. Also, our GICv3 driver only supports the\r
472 // system register CPU interface, so we can safely ignore the MMIO version\r
473 // which is listed after the sequence of redistributor interfaces.\r
474 // This means we are only interested in the first two memory regions\r
475 // supplied, and ignore everything else.\r
476 //\r
477 ASSERT (Len >= 32);\r
478\r
479 // RegProp[0..1] == { GICD base, GICD size }\r
480 DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
481 ASSERT (DistBase < MAX_UINT32);\r
482\r
483 // RegProp[2..3] == { GICR base, GICR size }\r
484 RedistBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);\r
485 ASSERT (RedistBase < MAX_UINT32);\r
486\r
487 PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);\r
488 PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);\r
ae26410e 489 PcdSet32 (PcdArmGicRevision, 3);\r
7b70dabb
AB
490\r
491 DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",\r
492 DistBase, RedistBase));\r
493 break;\r
494\r
ad106932
AB
495 case PropertyTypeRtc:\r
496 ASSERT (Len == 16);\r
497\r
498 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
499 ASSERT (RegBase < MAX_UINT32);\r
500\r
501 PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);\r
502\r
503 DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));\r
504 RtcNode = Node;\r
505 break;\r
506\r
507 case PropertyTypeTimer:\r
508 //\r
509 // - interrupts : Interrupt list for secure, non-secure, virtual and\r
510 // hypervisor timers, in that order.\r
511 //\r
512 InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);\r
967efdcd 513 ASSERT (Len == 36 || Len == 48);\r
ad106932
AB
514\r
515 SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)\r
516 + (InterruptProp[0].Type ? 16 : 0);\r
517 IntrNum = fdt32_to_cpu (InterruptProp[1].Number)\r
518 + (InterruptProp[1].Type ? 16 : 0);\r
519 VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)\r
520 + (InterruptProp[2].Type ? 16 : 0);\r
967efdcd
AB
521 HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)\r
522 + (InterruptProp[3].Type ? 16 : 0);\r
ad106932
AB
523\r
524 DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",\r
525 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));\r
526\r
527 PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);\r
528 PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);\r
529 PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);\r
530 PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);\r
531 break;\r
532\r
533 case PropertyTypePsci:\r
534 PsciMethod = fdt_getprop (DeviceTreeBase, Node, "method", &Len);\r
535\r
536 if (PsciMethod && AsciiStrnCmp (PsciMethod, "hvc", 3) == 0) {\r
537 PcdSet32 (PcdArmPsciMethod, 1);\r
538 } else if (PsciMethod && AsciiStrnCmp (PsciMethod, "smc", 3) == 0) {\r
539 PcdSet32 (PcdArmPsciMethod, 2);\r
540 } else {\r
541 DEBUG ((EFI_D_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,\r
542 PsciMethod));\r
543 }\r
544 break;\r
545\r
6abe83c3
AB
546 case PropertyTypeXen:\r
547 ASSERT (Len == 16);\r
548\r
549 //\r
550 // Retrieve the reg base from this node and wire it up to the\r
551 // MMIO flavor of the XenBus root device I/O protocol\r
552 //\r
553 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
554 Handle = NULL;\r
555 Status = XenIoMmioInstall (&Handle, RegBase);\r
556 if (EFI_ERROR (Status)) {\r
557 DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "\r
558 "(Status == %r)\n", __FUNCTION__, Status));\r
559 break;\r
560 }\r
561\r
562 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));\r
563\r
564 break;\r
565\r
ad106932
AB
566 default:\r
567 break;\r
568 }\r
569 }\r
570\r
571 //\r
572 // UEFI takes ownership of the RTC hardware, and exposes its functionality\r
573 // through the UEFI Runtime Services GetTime, SetTime, etc. This means we\r
574 // need to disable it in the device tree to prevent the OS from attaching its\r
575 // device driver as well.\r
576 //\r
577 if ((RtcNode != -1) &&\r
578 fdt_setprop_string (DeviceTreeBase, RtcNode, "status",\r
579 "disabled") != 0) {\r
580 DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));\r
581 }\r
582 return EFI_SUCCESS;\r
583}\r