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