blob: 9ed11e4cbfeaaafe9c49f8dde9b7eb08bf7902ee [file] [log] [blame]
Simon Glassec564b42016-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
10import fdt_util
11import 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
20class 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
Simon Glassd6a33912016-07-22 09:22:49 -060074 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
Simon Glassec564b42016-07-04 11:58:08 -060080class 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
117class 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()