dm: Add a library to provide simple device-tree access
[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 class Node:
75     """A device tree node
76
77     Properties:
78         name: Device tree node tname
79         path: Full path to node, along with the node name itself
80         _fdt: Device tree object
81         subnodes: A list of subnodes for this node, each a Node object
82         props: A dict of properties for this node, each a Prop object.
83             Keyed by property name
84     """
85     def __init__(self, fdt, name, path):
86         self.name = name
87         self.path = path
88         self._fdt = fdt
89         self.subnodes = []
90         self.props = {}
91
92     def Scan(self):
93         """Scan a node's properties and subnodes
94
95         This fills in the props and subnodes properties, recursively
96         searching into subnodes so that the entire tree is built.
97         """
98         for name, byte_list_str in self._fdt.GetProps(self.path).iteritems():
99             prop = Prop(name, byte_list_str)
100             self.props[name] = prop
101
102         for name in self._fdt.GetSubNodes(self.path):
103             sep = '' if self.path[-1] == '/' else '/'
104             path = self.path + sep + name
105             node = Node(self._fdt, name, path)
106             self.subnodes.append(node)
107
108             node.Scan()
109
110
111 class Fdt:
112     """Provides simple access to a flat device tree blob.
113
114     Properties:
115       fname: Filename of fdt
116       _root: Root of device tree (a Node object)
117     """
118
119     def __init__(self, fname):
120         self.fname = fname
121
122     def Scan(self):
123         """Scan a device tree, building up a tree of Node objects
124
125         This fills in the self._root property
126         """
127         self._root = Node(self, '/', '/')
128         self._root.Scan()
129
130     def GetRoot(self):
131         """Get the root Node of the device tree
132
133         Returns:
134             The root Node object
135         """
136         return self._root
137
138     def GetSubNodes(self, node):
139         """Returns a list of sub-nodes of a given node
140
141         Args:
142             node: Node name to return children from
143
144         Returns:
145             List of children in the node (each a string node name)
146
147         Raises:
148             CmdError: if the node does not exist.
149         """
150         out = command.Output('fdtget', self.fname, '-l', node)
151         return out.strip().splitlines()
152
153     def GetProps(self, node, convert_dashes=False):
154         """Get all properties from a node
155
156         Args:
157             node: full path to node name to look in
158             convert_dashes: True to convert - to _ in node names
159
160         Returns:
161             A dictionary containing all the properties, indexed by node name.
162             The entries are simply strings - no decoding of lists or numbers
163             is done.
164
165         Raises:
166             CmdError: if the node does not exist.
167         """
168         out = command.Output('fdtget', self.fname, node, '-p')
169         props = out.strip().splitlines()
170         props_dict = {}
171         for prop in props:
172             name = prop
173             if convert_dashes:
174                 prop = re.sub('-', '_', prop)
175             props_dict[prop] = self.GetProp(node, name)
176         return props_dict
177
178     def GetProp(self, node, prop, default=None, typespec=None):
179         """Get a property from a device tree.
180
181         This looks up the given node and property, and returns the value as a
182         string,
183
184         If the node or property does not exist, this will return the default
185         value.
186
187         Args:
188             node: Full path to node to look up.
189             prop: Property name to look up.
190             default: Default value to return if nothing is present in the fdt,
191                 or None to raise in this case. This will be converted to a
192                 string.
193             typespec: Type character to use (None for default, 's' for string)
194
195         Returns:
196             string containing the property value.
197
198         Raises:
199             CmdError: if the property does not exist and no default is provided.
200         """
201         args = [self.fname, node, prop, '-t', 'bx']
202         if default is not None:
203           args += ['-d', str(default)]
204         if typespec is not None:
205           args += ['-t%s' % typespec]
206         out = command.Output('fdtget', *args)
207         return out.strip()