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/HobLib.h>
24 #include <Guid/FdtHob.h>
26 #include <Protocol/FdtClient.h>
28 STATIC VOID
*mDeviceTreeBase
;
34 IN FDT_CLIENT_PROTOCOL
*This
,
36 IN CONST CHAR8
*PropertyName
,
37 OUT CONST VOID
**Prop
,
38 OUT UINT32
*PropSize OPTIONAL
43 ASSERT (mDeviceTreeBase
!= NULL
);
44 ASSERT (Prop
!= NULL
);
46 *Prop
= fdt_getprop (mDeviceTreeBase
, Node
, PropertyName
, &Len
);
51 if (PropSize
!= NULL
) {
61 IN FDT_CLIENT_PROTOCOL
*This
,
63 IN CONST CHAR8
*PropertyName
,
70 ASSERT (mDeviceTreeBase
!= NULL
);
72 Ret
= fdt_setprop (mDeviceTreeBase
, Node
, PropertyName
, Prop
, PropSize
);
74 return EFI_DEVICE_ERROR
;
83 FindNextCompatibleNode (
84 IN FDT_CLIENT_PROTOCOL
*This
,
85 IN CONST CHAR8
*CompatibleString
,
91 CONST CHAR8
*Type
, *Compatible
;
94 ASSERT (mDeviceTreeBase
!= NULL
);
95 ASSERT (Node
!= NULL
);
97 for (Prev
= PrevNode
;; Prev
= Next
) {
98 Next
= fdt_next_node (mDeviceTreeBase
, Prev
, NULL
);
103 Type
= fdt_getprop (mDeviceTreeBase
, Next
, "compatible", &Len
);
109 // A 'compatible' node may contain a sequence of NUL terminated
110 // compatible strings so check each one
112 for (Compatible
= Type
; Compatible
< Type
+ Len
&& *Compatible
;
113 Compatible
+= 1 + AsciiStrLen (Compatible
)) {
114 if (AsciiStrCmp (CompatibleString
, Compatible
) == 0) {
120 return EFI_NOT_FOUND
;
127 IN FDT_CLIENT_PROTOCOL
*This
,
128 IN CONST CHAR8
*CompatibleString
,
132 return FindNextCompatibleNode (This
, CompatibleString
, 0, Node
);
138 FindCompatibleNodeProperty (
139 IN FDT_CLIENT_PROTOCOL
*This
,
140 IN CONST CHAR8
*CompatibleString
,
141 IN CONST CHAR8
*PropertyName
,
142 OUT CONST VOID
**Prop
,
143 OUT UINT32
*PropSize OPTIONAL
149 Status
= FindCompatibleNode (This
, CompatibleString
, &Node
);
150 if (EFI_ERROR (Status
)) {
154 return GetNodeProperty (This
, Node
, PropertyName
, Prop
, PropSize
);
160 FindCompatibleNodeReg (
161 IN FDT_CLIENT_PROTOCOL
*This
,
162 IN CONST CHAR8
*CompatibleString
,
163 OUT CONST VOID
**Reg
,
164 OUT UINTN
*AddressCells
,
165 OUT UINTN
*SizeCells
,
171 ASSERT (RegSize
!= NULL
);
174 // Get the 'reg' property of this node. For now, we will assume
175 // 8 byte quantities for base and size, respectively.
176 // TODO use #cells root properties instead
178 Status
= FindCompatibleNodeProperty (This
, CompatibleString
, "reg", Reg
,
180 if (EFI_ERROR (Status
)) {
184 if ((*RegSize
% 16) != 0) {
186 "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",
187 __FUNCTION__
, CompatibleString
, *RegSize
));
188 return EFI_NOT_FOUND
;
200 FindNextMemoryNodeReg (
201 IN FDT_CLIENT_PROTOCOL
*This
,
204 OUT CONST VOID
**Reg
,
205 OUT UINTN
*AddressCells
,
206 OUT UINTN
*SizeCells
,
211 CONST CHAR8
*DeviceType
;
215 ASSERT (mDeviceTreeBase
!= NULL
);
216 ASSERT (Node
!= NULL
);
218 for (Prev
= PrevNode
;; Prev
= Next
) {
219 Next
= fdt_next_node (mDeviceTreeBase
, Prev
, NULL
);
224 DeviceType
= fdt_getprop (mDeviceTreeBase
, Next
, "device_type", &Len
);
225 if (DeviceType
!= NULL
&& AsciiStrCmp (DeviceType
, "memory") == 0) {
227 // Get the 'reg' property of this memory node. For now, we will assume
228 // 8 byte quantities for base and size, respectively.
229 // TODO use #cells root properties instead
231 Status
= GetNodeProperty (This
, Next
, "reg", Reg
, RegSize
);
232 if (EFI_ERROR (Status
)) {
234 "%a: ignoring memory node with no 'reg' property\n",
238 if ((*RegSize
% 16) != 0) {
240 "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n",
241 __FUNCTION__
, *RegSize
));
251 return EFI_NOT_FOUND
;
258 IN FDT_CLIENT_PROTOCOL
*This
,
260 OUT CONST VOID
**Reg
,
261 OUT UINTN
*AddressCells
,
262 OUT UINTN
*SizeCells
,
266 return FindNextMemoryNodeReg (This
, 0, Node
, Reg
, AddressCells
, SizeCells
,
273 GetOrInsertChosenNode (
274 IN FDT_CLIENT_PROTOCOL
*This
,
280 ASSERT (mDeviceTreeBase
!= NULL
);
281 ASSERT (Node
!= NULL
);
283 NewNode
= fdt_path_offset (mDeviceTreeBase
, "/chosen");
285 NewNode
= fdt_add_subnode (mDeviceTreeBase
, 0, "/chosen");
289 return EFI_OUT_OF_RESOURCES
;
297 STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol
= {
301 FindNextCompatibleNode
,
302 FindCompatibleNodeProperty
,
303 FindCompatibleNodeReg
,
305 FindNextMemoryNodeReg
,
306 GetOrInsertChosenNode
,
311 InitializeFdtClientDxe (
312 IN EFI_HANDLE ImageHandle
,
313 IN EFI_SYSTEM_TABLE
*SystemTable
317 VOID
*DeviceTreeBase
;
320 Hob
= GetFirstGuidHob (&gFdtHobGuid
);
321 if (Hob
== NULL
|| GET_GUID_HOB_DATA_SIZE (Hob
) != sizeof (UINT64
)) {
322 return EFI_NOT_FOUND
;
324 DeviceTreeBase
= (VOID
*)(UINTN
)*(UINT64
*)GET_GUID_HOB_DATA (Hob
);
326 if (fdt_check_header (DeviceTreeBase
) != 0) {
327 DEBUG ((EFI_D_ERROR
, "%a: No DTB found @ 0x%p\n", __FUNCTION__
,
329 return EFI_NOT_FOUND
;
332 mDeviceTreeBase
= DeviceTreeBase
;
334 DEBUG ((EFI_D_INFO
, "%a: DTB @ 0x%p\n", __FUNCTION__
, mDeviceTreeBase
));
336 if (!FeaturePcdGet (PcdPureAcpiBoot
)) {
338 // Only install the FDT as a configuration table if we want to leave it up
339 // to the OS to decide whether it prefers ACPI over DT.
341 Status
= gBS
->InstallConfigurationTable (&gFdtTableGuid
, DeviceTreeBase
);
342 ASSERT_EFI_ERROR (Status
);
345 return gBS
->InstallProtocolInterface (&ImageHandle
, &gFdtClientProtocolGuid
,
346 EFI_NATIVE_INTERFACE
, &mFdtClientProtocol
);