Merge tag 'dm-pull-18mar22' of https://source.denx.de/u-boot/custodians/u-boot-dm...
[platform/kernel/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 from patman import command
17 from patman import tools
18
19 def fdt32_to_cpu(val):
20     """Convert a device tree cell to an integer
21
22     Args:
23         Value to convert (4-character string representing the cell value)
24
25     Return:
26         A native-endian integer value
27     """
28     return struct.unpack('>I', val)[0]
29
30 def fdt64_to_cpu(val):
31     """Convert a device tree cell to an integer
32
33     Args:
34         val (list): Value to convert (list of 2 4-character strings representing
35             the cell value)
36
37     Return:
38         int: A native-endian integer value
39     """
40     return fdt32_to_cpu(val[0]) << 32 | fdt32_to_cpu(val[1])
41
42 def fdt_cells_to_cpu(val, cells):
43     """Convert one or two cells to a long integer
44
45     Args:
46         Value to convert (array of one or more 4-character strings)
47
48     Return:
49         A native-endian integer value
50     """
51     if not cells:
52         return 0
53     out = int(fdt32_to_cpu(val[0]))
54     if cells == 2:
55         out = out << 32 | fdt32_to_cpu(val[1])
56     return out
57
58 def EnsureCompiled(fname, tmpdir=None, capture_stderr=False):
59     """Compile an fdt .dts source file into a .dtb binary blob if needed.
60
61     Args:
62         fname: Filename (if .dts it will be compiled). It not it will be
63             left alone
64         tmpdir: Temporary directory for output files, or None to use the
65             tools-module output directory
66
67     Returns:
68         Filename of resulting .dtb file
69     """
70     _, ext = os.path.splitext(fname)
71     if ext != '.dts':
72         return fname
73
74     if tmpdir:
75         dts_input = os.path.join(tmpdir, 'source.dts')
76         dtb_output = os.path.join(tmpdir, 'source.dtb')
77     else:
78         dts_input = tools.get_output_filename('source.dts')
79         dtb_output = tools.get_output_filename('source.dtb')
80
81     search_paths = [os.path.join(os.getcwd(), 'include')]
82     root, _ = os.path.splitext(fname)
83     cc, args = tools.get_target_compile_tool('cc')
84     args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
85     args += ['-Ulinux']
86     for path in search_paths:
87         args.extend(['-I', path])
88     args += ['-o', dts_input, fname]
89     command.run(cc, *args)
90
91     # If we don't have a directory, put it in the tools tempdir
92     search_list = []
93     for path in search_paths:
94         search_list.extend(['-i', path])
95     dtc, args = tools.get_target_compile_tool('dtc')
96     args += ['-I', 'dts', '-o', dtb_output, '-O', 'dtb',
97             '-W', 'no-unit_address_vs_reg']
98     args.extend(search_list)
99     args.append(dts_input)
100     command.run(dtc, *args, capture_stderr=capture_stderr)
101     return dtb_output
102
103 def GetInt(node, propname, default=None):
104     """Get an integer from a property
105
106     Args:
107         node: Node object to read from
108         propname: property name to read
109         default: Default value to use if the node/property do not exist
110
111     Returns:
112         Integer value read, or default if none
113     """
114     prop = node.props.get(propname)
115     if not prop:
116         return default
117     if isinstance(prop.value, list):
118         raise ValueError("Node '%s' property '%s' has list value: expecting "
119                          "a single integer" % (node.name, propname))
120     value = fdt32_to_cpu(prop.value)
121     return value
122
123 def GetInt64(node, propname, default=None):
124     """Get a 64-bit integer from a property
125
126     Args:
127         node (Node): Node object to read from
128         propname (str): property name to read
129         default (int): Default value to use if the node/property do not exist
130
131     Returns:
132         int: value read, or default if none
133
134     Raises:
135         ValueError: Property is not of the correct size
136     """
137     prop = node.props.get(propname)
138     if not prop:
139         return default
140     if not isinstance(prop.value, list) or len(prop.value) != 2:
141         raise ValueError("Node '%s' property '%s' should be a list with 2 items for 64-bit values" %
142                          (node.name, propname))
143     value = fdt64_to_cpu(prop.value)
144     return value
145
146 def GetString(node, propname, default=None):
147     """Get a string from a property
148
149     Args:
150         node: Node object to read from
151         propname: property name to read
152         default: Default value to use if the node/property do not exist
153
154     Returns:
155         String value read, or default if none
156     """
157     prop = node.props.get(propname)
158     if not prop:
159         return default
160     value = prop.value
161     if not prop.bytes:
162         return ''
163     if isinstance(value, list):
164         raise ValueError("Node '%s' property '%s' has list value: expecting "
165                          "a single string" % (node.name, propname))
166     return value
167
168 def GetStringList(node, propname, default=None):
169     """Get a string list from a property
170
171     Args:
172         node (Node): Node object to read from
173         propname (str): property name to read
174         default (list of str): Default value to use if the node/property do not
175             exist, or None
176
177     Returns:
178         String value read, or default if none
179     """
180     prop = node.props.get(propname)
181     if not prop:
182         return default
183     value = prop.value
184     if not prop.bytes:
185         return []
186     if not isinstance(value, list):
187         strval = GetString(node, propname)
188         return [strval]
189     return value
190
191 def GetArgs(node, propname):
192     prop = node.props.get(propname)
193     if not prop:
194         raise ValueError(f"Node '{node.path}': Expected property '{propname}'")
195     if prop.bytes:
196         value = GetStringList(node, propname)
197     else:
198         value = []
199     if not value:
200         args = []
201     elif len(value) == 1:
202         args = value[0].split()
203     else:
204         args = value
205     return args
206
207 def GetBool(node, propname, default=False):
208     """Get an boolean from a property
209
210     Args:
211         node: Node object to read from
212         propname: property name to read
213         default: Default value to use if the node/property do not exist
214
215     Returns:
216         Boolean value read, or default if none (if you set this to True the
217             function will always return True)
218     """
219     if propname in node.props:
220         return True
221     return default
222
223 def GetByte(node, propname, default=None):
224     """Get an byte from a property
225
226     Args:
227         node: Node object to read from
228         propname: property name to read
229         default: Default value to use if the node/property do not exist
230
231     Returns:
232         Byte value read, or default if none
233     """
234     prop = node.props.get(propname)
235     if not prop:
236         return default
237     value = prop.value
238     if isinstance(value, list):
239         raise ValueError("Node '%s' property '%s' has list value: expecting "
240                          "a single byte" % (node.name, propname))
241     if len(value) != 1:
242         raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
243                          (node.name, propname, len(value), 1))
244     return ord(value[0])
245
246 def GetBytes(node, propname, size, default=None):
247     """Get a set of bytes from a property
248
249     Args:
250         node (Node): Node object to read from
251         propname (str): property name to read
252         size (int): Number of bytes to expect
253         default (bytes): Default value or None
254
255     Returns:
256         bytes: Bytes value read, or default if none
257     """
258     prop = node.props.get(propname)
259     if not prop:
260         return default
261     if len(prop.bytes) != size:
262         raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
263                          (node.name, propname, len(prop.bytes), size))
264     return prop.bytes
265
266 def GetPhandleList(node, propname):
267     """Get a list of phandles from a property
268
269     Args:
270         node: Node object to read from
271         propname: property name to read
272
273     Returns:
274         List of phandles read, each an integer
275     """
276     prop = node.props.get(propname)
277     if not prop:
278         return None
279     value = prop.value
280     if not isinstance(value, list):
281         value = [value]
282     return [fdt32_to_cpu(v) for v in value]
283
284 def GetDatatype(node, propname, datatype):
285     """Get a value of a given type from a property
286
287     Args:
288         node: Node object to read from
289         propname: property name to read
290         datatype: Type to read (str or int)
291
292     Returns:
293         value read, or None if none
294
295     Raises:
296         ValueError if datatype is not str or int
297     """
298     if datatype == str:
299         return GetString(node, propname)
300     elif datatype == int:
301         return GetInt(node, propname)
302     raise ValueError("fdt_util internal error: Unknown data type '%s'" %
303                      datatype)