]> git.sur5r.net Git - u-boot/blob - tools/dtoc/fdt_normal.py
dtoc: Prepare for supporting changing of device trees
[u-boot] / 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 class Prop(PropBase):
24     """A device tree property
25
26     Properties:
27         name: Property name (as per the device tree)
28         value: Property value as a string of bytes, or a list of strings of
29             bytes
30         type: Value type
31     """
32     def __init__(self, node, offset, name, bytes):
33         PropBase.__init__(self, node, offset, name)
34         self.bytes = bytes
35         if not bytes:
36             self.type = fdt.TYPE_BOOL
37             self.value = True
38             return
39         self.type, self.value = self.BytesToValue(bytes)
40
41 class Node(NodeBase):
42     """A device tree node
43
44     Properties:
45         offset: Integer offset in the device tree
46         name: Device tree node tname
47         path: Full path to node, along with the node name itself
48         _fdt: Device tree object
49         subnodes: A list of subnodes for this node, each a Node object
50         props: A dict of properties for this node, each a Prop object.
51             Keyed by property name
52     """
53     def __init__(self, fdt, offset, name, path):
54         NodeBase.__init__(self, fdt, offset, name, path)
55
56     def Offset(self):
57         """Returns the offset of a node, after checking the cache
58
59         This should be used instead of self._offset directly, to ensure that
60         the cache does not contain invalid offsets.
61         """
62         self._fdt.CheckCache()
63         return self._offset
64
65     def Scan(self):
66         """Scan a node's properties and subnodes
67
68         This fills in the props and subnodes properties, recursively
69         searching into subnodes so that the entire tree is built.
70         """
71         self.props = self._fdt.GetProps(self, self.path)
72
73         offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
74         while offset >= 0:
75             sep = '' if self.path[-1] == '/' else '/'
76             name = libfdt.Name(self._fdt.GetFdt(), offset)
77             path = self.path + sep + name
78             node = Node(self._fdt, offset, name, path)
79             self.subnodes.append(node)
80
81             node.Scan()
82             offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
83
84     def Refresh(self, my_offset):
85         """Fix up the _offset for each node, recursively
86
87         Note: This does not take account of property offsets - these will not
88         be updated.
89         """
90         if self._offset != my_offset:
91             #print '%s: %d -> %d\n' % (self.path, self._offset, my_offset)
92             self._offset = my_offset
93         offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
94         for subnode in self.subnodes:
95             subnode.Refresh(offset)
96             offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
97
98 class FdtNormal(Fdt):
99     """Provides simple access to a flat device tree blob using libfdt.
100
101     Properties:
102         _fdt: Device tree contents (bytearray)
103         _cached_offsets: True if all the nodes have a valid _offset property,
104             False if something has changed to invalidate the offsets
105     """
106     def __init__(self, fname):
107         Fdt.__init__(self, fname)
108         self._cached_offsets = False
109         if self._fname:
110             self._fname = fdt_util.EnsureCompiled(self._fname)
111
112             with open(self._fname) as fd:
113                 self._fdt = fd.read()
114
115     def GetFdt(self):
116         """Get the contents of the FDT
117
118         Returns:
119             The FDT contents as a string of bytes
120         """
121         return self._fdt
122
123     def GetProps(self, node, path):
124         """Get all properties from a node.
125
126         Args:
127             node: Full path to node name to look in.
128
129         Returns:
130             A dictionary containing all the properties, indexed by node name.
131             The entries are Prop objects.
132
133         Raises:
134             ValueError: if the node does not exist.
135         """
136         offset = libfdt.fdt_path_offset(self._fdt, path)
137         if offset < 0:
138             libfdt.Raise(offset)
139         props_dict = {}
140         poffset = libfdt.fdt_first_property_offset(self._fdt, offset)
141         while poffset >= 0:
142             dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
143             prop = Prop(node, poffset, libfdt.String(self._fdt, dprop.nameoff),
144                         libfdt.Data(dprop))
145             props_dict[prop.name] = prop
146
147             poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
148         return props_dict
149
150     def Invalidate(self):
151         """Mark our offset cache as invalid"""
152         self._cached_offsets = False
153
154     def CheckCache(self):
155         """Refresh the offset cache if needed"""
156         if self._cached_offsets:
157             return
158         self.Refresh()
159         self._cached_offsets = True
160
161     def Refresh(self):
162         """Refresh the offset cache"""
163         self._root.Refresh(0)
164
165     @classmethod
166     def Node(self, fdt, offset, name, path):
167         """Create a new node
168
169         This is used by Fdt.Scan() to create a new node using the correct
170         class.
171
172         Args:
173             fdt: Fdt object
174             offset: Offset of node
175             name: Node name
176             path: Full path to node
177         """
178         node = Node(fdt, offset, name, path)
179         return node