]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/FdtClientDxe/FdtClientDxe.c
ArmVirtPkg/FdtClientDxe: report address and size cell count directly
[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
AB
24#include <Guid/FdtHob.h>\r
25\r
26#include <Protocol/FdtClient.h>\r
27\r
28STATIC VOID *mDeviceTreeBase;\r
29\r
30STATIC\r
31EFI_STATUS\r
32GetNodeProperty (\r
33 IN FDT_CLIENT_PROTOCOL *This,\r
34 IN INT32 Node,\r
35 IN CONST CHAR8 *PropertyName,\r
36 OUT CONST VOID **Prop,\r
37 OUT UINT32 *PropSize OPTIONAL\r
38 )\r
39{\r
40 INT32 Len;\r
41\r
42 ASSERT (mDeviceTreeBase != NULL);\r
43 ASSERT (Prop != NULL);\r
44\r
45 *Prop = fdt_getprop (mDeviceTreeBase, Node, PropertyName, &Len);\r
46 if (*Prop == NULL) {\r
47 return EFI_NOT_FOUND;\r
48 }\r
49\r
50 if (PropSize != NULL) {\r
51 *PropSize = Len;\r
52 }\r
53 return EFI_SUCCESS;\r
54}\r
55\r
56STATIC\r
57EFI_STATUS\r
58SetNodeProperty (\r
59 IN FDT_CLIENT_PROTOCOL *This,\r
60 IN INT32 Node,\r
61 IN CONST CHAR8 *PropertyName,\r
62 IN CONST VOID *Prop,\r
63 IN UINT32 PropSize\r
64 )\r
65{\r
66 INT32 Ret;\r
67\r
68 ASSERT (mDeviceTreeBase != NULL);\r
69\r
70 Ret = fdt_setprop (mDeviceTreeBase, Node, PropertyName, Prop, PropSize);\r
71 if (Ret != 0) {\r
72 return EFI_DEVICE_ERROR;\r
73 }\r
74\r
75 return EFI_SUCCESS;\r
76}\r
77\r
78STATIC\r
79EFI_STATUS\r
80EFIAPI\r
81FindNextCompatibleNode (\r
82 IN FDT_CLIENT_PROTOCOL *This,\r
83 IN CONST CHAR8 *CompatibleString,\r
84 IN INT32 PrevNode,\r
85 OUT INT32 *Node\r
86 )\r
87{\r
88 INT32 Prev, Next;\r
89 CONST CHAR8 *Type, *Compatible;\r
90 INT32 Len;\r
91\r
92 ASSERT (mDeviceTreeBase != NULL);\r
93 ASSERT (Node != NULL);\r
94\r
95 for (Prev = PrevNode;; Prev = Next) {\r
96 Next = fdt_next_node (mDeviceTreeBase, Prev, NULL);\r
97 if (Next < 0) {\r
98 break;\r
99 }\r
100\r
101 Type = fdt_getprop (mDeviceTreeBase, Next, "compatible", &Len);\r
102 if (Type == NULL) {\r
103 continue;\r
104 }\r
105\r
106 //\r
107 // A 'compatible' node may contain a sequence of NUL terminated\r
108 // compatible strings so check each one\r
109 //\r
110 for (Compatible = Type; Compatible < Type + Len && *Compatible;\r
111 Compatible += 1 + AsciiStrLen (Compatible)) {\r
112 if (AsciiStrCmp (CompatibleString, Compatible) == 0) {\r
113 *Node = Next;\r
114 return EFI_SUCCESS;\r
115 }\r
116 }\r
117 }\r
118 return EFI_NOT_FOUND;\r
119}\r
120\r
121STATIC\r
122EFI_STATUS\r
123EFIAPI\r
124FindCompatibleNode (\r
125 IN FDT_CLIENT_PROTOCOL *This,\r
126 IN CONST CHAR8 *CompatibleString,\r
127 OUT INT32 *Node\r
128 )\r
129{\r
130 return FindNextCompatibleNode (This, CompatibleString, 0, Node);\r
131}\r
132\r
133STATIC\r
134EFI_STATUS\r
135EFIAPI\r
136FindCompatibleNodeProperty (\r
137 IN FDT_CLIENT_PROTOCOL *This,\r
138 IN CONST CHAR8 *CompatibleString,\r
139 IN CONST CHAR8 *PropertyName,\r
140 OUT CONST VOID **Prop,\r
141 OUT UINT32 *PropSize OPTIONAL\r
142 )\r
143{\r
144 EFI_STATUS Status;\r
145 INT32 Node;\r
146\r
147 Status = FindCompatibleNode (This, CompatibleString, &Node);\r
148 if (EFI_ERROR (Status)) {\r
149 return Status;\r
150 }\r
151\r
152 return GetNodeProperty (This, Node, PropertyName, Prop, PropSize);\r
153}\r
154\r
155STATIC\r
156EFI_STATUS\r
157EFIAPI\r
158FindCompatibleNodeReg (\r
159 IN FDT_CLIENT_PROTOCOL *This,\r
160 IN CONST CHAR8 *CompatibleString,\r
161 OUT CONST VOID **Reg,\r
cfc8d51c
AB
162 OUT UINTN *AddressCells,\r
163 OUT UINTN *SizeCells,\r
30740795
AB
164 OUT UINT32 *RegSize\r
165 )\r
166{\r
167 EFI_STATUS Status;\r
168\r
169 ASSERT (RegSize != NULL);\r
170\r
171 //\r
172 // Get the 'reg' property of this node. For now, we will assume\r
173 // 8 byte quantities for base and size, respectively.\r
174 // TODO use #cells root properties instead\r
175 //\r
176 Status = FindCompatibleNodeProperty (This, CompatibleString, "reg", Reg,\r
177 RegSize);\r
178 if (EFI_ERROR (Status)) {\r
179 return Status;\r
180 }\r
181\r
38ed4a9e 182 if ((*RegSize % 16) != 0) {\r
30740795
AB
183 DEBUG ((EFI_D_ERROR,\r
184 "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",\r
185 __FUNCTION__, CompatibleString, *RegSize));\r
186 return EFI_NOT_FOUND;\r
187 }\r
188\r
cfc8d51c
AB
189 *AddressCells = 2;\r
190 *SizeCells = 2;\r
30740795
AB
191\r
192 return EFI_SUCCESS;\r
193}\r
194\r
195STATIC\r
196EFI_STATUS\r
197GetOrInsertChosenNode (\r
198 IN FDT_CLIENT_PROTOCOL *This,\r
199 OUT INT32 *Node\r
200 )\r
201{\r
202 INT32 NewNode;\r
203\r
204 ASSERT (mDeviceTreeBase != NULL);\r
205 ASSERT (Node != NULL);\r
206\r
207 NewNode = fdt_path_offset (mDeviceTreeBase, "/chosen");\r
208 if (NewNode < 0) {\r
209 NewNode = fdt_add_subnode (mDeviceTreeBase, 0, "/chosen");\r
210 }\r
211\r
212 if (NewNode < 0) {\r
213 return EFI_OUT_OF_RESOURCES;\r
214 }\r
215\r
216 *Node = NewNode;\r
217\r
218 return EFI_SUCCESS;\r
219}\r
220\r
221STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = {\r
222 GetNodeProperty,\r
223 SetNodeProperty,\r
224 FindCompatibleNode,\r
225 FindNextCompatibleNode,\r
226 FindCompatibleNodeProperty,\r
227 FindCompatibleNodeReg,\r
228 GetOrInsertChosenNode,\r
229};\r
230\r
231EFI_STATUS\r
232EFIAPI\r
233InitializeFdtClientDxe (\r
234 IN EFI_HANDLE ImageHandle,\r
235 IN EFI_SYSTEM_TABLE *SystemTable\r
236 )\r
237{\r
238 VOID *Hob;\r
239 VOID *DeviceTreeBase;\r
1e7143d8 240 EFI_STATUS Status;\r
30740795
AB
241\r
242 Hob = GetFirstGuidHob (&gFdtHobGuid);\r
243 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {\r
244 return EFI_NOT_FOUND;\r
245 }\r
246 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);\r
247\r
248 if (fdt_check_header (DeviceTreeBase) != 0) {\r
249 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__,\r
250 DeviceTreeBase));\r
251 return EFI_NOT_FOUND;\r
252 }\r
253\r
254 mDeviceTreeBase = DeviceTreeBase;\r
255\r
256 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, mDeviceTreeBase));\r
257\r
1e7143d8
AB
258 if (!FeaturePcdGet (PcdPureAcpiBoot)) {\r
259 //\r
260 // Only install the FDT as a configuration table if we want to leave it up\r
261 // to the OS to decide whether it prefers ACPI over DT.\r
262 //\r
263 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);\r
264 ASSERT_EFI_ERROR (Status);\r
265 }\r
266\r
30740795
AB
267 return gBS->InstallProtocolInterface (&ImageHandle, &gFdtClientProtocolGuid,\r
268 EFI_NATIVE_INTERFACE, &mFdtClientProtocol);\r
269}\r