]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.c
EmbeddedPkg: Apply uncrustify changes
[mirror_edk2.git] / EmbeddedPkg / Drivers / FdtClientDxe / FdtClientDxe.c
CommitLineData
30740795
AB
1/** @file\r
2* FDT client driver\r
3*\r
4* Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
5*\r
9792fb0e 6* SPDX-License-Identifier: BSD-2-Clause-Patent\r
30740795
AB
7*\r
8**/\r
9\r
10#include <Library/BaseLib.h>\r
11#include <Library/DebugLib.h>\r
12#include <Library/UefiDriverEntryPoint.h>\r
13#include <Library/UefiBootServicesTableLib.h>\r
14#include <Library/HobLib.h>\r
15#include <libfdt.h>\r
16\r
1e7143d8 17#include <Guid/Fdt.h>\r
30740795 18#include <Guid/FdtHob.h>\r
51b09a2c 19#include <Guid/PlatformHasDeviceTree.h>\r
30740795
AB
20\r
21#include <Protocol/FdtClient.h>\r
22\r
23STATIC VOID *mDeviceTreeBase;\r
24\r
25STATIC\r
26EFI_STATUS\r
eec1ba7d 27EFIAPI\r
30740795 28GetNodeProperty (\r
e7108d0e
MK
29 IN FDT_CLIENT_PROTOCOL *This,\r
30 IN INT32 Node,\r
31 IN CONST CHAR8 *PropertyName,\r
32 OUT CONST VOID **Prop,\r
33 OUT UINT32 *PropSize OPTIONAL\r
30740795
AB
34 )\r
35{\r
e7108d0e 36 INT32 Len;\r
30740795
AB
37\r
38 ASSERT (mDeviceTreeBase != NULL);\r
39 ASSERT (Prop != NULL);\r
40\r
41 *Prop = fdt_getprop (mDeviceTreeBase, Node, PropertyName, &Len);\r
42 if (*Prop == NULL) {\r
43 return EFI_NOT_FOUND;\r
44 }\r
45\r
46 if (PropSize != NULL) {\r
47 *PropSize = Len;\r
48 }\r
e7108d0e 49\r
30740795
AB
50 return EFI_SUCCESS;\r
51}\r
52\r
53STATIC\r
54EFI_STATUS\r
eec1ba7d 55EFIAPI\r
30740795 56SetNodeProperty (\r
e7108d0e
MK
57 IN FDT_CLIENT_PROTOCOL *This,\r
58 IN INT32 Node,\r
59 IN CONST CHAR8 *PropertyName,\r
60 IN CONST VOID *Prop,\r
61 IN UINT32 PropSize\r
30740795
AB
62 )\r
63{\r
e7108d0e 64 INT32 Ret;\r
30740795
AB
65\r
66 ASSERT (mDeviceTreeBase != NULL);\r
67\r
68 Ret = fdt_setprop (mDeviceTreeBase, Node, PropertyName, Prop, PropSize);\r
69 if (Ret != 0) {\r
70 return EFI_DEVICE_ERROR;\r
71 }\r
72\r
73 return EFI_SUCCESS;\r
74}\r
75\r
32f59757
AB
76STATIC\r
77BOOLEAN\r
78IsNodeEnabled (\r
e7108d0e 79 INT32 Node\r
32f59757
AB
80 )\r
81{\r
e7108d0e
MK
82 CONST CHAR8 *NodeStatus;\r
83 INT32 Len;\r
32f59757
AB
84\r
85 //\r
86 // A missing status property implies 'ok' so ignore any errors that\r
87 // may occur here. If the status property is present, check whether\r
88 // it is set to 'ok' or 'okay', anything else is treated as 'disabled'.\r
89 //\r
90 NodeStatus = fdt_getprop (mDeviceTreeBase, Node, "status", &Len);\r
91 if (NodeStatus == NULL) {\r
92 return TRUE;\r
93 }\r
e7108d0e
MK
94\r
95 if ((Len >= 5) && (AsciiStrCmp (NodeStatus, "okay") == 0)) {\r
32f59757
AB
96 return TRUE;\r
97 }\r
e7108d0e
MK
98\r
99 if ((Len >= 3) && (AsciiStrCmp (NodeStatus, "ok") == 0)) {\r
32f59757
AB
100 return TRUE;\r
101 }\r
e7108d0e 102\r
32f59757
AB
103 return FALSE;\r
104}\r
105\r
30740795
AB
106STATIC\r
107EFI_STATUS\r
108EFIAPI\r
109FindNextCompatibleNode (\r
e7108d0e
MK
110 IN FDT_CLIENT_PROTOCOL *This,\r
111 IN CONST CHAR8 *CompatibleString,\r
112 IN INT32 PrevNode,\r
113 OUT INT32 *Node\r
30740795
AB
114 )\r
115{\r
e7108d0e
MK
116 INT32 Prev, Next;\r
117 CONST CHAR8 *Type, *Compatible;\r
118 INT32 Len;\r
30740795
AB
119\r
120 ASSERT (mDeviceTreeBase != NULL);\r
121 ASSERT (Node != NULL);\r
122\r
e7108d0e 123 for (Prev = PrevNode; ; Prev = Next) {\r
30740795
AB
124 Next = fdt_next_node (mDeviceTreeBase, Prev, NULL);\r
125 if (Next < 0) {\r
126 break;\r
127 }\r
128\r
32f59757
AB
129 if (!IsNodeEnabled (Next)) {\r
130 continue;\r
131 }\r
132\r
30740795
AB
133 Type = fdt_getprop (mDeviceTreeBase, Next, "compatible", &Len);\r
134 if (Type == NULL) {\r
135 continue;\r
136 }\r
137\r
138 //\r
139 // A 'compatible' node may contain a sequence of NUL terminated\r
140 // compatible strings so check each one\r
141 //\r
142 for (Compatible = Type; Compatible < Type + Len && *Compatible;\r
e7108d0e
MK
143 Compatible += 1 + AsciiStrLen (Compatible))\r
144 {\r
30740795
AB
145 if (AsciiStrCmp (CompatibleString, Compatible) == 0) {\r
146 *Node = Next;\r
147 return EFI_SUCCESS;\r
148 }\r
149 }\r
150 }\r
e7108d0e 151\r
30740795
AB
152 return EFI_NOT_FOUND;\r
153}\r
154\r
155STATIC\r
156EFI_STATUS\r
157EFIAPI\r
158FindCompatibleNode (\r
e7108d0e
MK
159 IN FDT_CLIENT_PROTOCOL *This,\r
160 IN CONST CHAR8 *CompatibleString,\r
161 OUT INT32 *Node\r
30740795
AB
162 )\r
163{\r
164 return FindNextCompatibleNode (This, CompatibleString, 0, Node);\r
165}\r
166\r
167STATIC\r
168EFI_STATUS\r
169EFIAPI\r
170FindCompatibleNodeProperty (\r
e7108d0e
MK
171 IN FDT_CLIENT_PROTOCOL *This,\r
172 IN CONST CHAR8 *CompatibleString,\r
173 IN CONST CHAR8 *PropertyName,\r
174 OUT CONST VOID **Prop,\r
175 OUT UINT32 *PropSize OPTIONAL\r
30740795
AB
176 )\r
177{\r
e7108d0e
MK
178 EFI_STATUS Status;\r
179 INT32 Node;\r
30740795
AB
180\r
181 Status = FindCompatibleNode (This, CompatibleString, &Node);\r
182 if (EFI_ERROR (Status)) {\r
183 return Status;\r
184 }\r
185\r
186 return GetNodeProperty (This, Node, PropertyName, Prop, PropSize);\r
187}\r
188\r
189STATIC\r
190EFI_STATUS\r
191EFIAPI\r
192FindCompatibleNodeReg (\r
e7108d0e
MK
193 IN FDT_CLIENT_PROTOCOL *This,\r
194 IN CONST CHAR8 *CompatibleString,\r
195 OUT CONST VOID **Reg,\r
196 OUT UINTN *AddressCells,\r
197 OUT UINTN *SizeCells,\r
198 OUT UINT32 *RegSize\r
30740795
AB
199 )\r
200{\r
e7108d0e 201 EFI_STATUS Status;\r
30740795
AB
202\r
203 ASSERT (RegSize != NULL);\r
204\r
205 //\r
206 // Get the 'reg' property of this node. For now, we will assume\r
207 // 8 byte quantities for base and size, respectively.\r
208 // TODO use #cells root properties instead\r
209 //\r
e7108d0e
MK
210 Status = FindCompatibleNodeProperty (\r
211 This,\r
212 CompatibleString,\r
213 "reg",\r
214 Reg,\r
215 RegSize\r
216 );\r
30740795
AB
217 if (EFI_ERROR (Status)) {\r
218 return Status;\r
219 }\r
220\r
38ed4a9e 221 if ((*RegSize % 16) != 0) {\r
e7108d0e
MK
222 DEBUG ((\r
223 DEBUG_ERROR,\r
30740795 224 "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",\r
e7108d0e
MK
225 __FUNCTION__,\r
226 CompatibleString,\r
227 *RegSize\r
228 ));\r
30740795
AB
229 return EFI_NOT_FOUND;\r
230 }\r
231\r
cfc8d51c 232 *AddressCells = 2;\r
e7108d0e 233 *SizeCells = 2;\r
30740795
AB
234\r
235 return EFI_SUCCESS;\r
236}\r
237\r
969d2eb3
AB
238STATIC\r
239EFI_STATUS\r
240EFIAPI\r
241FindNextMemoryNodeReg (\r
e7108d0e
MK
242 IN FDT_CLIENT_PROTOCOL *This,\r
243 IN INT32 PrevNode,\r
244 OUT INT32 *Node,\r
245 OUT CONST VOID **Reg,\r
246 OUT UINTN *AddressCells,\r
247 OUT UINTN *SizeCells,\r
248 OUT UINT32 *RegSize\r
969d2eb3
AB
249 )\r
250{\r
e7108d0e
MK
251 INT32 Prev, Next;\r
252 CONST CHAR8 *DeviceType;\r
253 INT32 Len;\r
254 EFI_STATUS Status;\r
969d2eb3
AB
255\r
256 ASSERT (mDeviceTreeBase != NULL);\r
257 ASSERT (Node != NULL);\r
258\r
e7108d0e 259 for (Prev = PrevNode; ; Prev = Next) {\r
969d2eb3
AB
260 Next = fdt_next_node (mDeviceTreeBase, Prev, NULL);\r
261 if (Next < 0) {\r
262 break;\r
263 }\r
264\r
32f59757
AB
265 if (!IsNodeEnabled (Next)) {\r
266 DEBUG ((DEBUG_WARN, "%a: ignoring disabled memory node\n", __FUNCTION__));\r
d0140443
AB
267 continue;\r
268 }\r
269\r
969d2eb3 270 DeviceType = fdt_getprop (mDeviceTreeBase, Next, "device_type", &Len);\r
e7108d0e 271 if ((DeviceType != NULL) && (AsciiStrCmp (DeviceType, "memory") == 0)) {\r
969d2eb3
AB
272 //\r
273 // Get the 'reg' property of this memory node. For now, we will assume\r
274 // 8 byte quantities for base and size, respectively.\r
275 // TODO use #cells root properties instead\r
276 //\r
277 Status = GetNodeProperty (This, Next, "reg", Reg, RegSize);\r
278 if (EFI_ERROR (Status)) {\r
e7108d0e
MK
279 DEBUG ((\r
280 DEBUG_WARN,\r
969d2eb3 281 "%a: ignoring memory node with no 'reg' property\n",\r
e7108d0e
MK
282 __FUNCTION__\r
283 ));\r
969d2eb3
AB
284 continue;\r
285 }\r
e7108d0e 286\r
969d2eb3 287 if ((*RegSize % 16) != 0) {\r
e7108d0e
MK
288 DEBUG ((\r
289 DEBUG_WARN,\r
969d2eb3 290 "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n",\r
e7108d0e
MK
291 __FUNCTION__,\r
292 *RegSize\r
293 ));\r
969d2eb3
AB
294 continue;\r
295 }\r
296\r
e7108d0e 297 *Node = Next;\r
969d2eb3 298 *AddressCells = 2;\r
e7108d0e 299 *SizeCells = 2;\r
969d2eb3
AB
300 return EFI_SUCCESS;\r
301 }\r
302 }\r
e7108d0e 303\r
969d2eb3
AB
304 return EFI_NOT_FOUND;\r
305}\r
306\r
307STATIC\r
308EFI_STATUS\r
309EFIAPI\r
310FindMemoryNodeReg (\r
e7108d0e
MK
311 IN FDT_CLIENT_PROTOCOL *This,\r
312 OUT INT32 *Node,\r
313 OUT CONST VOID **Reg,\r
314 OUT UINTN *AddressCells,\r
315 OUT UINTN *SizeCells,\r
316 OUT UINT32 *RegSize\r
969d2eb3
AB
317 )\r
318{\r
e7108d0e
MK
319 return FindNextMemoryNodeReg (\r
320 This,\r
321 0,\r
322 Node,\r
323 Reg,\r
324 AddressCells,\r
325 SizeCells,\r
326 RegSize\r
327 );\r
969d2eb3
AB
328}\r
329\r
30740795
AB
330STATIC\r
331EFI_STATUS\r
eec1ba7d 332EFIAPI\r
30740795 333GetOrInsertChosenNode (\r
e7108d0e
MK
334 IN FDT_CLIENT_PROTOCOL *This,\r
335 OUT INT32 *Node\r
30740795
AB
336 )\r
337{\r
e7108d0e 338 INT32 NewNode;\r
30740795
AB
339\r
340 ASSERT (mDeviceTreeBase != NULL);\r
341 ASSERT (Node != NULL);\r
342\r
343 NewNode = fdt_path_offset (mDeviceTreeBase, "/chosen");\r
344 if (NewNode < 0) {\r
345 NewNode = fdt_add_subnode (mDeviceTreeBase, 0, "/chosen");\r
346 }\r
347\r
348 if (NewNode < 0) {\r
349 return EFI_OUT_OF_RESOURCES;\r
350 }\r
351\r
352 *Node = NewNode;\r
353\r
354 return EFI_SUCCESS;\r
355}\r
356\r
e7108d0e 357STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = {\r
30740795
AB
358 GetNodeProperty,\r
359 SetNodeProperty,\r
360 FindCompatibleNode,\r
361 FindNextCompatibleNode,\r
362 FindCompatibleNodeProperty,\r
363 FindCompatibleNodeReg,\r
969d2eb3
AB
364 FindMemoryNodeReg,\r
365 FindNextMemoryNodeReg,\r
30740795
AB
366 GetOrInsertChosenNode,\r
367};\r
368\r
51b09a2c
LE
369STATIC\r
370VOID\r
371EFIAPI\r
372OnPlatformHasDeviceTree (\r
e7108d0e
MK
373 IN EFI_EVENT Event,\r
374 IN VOID *Context\r
51b09a2c
LE
375 )\r
376{\r
e7108d0e
MK
377 EFI_STATUS Status;\r
378 VOID *Interface;\r
379 VOID *DeviceTreeBase;\r
51b09a2c
LE
380\r
381 Status = gBS->LocateProtocol (\r
382 &gEdkiiPlatformHasDeviceTreeGuid,\r
383 NULL, // Registration\r
384 &Interface\r
385 );\r
386 if (EFI_ERROR (Status)) {\r
387 return;\r
388 }\r
389\r
390 DeviceTreeBase = Context;\r
391 DEBUG ((\r
392 DEBUG_INFO,\r
393 "%a: exposing DTB @ 0x%p to OS\n",\r
394 __FUNCTION__,\r
395 DeviceTreeBase\r
396 ));\r
397 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);\r
398 ASSERT_EFI_ERROR (Status);\r
399\r
400 gBS->CloseEvent (Event);\r
401}\r
402\r
30740795
AB
403EFI_STATUS\r
404EFIAPI\r
405InitializeFdtClientDxe (\r
e7108d0e
MK
406 IN EFI_HANDLE ImageHandle,\r
407 IN EFI_SYSTEM_TABLE *SystemTable\r
30740795
AB
408 )\r
409{\r
e7108d0e
MK
410 VOID *Hob;\r
411 VOID *DeviceTreeBase;\r
412 EFI_STATUS Status;\r
413 EFI_EVENT PlatformHasDeviceTreeEvent;\r
414 VOID *Registration;\r
30740795
AB
415\r
416 Hob = GetFirstGuidHob (&gFdtHobGuid);\r
e7108d0e 417 if ((Hob == NULL) || (GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64))) {\r
30740795
AB
418 return EFI_NOT_FOUND;\r
419 }\r
e7108d0e 420\r
30740795
AB
421 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);\r
422\r
423 if (fdt_check_header (DeviceTreeBase) != 0) {\r
e7108d0e
MK
424 DEBUG ((\r
425 DEBUG_ERROR,\r
426 "%a: No DTB found @ 0x%p\n",\r
427 __FUNCTION__,\r
428 DeviceTreeBase\r
429 ));\r
30740795
AB
430 return EFI_NOT_FOUND;\r
431 }\r
432\r
433 mDeviceTreeBase = DeviceTreeBase;\r
434\r
a1878955 435 DEBUG ((DEBUG_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, mDeviceTreeBase));\r
30740795 436\r
51b09a2c
LE
437 //\r
438 // Register a protocol notify for the EDKII Platform Has Device Tree\r
439 // Protocol.\r
440 //\r
441 Status = gBS->CreateEvent (\r
442 EVT_NOTIFY_SIGNAL,\r
443 TPL_CALLBACK,\r
444 OnPlatformHasDeviceTree,\r
445 DeviceTreeBase, // Context\r
446 &PlatformHasDeviceTreeEvent\r
447 );\r
448 if (EFI_ERROR (Status)) {\r
449 DEBUG ((DEBUG_ERROR, "%a: CreateEvent(): %r\n", __FUNCTION__, Status));\r
450 return Status;\r
451 }\r
452\r
453 Status = gBS->RegisterProtocolNotify (\r
454 &gEdkiiPlatformHasDeviceTreeGuid,\r
455 PlatformHasDeviceTreeEvent,\r
456 &Registration\r
457 );\r
458 if (EFI_ERROR (Status)) {\r
459 DEBUG ((\r
460 DEBUG_ERROR,\r
461 "%a: RegisterProtocolNotify(): %r\n",\r
462 __FUNCTION__,\r
463 Status\r
464 ));\r
465 goto CloseEvent;\r
466 }\r
467\r
468 //\r
469 // Kick the event; the protocol could be available already.\r
470 //\r
471 Status = gBS->SignalEvent (PlatformHasDeviceTreeEvent);\r
472 if (EFI_ERROR (Status)) {\r
473 DEBUG ((DEBUG_ERROR, "%a: SignalEvent(): %r\n", __FUNCTION__, Status));\r
474 goto CloseEvent;\r
1e7143d8
AB
475 }\r
476\r
51b09a2c
LE
477 Status = gBS->InstallProtocolInterface (\r
478 &ImageHandle,\r
479 &gFdtClientProtocolGuid,\r
480 EFI_NATIVE_INTERFACE,\r
481 &mFdtClientProtocol\r
482 );\r
483 if (EFI_ERROR (Status)) {\r
484 DEBUG ((\r
485 DEBUG_ERROR,\r
486 "%a: InstallProtocolInterface(): %r\n",\r
487 __FUNCTION__,\r
488 Status\r
489 ));\r
490 goto CloseEvent;\r
491 }\r
492\r
493 return Status;\r
494\r
495CloseEvent:\r
496 gBS->CloseEvent (PlatformHasDeviceTreeEvent);\r
497 return Status;\r
30740795 498}\r