blob: ca5335ba5b2bf561ddbec86ae69ab448db892b03 [file] [log] [blame]
Simon Glassa2a6f042016-07-04 11:58:11 -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
Simon Glass1f941b62016-07-25 18:59:04 -06009import struct
10import sys
11
12import fdt
13from fdt import Fdt, NodeBase, PropBase
Simon Glassa2a6f042016-07-04 11:58:11 -060014import fdt_util
15import libfdt
Simon Glassa2a6f042016-07-04 11:58:11 -060016
17# This deals with a device tree, presenting it as a list of Node and Prop
18# objects, representing nodes and properties, respectively.
19#
20# This implementation uses a libfdt Python library to access the device tree,
21# so it is fairly efficient.
22
Simon Glass1f941b62016-07-25 18:59:04 -060023class Prop(PropBase):
Simon Glassa2a6f042016-07-04 11:58:11 -060024 """A device tree property
25
26 Properties:
27 name: Property name (as per the device tree)
28 value: Property value as a string of bytes, or a list of strings of
29 bytes
30 type: Value type
31 """
Simon Glass1f941b62016-07-25 18:59:04 -060032 def __init__(self, node, offset, name, bytes):
33 PropBase.__init__(self, node, offset, name)
34 self.bytes = bytes
Simon Glassa2a6f042016-07-04 11:58:11 -060035 if not bytes:
36 self.type = fdt_util.TYPE_BOOL
37 self.value = True
38 return
39 self.type, self.value = fdt_util.BytesToValue(bytes)
40
41 def GetPhandle(self):
42 """Get a (single) phandle value from a property
43
44 Gets the phandle valuie from a property and returns it as an integer
45 """
46 return fdt_util.fdt32_to_cpu(self.value[:4])
47
48 def Widen(self, newprop):
49 """Figure out which property type is more general
50
51 Given a current property and a new property, this function returns the
52 one that is less specific as to type. The less specific property will
53 be ble to represent the data in the more specific property. This is
54 used for things like:
55
56 node1 {
57 compatible = "fred";
58 value = <1>;
59 };
60 node1 {
61 compatible = "fred";
62 value = <1 2>;
63 };
64
65 He we want to use an int array for 'value'. The first property
66 suggests that a single int is enough, but the second one shows that
67 it is not. Calling this function with these two propertes would
68 update the current property to be like the second, since it is less
69 specific.
70 """
71 if newprop.type < self.type:
72 self.type = newprop.type
73
74 if type(newprop.value) == list and type(self.value) != list:
75 self.value = [self.value]
76
77 if type(self.value) == list and len(newprop.value) > len(self.value):
78 val = fdt_util.GetEmpty(self.type)
79 while len(self.value) < len(newprop.value):
80 self.value.append(val)
81
82
Simon Glass1f941b62016-07-25 18:59:04 -060083class Node(NodeBase):
Simon Glassa2a6f042016-07-04 11:58:11 -060084 """A device tree node
85
86 Properties:
87 offset: Integer offset in the device tree
88 name: Device tree node tname
89 path: Full path to node, along with the node name itself
90 _fdt: Device tree object
91 subnodes: A list of subnodes for this node, each a Node object
92 props: A dict of properties for this node, each a Prop object.
93 Keyed by property name
94 """
95 def __init__(self, fdt, offset, name, path):
Simon Glass1f941b62016-07-25 18:59:04 -060096 NodeBase.__init__(self, fdt, offset, name, path)
Simon Glassa2a6f042016-07-04 11:58:11 -060097
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 self.props = self._fdt.GetProps(self.path)
105
Simon Glass1f941b62016-07-25 18:59:04 -0600106 offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
Simon Glassa2a6f042016-07-04 11:58:11 -0600107 while offset >= 0:
108 sep = '' if self.path[-1] == '/' else '/'
109 name = libfdt.Name(self._fdt.GetFdt(), offset)
110 path = self.path + sep + name
111 node = Node(self._fdt, offset, name, path)
112 self.subnodes.append(node)
113
114 node.Scan()
115 offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
116
117
Simon Glass1f941b62016-07-25 18:59:04 -0600118class FdtNormal(Fdt):
119 """Provides simple access to a flat device tree blob using libfdt.
Simon Glassa2a6f042016-07-04 11:58:11 -0600120
121 Properties:
Simon Glass1f941b62016-07-25 18:59:04 -0600122 _fdt: Device tree contents (bytearray)
123 _cached_offsets: True if all the nodes have a valid _offset property,
124 False if something has changed to invalidate the offsets
Simon Glassa2a6f042016-07-04 11:58:11 -0600125 """
Simon Glassa2a6f042016-07-04 11:58:11 -0600126 def __init__(self, fname):
Simon Glass1f941b62016-07-25 18:59:04 -0600127 Fdt.__init__(self, fname)
128 with open(self._fname) as fd:
Simon Glassa2a6f042016-07-04 11:58:11 -0600129 self._fdt = fd.read()
130
131 def GetFdt(self):
132 """Get the contents of the FDT
133
134 Returns:
135 The FDT contents as a string of bytes
136 """
137 return self._fdt
138
139 def Scan(self):
140 """Scan a device tree, building up a tree of Node objects
141
142 This fills in the self._root property
143 """
144 self._root = Node(self, 0, '/', '/')
145 self._root.Scan()
146
147 def GetRoot(self):
148 """Get the root Node of the device tree
149
150 Returns:
151 The root Node object
152 """
153 return self._root
154
155 def GetProps(self, node):
156 """Get all properties from a node.
157
158 Args:
159 node: Full path to node name to look in.
160
161 Returns:
162 A dictionary containing all the properties, indexed by node name.
163 The entries are Prop objects.
164
165 Raises:
166 ValueError: if the node does not exist.
167 """
168 offset = libfdt.fdt_path_offset(self._fdt, node)
169 if offset < 0:
170 libfdt.Raise(offset)
171 props_dict = {}
172 poffset = libfdt.fdt_first_property_offset(self._fdt, offset)
173 while poffset >= 0:
174 dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
Simon Glass1f941b62016-07-25 18:59:04 -0600175 prop = Prop(node, poffset, libfdt.String(self._fdt, dprop.nameoff),
176 libfdt.Data(dprop))
Simon Glassa2a6f042016-07-04 11:58:11 -0600177 props_dict[prop.name] = prop
178
179 poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
180 return props_dict
Simon Glass1f941b62016-07-25 18:59:04 -0600181
182 @classmethod
183 def Node(self, fdt, offset, name, path):
184 """Create a new node
185
186 This is used by Fdt.Scan() to create a new node using the correct
187 class.
188
189 Args:
190 fdt: Fdt object
191 offset: Offset of node
192 name: Node name
193 path: Full path to node
194 """
195 node = Node(fdt, offset, name, path)
196 return node