blob: 1c8c9c7a6dc3d328ecd15c01e6a4a2030ab93cf0 [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
Simon Glassc2470f42016-07-25 18:59:11 -0600101 def GetProps(self, node):
Simon Glassfa8974d2016-07-04 11:58:08 -0600102 """Get all properties from a node
103
104 Args:
105 node: full path to node name to look in
Simon Glassfa8974d2016-07-04 11:58:08 -0600106
107 Returns:
108 A dictionary containing all the properties, indexed by node name.
109 The entries are simply strings - no decoding of lists or numbers
110 is done.
111
112 Raises:
113 CmdError: if the node does not exist.
114 """
Simon Glass1f941b62016-07-25 18:59:04 -0600115 out = command.Output('fdtget', self._fname, node, '-p')
Simon Glassfa8974d2016-07-04 11:58:08 -0600116 props = out.strip().splitlines()
117 props_dict = {}
118 for prop in props:
119 name = prop
Simon Glassfa8974d2016-07-04 11:58:08 -0600120 props_dict[prop] = self.GetProp(node, name)
121 return props_dict
122
123 def GetProp(self, node, prop, default=None, typespec=None):
124 """Get a property from a device tree.
125
126 This looks up the given node and property, and returns the value as a
127 string,
128
129 If the node or property does not exist, this will return the default
130 value.
131
132 Args:
133 node: Full path to node to look up.
134 prop: Property name to look up.
135 default: Default value to return if nothing is present in the fdt,
136 or None to raise in this case. This will be converted to a
137 string.
138 typespec: Type character to use (None for default, 's' for string)
139
140 Returns:
141 string containing the property value.
142
143 Raises:
144 CmdError: if the property does not exist and no default is provided.
145 """
Simon Glass1f941b62016-07-25 18:59:04 -0600146 args = [self._fname, node, prop, '-t', 'bx']
Simon Glassfa8974d2016-07-04 11:58:08 -0600147 if default is not None:
148 args += ['-d', str(default)]
149 if typespec is not None:
150 args += ['-t%s' % typespec]
151 out = command.Output('fdtget', *args)
152 return out.strip()
Simon Glass1f941b62016-07-25 18:59:04 -0600153
154 @classmethod
155 def Node(self, fdt, offset, name, path):
156 """Create a new node
157
158 This is used by Fdt.Scan() to create a new node using the correct
159 class.
160
161 Args:
162 fdt: Fdt object
163 offset: Offset of node
164 name: Node name
165 path: Full path to node
166 """
167 node = Node(fdt, offset, name, path)
168 return node