Merge branch 'rmobile' of git://git.denx.de/u-boot-sh
[platform/kernel/u-boot.git] / tools / dtoc / fdt_fallback.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 command
10 import fdt_util
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 the fdtget tool to access the device tree, so it
17 # is not very efficient for larger trees. The tool is called once for each
18 # node and property in the tree.
19
20 class Prop:
21     """A device tree property
22
23     Properties:
24         name: Property name (as per the device tree)
25         value: Property value as a string of bytes, or a list of strings of
26             bytes
27         type: Value type
28     """
29     def __init__(self, name, byte_list_str):
30         self.name = name
31         self.value = None
32         if not byte_list_str.strip():
33             self.type = fdt_util.TYPE_BOOL
34             return
35         bytes = [chr(int(byte, 16)) for byte in byte_list_str.strip().split(' ')]
36         self.type, self.value = fdt_util.BytesToValue(''.join(bytes))
37
38     def GetPhandle(self):
39         """Get a (single) phandle value from a property
40
41         Gets the phandle valuie from a property and returns it as an integer
42         """
43         return fdt_util.fdt32_to_cpu(self.value[:4])
44
45     def Widen(self, newprop):
46         """Figure out which property type is more general
47
48         Given a current property and a new property, this function returns the
49         one that is less specific as to type. The less specific property will
50         be ble to represent the data in the more specific property. This is
51         used for things like:
52
53             node1 {
54                 compatible = "fred";
55                 value = <1>;
56             };
57             node1 {
58                 compatible = "fred";
59                 value = <1 2>;
60             };
61
62         He we want to use an int array for 'value'. The first property
63         suggests that a single int is enough, but the second one shows that
64         it is not. Calling this function with these two propertes would
65         update the current property to be like the second, since it is less
66         specific.
67         """
68         if newprop.type < self.type:
69             self.type = newprop.type
70
71         if type(newprop.value) == list and type(self.value) != list:
72             self.value = newprop.value
73
74         if type(self.value) == list and len(newprop.value) > len(self.value):
75             val = fdt_util.GetEmpty(self.type)
76             while len(self.value) < len(newprop.value):
77                 self.value.append(val)
78
79
80 class Node:
81     """A device tree node
82
83     Properties:
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, name, path):
92         self.name = name
93         self.path = path
94         self._fdt = fdt
95         self.subnodes = []
96         self.props = {}
97
98     def Scan(self):
99         """Scan a node's properties and subnodes
100
101         This fills in the props and subnodes properties, recursively
102         searching into subnodes so that the entire tree is built.
103         """
104         for name, byte_list_str in self._fdt.GetProps(self.path).iteritems():
105             prop = Prop(name, byte_list_str)
106             self.props[name] = prop
107
108         for name in self._fdt.GetSubNodes(self.path):
109             sep = '' if self.path[-1] == '/' else '/'
110             path = self.path + sep + name
111             node = Node(self._fdt, name, path)
112             self.subnodes.append(node)
113
114             node.Scan()
115
116
117 class Fdt:
118     """Provides simple access to a flat device tree blob.
119
120     Properties:
121       fname: Filename of fdt
122       _root: Root of device tree (a Node object)
123     """
124
125     def __init__(self, fname):
126         self.fname = fname
127
128     def Scan(self):
129         """Scan a device tree, building up a tree of Node objects
130
131         This fills in the self._root property
132         """
133         self._root = Node(self, '/', '/')
134         self._root.Scan()
135
136     def GetRoot(self):
137         """Get the root Node of the device tree
138
139         Returns:
140             The root Node object
141         """
142         return self._root
143
144     def GetSubNodes(self, node):
145         """Returns a list of sub-nodes of a given node
146
147         Args:
148             node: Node name to return children from
149
150         Returns:
151             List of children in the node (each a string node name)
152
153         Raises:
154             CmdError: if the node does not exist.
155         """
156         out = command.Output('fdtget', self.fname, '-l', node)
157         return out.strip().splitlines()
158
159     def GetProps(self, node, convert_dashes=False):
160         """Get all properties from a node
161
162         Args:
163             node: full path to node name to look in
164             convert_dashes: True to convert - to _ in node names
165
166         Returns:
167             A dictionary containing all the properties, indexed by node name.
168             The entries are simply strings - no decoding of lists or numbers
169             is done.
170
171         Raises:
172             CmdError: if the node does not exist.
173         """
174         out = command.Output('fdtget', self.fname, node, '-p')
175         props = out.strip().splitlines()
176         props_dict = {}
177         for prop in props:
178             name = prop
179             if convert_dashes:
180                 prop = re.sub('-', '_', prop)
181             props_dict[prop] = self.GetProp(node, name)
182         return props_dict
183
184     def GetProp(self, node, prop, default=None, typespec=None):
185         """Get a property from a device tree.
186
187         This looks up the given node and property, and returns the value as a
188         string,
189
190         If the node or property does not exist, this will return the default
191         value.
192
193         Args:
194             node: Full path to node to look up.
195             prop: Property name to look up.
196             default: Default value to return if nothing is present in the fdt,
197                 or None to raise in this case. This will be converted to a
198                 string.
199             typespec: Type character to use (None for default, 's' for string)
200
201         Returns:
202             string containing the property value.
203
204         Raises:
205             CmdError: if the property does not exist and no default is provided.
206         """
207         args = [self.fname, node, prop, '-t', 'bx']
208         if default is not None:
209           args += ['-d', str(default)]
210         if typespec is not None:
211           args += ['-t%s' % typespec]
212         out = command.Output('fdtget', *args)
213         return out.strip()