3 # Copyright (C) 2016 Google, Inc
4 # Written by Simon Glass <sjg@chromium.org>
6 # SPDX-License-Identifier: GPL-2.0+
14 # This deals with a device tree, presenting it as an assortment of Node and
15 # Prop objects, representing nodes and properties, respectively. This file
16 # contains the base classes and defines the high-level API. Most of the
17 # implementation is in the FdtFallback and FdtNormal subclasses. See
18 # fdt_select.py for how to create an Fdt object.
20 # A list of types we support
21 (TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
23 def CheckErr(errnum, msg):
25 raise ValueError('Error %d: %s: %s' %
26 (errnum, libfdt.fdt_strerror(errnum), msg))
29 """A device tree property
32 name: Property name (as per the device tree)
33 value: Property value as a string of bytes, or a list of strings of
37 def __init__(self, node, offset, name):
44 """Get a (single) phandle value from a property
46 Gets the phandle valuie from a property and returns it as an integer
48 return fdt_util.fdt32_to_cpu(self.value[:4])
50 def Widen(self, newprop):
51 """Figure out which property type is more general
53 Given a current property and a new property, this function returns the
54 one that is less specific as to type. The less specific property will
55 be ble to represent the data in the more specific property. This is
67 He we want to use an int array for 'value'. The first property
68 suggests that a single int is enough, but the second one shows that
69 it is not. Calling this function with these two propertes would
70 update the current property to be like the second, since it is less
73 if newprop.type < self.type:
74 self.type = newprop.type
76 if type(newprop.value) == list and type(self.value) != list:
77 self.value = [self.value]
79 if type(self.value) == list and len(newprop.value) > len(self.value):
80 val = self.GetEmpty(self.type)
81 while len(self.value) < len(newprop.value):
82 self.value.append(val)
84 def BytesToValue(self, bytes):
85 """Converts a string of bytes into a type and value
88 A string containing bytes
93 Data, either a single element or a list of elements. Each element
95 TYPE_STRING: string value from the property
96 TYPE_INT: a byte-swapped integer stored as a 4-byte string
97 TYPE_BYTE: a byte stored as a single-byte string
100 strings = bytes.split('\0')
102 count = len(strings) - 1
103 if count > 0 and not strings[-1]:
104 for string in strings[:-1]:
109 if ch < ' ' or ch > '~':
116 return TYPE_STRING, strings[0]
118 return TYPE_STRING, strings[:-1]
121 return TYPE_BYTE, bytes[0]
123 return TYPE_BYTE, list(bytes)
125 for i in range(0, size, 4):
126 val.append(bytes[i:i + 4])
128 return TYPE_INT, val[0]
132 def GetEmpty(self, type):
133 """Get an empty / zero value of the given type
136 A single value of the given type
138 if type == TYPE_BYTE:
140 elif type == TYPE_INT:
141 return struct.pack('<I', 0);
142 elif type == TYPE_STRING:
148 """A device tree node
151 offset: Integer offset in the device tree
152 name: Device tree node tname
153 path: Full path to node, along with the node name itself
154 _fdt: Device tree object
155 subnodes: A list of subnodes for this node, each a Node object
156 props: A dict of properties for this node, each a Prop object.
157 Keyed by property name
159 def __init__(self, fdt, offset, name, path):
161 self._offset = offset
167 def _FindNode(self, name):
168 """Find a node given its name
171 name: Node name to look for
173 Node object if found, else None
175 for subnode in self.subnodes:
176 if subnode.name == name:
181 """Scan the subnodes of a node
183 This should be implemented by subclasses
185 raise NotImplementedError()
187 def DeleteProp(self, prop_name):
188 """Delete a property of a node
190 This should be implemented by subclasses
193 prop_name: Name of the property to delete
195 raise NotImplementedError()
198 """Provides simple access to a flat device tree blob.
201 fname: Filename of fdt
202 _root: Root of device tree (a Node object)
204 def __init__(self, fname):
207 def Scan(self, root='/'):
208 """Scan a device tree, building up a tree of Node objects
210 This fills in the self._root property
215 TODO(sjg@chromium.org): Implement the 'root' parameter
217 self._root = self.Node(self, 0, '/', '/')
221 """Get the root Node of the device tree
228 def GetNode(self, path):
229 """Look up a node from its path
232 path: Path to look up, e.g. '/microcode/update@0'
234 Node object, or None if not found
237 for part in path.split('/')[1:]:
238 node = node._FindNode(part)
244 """Flush device tree changes back to the file
246 If the device tree has changed in memory, write it back to the file.
247 Subclasses can implement this if needed.
252 """Pack the device tree down to its minimum size
254 When nodes and properties shrink or are deleted, wasted space can
255 build up in the device tree binary. Subclasses can implement this
256 to remove that spare space.