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
;
33 IN FDT_CLIENT_PROTOCOL
*This
,
35 IN CONST CHAR8
*PropertyName
,
36 OUT CONST VOID
**Prop
,
37 OUT UINT32
*PropSize OPTIONAL
42 ASSERT (mDeviceTreeBase
!= NULL
);
43 ASSERT (Prop
!= NULL
);
45 *Prop
= fdt_getprop (mDeviceTreeBase
, Node
, PropertyName
, &Len
);
50 if (PropSize
!= NULL
) {
59 IN FDT_CLIENT_PROTOCOL
*This
,
61 IN CONST CHAR8
*PropertyName
,
68 ASSERT (mDeviceTreeBase
!= NULL
);
70 Ret
= fdt_setprop (mDeviceTreeBase
, Node
, PropertyName
, Prop
, PropSize
);
72 return EFI_DEVICE_ERROR
;
81 FindNextCompatibleNode (
82 IN FDT_CLIENT_PROTOCOL
*This
,
83 IN CONST CHAR8
*CompatibleString
,
89 CONST CHAR8
*Type
, *Compatible
;
92 ASSERT (mDeviceTreeBase
!= NULL
);
93 ASSERT (Node
!= NULL
);
95 for (Prev
= PrevNode
;; Prev
= Next
) {
96 Next
= fdt_next_node (mDeviceTreeBase
, Prev
, NULL
);
101 Type
= fdt_getprop (mDeviceTreeBase
, Next
, "compatible", &Len
);
107 // A 'compatible' node may contain a sequence of NUL terminated
108 // compatible strings so check each one
110 for (Compatible
= Type
; Compatible
< Type
+ Len
&& *Compatible
;
111 Compatible
+= 1 + AsciiStrLen (Compatible
)) {
112 if (AsciiStrCmp (CompatibleString
, Compatible
) == 0) {
118 return EFI_NOT_FOUND
;
125 IN FDT_CLIENT_PROTOCOL
*This
,
126 IN CONST CHAR8
*CompatibleString
,
130 return FindNextCompatibleNode (This
, CompatibleString
, 0, Node
);
136 FindCompatibleNodeProperty (
137 IN FDT_CLIENT_PROTOCOL
*This
,
138 IN CONST CHAR8
*CompatibleString
,
139 IN CONST CHAR8
*PropertyName
,
140 OUT CONST VOID
**Prop
,
141 OUT UINT32
*PropSize OPTIONAL
147 Status
= FindCompatibleNode (This
, CompatibleString
, &Node
);
148 if (EFI_ERROR (Status
)) {
152 return GetNodeProperty (This
, Node
, PropertyName
, Prop
, PropSize
);
158 FindCompatibleNodeReg (
159 IN FDT_CLIENT_PROTOCOL
*This
,
160 IN CONST CHAR8
*CompatibleString
,
161 OUT CONST VOID
**Reg
,
162 OUT UINTN
*AddressCells
,
163 OUT UINTN
*SizeCells
,
169 ASSERT (RegSize
!= NULL
);
172 // Get the 'reg' property of this node. For now, we will assume
173 // 8 byte quantities for base and size, respectively.
174 // TODO use #cells root properties instead
176 Status
= FindCompatibleNodeProperty (This
, CompatibleString
, "reg", Reg
,
178 if (EFI_ERROR (Status
)) {
182 if ((*RegSize
% 16) != 0) {
184 "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",
185 __FUNCTION__
, CompatibleString
, *RegSize
));
186 return EFI_NOT_FOUND
;
198 FindNextMemoryNodeReg (
199 IN FDT_CLIENT_PROTOCOL
*This
,
202 OUT CONST VOID
**Reg
,
203 OUT UINTN
*AddressCells
,
204 OUT UINTN
*SizeCells
,
209 CONST CHAR8
*DeviceType
;
213 ASSERT (mDeviceTreeBase
!= NULL
);
214 ASSERT (Node
!= NULL
);
216 for (Prev
= PrevNode
;; Prev
= Next
) {
217 Next
= fdt_next_node (mDeviceTreeBase
, Prev
, NULL
);
222 DeviceType
= fdt_getprop (mDeviceTreeBase
, Next
, "device_type", &Len
);
223 if (DeviceType
!= NULL
&& AsciiStrCmp (DeviceType
, "memory") == 0) {
225 // Get the 'reg' property of this memory node. For now, we will assume
226 // 8 byte quantities for base and size, respectively.
227 // TODO use #cells root properties instead
229 Status
= GetNodeProperty (This
, Next
, "reg", Reg
, RegSize
);
230 if (EFI_ERROR (Status
)) {
232 "%a: ignoring memory node with no 'reg' property\n",
236 if ((*RegSize
% 16) != 0) {
238 "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n",
239 __FUNCTION__
, *RegSize
));
249 return EFI_NOT_FOUND
;
256 IN FDT_CLIENT_PROTOCOL
*This
,
258 OUT CONST VOID
**Reg
,
259 OUT UINTN
*AddressCells
,
260 OUT UINTN
*SizeCells
,
264 return FindNextMemoryNodeReg (This
, 0, Node
, Reg
, AddressCells
, SizeCells
,
270 GetOrInsertChosenNode (
271 IN FDT_CLIENT_PROTOCOL
*This
,
277 ASSERT (mDeviceTreeBase
!= NULL
);
278 ASSERT (Node
!= NULL
);
280 NewNode
= fdt_path_offset (mDeviceTreeBase
, "/chosen");
282 NewNode
= fdt_add_subnode (mDeviceTreeBase
, 0, "/chosen");
286 return EFI_OUT_OF_RESOURCES
;
294 STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol
= {
298 FindNextCompatibleNode
,
299 FindCompatibleNodeProperty
,
300 FindCompatibleNodeReg
,
302 FindNextMemoryNodeReg
,
303 GetOrInsertChosenNode
,
308 InitializeFdtClientDxe (
309 IN EFI_HANDLE ImageHandle
,
310 IN EFI_SYSTEM_TABLE
*SystemTable
314 VOID
*DeviceTreeBase
;
317 Hob
= GetFirstGuidHob (&gFdtHobGuid
);
318 if (Hob
== NULL
|| GET_GUID_HOB_DATA_SIZE (Hob
) != sizeof (UINT64
)) {
319 return EFI_NOT_FOUND
;
321 DeviceTreeBase
= (VOID
*)(UINTN
)*(UINT64
*)GET_GUID_HOB_DATA (Hob
);
323 if (fdt_check_header (DeviceTreeBase
) != 0) {
324 DEBUG ((EFI_D_ERROR
, "%a: No DTB found @ 0x%p\n", __FUNCTION__
,
326 return EFI_NOT_FOUND
;
329 mDeviceTreeBase
= DeviceTreeBase
;
331 DEBUG ((EFI_D_INFO
, "%a: DTB @ 0x%p\n", __FUNCTION__
, mDeviceTreeBase
));
333 if (!FeaturePcdGet (PcdPureAcpiBoot
)) {
335 // Only install the FDT as a configuration table if we want to leave it up
336 // to the OS to decide whether it prefers ACPI over DT.
338 Status
= gBS
->InstallConfigurationTable (&gFdtTableGuid
, DeviceTreeBase
);
339 ASSERT_EFI_ERROR (Status
);
342 return gBS
->InstallProtocolInterface (&ImageHandle
, &gFdtClientProtocolGuid
,
343 EFI_NATIVE_INTERFACE
, &mFdtClientProtocol
);