blob: 26f4a4ee56293366bf22d6bc57f222d20e36b141 [file] [log] [blame]
Simon Glassa06a34b2016-07-25 18:59:04 -06001#!/usr/bin/python
Tom Rini83d290c2018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glassa06a34b2016-07-25 18:59:04 -06003#
4# Copyright (C) 2016 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
Simon Glassa06a34b2016-07-25 18:59:04 -06007
8import struct
9import sys
10
11import fdt_util
Simon Glass7b75b442017-05-27 07:38:28 -060012import libfdt
Simon Glass117f57b2018-07-06 10:27:26 -060013from libfdt import QUIET_NOTFOUND
Simon Glassa06a34b2016-07-25 18:59:04 -060014
15# This deals with a device tree, presenting it as an assortment of Node and
16# Prop objects, representing nodes and properties, respectively. This file
Simon Glass99ed4a22017-05-27 07:38:30 -060017# contains the base classes and defines the high-level API. You can use
18# FdtScan() as a convenience function to create and scan an Fdt.
Simon Glass7b75b442017-05-27 07:38:28 -060019
20# This implementation uses a libfdt Python library to access the device tree,
21# so it is fairly efficient.
Simon Glassa06a34b2016-07-25 18:59:04 -060022
Simon Glassbc1dea32016-07-25 18:59:05 -060023# A list of types we support
Simon Glassfbdfd222017-08-29 14:15:48 -060024(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, TYPE_INT64) = range(5)
Simon Glassbc1dea32016-07-25 18:59:05 -060025
Simon Glassa06a34b2016-07-25 18:59:04 -060026def CheckErr(errnum, msg):
27 if errnum:
28 raise ValueError('Error %d: %s: %s' %
29 (errnum, libfdt.fdt_strerror(errnum), msg))
30
Simon Glass7b75b442017-05-27 07:38:28 -060031class Prop:
Simon Glassa06a34b2016-07-25 18:59:04 -060032 """A device tree property
33
34 Properties:
35 name: Property name (as per the device tree)
36 value: Property value as a string of bytes, or a list of strings of
37 bytes
38 type: Value type
39 """
Simon Glass7b75b442017-05-27 07:38:28 -060040 def __init__(self, node, offset, name, bytes):
Simon Glassa06a34b2016-07-25 18:59:04 -060041 self._node = node
42 self._offset = offset
43 self.name = name
44 self.value = None
Simon Glass7b75b442017-05-27 07:38:28 -060045 self.bytes = str(bytes)
Simon Glassfa80c252018-09-14 04:57:13 -060046 self.dirty = False
Simon Glass7b75b442017-05-27 07:38:28 -060047 if not bytes:
48 self.type = TYPE_BOOL
49 self.value = True
50 return
51 self.type, self.value = self.BytesToValue(bytes)
Simon Glassa06a34b2016-07-25 18:59:04 -060052
Simon Glassf9b88b32018-07-06 10:27:29 -060053 def RefreshOffset(self, poffset):
54 self._offset = poffset
55
Simon Glassc322a852016-07-25 18:59:06 -060056 def Widen(self, newprop):
57 """Figure out which property type is more general
58
59 Given a current property and a new property, this function returns the
60 one that is less specific as to type. The less specific property will
61 be ble to represent the data in the more specific property. This is
62 used for things like:
63
64 node1 {
65 compatible = "fred";
66 value = <1>;
67 };
68 node1 {
69 compatible = "fred";
70 value = <1 2>;
71 };
72
73 He we want to use an int array for 'value'. The first property
74 suggests that a single int is enough, but the second one shows that
75 it is not. Calling this function with these two propertes would
76 update the current property to be like the second, since it is less
77 specific.
78 """
79 if newprop.type < self.type:
80 self.type = newprop.type
81
82 if type(newprop.value) == list and type(self.value) != list:
83 self.value = [self.value]
84
85 if type(self.value) == list and len(newprop.value) > len(self.value):
86 val = self.GetEmpty(self.type)
87 while len(self.value) < len(newprop.value):
88 self.value.append(val)
89
Simon Glassbc1dea32016-07-25 18:59:05 -060090 def BytesToValue(self, bytes):
91 """Converts a string of bytes into a type and value
92
93 Args:
94 A string containing bytes
95
96 Return:
97 A tuple:
98 Type of data
99 Data, either a single element or a list of elements. Each element
100 is one of:
101 TYPE_STRING: string value from the property
102 TYPE_INT: a byte-swapped integer stored as a 4-byte string
103 TYPE_BYTE: a byte stored as a single-byte string
104 """
Simon Glassb4360202017-05-27 07:38:22 -0600105 bytes = str(bytes)
Simon Glassbc1dea32016-07-25 18:59:05 -0600106 size = len(bytes)
107 strings = bytes.split('\0')
108 is_string = True
109 count = len(strings) - 1
110 if count > 0 and not strings[-1]:
111 for string in strings[:-1]:
112 if not string:
113 is_string = False
114 break
115 for ch in string:
116 if ch < ' ' or ch > '~':
117 is_string = False
118 break
119 else:
120 is_string = False
121 if is_string:
122 if count == 1:
123 return TYPE_STRING, strings[0]
124 else:
125 return TYPE_STRING, strings[:-1]
126 if size % 4:
127 if size == 1:
128 return TYPE_BYTE, bytes[0]
129 else:
130 return TYPE_BYTE, list(bytes)
131 val = []
132 for i in range(0, size, 4):
133 val.append(bytes[i:i + 4])
134 if size == 4:
135 return TYPE_INT, val[0]
136 else:
137 return TYPE_INT, val
138
Simon Glass2ba98752018-07-06 10:27:24 -0600139 @classmethod
Simon Glassbc1dea32016-07-25 18:59:05 -0600140 def GetEmpty(self, type):
141 """Get an empty / zero value of the given type
142
143 Returns:
144 A single value of the given type
145 """
146 if type == TYPE_BYTE:
147 return chr(0)
148 elif type == TYPE_INT:
Simon Glassaf53f5a2018-09-14 04:57:14 -0600149 return struct.pack('>I', 0);
Simon Glassbc1dea32016-07-25 18:59:05 -0600150 elif type == TYPE_STRING:
151 return ''
152 else:
153 return True
154
Simon Glassbabdbde2016-07-25 18:59:16 -0600155 def GetOffset(self):
156 """Get the offset of a property
157
Simon Glassbabdbde2016-07-25 18:59:16 -0600158 Returns:
Simon Glass7b75b442017-05-27 07:38:28 -0600159 The offset of the property (struct fdt_property) within the file
Simon Glassbabdbde2016-07-25 18:59:16 -0600160 """
Simon Glassf9b88b32018-07-06 10:27:29 -0600161 self._node._fdt.CheckCache()
Simon Glass7b75b442017-05-27 07:38:28 -0600162 return self._node._fdt.GetStructOffset(self._offset)
Simon Glassbabdbde2016-07-25 18:59:16 -0600163
Simon Glassfa80c252018-09-14 04:57:13 -0600164 def SetInt(self, val):
165 """Set the integer value of the property
166
167 The device tree is marked dirty so that the value will be written to
168 the block on the next sync.
169
170 Args:
171 val: Integer value (32-bit, single cell)
172 """
173 self.bytes = struct.pack('>I', val);
174 self.value = val
175 self.type = TYPE_INT
176 self.dirty = True
177
178 def Sync(self, auto_resize=False):
179 """Sync property changes back to the device tree
180
181 This updates the device tree blob with any changes to this property
182 since the last sync.
183
184 Args:
185 auto_resize: Resize the device tree automatically if it does not
186 have enough space for the update
187
188 Raises:
189 FdtException if auto_resize is False and there is not enough space
190 """
191 if self._offset is None or self.dirty:
192 node = self._node
193 fdt_obj = node._fdt._fdt_obj
194 if auto_resize:
195 while fdt_obj.setprop(node.Offset(), self.name, self.bytes,
196 (libfdt.NOSPACE,)) == -libfdt.NOSPACE:
197 fdt_obj.resize(fdt_obj.totalsize() + 1024)
198 fdt_obj.setprop(node.Offset(), self.name, self.bytes)
199 else:
200 fdt_obj.setprop(node.Offset(), self.name, self.bytes)
201
202
Simon Glass7b75b442017-05-27 07:38:28 -0600203class Node:
Simon Glassa06a34b2016-07-25 18:59:04 -0600204 """A device tree node
205
206 Properties:
207 offset: Integer offset in the device tree
208 name: Device tree node tname
209 path: Full path to node, along with the node name itself
210 _fdt: Device tree object
211 subnodes: A list of subnodes for this node, each a Node object
212 props: A dict of properties for this node, each a Prop object.
213 Keyed by property name
214 """
Simon Glass979ab022017-08-29 14:15:47 -0600215 def __init__(self, fdt, parent, offset, name, path):
Simon Glassa06a34b2016-07-25 18:59:04 -0600216 self._fdt = fdt
Simon Glass979ab022017-08-29 14:15:47 -0600217 self.parent = parent
Simon Glassa06a34b2016-07-25 18:59:04 -0600218 self._offset = offset
219 self.name = name
220 self.path = path
221 self.subnodes = []
222 self.props = {}
223
Simon Glass94a7c602018-07-17 13:25:46 -0600224 def GetFdt(self):
225 """Get the Fdt object for this node
226
227 Returns:
228 Fdt object
229 """
230 return self._fdt
231
Simon Glass1d858882018-07-17 13:25:41 -0600232 def FindNode(self, name):
Simon Glassf7a2aee2016-07-25 18:59:07 -0600233 """Find a node given its name
234
235 Args:
236 name: Node name to look for
237 Returns:
238 Node object if found, else None
239 """
240 for subnode in self.subnodes:
241 if subnode.name == name:
242 return subnode
243 return None
244
Simon Glass7b75b442017-05-27 07:38:28 -0600245 def Offset(self):
246 """Returns the offset of a node, after checking the cache
Simon Glassf7a2aee2016-07-25 18:59:07 -0600247
Simon Glass7b75b442017-05-27 07:38:28 -0600248 This should be used instead of self._offset directly, to ensure that
249 the cache does not contain invalid offsets.
Simon Glassf7a2aee2016-07-25 18:59:07 -0600250 """
Simon Glass7b75b442017-05-27 07:38:28 -0600251 self._fdt.CheckCache()
252 return self._offset
253
254 def Scan(self):
255 """Scan a node's properties and subnodes
256
257 This fills in the props and subnodes properties, recursively
258 searching into subnodes so that the entire tree is built.
259 """
Simon Glass117f57b2018-07-06 10:27:26 -0600260 fdt_obj = self._fdt._fdt_obj
Simon Glass7b75b442017-05-27 07:38:28 -0600261 self.props = self._fdt.GetProps(self)
Simon Glass117f57b2018-07-06 10:27:26 -0600262 phandle = fdt_obj.get_phandle(self.Offset())
Simon Glass09264e02017-08-29 14:15:52 -0600263 if phandle:
Simon Glass117f57b2018-07-06 10:27:26 -0600264 self._fdt.phandle_to_node[phandle] = self
Simon Glass7b75b442017-05-27 07:38:28 -0600265
Simon Glass117f57b2018-07-06 10:27:26 -0600266 offset = fdt_obj.first_subnode(self.Offset(), QUIET_NOTFOUND)
Simon Glass7b75b442017-05-27 07:38:28 -0600267 while offset >= 0:
268 sep = '' if self.path[-1] == '/' else '/'
Simon Glass117f57b2018-07-06 10:27:26 -0600269 name = fdt_obj.get_name(offset)
Simon Glass7b75b442017-05-27 07:38:28 -0600270 path = self.path + sep + name
Simon Glass979ab022017-08-29 14:15:47 -0600271 node = Node(self._fdt, self, offset, name, path)
Simon Glass7b75b442017-05-27 07:38:28 -0600272 self.subnodes.append(node)
273
274 node.Scan()
Simon Glass117f57b2018-07-06 10:27:26 -0600275 offset = fdt_obj.next_subnode(offset, QUIET_NOTFOUND)
Simon Glass7b75b442017-05-27 07:38:28 -0600276
277 def Refresh(self, my_offset):
278 """Fix up the _offset for each node, recursively
279
280 Note: This does not take account of property offsets - these will not
281 be updated.
282 """
Simon Glass96066242018-07-06 10:27:27 -0600283 fdt_obj = self._fdt._fdt_obj
Simon Glass7b75b442017-05-27 07:38:28 -0600284 if self._offset != my_offset:
Simon Glass7b75b442017-05-27 07:38:28 -0600285 self._offset = my_offset
Simon Glass96066242018-07-06 10:27:27 -0600286 offset = fdt_obj.first_subnode(self._offset, QUIET_NOTFOUND)
Simon Glass7b75b442017-05-27 07:38:28 -0600287 for subnode in self.subnodes:
Simon Glassf9b88b32018-07-06 10:27:29 -0600288 if subnode.name != fdt_obj.get_name(offset):
289 raise ValueError('Internal error, node name mismatch %s != %s' %
290 (subnode.name, fdt_obj.get_name(offset)))
Simon Glass7b75b442017-05-27 07:38:28 -0600291 subnode.Refresh(offset)
Simon Glass96066242018-07-06 10:27:27 -0600292 offset = fdt_obj.next_subnode(offset, QUIET_NOTFOUND)
Simon Glassf9b88b32018-07-06 10:27:29 -0600293 if offset != -libfdt.FDT_ERR_NOTFOUND:
294 raise ValueError('Internal error, offset == %d' % offset)
295
296 poffset = fdt_obj.first_property_offset(self._offset, QUIET_NOTFOUND)
297 while poffset >= 0:
298 p = fdt_obj.get_property_by_offset(poffset)
299 prop = self.props.get(p.name)
300 if not prop:
301 raise ValueError("Internal error, property '%s' missing, "
302 'offset %d' % (p.name, poffset))
303 prop.RefreshOffset(poffset)
304 poffset = fdt_obj.next_property_offset(poffset, QUIET_NOTFOUND)
Simon Glassf7a2aee2016-07-25 18:59:07 -0600305
Simon Glass2a70d892016-07-25 18:59:14 -0600306 def DeleteProp(self, prop_name):
307 """Delete a property of a node
308
Simon Glass7b75b442017-05-27 07:38:28 -0600309 The property is deleted and the offset cache is invalidated.
Simon Glass2a70d892016-07-25 18:59:14 -0600310
311 Args:
312 prop_name: Name of the property to delete
Simon Glass7b75b442017-05-27 07:38:28 -0600313 Raises:
314 ValueError if the property does not exist
Simon Glass2a70d892016-07-25 18:59:14 -0600315 """
Simon Glass96066242018-07-06 10:27:27 -0600316 CheckErr(self._fdt._fdt_obj.delprop(self.Offset(), prop_name),
Simon Glass7b75b442017-05-27 07:38:28 -0600317 "Node '%s': delete property: '%s'" % (self.path, prop_name))
318 del self.props[prop_name]
319 self._fdt.Invalidate()
Simon Glass2a70d892016-07-25 18:59:14 -0600320
Simon Glass116adec2018-07-06 10:27:38 -0600321 def AddZeroProp(self, prop_name):
322 """Add a new property to the device tree with an integer value of 0.
323
324 Args:
325 prop_name: Name of property
326 """
Simon Glassfa80c252018-09-14 04:57:13 -0600327 self.props[prop_name] = Prop(self, None, prop_name, '\0' * 4)
Simon Glass116adec2018-07-06 10:27:38 -0600328
329 def SetInt(self, prop_name, val):
330 """Update an integer property int the device tree.
331
332 This is not allowed to change the size of the FDT.
333
334 Args:
335 prop_name: Name of property
336 val: Value to set
337 """
Simon Glassfa80c252018-09-14 04:57:13 -0600338 self.props[prop_name].SetInt(val)
339
Simon Glasse21c27a2018-09-14 04:57:15 -0600340 def AddSubnode(self, name):
341 path = self.path + '/' + name
342 subnode = Node(self._fdt, self, None, name, path)
343 self.subnodes.append(subnode)
344 return subnode
345
Simon Glassfa80c252018-09-14 04:57:13 -0600346 def Sync(self, auto_resize=False):
347 """Sync node changes back to the device tree
348
349 This updates the device tree blob with any changes to this node and its
350 subnodes since the last sync.
351
352 Args:
353 auto_resize: Resize the device tree automatically if it does not
354 have enough space for the update
355
356 Raises:
357 FdtException if auto_resize is False and there is not enough space
358 """
Simon Glasse21c27a2018-09-14 04:57:15 -0600359 if self._offset is None:
360 # The subnode doesn't exist yet, so add it
361 fdt_obj = self._fdt._fdt_obj
362 if auto_resize:
363 while True:
364 offset = fdt_obj.add_subnode(self.parent._offset, self.name,
365 (libfdt.NOSPACE,))
366 if offset != -libfdt.NOSPACE:
367 break
368 fdt_obj.resize(fdt_obj.totalsize() + 1024)
369 else:
370 offset = fdt_obj.add_subnode(self.parent._offset, self.name)
371 self._offset = offset
372
Simon Glassfa80c252018-09-14 04:57:13 -0600373 # Sync subnodes in reverse so that we don't disturb node offsets for
374 # nodes that are earlier in the DT. This avoids an O(n^2) rescan of
375 # node offsets.
376 for node in reversed(self.subnodes):
377 node.Sync(auto_resize)
378
379 # Sync properties now, whose offsets should not have been disturbed.
380 # We do this after subnodes, since this disturbs the offsets of these
381 # properties.
382 prop_list = sorted(self.props.values(), key=lambda prop: prop._offset,
383 reverse=True)
384 for prop in prop_list:
385 prop.Sync(auto_resize)
Simon Glass116adec2018-07-06 10:27:38 -0600386
387
Simon Glassa06a34b2016-07-25 18:59:04 -0600388class Fdt:
Simon Glass7b75b442017-05-27 07:38:28 -0600389 """Provides simple access to a flat device tree blob using libfdts.
Simon Glassa06a34b2016-07-25 18:59:04 -0600390
391 Properties:
392 fname: Filename of fdt
393 _root: Root of device tree (a Node object)
394 """
395 def __init__(self, fname):
396 self._fname = fname
Simon Glass7b75b442017-05-27 07:38:28 -0600397 self._cached_offsets = False
Simon Glass09264e02017-08-29 14:15:52 -0600398 self.phandle_to_node = {}
Simon Glass7b75b442017-05-27 07:38:28 -0600399 if self._fname:
400 self._fname = fdt_util.EnsureCompiled(self._fname)
401
402 with open(self._fname) as fd:
Simon Glass96066242018-07-06 10:27:27 -0600403 self._fdt_obj = libfdt.Fdt(fd.read())
Simon Glassf7a2aee2016-07-25 18:59:07 -0600404
Simon Glass94a7c602018-07-17 13:25:46 -0600405 def LookupPhandle(self, phandle):
406 """Look up a phandle
407
408 Args:
409 phandle: Phandle to look up (int)
410
411 Returns:
412 Node object the phandle points to
413 """
414 return self.phandle_to_node.get(phandle)
415
Simon Glassf7a2aee2016-07-25 18:59:07 -0600416 def Scan(self, root='/'):
417 """Scan a device tree, building up a tree of Node objects
418
419 This fills in the self._root property
420
421 Args:
422 root: Ignored
423
424 TODO(sjg@chromium.org): Implement the 'root' parameter
425 """
Simon Glassf9b88b32018-07-06 10:27:29 -0600426 self._cached_offsets = True
Simon Glass979ab022017-08-29 14:15:47 -0600427 self._root = self.Node(self, None, 0, '/', '/')
Simon Glassf7a2aee2016-07-25 18:59:07 -0600428 self._root.Scan()
429
430 def GetRoot(self):
431 """Get the root Node of the device tree
432
433 Returns:
434 The root Node object
435 """
436 return self._root
437
438 def GetNode(self, path):
439 """Look up a node from its path
440
441 Args:
442 path: Path to look up, e.g. '/microcode/update@0'
443 Returns:
444 Node object, or None if not found
445 """
446 node = self._root
Simon Glassb9066ff2018-07-06 10:27:30 -0600447 parts = path.split('/')
448 if len(parts) < 2:
449 return None
450 for part in parts[1:]:
Simon Glass1d858882018-07-17 13:25:41 -0600451 node = node.FindNode(part)
Simon Glassf7a2aee2016-07-25 18:59:07 -0600452 if not node:
453 return None
454 return node
455
Simon Glassda5f7492016-07-25 18:59:15 -0600456 def Flush(self):
457 """Flush device tree changes back to the file
458
459 If the device tree has changed in memory, write it back to the file.
Simon Glassda5f7492016-07-25 18:59:15 -0600460 """
Simon Glass7b75b442017-05-27 07:38:28 -0600461 with open(self._fname, 'wb') as fd:
Simon Glass96066242018-07-06 10:27:27 -0600462 fd.write(self._fdt_obj.as_bytearray())
Simon Glassda5f7492016-07-25 18:59:15 -0600463
Simon Glassfa80c252018-09-14 04:57:13 -0600464 def Sync(self, auto_resize=False):
465 """Make sure any DT changes are written to the blob
466
467 Args:
468 auto_resize: Resize the device tree automatically if it does not
469 have enough space for the update
470
471 Raises:
472 FdtException if auto_resize is False and there is not enough space
473 """
474 self._root.Sync(auto_resize)
475 self.Invalidate()
476
Simon Glassda5f7492016-07-25 18:59:15 -0600477 def Pack(self):
478 """Pack the device tree down to its minimum size
479
480 When nodes and properties shrink or are deleted, wasted space can
Simon Glass7b75b442017-05-27 07:38:28 -0600481 build up in the device tree binary.
Simon Glassda5f7492016-07-25 18:59:15 -0600482 """
Simon Glass117f57b2018-07-06 10:27:26 -0600483 CheckErr(self._fdt_obj.pack(), 'pack')
484 self.Invalidate()
Simon Glass7b75b442017-05-27 07:38:28 -0600485
Simon Glass96066242018-07-06 10:27:27 -0600486 def GetContents(self):
Simon Glass7b75b442017-05-27 07:38:28 -0600487 """Get the contents of the FDT
488
489 Returns:
490 The FDT contents as a string of bytes
491 """
Simon Glass96066242018-07-06 10:27:27 -0600492 return self._fdt_obj.as_bytearray()
Simon Glass7b75b442017-05-27 07:38:28 -0600493
Simon Glass2ba98752018-07-06 10:27:24 -0600494 def GetFdtObj(self):
495 """Get the contents of the FDT
496
497 Returns:
498 The FDT contents as a libfdt.Fdt object
499 """
500 return self._fdt_obj
501
Simon Glass7b75b442017-05-27 07:38:28 -0600502 def GetProps(self, node):
503 """Get all properties from a node.
504
505 Args:
506 node: Full path to node name to look in.
507
508 Returns:
509 A dictionary containing all the properties, indexed by node name.
510 The entries are Prop objects.
511
512 Raises:
513 ValueError: if the node does not exist.
514 """
515 props_dict = {}
Simon Glass117f57b2018-07-06 10:27:26 -0600516 poffset = self._fdt_obj.first_property_offset(node._offset,
517 QUIET_NOTFOUND)
Simon Glass7b75b442017-05-27 07:38:28 -0600518 while poffset >= 0:
519 p = self._fdt_obj.get_property_by_offset(poffset)
Simon Glass3def0cf2018-07-06 10:27:20 -0600520 prop = Prop(node, poffset, p.name, p)
Simon Glass7b75b442017-05-27 07:38:28 -0600521 props_dict[prop.name] = prop
522
Simon Glass117f57b2018-07-06 10:27:26 -0600523 poffset = self._fdt_obj.next_property_offset(poffset,
524 QUIET_NOTFOUND)
Simon Glass7b75b442017-05-27 07:38:28 -0600525 return props_dict
526
527 def Invalidate(self):
528 """Mark our offset cache as invalid"""
529 self._cached_offsets = False
530
531 def CheckCache(self):
532 """Refresh the offset cache if needed"""
533 if self._cached_offsets:
534 return
535 self.Refresh()
536 self._cached_offsets = True
537
538 def Refresh(self):
539 """Refresh the offset cache"""
540 self._root.Refresh(0)
541
542 def GetStructOffset(self, offset):
543 """Get the file offset of a given struct offset
544
545 Args:
546 offset: Offset within the 'struct' region of the device tree
547 Returns:
548 Position of @offset within the device tree binary
549 """
Simon Glass117f57b2018-07-06 10:27:26 -0600550 return self._fdt_obj.off_dt_struct() + offset
Simon Glass7b75b442017-05-27 07:38:28 -0600551
552 @classmethod
Simon Glass979ab022017-08-29 14:15:47 -0600553 def Node(self, fdt, parent, offset, name, path):
Simon Glass7b75b442017-05-27 07:38:28 -0600554 """Create a new node
555
556 This is used by Fdt.Scan() to create a new node using the correct
557 class.
558
559 Args:
560 fdt: Fdt object
Simon Glass979ab022017-08-29 14:15:47 -0600561 parent: Parent node, or None if this is the root node
Simon Glass7b75b442017-05-27 07:38:28 -0600562 offset: Offset of node
563 name: Node name
564 path: Full path to node
565 """
Simon Glass979ab022017-08-29 14:15:47 -0600566 node = Node(fdt, parent, offset, name, path)
Simon Glass7b75b442017-05-27 07:38:28 -0600567 return node
Simon Glass99ed4a22017-05-27 07:38:30 -0600568
569def FdtScan(fname):
Simon Glassdfe5f5b2018-07-06 10:27:32 -0600570 """Returns a new Fdt object"""
Simon Glass99ed4a22017-05-27 07:38:30 -0600571 dtb = Fdt(fname)
572 dtb.Scan()
573 return dtb