]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/FdtClientDxe/FdtClientDxe.c
ArmVirtPkg/FdtClientDxe: make DT table installation !ACPI dependent
[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
78c41ff5 20#include <Library/UefiLib.h>\r
30740795
AB
21#include <Library/HobLib.h>\r
22#include <libfdt.h>\r
23\r
78c41ff5 24#include <Guid/Acpi.h>\r
18f6d4df 25#include <Guid/EventGroup.h>\r
1e7143d8 26#include <Guid/Fdt.h>\r
30740795
AB
27#include <Guid/FdtHob.h>\r
28\r
29#include <Protocol/FdtClient.h>\r
30\r
31STATIC VOID *mDeviceTreeBase;\r
32\r
33STATIC\r
34EFI_STATUS\r
eec1ba7d 35EFIAPI\r
30740795
AB
36GetNodeProperty (\r
37 IN FDT_CLIENT_PROTOCOL *This,\r
38 IN INT32 Node,\r
39 IN CONST CHAR8 *PropertyName,\r
40 OUT CONST VOID **Prop,\r
41 OUT UINT32 *PropSize OPTIONAL\r
42 )\r
43{\r
44 INT32 Len;\r
45\r
46 ASSERT (mDeviceTreeBase != NULL);\r
47 ASSERT (Prop != NULL);\r
48\r
49 *Prop = fdt_getprop (mDeviceTreeBase, Node, PropertyName, &Len);\r
50 if (*Prop == NULL) {\r
51 return EFI_NOT_FOUND;\r
52 }\r
53\r
54 if (PropSize != NULL) {\r
55 *PropSize = Len;\r
56 }\r
57 return EFI_SUCCESS;\r
58}\r
59\r
60STATIC\r
61EFI_STATUS\r
eec1ba7d 62EFIAPI\r
30740795
AB
63SetNodeProperty (\r
64 IN FDT_CLIENT_PROTOCOL *This,\r
65 IN INT32 Node,\r
66 IN CONST CHAR8 *PropertyName,\r
67 IN CONST VOID *Prop,\r
68 IN UINT32 PropSize\r
69 )\r
70{\r
71 INT32 Ret;\r
72\r
73 ASSERT (mDeviceTreeBase != NULL);\r
74\r
75 Ret = fdt_setprop (mDeviceTreeBase, Node, PropertyName, Prop, PropSize);\r
76 if (Ret != 0) {\r
77 return EFI_DEVICE_ERROR;\r
78 }\r
79\r
80 return EFI_SUCCESS;\r
81}\r
82\r
83STATIC\r
84EFI_STATUS\r
85EFIAPI\r
86FindNextCompatibleNode (\r
87 IN FDT_CLIENT_PROTOCOL *This,\r
88 IN CONST CHAR8 *CompatibleString,\r
89 IN INT32 PrevNode,\r
90 OUT INT32 *Node\r
91 )\r
92{\r
93 INT32 Prev, Next;\r
94 CONST CHAR8 *Type, *Compatible;\r
95 INT32 Len;\r
96\r
97 ASSERT (mDeviceTreeBase != NULL);\r
98 ASSERT (Node != NULL);\r
99\r
100 for (Prev = PrevNode;; Prev = Next) {\r
101 Next = fdt_next_node (mDeviceTreeBase, Prev, NULL);\r
102 if (Next < 0) {\r
103 break;\r
104 }\r
105\r
106 Type = fdt_getprop (mDeviceTreeBase, Next, "compatible", &Len);\r
107 if (Type == NULL) {\r
108 continue;\r
109 }\r
110\r
111 //\r
112 // A 'compatible' node may contain a sequence of NUL terminated\r
113 // compatible strings so check each one\r
114 //\r
115 for (Compatible = Type; Compatible < Type + Len && *Compatible;\r
116 Compatible += 1 + AsciiStrLen (Compatible)) {\r
117 if (AsciiStrCmp (CompatibleString, Compatible) == 0) {\r
118 *Node = Next;\r
119 return EFI_SUCCESS;\r
120 }\r
121 }\r
122 }\r
123 return EFI_NOT_FOUND;\r
124}\r
125\r
126STATIC\r
127EFI_STATUS\r
128EFIAPI\r
129FindCompatibleNode (\r
130 IN FDT_CLIENT_PROTOCOL *This,\r
131 IN CONST CHAR8 *CompatibleString,\r
132 OUT INT32 *Node\r
133 )\r
134{\r
135 return FindNextCompatibleNode (This, CompatibleString, 0, Node);\r
136}\r
137\r
138STATIC\r
139EFI_STATUS\r
140EFIAPI\r
141FindCompatibleNodeProperty (\r
142 IN FDT_CLIENT_PROTOCOL *This,\r
143 IN CONST CHAR8 *CompatibleString,\r
144 IN CONST CHAR8 *PropertyName,\r
145 OUT CONST VOID **Prop,\r
146 OUT UINT32 *PropSize OPTIONAL\r
147 )\r
148{\r
149 EFI_STATUS Status;\r
150 INT32 Node;\r
151\r
152 Status = FindCompatibleNode (This, CompatibleString, &Node);\r
153 if (EFI_ERROR (Status)) {\r
154 return Status;\r
155 }\r
156\r
157 return GetNodeProperty (This, Node, PropertyName, Prop, PropSize);\r
158}\r
159\r
160STATIC\r
161EFI_STATUS\r
162EFIAPI\r
163FindCompatibleNodeReg (\r
164 IN FDT_CLIENT_PROTOCOL *This,\r
165 IN CONST CHAR8 *CompatibleString,\r
166 OUT CONST VOID **Reg,\r
cfc8d51c
AB
167 OUT UINTN *AddressCells,\r
168 OUT UINTN *SizeCells,\r
30740795
AB
169 OUT UINT32 *RegSize\r
170 )\r
171{\r
172 EFI_STATUS Status;\r
173\r
174 ASSERT (RegSize != NULL);\r
175\r
176 //\r
177 // Get the 'reg' property of this node. For now, we will assume\r
178 // 8 byte quantities for base and size, respectively.\r
179 // TODO use #cells root properties instead\r
180 //\r
181 Status = FindCompatibleNodeProperty (This, CompatibleString, "reg", Reg,\r
182 RegSize);\r
183 if (EFI_ERROR (Status)) {\r
184 return Status;\r
185 }\r
186\r
38ed4a9e 187 if ((*RegSize % 16) != 0) {\r
30740795
AB
188 DEBUG ((EFI_D_ERROR,\r
189 "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",\r
190 __FUNCTION__, CompatibleString, *RegSize));\r
191 return EFI_NOT_FOUND;\r
192 }\r
193\r
cfc8d51c
AB
194 *AddressCells = 2;\r
195 *SizeCells = 2;\r
30740795
AB
196\r
197 return EFI_SUCCESS;\r
198}\r
199\r
969d2eb3
AB
200STATIC\r
201EFI_STATUS\r
202EFIAPI\r
203FindNextMemoryNodeReg (\r
204 IN FDT_CLIENT_PROTOCOL *This,\r
205 IN INT32 PrevNode,\r
206 OUT INT32 *Node,\r
207 OUT CONST VOID **Reg,\r
208 OUT UINTN *AddressCells,\r
209 OUT UINTN *SizeCells,\r
210 OUT UINT32 *RegSize\r
211 )\r
212{\r
213 INT32 Prev, Next;\r
214 CONST CHAR8 *DeviceType;\r
215 INT32 Len;\r
216 EFI_STATUS Status;\r
217\r
218 ASSERT (mDeviceTreeBase != NULL);\r
219 ASSERT (Node != NULL);\r
220\r
221 for (Prev = PrevNode;; Prev = Next) {\r
222 Next = fdt_next_node (mDeviceTreeBase, Prev, NULL);\r
223 if (Next < 0) {\r
224 break;\r
225 }\r
226\r
227 DeviceType = fdt_getprop (mDeviceTreeBase, Next, "device_type", &Len);\r
228 if (DeviceType != NULL && AsciiStrCmp (DeviceType, "memory") == 0) {\r
229 //\r
230 // Get the 'reg' property of this memory node. For now, we will assume\r
231 // 8 byte quantities for base and size, respectively.\r
232 // TODO use #cells root properties instead\r
233 //\r
234 Status = GetNodeProperty (This, Next, "reg", Reg, RegSize);\r
235 if (EFI_ERROR (Status)) {\r
236 DEBUG ((EFI_D_WARN,\r
237 "%a: ignoring memory node with no 'reg' property\n",\r
238 __FUNCTION__));\r
239 continue;\r
240 }\r
241 if ((*RegSize % 16) != 0) {\r
242 DEBUG ((EFI_D_WARN,\r
243 "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n",\r
244 __FUNCTION__, *RegSize));\r
245 continue;\r
246 }\r
247\r
248 *Node = Next;\r
249 *AddressCells = 2;\r
250 *SizeCells = 2;\r
251 return EFI_SUCCESS;\r
252 }\r
253 }\r
254 return EFI_NOT_FOUND;\r
255}\r
256\r
257STATIC\r
258EFI_STATUS\r
259EFIAPI\r
260FindMemoryNodeReg (\r
261 IN FDT_CLIENT_PROTOCOL *This,\r
262 OUT INT32 *Node,\r
263 OUT CONST VOID **Reg,\r
264 OUT UINTN *AddressCells,\r
265 OUT UINTN *SizeCells,\r
266 OUT UINT32 *RegSize\r
267 )\r
268{\r
269 return FindNextMemoryNodeReg (This, 0, Node, Reg, AddressCells, SizeCells,\r
270 RegSize);\r
271}\r
272\r
30740795
AB
273STATIC\r
274EFI_STATUS\r
eec1ba7d 275EFIAPI\r
30740795
AB
276GetOrInsertChosenNode (\r
277 IN FDT_CLIENT_PROTOCOL *This,\r
278 OUT INT32 *Node\r
279 )\r
280{\r
281 INT32 NewNode;\r
282\r
283 ASSERT (mDeviceTreeBase != NULL);\r
284 ASSERT (Node != NULL);\r
285\r
286 NewNode = fdt_path_offset (mDeviceTreeBase, "/chosen");\r
287 if (NewNode < 0) {\r
288 NewNode = fdt_add_subnode (mDeviceTreeBase, 0, "/chosen");\r
289 }\r
290\r
291 if (NewNode < 0) {\r
292 return EFI_OUT_OF_RESOURCES;\r
293 }\r
294\r
295 *Node = NewNode;\r
296\r
297 return EFI_SUCCESS;\r
298}\r
299\r
300STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = {\r
301 GetNodeProperty,\r
302 SetNodeProperty,\r
303 FindCompatibleNode,\r
304 FindNextCompatibleNode,\r
305 FindCompatibleNodeProperty,\r
306 FindCompatibleNodeReg,\r
969d2eb3
AB
307 FindMemoryNodeReg,\r
308 FindNextMemoryNodeReg,\r
30740795
AB
309 GetOrInsertChosenNode,\r
310};\r
311\r
18f6d4df
AB
312STATIC\r
313VOID\r
314EFIAPI\r
315OnReadyToBoot (\r
316 EFI_EVENT Event,\r
317 VOID *Context\r
318 )\r
319{\r
320 EFI_STATUS Status;\r
78c41ff5 321 VOID *Table;\r
18f6d4df 322\r
78c41ff5
AB
323 //\r
324 // Only install the FDT as a configuration table if we are not exposing\r
325 // ACPI 2.0 (or later) tables. Note that the legacy ACPI table GUID has\r
326 // no meaning on ARM since we need at least ACPI 5.0 support, and the\r
327 // 64-bit ACPI 2.0 table GUID is mandatory in that case.\r
328 //\r
329 Status = EfiGetSystemConfigurationTable (&gEfiAcpi20TableGuid, &Table);\r
330 if (EFI_ERROR (Status) || Table == NULL) {\r
18f6d4df
AB
331 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, mDeviceTreeBase);\r
332 ASSERT_EFI_ERROR (Status);\r
333 }\r
334\r
335 gBS->CloseEvent (Event);\r
336}\r
337\r
338STATIC EFI_EVENT mReadyToBootEvent;\r
339\r
30740795
AB
340EFI_STATUS\r
341EFIAPI\r
342InitializeFdtClientDxe (\r
343 IN EFI_HANDLE ImageHandle,\r
344 IN EFI_SYSTEM_TABLE *SystemTable\r
345 )\r
346{\r
347 VOID *Hob;\r
348 VOID *DeviceTreeBase;\r
1e7143d8 349 EFI_STATUS Status;\r
30740795
AB
350\r
351 Hob = GetFirstGuidHob (&gFdtHobGuid);\r
352 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {\r
353 return EFI_NOT_FOUND;\r
354 }\r
355 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);\r
356\r
357 if (fdt_check_header (DeviceTreeBase) != 0) {\r
358 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__,\r
359 DeviceTreeBase));\r
360 return EFI_NOT_FOUND;\r
361 }\r
362\r
363 mDeviceTreeBase = DeviceTreeBase;\r
364\r
365 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, mDeviceTreeBase));\r
366\r
18f6d4df
AB
367 Status = gBS->InstallProtocolInterface (&ImageHandle, &gFdtClientProtocolGuid,\r
368 EFI_NATIVE_INTERFACE, &mFdtClientProtocol);\r
369 if (EFI_ERROR (Status)) {\r
370 return Status;\r
1e7143d8
AB
371 }\r
372\r
18f6d4df
AB
373 Status = gBS->CreateEventEx (\r
374 EVT_NOTIFY_SIGNAL,\r
375 TPL_CALLBACK,\r
376 OnReadyToBoot,\r
377 NULL,\r
378 &gEfiEventReadyToBootGuid,\r
379 &mReadyToBootEvent\r
380 );\r
381 ASSERT_EFI_ERROR (Status);\r
382\r
383 return EFI_SUCCESS;\r
30740795 384}\r