4 * Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
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
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.
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/UefiDriverEntryPoint.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiLib.h>
21 #include <Library/HobLib.h>
24 #include <Guid/Acpi.h>
25 #include <Guid/EventGroup.h>
27 #include <Guid/FdtHob.h>
29 #include <Protocol/FdtClient.h>
31 STATIC VOID
*mDeviceTreeBase
;
37 IN FDT_CLIENT_PROTOCOL
*This
,
39 IN CONST CHAR8
*PropertyName
,
40 OUT CONST VOID
**Prop
,
41 OUT UINT32
*PropSize OPTIONAL
46 ASSERT (mDeviceTreeBase
!= NULL
);
47 ASSERT (Prop
!= NULL
);
49 *Prop
= fdt_getprop (mDeviceTreeBase
, Node
, PropertyName
, &Len
);
54 if (PropSize
!= NULL
) {
64 IN FDT_CLIENT_PROTOCOL
*This
,
66 IN CONST CHAR8
*PropertyName
,
73 ASSERT (mDeviceTreeBase
!= NULL
);
75 Ret
= fdt_setprop (mDeviceTreeBase
, Node
, PropertyName
, Prop
, PropSize
);
77 return EFI_DEVICE_ERROR
;
86 FindNextCompatibleNode (
87 IN FDT_CLIENT_PROTOCOL
*This
,
88 IN CONST CHAR8
*CompatibleString
,
94 CONST CHAR8
*Type
, *Compatible
;
97 ASSERT (mDeviceTreeBase
!= NULL
);
98 ASSERT (Node
!= NULL
);
100 for (Prev
= PrevNode
;; Prev
= Next
) {
101 Next
= fdt_next_node (mDeviceTreeBase
, Prev
, NULL
);
106 Type
= fdt_getprop (mDeviceTreeBase
, Next
, "compatible", &Len
);
112 // A 'compatible' node may contain a sequence of NUL terminated
113 // compatible strings so check each one
115 for (Compatible
= Type
; Compatible
< Type
+ Len
&& *Compatible
;
116 Compatible
+= 1 + AsciiStrLen (Compatible
)) {
117 if (AsciiStrCmp (CompatibleString
, Compatible
) == 0) {
123 return EFI_NOT_FOUND
;
130 IN FDT_CLIENT_PROTOCOL
*This
,
131 IN CONST CHAR8
*CompatibleString
,
135 return FindNextCompatibleNode (This
, CompatibleString
, 0, Node
);
141 FindCompatibleNodeProperty (
142 IN FDT_CLIENT_PROTOCOL
*This
,
143 IN CONST CHAR8
*CompatibleString
,
144 IN CONST CHAR8
*PropertyName
,
145 OUT CONST VOID
**Prop
,
146 OUT UINT32
*PropSize OPTIONAL
152 Status
= FindCompatibleNode (This
, CompatibleString
, &Node
);
153 if (EFI_ERROR (Status
)) {
157 return GetNodeProperty (This
, Node
, PropertyName
, Prop
, PropSize
);
163 FindCompatibleNodeReg (
164 IN FDT_CLIENT_PROTOCOL
*This
,
165 IN CONST CHAR8
*CompatibleString
,
166 OUT CONST VOID
**Reg
,
167 OUT UINTN
*AddressCells
,
168 OUT UINTN
*SizeCells
,
174 ASSERT (RegSize
!= NULL
);
177 // Get the 'reg' property of this node. For now, we will assume
178 // 8 byte quantities for base and size, respectively.
179 // TODO use #cells root properties instead
181 Status
= FindCompatibleNodeProperty (This
, CompatibleString
, "reg", Reg
,
183 if (EFI_ERROR (Status
)) {
187 if ((*RegSize
% 16) != 0) {
189 "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",
190 __FUNCTION__
, CompatibleString
, *RegSize
));
191 return EFI_NOT_FOUND
;
203 FindNextMemoryNodeReg (
204 IN FDT_CLIENT_PROTOCOL
*This
,
207 OUT CONST VOID
**Reg
,
208 OUT UINTN
*AddressCells
,
209 OUT UINTN
*SizeCells
,
214 CONST CHAR8
*DeviceType
;
218 ASSERT (mDeviceTreeBase
!= NULL
);
219 ASSERT (Node
!= NULL
);
221 for (Prev
= PrevNode
;; Prev
= Next
) {
222 Next
= fdt_next_node (mDeviceTreeBase
, Prev
, NULL
);
227 DeviceType
= fdt_getprop (mDeviceTreeBase
, Next
, "device_type", &Len
);
228 if (DeviceType
!= NULL
&& AsciiStrCmp (DeviceType
, "memory") == 0) {
230 // Get the 'reg' property of this memory node. For now, we will assume
231 // 8 byte quantities for base and size, respectively.
232 // TODO use #cells root properties instead
234 Status
= GetNodeProperty (This
, Next
, "reg", Reg
, RegSize
);
235 if (EFI_ERROR (Status
)) {
237 "%a: ignoring memory node with no 'reg' property\n",
241 if ((*RegSize
% 16) != 0) {
243 "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n",
244 __FUNCTION__
, *RegSize
));
254 return EFI_NOT_FOUND
;
261 IN FDT_CLIENT_PROTOCOL
*This
,
263 OUT CONST VOID
**Reg
,
264 OUT UINTN
*AddressCells
,
265 OUT UINTN
*SizeCells
,
269 return FindNextMemoryNodeReg (This
, 0, Node
, Reg
, AddressCells
, SizeCells
,
276 GetOrInsertChosenNode (
277 IN FDT_CLIENT_PROTOCOL
*This
,
283 ASSERT (mDeviceTreeBase
!= NULL
);
284 ASSERT (Node
!= NULL
);
286 NewNode
= fdt_path_offset (mDeviceTreeBase
, "/chosen");
288 NewNode
= fdt_add_subnode (mDeviceTreeBase
, 0, "/chosen");
292 return EFI_OUT_OF_RESOURCES
;
300 STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol
= {
304 FindNextCompatibleNode
,
305 FindCompatibleNodeProperty
,
306 FindCompatibleNodeReg
,
308 FindNextMemoryNodeReg
,
309 GetOrInsertChosenNode
,
324 // Only install the FDT as a configuration table if we are not exposing
325 // ACPI 2.0 (or later) tables. Note that the legacy ACPI table GUID has
326 // no meaning on ARM since we need at least ACPI 5.0 support, and the
327 // 64-bit ACPI 2.0 table GUID is mandatory in that case.
329 Status
= EfiGetSystemConfigurationTable (&gEfiAcpi20TableGuid
, &Table
);
330 if (EFI_ERROR (Status
) || Table
== NULL
) {
331 Status
= gBS
->InstallConfigurationTable (&gFdtTableGuid
, mDeviceTreeBase
);
332 ASSERT_EFI_ERROR (Status
);
335 gBS
->CloseEvent (Event
);
338 STATIC EFI_EVENT mReadyToBootEvent
;
342 InitializeFdtClientDxe (
343 IN EFI_HANDLE ImageHandle
,
344 IN EFI_SYSTEM_TABLE
*SystemTable
348 VOID
*DeviceTreeBase
;
351 Hob
= GetFirstGuidHob (&gFdtHobGuid
);
352 if (Hob
== NULL
|| GET_GUID_HOB_DATA_SIZE (Hob
) != sizeof (UINT64
)) {
353 return EFI_NOT_FOUND
;
355 DeviceTreeBase
= (VOID
*)(UINTN
)*(UINT64
*)GET_GUID_HOB_DATA (Hob
);
357 if (fdt_check_header (DeviceTreeBase
) != 0) {
358 DEBUG ((EFI_D_ERROR
, "%a: No DTB found @ 0x%p\n", __FUNCTION__
,
360 return EFI_NOT_FOUND
;
363 mDeviceTreeBase
= DeviceTreeBase
;
365 DEBUG ((EFI_D_INFO
, "%a: DTB @ 0x%p\n", __FUNCTION__
, mDeviceTreeBase
));
367 Status
= gBS
->InstallProtocolInterface (&ImageHandle
, &gFdtClientProtocolGuid
,
368 EFI_NATIVE_INTERFACE
, &mFdtClientProtocol
);
369 if (EFI_ERROR (Status
)) {
373 Status
= gBS
->CreateEventEx (
378 &gEfiEventReadyToBootGuid
,
381 ASSERT_EFI_ERROR (Status
);