]> git.sur5r.net Git - u-boot/blob - tools/dtoc/fdt.py
dm: Add a more efficient libfdt library
[u-boot] / tools / dtoc / fdt.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 fdt_util
10 import libfdt
11 import sys
12
13 # This deals with a device tree, presenting it as a list of Node and Prop
14 # objects, representing nodes and properties, respectively.
15 #
16 # This implementation uses a libfdt Python library to access the device tree,
17 # so it is fairly efficient.
18
19 class Prop:
20     """A device tree property
21
22     Properties:
23         name: Property name (as per the device tree)
24         value: Property value as a string of bytes, or a list of strings of
25             bytes
26         type: Value type
27     """
28     def __init__(self, name, bytes):
29         self.name = name
30         self.value = None
31         if not bytes:
32             self.type = fdt_util.TYPE_BOOL
33             self.value = True
34             return
35         self.type, self.value = fdt_util.BytesToValue(bytes)
36
37     def GetPhandle(self):
38         """Get a (single) phandle value from a property
39
40         Gets the phandle valuie from a property and returns it as an integer
41         """
42         return fdt_util.fdt32_to_cpu(self.value[:4])
43
44     def Widen(self, newprop):
45         """Figure out which property type is more general
46
47         Given a current property and a new property, this function returns the
48         one that is less specific as to type. The less specific property will
49         be ble to represent the data in the more specific property. This is
50         used for things like:
51
52             node1 {
53                 compatible = "fred";
54                 value = <1>;
55             };
56             node1 {
57                 compatible = "fred";
58                 value = <1 2>;
59             };
60
61         He we want to use an int array for 'value'. The first property
62         suggests that a single int is enough, but the second one shows that
63         it is not. Calling this function with these two propertes would
64         update the current property to be like the second, since it is less
65         specific.
66         """
67         if newprop.type < self.type:
68             self.type = newprop.type
69
70         if type(newprop.value) == list and type(self.value) != list:
71             self.value = [self.value]
72
73         if type(self.value) == list and len(newprop.value) > len(self.value):
74             val = fdt_util.GetEmpty(self.type)
75             while len(self.value) < len(newprop.value):
76                 self.value.append(val)
77
78
79 class Node:
80     """A device tree node
81
82     Properties:
83         offset: Integer offset in the device tree
84         name: Device tree node tname
85         path: Full path to node, along with the node name itself
86         _fdt: Device tree object
87         subnodes: A list of subnodes for this node, each a Node object
88         props: A dict of properties for this node, each a Prop object.
89             Keyed by property name
90     """
91     def __init__(self, fdt, offset, name, path):
92         self.offset = offset
93         self.name = name
94         self.path = path
95         self._fdt = fdt
96         self.subnodes = []
97         self.props = {}
98
99     def Scan(self):
100         """Scan a node's properties and subnodes
101
102         This fills in the props and subnodes properties, recursively
103         searching into subnodes so that the entire tree is built.
104         """
105         self.props = self._fdt.GetProps(self.path)
106
107         offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset)
108         while offset >= 0:
109             sep = '' if self.path[-1] == '/' else '/'
110             name = libfdt.Name(self._fdt.GetFdt(), offset)
111             path = self.path + sep + name
112             node = Node(self._fdt, offset, name, path)
113             self.subnodes.append(node)
114
115             node.Scan()
116             offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
117
118
119 class Fdt:
120     """Provides simple access to a flat device tree blob.
121
122     Properties:
123       fname: Filename of fdt
124       _root: Root of device tree (a Node object)
125     """
126
127     def __init__(self, fname):
128         self.fname = fname
129         with open(fname) as fd:
130             self._fdt = fd.read()
131
132     def GetFdt(self):
133         """Get the contents of the FDT
134
135         Returns:
136             The FDT contents as a string of bytes
137         """
138         return self._fdt
139
140     def Scan(self):
141         """Scan a device tree, building up a tree of Node objects
142
143         This fills in the self._root property
144         """
145         self._root = Node(self, 0, '/', '/')
146         self._root.Scan()
147
148     def GetRoot(self):
149         """Get the root Node of the device tree
150
151         Returns:
152             The root Node object
153         """
154         return self._root
155
156     def GetProps(self, node):
157         """Get all properties from a node.
158
159         Args:
160             node: Full path to node name to look in.
161
162         Returns:
163             A dictionary containing all the properties, indexed by node name.
164             The entries are Prop objects.
165
166         Raises:
167             ValueError: if the node does not exist.
168         """
169         offset = libfdt.fdt_path_offset(self._fdt, node)
170         if offset < 0:
171             libfdt.Raise(offset)
172         props_dict = {}
173         poffset = libfdt.fdt_first_property_offset(self._fdt, offset)
174         while poffset >= 0:
175             dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
176             prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop))
177             props_dict[prop.name] = prop
178
179             poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
180         return props_dict