Merge https://gitlab.denx.de/u-boot/custodians/u-boot-marvell
[oweals/u-boot.git] / tools / dtoc / fdt_util.py
1 #!/usr/bin/python
2 # SPDX-License-Identifier: GPL-2.0+
3 #
4 # Copyright (C) 2016 Google, Inc
5 # Written by Simon Glass <sjg@chromium.org>
6 #
7
8 # Utility functions for reading from a device tree. Once the upstream pylibfdt
9 # implementation advances far enough, we should be able to drop these.
10
11 import os
12 import struct
13 import sys
14 import tempfile
15
16 import command
17 import tools
18
19 VERSION3 = sys.version_info > (3, 0)
20
21 def get_plain_bytes(val):
22     """Handle Python 3 strings"""
23     if isinstance(val, bytes):
24         val = val.decode('utf-8')
25     return val.encode('raw_unicode_escape')
26
27 def fdt32_to_cpu(val):
28     """Convert a device tree cell to an integer
29
30     Args:
31         Value to convert (4-character string representing the cell value)
32
33     Return:
34         A native-endian integer value
35     """
36     if VERSION3:
37         # This code is not reached in Python 2
38         val = get_plain_bytes(val)  # pragma: no cover
39     return struct.unpack('>I', val)[0]
40
41 def fdt_cells_to_cpu(val, cells):
42     """Convert one or two cells to a long integer
43
44     Args:
45         Value to convert (array of one or more 4-character strings)
46
47     Return:
48         A native-endian long value
49     """
50     if not cells:
51         return 0
52     out = long(fdt32_to_cpu(val[0]))
53     if cells == 2:
54         out = out << 32 | fdt32_to_cpu(val[1])
55     return out
56
57 def EnsureCompiled(fname, capture_stderr=False):
58     """Compile an fdt .dts source file into a .dtb binary blob if needed.
59
60     Args:
61         fname: Filename (if .dts it will be compiled). It not it will be
62             left alone
63
64     Returns:
65         Filename of resulting .dtb file
66     """
67     _, ext = os.path.splitext(fname)
68     if ext != '.dts':
69         return fname
70
71     dts_input = tools.GetOutputFilename('source.dts')
72     dtb_output = tools.GetOutputFilename('source.dtb')
73
74     search_paths = [os.path.join(os.getcwd(), 'include')]
75     root, _ = os.path.splitext(fname)
76     args = ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
77     args += ['-Ulinux']
78     for path in search_paths:
79         args.extend(['-I', path])
80     args += ['-o', dts_input, fname]
81     command.Run('cc', *args)
82
83     # If we don't have a directory, put it in the tools tempdir
84     search_list = []
85     for path in search_paths:
86         search_list.extend(['-i', path])
87     args = ['-I', 'dts', '-o', dtb_output, '-O', 'dtb',
88             '-W', 'no-unit_address_vs_reg']
89     args.extend(search_list)
90     args.append(dts_input)
91     dtc = os.environ.get('DTC') or 'dtc'
92     command.Run(dtc, *args, capture_stderr=capture_stderr)
93     return dtb_output
94
95 def GetInt(node, propname, default=None):
96     """Get an integer from a property
97
98     Args:
99         node: Node object to read from
100         propname: property name to read
101         default: Default value to use if the node/property do not exist
102
103     Returns:
104         Integer value read, or default if none
105     """
106     prop = node.props.get(propname)
107     if not prop:
108         return default
109     if isinstance(prop.value, list):
110         raise ValueError("Node '%s' property '%s' has list value: expecting "
111                          "a single integer" % (node.name, propname))
112     value = fdt32_to_cpu(prop.value)
113     return value
114
115 def GetString(node, propname, default=None):
116     """Get a string from a property
117
118     Args:
119         node: Node object to read from
120         propname: property name to read
121         default: Default value to use if the node/property do not exist
122
123     Returns:
124         String value read, or default if none
125     """
126     prop = node.props.get(propname)
127     if not prop:
128         return default
129     value = prop.value
130     if isinstance(value, list):
131         raise ValueError("Node '%s' property '%s' has list value: expecting "
132                          "a single string" % (node.name, propname))
133     return value
134
135 def GetBool(node, propname, default=False):
136     """Get an boolean from a property
137
138     Args:
139         node: Node object to read from
140         propname: property name to read
141         default: Default value to use if the node/property do not exist
142
143     Returns:
144         Boolean value read, or default if none (if you set this to True the
145             function will always return True)
146     """
147     if propname in node.props:
148         return True
149     return default
150
151 def GetByte(node, propname, default=None):
152     """Get an byte from a property
153
154     Args:
155         node: Node object to read from
156         propname: property name to read
157         default: Default value to use if the node/property do not exist
158
159     Returns:
160         Byte value read, or default if none
161     """
162     prop = node.props.get(propname)
163     if not prop:
164         return default
165     value = prop.value
166     if isinstance(value, list):
167         raise ValueError("Node '%s' property '%s' has list value: expecting "
168                          "a single byte" % (node.name, propname))
169     if len(value) != 1:
170         raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
171                          (node.name, propname, len(value), 1))
172     return ord(value[0])
173
174 def GetPhandleList(node, propname):
175     """Get a list of phandles from a property
176
177     Args:
178         node: Node object to read from
179         propname: property name to read
180
181     Returns:
182         List of phandles read, each an integer
183     """
184     prop = node.props.get(propname)
185     if not prop:
186         return None
187     value = prop.value
188     if not isinstance(value, list):
189         value = [value]
190     return [fdt32_to_cpu(v) for v in value]
191
192 def GetDatatype(node, propname, datatype):
193     """Get a value of a given type from a property
194
195     Args:
196         node: Node object to read from
197         propname: property name to read
198         datatype: Type to read (str or int)
199
200     Returns:
201         value read, or None if none
202
203     Raises:
204         ValueError if datatype is not str or int
205     """
206     if datatype == str:
207         return GetString(node, propname)
208     elif datatype == int:
209         return GetInt(node, propname)
210     raise ValueError("fdt_util internal error: Unknown data type '%s'" %
211                      datatype)