blob: 1d913a925ecc714d930506b9e16421fea1ee2966 [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
9import fdt_util
10import libfdt
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 a libfdt Python library to access the device tree,
17# so it is fairly efficient.
18
19class Prop:
20 """A device tree property
21
22 Properties:
23 name: Property name (as per the device tree)
24 value: Property value as a string of bytes, or a list of strings of
25 bytes
26 type: Value type
27 """
28 def __init__(self, name, bytes):
29 self.name = name
30 self.value = None
31 if not bytes:
32 self.type = fdt_util.TYPE_BOOL
33 self.value = True
34 return
35 self.type, self.value = fdt_util.BytesToValue(bytes)
36
37 def GetPhandle(self):
38 """Get a (single) phandle value from a property
39
40 Gets the phandle valuie from a property and returns it as an integer
41 """
42 return fdt_util.fdt32_to_cpu(self.value[:4])
43
44 def Widen(self, newprop):
45 """Figure out which property type is more general
46
47 Given a current property and a new property, this function returns the
48 one that is less specific as to type. The less specific property will
49 be ble to represent the data in the more specific property. This is
50 used for things like:
51
52 node1 {
53 compatible = "fred";
54 value = <1>;
55 };
56 node1 {
57 compatible = "fred";
58 value = <1 2>;
59 };
60
61 He we want to use an int array for 'value'. The first property
62 suggests that a single int is enough, but the second one shows that
63 it is not. Calling this function with these two propertes would
64 update the current property to be like the second, since it is less
65 specific.
66 """
67 if newprop.type < self.type:
68 self.type = newprop.type
69
70 if type(newprop.value) == list and type(self.value) != list:
71 self.value = [self.value]
72
73 if type(self.value) == list and len(newprop.value) > len(self.value):
74 val = fdt_util.GetEmpty(self.type)
75 while len(self.value) < len(newprop.value):
76 self.value.append(val)
77
78
79class Node:
80 """A device tree node
81
82 Properties:
83 offset: Integer offset in the device tree
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, offset, name, path):
92 self.offset = offset
93 self.name = name
94 self.path = path
95 self._fdt = fdt
96 self.subnodes = []
97 self.props = {}
98
99 def Scan(self):
100 """Scan a node's properties and subnodes
101
102 This fills in the props and subnodes properties, recursively
103 searching into subnodes so that the entire tree is built.
104 """
105 self.props = self._fdt.GetProps(self.path)
106
107 offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset)
108 while offset >= 0:
109 sep = '' if self.path[-1] == '/' else '/'
110 name = libfdt.Name(self._fdt.GetFdt(), offset)
111 path = self.path + sep + name
112 node = Node(self._fdt, offset, name, path)
113 self.subnodes.append(node)
114
115 node.Scan()
116 offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
117
118
119class Fdt:
120 """Provides simple access to a flat device tree blob.
121
122 Properties:
123 fname: Filename of fdt
124 _root: Root of device tree (a Node object)
125 """
126
127 def __init__(self, fname):
128 self.fname = fname
129 with open(fname) as fd:
130 self._fdt = fd.read()
131
132 def GetFdt(self):
133 """Get the contents of the FDT
134
135 Returns:
136 The FDT contents as a string of bytes
137 """
138 return self._fdt
139
140 def Scan(self):
141 """Scan a device tree, building up a tree of Node objects
142
143 This fills in the self._root property
144 """
145 self._root = Node(self, 0, '/', '/')
146 self._root.Scan()
147
148 def GetRoot(self):
149 """Get the root Node of the device tree
150
151 Returns:
152 The root Node object
153 """
154 return self._root
155
156 def GetProps(self, node):
157 """Get all properties from a node.
158
159 Args:
160 node: Full path to node name to look in.
161
162 Returns:
163 A dictionary containing all the properties, indexed by node name.
164 The entries are Prop objects.
165
166 Raises:
167 ValueError: if the node does not exist.
168 """
169 offset = libfdt.fdt_path_offset(self._fdt, node)
170 if offset < 0:
171 libfdt.Raise(offset)
172 props_dict = {}
173 poffset = libfdt.fdt_first_property_offset(self._fdt, offset)
174 while poffset >= 0:
175 dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
176 prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop))
177 props_dict[prop.name] = prop
178
179 poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
180 return props_dict