odroid: remove CONFIG_DM_I2C_COMPAT config
[platform/kernel/u-boot.git] / tools / dtoc / fdt_normal.py
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
9 import struct
10 import sys
11
12 import fdt
13 from fdt import Fdt, NodeBase, PropBase
14 import fdt_util
15 import libfdt
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
23 def CheckErr(errnum, msg):
24     if errnum:
25         raise ValueError('Error %d: %s: %s' %
26             (errnum, libfdt.fdt_strerror(errnum), msg))
27
28 class Prop(PropBase):
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     """
37     def __init__(self, node, offset, name, bytes):
38         PropBase.__init__(self, node, offset, name)
39         self.bytes = bytes
40         if not bytes:
41             self.type = fdt.TYPE_BOOL
42             self.value = True
43             return
44         self.type, self.value = self.BytesToValue(bytes)
45
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
54 class Node(NodeBase):
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):
67         NodeBase.__init__(self, fdt, offset, name, path)
68
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
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         """
84         self.props = self._fdt.GetProps(self)
85
86         offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
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
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)
110
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
126 class FdtNormal(Fdt):
127     """Provides simple access to a flat device tree blob using libfdt.
128
129     Properties:
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
133     """
134     def __init__(self, fname):
135         Fdt.__init__(self, fname)
136         self._cached_offsets = False
137         if self._fname:
138             self._fname = fdt_util.EnsureCompiled(self._fname)
139
140             with open(self._fname) as fd:
141                 self._fdt = bytearray(fd.read())
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
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
162     def GetProps(self, node):
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         """
175         props_dict = {}
176         poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset)
177         while poffset >= 0:
178             dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
179             prop = Prop(node, poffset, libfdt.String(self._fdt, dprop.nameoff),
180                         libfdt.Data(dprop))
181             props_dict[prop.name] = prop
182
183             poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
184         return props_dict
185
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
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
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