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