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