xref: /rk3399_rockchip-uboot/tools/dtoc/fdt.py (revision f7a2aeeeb8d4bbbb9bfd788903942062c8535efb)
1a06a34b2SSimon Glass#!/usr/bin/python
2a06a34b2SSimon Glass#
3a06a34b2SSimon Glass# Copyright (C) 2016 Google, Inc
4a06a34b2SSimon Glass# Written by Simon Glass <sjg@chromium.org>
5a06a34b2SSimon Glass#
6a06a34b2SSimon Glass# SPDX-License-Identifier:      GPL-2.0+
7a06a34b2SSimon Glass#
8a06a34b2SSimon Glass
9a06a34b2SSimon Glassimport struct
10a06a34b2SSimon Glassimport sys
11a06a34b2SSimon Glass
12a06a34b2SSimon Glassimport fdt_util
13a06a34b2SSimon Glass
14a06a34b2SSimon Glass# This deals with a device tree, presenting it as an assortment of Node and
15a06a34b2SSimon Glass# Prop objects, representing nodes and properties, respectively. This file
16a06a34b2SSimon Glass# contains the base classes and defines the high-level API. Most of the
17a06a34b2SSimon Glass# implementation is in the FdtFallback and FdtNormal subclasses. See
18a06a34b2SSimon Glass# fdt_select.py for how to create an Fdt object.
19a06a34b2SSimon Glass
20bc1dea36SSimon Glass# A list of types we support
21bc1dea36SSimon Glass(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
22bc1dea36SSimon Glass
23a06a34b2SSimon Glassdef CheckErr(errnum, msg):
24a06a34b2SSimon Glass    if errnum:
25a06a34b2SSimon Glass        raise ValueError('Error %d: %s: %s' %
26a06a34b2SSimon Glass            (errnum, libfdt.fdt_strerror(errnum), msg))
27a06a34b2SSimon Glass
28a06a34b2SSimon Glassclass PropBase:
29a06a34b2SSimon Glass    """A device tree property
30a06a34b2SSimon Glass
31a06a34b2SSimon Glass    Properties:
32a06a34b2SSimon Glass        name: Property name (as per the device tree)
33a06a34b2SSimon Glass        value: Property value as a string of bytes, or a list of strings of
34a06a34b2SSimon Glass            bytes
35a06a34b2SSimon Glass        type: Value type
36a06a34b2SSimon Glass    """
37a06a34b2SSimon Glass    def __init__(self, node, offset, name):
38a06a34b2SSimon Glass        self._node = node
39a06a34b2SSimon Glass        self._offset = offset
40a06a34b2SSimon Glass        self.name = name
41a06a34b2SSimon Glass        self.value = None
42a06a34b2SSimon Glass
43c322a850SSimon Glass    def GetPhandle(self):
44c322a850SSimon Glass        """Get a (single) phandle value from a property
45c322a850SSimon Glass
46c322a850SSimon Glass        Gets the phandle valuie from a property and returns it as an integer
47c322a850SSimon Glass        """
48c322a850SSimon Glass        return fdt_util.fdt32_to_cpu(self.value[:4])
49c322a850SSimon Glass
50c322a850SSimon Glass    def Widen(self, newprop):
51c322a850SSimon Glass        """Figure out which property type is more general
52c322a850SSimon Glass
53c322a850SSimon Glass        Given a current property and a new property, this function returns the
54c322a850SSimon Glass        one that is less specific as to type. The less specific property will
55c322a850SSimon Glass        be ble to represent the data in the more specific property. This is
56c322a850SSimon Glass        used for things like:
57c322a850SSimon Glass
58c322a850SSimon Glass            node1 {
59c322a850SSimon Glass                compatible = "fred";
60c322a850SSimon Glass                value = <1>;
61c322a850SSimon Glass            };
62c322a850SSimon Glass            node1 {
63c322a850SSimon Glass                compatible = "fred";
64c322a850SSimon Glass                value = <1 2>;
65c322a850SSimon Glass            };
66c322a850SSimon Glass
67c322a850SSimon Glass        He we want to use an int array for 'value'. The first property
68c322a850SSimon Glass        suggests that a single int is enough, but the second one shows that
69c322a850SSimon Glass        it is not. Calling this function with these two propertes would
70c322a850SSimon Glass        update the current property to be like the second, since it is less
71c322a850SSimon Glass        specific.
72c322a850SSimon Glass        """
73c322a850SSimon Glass        if newprop.type < self.type:
74c322a850SSimon Glass            self.type = newprop.type
75c322a850SSimon Glass
76c322a850SSimon Glass        if type(newprop.value) == list and type(self.value) != list:
77c322a850SSimon Glass            self.value = [self.value]
78c322a850SSimon Glass
79c322a850SSimon Glass        if type(self.value) == list and len(newprop.value) > len(self.value):
80c322a850SSimon Glass            val = self.GetEmpty(self.type)
81c322a850SSimon Glass            while len(self.value) < len(newprop.value):
82c322a850SSimon Glass                self.value.append(val)
83c322a850SSimon Glass
84bc1dea36SSimon Glass    def BytesToValue(self, bytes):
85bc1dea36SSimon Glass        """Converts a string of bytes into a type and value
86bc1dea36SSimon Glass
87bc1dea36SSimon Glass        Args:
88bc1dea36SSimon Glass            A string containing bytes
89bc1dea36SSimon Glass
90bc1dea36SSimon Glass        Return:
91bc1dea36SSimon Glass            A tuple:
92bc1dea36SSimon Glass                Type of data
93bc1dea36SSimon Glass                Data, either a single element or a list of elements. Each element
94bc1dea36SSimon Glass                is one of:
95bc1dea36SSimon Glass                    TYPE_STRING: string value from the property
96bc1dea36SSimon Glass                    TYPE_INT: a byte-swapped integer stored as a 4-byte string
97bc1dea36SSimon Glass                    TYPE_BYTE: a byte stored as a single-byte string
98bc1dea36SSimon Glass        """
99bc1dea36SSimon Glass        size = len(bytes)
100bc1dea36SSimon Glass        strings = bytes.split('\0')
101bc1dea36SSimon Glass        is_string = True
102bc1dea36SSimon Glass        count = len(strings) - 1
103bc1dea36SSimon Glass        if count > 0 and not strings[-1]:
104bc1dea36SSimon Glass            for string in strings[:-1]:
105bc1dea36SSimon Glass                if not string:
106bc1dea36SSimon Glass                    is_string = False
107bc1dea36SSimon Glass                    break
108bc1dea36SSimon Glass                for ch in string:
109bc1dea36SSimon Glass                    if ch < ' ' or ch > '~':
110bc1dea36SSimon Glass                        is_string = False
111bc1dea36SSimon Glass                        break
112bc1dea36SSimon Glass        else:
113bc1dea36SSimon Glass            is_string = False
114bc1dea36SSimon Glass        if is_string:
115bc1dea36SSimon Glass            if count == 1:
116bc1dea36SSimon Glass                return TYPE_STRING, strings[0]
117bc1dea36SSimon Glass            else:
118bc1dea36SSimon Glass                return TYPE_STRING, strings[:-1]
119bc1dea36SSimon Glass        if size % 4:
120bc1dea36SSimon Glass            if size == 1:
121bc1dea36SSimon Glass                return TYPE_BYTE, bytes[0]
122bc1dea36SSimon Glass            else:
123bc1dea36SSimon Glass                return TYPE_BYTE, list(bytes)
124bc1dea36SSimon Glass        val = []
125bc1dea36SSimon Glass        for i in range(0, size, 4):
126bc1dea36SSimon Glass            val.append(bytes[i:i + 4])
127bc1dea36SSimon Glass        if size == 4:
128bc1dea36SSimon Glass            return TYPE_INT, val[0]
129bc1dea36SSimon Glass        else:
130bc1dea36SSimon Glass            return TYPE_INT, val
131bc1dea36SSimon Glass
132bc1dea36SSimon Glass    def GetEmpty(self, type):
133bc1dea36SSimon Glass        """Get an empty / zero value of the given type
134bc1dea36SSimon Glass
135bc1dea36SSimon Glass        Returns:
136bc1dea36SSimon Glass            A single value of the given type
137bc1dea36SSimon Glass        """
138bc1dea36SSimon Glass        if type == TYPE_BYTE:
139bc1dea36SSimon Glass            return chr(0)
140bc1dea36SSimon Glass        elif type == TYPE_INT:
141bc1dea36SSimon Glass            return struct.pack('<I', 0);
142bc1dea36SSimon Glass        elif type == TYPE_STRING:
143bc1dea36SSimon Glass            return ''
144bc1dea36SSimon Glass        else:
145bc1dea36SSimon Glass            return True
146bc1dea36SSimon Glass
147a06a34b2SSimon Glassclass NodeBase:
148a06a34b2SSimon Glass    """A device tree node
149a06a34b2SSimon Glass
150a06a34b2SSimon Glass    Properties:
151a06a34b2SSimon Glass        offset: Integer offset in the device tree
152a06a34b2SSimon Glass        name: Device tree node tname
153a06a34b2SSimon Glass        path: Full path to node, along with the node name itself
154a06a34b2SSimon Glass        _fdt: Device tree object
155a06a34b2SSimon Glass        subnodes: A list of subnodes for this node, each a Node object
156a06a34b2SSimon Glass        props: A dict of properties for this node, each a Prop object.
157a06a34b2SSimon Glass            Keyed by property name
158a06a34b2SSimon Glass    """
159a06a34b2SSimon Glass    def __init__(self, fdt, offset, name, path):
160a06a34b2SSimon Glass        self._fdt = fdt
161a06a34b2SSimon Glass        self._offset = offset
162a06a34b2SSimon Glass        self.name = name
163a06a34b2SSimon Glass        self.path = path
164a06a34b2SSimon Glass        self.subnodes = []
165a06a34b2SSimon Glass        self.props = {}
166a06a34b2SSimon Glass
167*f7a2aeeeSSimon Glass    def _FindNode(self, name):
168*f7a2aeeeSSimon Glass        """Find a node given its name
169*f7a2aeeeSSimon Glass
170*f7a2aeeeSSimon Glass        Args:
171*f7a2aeeeSSimon Glass            name: Node name to look for
172*f7a2aeeeSSimon Glass        Returns:
173*f7a2aeeeSSimon Glass            Node object if found, else None
174*f7a2aeeeSSimon Glass        """
175*f7a2aeeeSSimon Glass        for subnode in self.subnodes:
176*f7a2aeeeSSimon Glass            if subnode.name == name:
177*f7a2aeeeSSimon Glass                return subnode
178*f7a2aeeeSSimon Glass        return None
179*f7a2aeeeSSimon Glass
180*f7a2aeeeSSimon Glass    def Scan(self):
181*f7a2aeeeSSimon Glass        """Scan the subnodes of a node
182*f7a2aeeeSSimon Glass
183*f7a2aeeeSSimon Glass        This should be implemented by subclasses
184*f7a2aeeeSSimon Glass        """
185*f7a2aeeeSSimon Glass        raise NotImplementedError()
186*f7a2aeeeSSimon Glass
187a06a34b2SSimon Glassclass Fdt:
188a06a34b2SSimon Glass    """Provides simple access to a flat device tree blob.
189a06a34b2SSimon Glass
190a06a34b2SSimon Glass    Properties:
191a06a34b2SSimon Glass      fname: Filename of fdt
192a06a34b2SSimon Glass      _root: Root of device tree (a Node object)
193a06a34b2SSimon Glass    """
194a06a34b2SSimon Glass    def __init__(self, fname):
195a06a34b2SSimon Glass        self._fname = fname
196*f7a2aeeeSSimon Glass
197*f7a2aeeeSSimon Glass    def Scan(self, root='/'):
198*f7a2aeeeSSimon Glass        """Scan a device tree, building up a tree of Node objects
199*f7a2aeeeSSimon Glass
200*f7a2aeeeSSimon Glass        This fills in the self._root property
201*f7a2aeeeSSimon Glass
202*f7a2aeeeSSimon Glass        Args:
203*f7a2aeeeSSimon Glass            root: Ignored
204*f7a2aeeeSSimon Glass
205*f7a2aeeeSSimon Glass        TODO(sjg@chromium.org): Implement the 'root' parameter
206*f7a2aeeeSSimon Glass        """
207*f7a2aeeeSSimon Glass        self._root = self.Node(self, 0, '/', '/')
208*f7a2aeeeSSimon Glass        self._root.Scan()
209*f7a2aeeeSSimon Glass
210*f7a2aeeeSSimon Glass    def GetRoot(self):
211*f7a2aeeeSSimon Glass        """Get the root Node of the device tree
212*f7a2aeeeSSimon Glass
213*f7a2aeeeSSimon Glass        Returns:
214*f7a2aeeeSSimon Glass            The root Node object
215*f7a2aeeeSSimon Glass        """
216*f7a2aeeeSSimon Glass        return self._root
217*f7a2aeeeSSimon Glass
218*f7a2aeeeSSimon Glass    def GetNode(self, path):
219*f7a2aeeeSSimon Glass        """Look up a node from its path
220*f7a2aeeeSSimon Glass
221*f7a2aeeeSSimon Glass        Args:
222*f7a2aeeeSSimon Glass            path: Path to look up, e.g. '/microcode/update@0'
223*f7a2aeeeSSimon Glass        Returns:
224*f7a2aeeeSSimon Glass            Node object, or None if not found
225*f7a2aeeeSSimon Glass        """
226*f7a2aeeeSSimon Glass        node = self._root
227*f7a2aeeeSSimon Glass        for part in path.split('/')[1:]:
228*f7a2aeeeSSimon Glass            node = node._FindNode(part)
229*f7a2aeeeSSimon Glass            if not node:
230*f7a2aeeeSSimon Glass                return None
231*f7a2aeeeSSimon Glass        return node
232*f7a2aeeeSSimon Glass
233