blob: 798c51097ef341b61e91a50be5c235a95db7be57 [file] [log] [blame]
Simon Glassfa8974d2016-07-04 11:58:08 -06001#!/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
9import command
Simon Glass1f941b62016-07-25 18:59:04 -060010import fdt
11from fdt import Fdt, NodeBase, PropBase
Simon Glassfa8974d2016-07-04 11:58:08 -060012import fdt_util
13import sys
14
15# This deals with a device tree, presenting it as a list of Node and Prop
16# objects, representing nodes and properties, respectively.
17#
18# This implementation uses the fdtget tool to access the device tree, so it
19# is not very efficient for larger trees. The tool is called once for each
20# node and property in the tree.
21
Simon Glass1f941b62016-07-25 18:59:04 -060022class Prop(PropBase):
Simon Glassfa8974d2016-07-04 11:58:08 -060023 """A device tree property
24
25 Properties:
26 name: Property name (as per the device tree)
27 value: Property value as a string of bytes, or a list of strings of
28 bytes
29 type: Value type
30 """
Simon Glass1f941b62016-07-25 18:59:04 -060031 def __init__(self, node, name, byte_list_str):
32 PropBase.__init__(self, node, 0, name)
Simon Glassfa8974d2016-07-04 11:58:08 -060033 if not byte_list_str.strip():
Simon Glassb1a5e262016-07-25 18:59:05 -060034 self.type = fdt.TYPE_BOOL
Simon Glassfa8974d2016-07-04 11:58:08 -060035 return
Simon Glass1f941b62016-07-25 18:59:04 -060036 self.bytes = [chr(int(byte, 16))
37 for byte in byte_list_str.strip().split(' ')]
Simon Glassb1a5e262016-07-25 18:59:05 -060038 self.type, self.value = self.BytesToValue(''.join(self.bytes))
Simon Glassfa8974d2016-07-04 11:58:08 -060039
40 def GetPhandle(self):
41 """Get a (single) phandle value from a property
42
43 Gets the phandle valuie from a property and returns it as an integer
44 """
45 return fdt_util.fdt32_to_cpu(self.value[:4])
46
47 def Widen(self, newprop):
48 """Figure out which property type is more general
49
50 Given a current property and a new property, this function returns the
51 one that is less specific as to type. The less specific property will
52 be ble to represent the data in the more specific property. This is
53 used for things like:
54
55 node1 {
56 compatible = "fred";
57 value = <1>;
58 };
59 node1 {
60 compatible = "fred";
61 value = <1 2>;
62 };
63
64 He we want to use an int array for 'value'. The first property
65 suggests that a single int is enough, but the second one shows that
66 it is not. Calling this function with these two propertes would
67 update the current property to be like the second, since it is less
68 specific.
69 """
70 if newprop.type < self.type:
71 self.type = newprop.type
72
73 if type(newprop.value) == list and type(self.value) != list:
74 self.value = newprop.value
75
Simon Glass90313a92016-07-22 09:22:49 -060076 if type(self.value) == list and len(newprop.value) > len(self.value):
77 val = fdt_util.GetEmpty(self.type)
78 while len(self.value) < len(newprop.value):
79 self.value.append(val)
80
81
Simon Glass1f941b62016-07-25 18:59:04 -060082class Node(NodeBase):
Simon Glassfa8974d2016-07-04 11:58:08 -060083 """A device tree node
84
85 Properties:
86 name: Device tree node tname
87 path: Full path to node, along with the node name itself
88 _fdt: Device tree object
89 subnodes: A list of subnodes for this node, each a Node object
90 props: A dict of properties for this node, each a Prop object.
91 Keyed by property name
92 """
Simon Glass1f941b62016-07-25 18:59:04 -060093 def __init__(self, fdt, offset, name, path):
94 NodeBase.__init__(self, fdt, offset, name, path)
Simon Glassfa8974d2016-07-04 11:58:08 -060095
96 def Scan(self):
97 """Scan a node's properties and subnodes
98
99 This fills in the props and subnodes properties, recursively
100 searching into subnodes so that the entire tree is built.
101 """
102 for name, byte_list_str in self._fdt.GetProps(self.path).iteritems():
Simon Glass1f941b62016-07-25 18:59:04 -0600103 prop = Prop(self, name, byte_list_str)
Simon Glassfa8974d2016-07-04 11:58:08 -0600104 self.props[name] = prop
105
106 for name in self._fdt.GetSubNodes(self.path):
107 sep = '' if self.path[-1] == '/' else '/'
108 path = self.path + sep + name
Simon Glass1f941b62016-07-25 18:59:04 -0600109 node = Node(self._fdt, 0, name, path)
Simon Glassfa8974d2016-07-04 11:58:08 -0600110 self.subnodes.append(node)
111
112 node.Scan()
113
114
Simon Glass1f941b62016-07-25 18:59:04 -0600115class FdtFallback(Fdt):
116 """Provides simple access to a flat device tree blob using fdtget/fdtput
Simon Glassfa8974d2016-07-04 11:58:08 -0600117
118 Properties:
Simon Glass1f941b62016-07-25 18:59:04 -0600119 See superclass
Simon Glassfa8974d2016-07-04 11:58:08 -0600120 """
121
122 def __init__(self, fname):
Simon Glass1f941b62016-07-25 18:59:04 -0600123 Fdt.__init__(self, fname)
Simon Glassfa8974d2016-07-04 11:58:08 -0600124
125 def Scan(self):
126 """Scan a device tree, building up a tree of Node objects
127
128 This fills in the self._root property
129 """
Simon Glass1f941b62016-07-25 18:59:04 -0600130 self._root = Node(self, 0, '/', '/')
Simon Glassfa8974d2016-07-04 11:58:08 -0600131 self._root.Scan()
132
133 def GetRoot(self):
134 """Get the root Node of the device tree
135
136 Returns:
137 The root Node object
138 """
139 return self._root
140
141 def GetSubNodes(self, node):
142 """Returns a list of sub-nodes of a given node
143
144 Args:
145 node: Node name to return children from
146
147 Returns:
148 List of children in the node (each a string node name)
149
150 Raises:
151 CmdError: if the node does not exist.
152 """
Simon Glass1f941b62016-07-25 18:59:04 -0600153 out = command.Output('fdtget', self._fname, '-l', node)
Simon Glassfa8974d2016-07-04 11:58:08 -0600154 return out.strip().splitlines()
155
156 def GetProps(self, node, convert_dashes=False):
157 """Get all properties from a node
158
159 Args:
160 node: full path to node name to look in
161 convert_dashes: True to convert - to _ in node names
162
163 Returns:
164 A dictionary containing all the properties, indexed by node name.
165 The entries are simply strings - no decoding of lists or numbers
166 is done.
167
168 Raises:
169 CmdError: if the node does not exist.
170 """
Simon Glass1f941b62016-07-25 18:59:04 -0600171 out = command.Output('fdtget', self._fname, node, '-p')
Simon Glassfa8974d2016-07-04 11:58:08 -0600172 props = out.strip().splitlines()
173 props_dict = {}
174 for prop in props:
175 name = prop
176 if convert_dashes:
177 prop = re.sub('-', '_', prop)
178 props_dict[prop] = self.GetProp(node, name)
179 return props_dict
180
181 def GetProp(self, node, prop, default=None, typespec=None):
182 """Get a property from a device tree.
183
184 This looks up the given node and property, and returns the value as a
185 string,
186
187 If the node or property does not exist, this will return the default
188 value.
189
190 Args:
191 node: Full path to node to look up.
192 prop: Property name to look up.
193 default: Default value to return if nothing is present in the fdt,
194 or None to raise in this case. This will be converted to a
195 string.
196 typespec: Type character to use (None for default, 's' for string)
197
198 Returns:
199 string containing the property value.
200
201 Raises:
202 CmdError: if the property does not exist and no default is provided.
203 """
Simon Glass1f941b62016-07-25 18:59:04 -0600204 args = [self._fname, node, prop, '-t', 'bx']
Simon Glassfa8974d2016-07-04 11:58:08 -0600205 if default is not None:
206 args += ['-d', str(default)]
207 if typespec is not None:
208 args += ['-t%s' % typespec]
209 out = command.Output('fdtget', *args)
210 return out.strip()
Simon Glass1f941b62016-07-25 18:59:04 -0600211
212 @classmethod
213 def Node(self, fdt, offset, name, path):
214 """Create a new node
215
216 This is used by Fdt.Scan() to create a new node using the correct
217 class.
218
219 Args:
220 fdt: Fdt object
221 offset: Offset of node
222 name: Node name
223 path: Full path to node
224 """
225 node = Node(fdt, offset, name, path)
226 return node