blob: f76f42a10165dd38cce837b7b3b4280c3749c397 [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
Simon Glass90313a92016-07-22 09:22:49 -060040
Simon Glass1f941b62016-07-25 18:59:04 -060041class Node(NodeBase):
Simon Glassfa8974d2016-07-04 11:58:08 -060042 """A device tree node
43
44 Properties:
45 name: Device tree node tname
46 path: Full path to node, along with the node name itself
47 _fdt: Device tree object
48 subnodes: A list of subnodes for this node, each a Node object
49 props: A dict of properties for this node, each a Prop object.
50 Keyed by property name
51 """
Simon Glass1f941b62016-07-25 18:59:04 -060052 def __init__(self, fdt, offset, name, path):
53 NodeBase.__init__(self, fdt, offset, name, path)
Simon Glassfa8974d2016-07-04 11:58:08 -060054
55 def Scan(self):
56 """Scan a node's properties and subnodes
57
58 This fills in the props and subnodes properties, recursively
59 searching into subnodes so that the entire tree is built.
60 """
61 for name, byte_list_str in self._fdt.GetProps(self.path).iteritems():
Simon Glass1f941b62016-07-25 18:59:04 -060062 prop = Prop(self, name, byte_list_str)
Simon Glassfa8974d2016-07-04 11:58:08 -060063 self.props[name] = prop
64
65 for name in self._fdt.GetSubNodes(self.path):
66 sep = '' if self.path[-1] == '/' else '/'
67 path = self.path + sep + name
Simon Glass1f941b62016-07-25 18:59:04 -060068 node = Node(self._fdt, 0, name, path)
Simon Glassfa8974d2016-07-04 11:58:08 -060069 self.subnodes.append(node)
70
71 node.Scan()
72
73
Simon Glass1f941b62016-07-25 18:59:04 -060074class FdtFallback(Fdt):
75 """Provides simple access to a flat device tree blob using fdtget/fdtput
Simon Glassfa8974d2016-07-04 11:58:08 -060076
77 Properties:
Simon Glass1f941b62016-07-25 18:59:04 -060078 See superclass
Simon Glassfa8974d2016-07-04 11:58:08 -060079 """
80
81 def __init__(self, fname):
Simon Glass1f941b62016-07-25 18:59:04 -060082 Fdt.__init__(self, fname)
Simon Glassefc9bf62016-07-25 18:59:10 -060083 if self._fname:
84 self._fname = fdt_util.EnsureCompiled(self._fname)
Simon Glassfa8974d2016-07-04 11:58:08 -060085
Simon Glassfa8974d2016-07-04 11:58:08 -060086 def GetSubNodes(self, node):
87 """Returns a list of sub-nodes of a given node
88
89 Args:
90 node: Node name to return children from
91
92 Returns:
93 List of children in the node (each a string node name)
94
95 Raises:
96 CmdError: if the node does not exist.
97 """
Simon Glass1f941b62016-07-25 18:59:04 -060098 out = command.Output('fdtget', self._fname, '-l', node)
Simon Glassfa8974d2016-07-04 11:58:08 -060099 return out.strip().splitlines()
100
101 def GetProps(self, node, convert_dashes=False):
102 """Get all properties from a node
103
104 Args:
105 node: full path to node name to look in
106 convert_dashes: True to convert - to _ in node names
107
108 Returns:
109 A dictionary containing all the properties, indexed by node name.
110 The entries are simply strings - no decoding of lists or numbers
111 is done.
112
113 Raises:
114 CmdError: if the node does not exist.
115 """
Simon Glass1f941b62016-07-25 18:59:04 -0600116 out = command.Output('fdtget', self._fname, node, '-p')
Simon Glassfa8974d2016-07-04 11:58:08 -0600117 props = out.strip().splitlines()
118 props_dict = {}
119 for prop in props:
120 name = prop
121 if convert_dashes:
122 prop = re.sub('-', '_', prop)
123 props_dict[prop] = self.GetProp(node, name)
124 return props_dict
125
126 def GetProp(self, node, prop, default=None, typespec=None):
127 """Get a property from a device tree.
128
129 This looks up the given node and property, and returns the value as a
130 string,
131
132 If the node or property does not exist, this will return the default
133 value.
134
135 Args:
136 node: Full path to node to look up.
137 prop: Property name to look up.
138 default: Default value to return if nothing is present in the fdt,
139 or None to raise in this case. This will be converted to a
140 string.
141 typespec: Type character to use (None for default, 's' for string)
142
143 Returns:
144 string containing the property value.
145
146 Raises:
147 CmdError: if the property does not exist and no default is provided.
148 """
Simon Glass1f941b62016-07-25 18:59:04 -0600149 args = [self._fname, node, prop, '-t', 'bx']
Simon Glassfa8974d2016-07-04 11:58:08 -0600150 if default is not None:
151 args += ['-d', str(default)]
152 if typespec is not None:
153 args += ['-t%s' % typespec]
154 out = command.Output('fdtget', *args)
155 return out.strip()
Simon Glass1f941b62016-07-25 18:59:04 -0600156
157 @classmethod
158 def Node(self, fdt, offset, name, path):
159 """Create a new node
160
161 This is used by Fdt.Scan() to create a new node using the correct
162 class.
163
164 Args:
165 fdt: Fdt object
166 offset: Offset of node
167 name: Node name
168 path: Full path to node
169 """
170 node = Node(fdt, offset, name, path)
171 return node