]> git.ipfire.org Git - people/ms/u-boot.git/blame - tools/dtoc/fdt_normal.py
Merge branch 'master' of git://git.denx.de/u-boot-net
[people/ms/u-boot.git] / tools / dtoc / fdt_normal.py
CommitLineData
76bce10d
SG
1#!/usr/bin/python
2#
3# Copyright (C) 2016 Google, Inc
4# Written by Simon Glass <sjg@chromium.org>
5#
6# SPDX-License-Identifier: GPL-2.0+
7#
8
a06a34b2
SG
9import struct
10import sys
11
12import fdt
13from fdt import Fdt, NodeBase, PropBase
76bce10d
SG
14import fdt_util
15import libfdt
76bce10d
SG
16
17# This deals with a device tree, presenting it as a list of Node and Prop
18# objects, representing nodes and properties, respectively.
19#
20# This implementation uses a libfdt Python library to access the device tree,
21# so it is fairly efficient.
22
2a70d897
SG
23def CheckErr(errnum, msg):
24 if errnum:
25 raise ValueError('Error %d: %s: %s' %
26 (errnum, libfdt.fdt_strerror(errnum), msg))
27
a06a34b2 28class Prop(PropBase):
76bce10d
SG
29 """A device tree property
30
31 Properties:
32 name: Property name (as per the device tree)
33 value: Property value as a string of bytes, or a list of strings of
34 bytes
35 type: Value type
36 """
a06a34b2
SG
37 def __init__(self, node, offset, name, bytes):
38 PropBase.__init__(self, node, offset, name)
39 self.bytes = bytes
76bce10d 40 if not bytes:
bc1dea36 41 self.type = fdt.TYPE_BOOL
76bce10d
SG
42 self.value = True
43 return
bc1dea36 44 self.type, self.value = self.BytesToValue(bytes)
76bce10d 45
babdbde6
SG
46 def GetOffset(self):
47 """Get the offset of a property
48
49 Returns:
50 The offset of the property (struct fdt_property) within the file
51 """
52 return self._node._fdt.GetStructOffset(self._offset)
53
a06a34b2 54class Node(NodeBase):
76bce10d
SG
55 """A device tree node
56
57 Properties:
58 offset: Integer offset in the device tree
59 name: Device tree node tname
60 path: Full path to node, along with the node name itself
61 _fdt: Device tree object
62 subnodes: A list of subnodes for this node, each a Node object
63 props: A dict of properties for this node, each a Prop object.
64 Keyed by property name
65 """
66 def __init__(self, fdt, offset, name, path):
a06a34b2 67 NodeBase.__init__(self, fdt, offset, name, path)
76bce10d 68
346179f0
SG
69 def Offset(self):
70 """Returns the offset of a node, after checking the cache
71
72 This should be used instead of self._offset directly, to ensure that
73 the cache does not contain invalid offsets.
74 """
75 self._fdt.CheckCache()
76 return self._offset
77
76bce10d
SG
78 def Scan(self):
79 """Scan a node's properties and subnodes
80
81 This fills in the props and subnodes properties, recursively
82 searching into subnodes so that the entire tree is built.
83 """
8828254c 84 self.props = self._fdt.GetProps(self)
76bce10d 85
346179f0 86 offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
76bce10d
SG
87 while offset >= 0:
88 sep = '' if self.path[-1] == '/' else '/'
89 name = libfdt.Name(self._fdt.GetFdt(), offset)
90 path = self.path + sep + name
91 node = Node(self._fdt, offset, name, path)
92 self.subnodes.append(node)
93
94 node.Scan()
95 offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
96
346179f0
SG
97 def Refresh(self, my_offset):
98 """Fix up the _offset for each node, recursively
99
100 Note: This does not take account of property offsets - these will not
101 be updated.
102 """
103 if self._offset != my_offset:
104 #print '%s: %d -> %d\n' % (self.path, self._offset, my_offset)
105 self._offset = my_offset
106 offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
107 for subnode in self.subnodes:
108 subnode.Refresh(offset)
109 offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
76bce10d 110
2a70d897
SG
111 def DeleteProp(self, prop_name):
112 """Delete a property of a node
113
114 The property is deleted and the offset cache is invalidated.
115
116 Args:
117 prop_name: Name of the property to delete
118 Raises:
119 ValueError if the property does not exist
120 """
121 CheckErr(libfdt.fdt_delprop(self._fdt.GetFdt(), self.Offset(), prop_name),
122 "Node '%s': delete property: '%s'" % (self.path, prop_name))
123 del self.props[prop_name]
124 self._fdt.Invalidate()
125
a06a34b2
SG
126class FdtNormal(Fdt):
127 """Provides simple access to a flat device tree blob using libfdt.
76bce10d
SG
128
129 Properties:
a06a34b2
SG
130 _fdt: Device tree contents (bytearray)
131 _cached_offsets: True if all the nodes have a valid _offset property,
132 False if something has changed to invalidate the offsets
76bce10d 133 """
76bce10d 134 def __init__(self, fname):
a06a34b2 135 Fdt.__init__(self, fname)
346179f0 136 self._cached_offsets = False
355c67c3
SG
137 if self._fname:
138 self._fname = fdt_util.EnsureCompiled(self._fname)
139
140 with open(self._fname) as fd:
0170804f 141 self._fdt = bytearray(fd.read())
76bce10d
SG
142
143 def GetFdt(self):
144 """Get the contents of the FDT
145
146 Returns:
147 The FDT contents as a string of bytes
148 """
149 return self._fdt
150
da5f7499
SG
151 def Flush(self):
152 """Flush device tree changes back to the file"""
153 with open(self._fname, 'wb') as fd:
154 fd.write(self._fdt)
155
156 def Pack(self):
157 """Pack the device tree down to its minimum size"""
158 CheckErr(libfdt.fdt_pack(self._fdt), 'pack')
159 fdt_len = libfdt.fdt_totalsize(self._fdt)
160 del self._fdt[fdt_len:]
161
8828254c 162 def GetProps(self, node):
76bce10d
SG
163 """Get all properties from a node.
164
165 Args:
166 node: Full path to node name to look in.
167
168 Returns:
169 A dictionary containing all the properties, indexed by node name.
170 The entries are Prop objects.
171
172 Raises:
173 ValueError: if the node does not exist.
174 """
76bce10d 175 props_dict = {}
8828254c 176 poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset)
76bce10d
SG
177 while poffset >= 0:
178 dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
a06a34b2
SG
179 prop = Prop(node, poffset, libfdt.String(self._fdt, dprop.nameoff),
180 libfdt.Data(dprop))
76bce10d
SG
181 props_dict[prop.name] = prop
182
183 poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
184 return props_dict
a06a34b2 185
346179f0
SG
186 def Invalidate(self):
187 """Mark our offset cache as invalid"""
188 self._cached_offsets = False
189
190 def CheckCache(self):
191 """Refresh the offset cache if needed"""
192 if self._cached_offsets:
193 return
194 self.Refresh()
195 self._cached_offsets = True
196
197 def Refresh(self):
198 """Refresh the offset cache"""
199 self._root.Refresh(0)
200
babdbde6
SG
201 def GetStructOffset(self, offset):
202 """Get the file offset of a given struct offset
203
204 Args:
205 offset: Offset within the 'struct' region of the device tree
206 Returns:
207 Position of @offset within the device tree binary
208 """
209 return libfdt.fdt_off_dt_struct(self._fdt) + offset
210
a06a34b2
SG
211 @classmethod
212 def Node(self, fdt, offset, name, path):
213 """Create a new node
214
215 This is used by Fdt.Scan() to create a new node using the correct
216 class.
217
218 Args:
219 fdt: Fdt object
220 offset: Offset of node
221 name: Node name
222 path: Full path to node
223 """
224 node = Node(fdt, offset, name, path)
225 return node