Prepare v2023.10
[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 u_boot_pylib import command
17 from u_boot_pylib 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 GetPhandleNameOffset(node, propname):
285     """Get a <&phandle>, "string", <offset> value from a property
286
287     Args:
288         node: Node object to read from
289         propname: property name to read
290
291     Returns:
292         tuple:
293             Node object
294             str
295             int
296         or None if the property does not exist
297     """
298     prop = node.props.get(propname)
299     if not prop:
300         return None
301     value = prop.bytes
302     phandle = fdt32_to_cpu(value[:4])
303     node = node.GetFdt().LookupPhandle(phandle)
304     name = ''
305     for byte in value[4:]:
306         if not byte:
307             break
308         name += chr(byte)
309     val = fdt32_to_cpu(value[4 + len(name) + 1:])
310     return node, name, val
311
312 def GetDatatype(node, propname, datatype):
313     """Get a value of a given type from a property
314
315     Args:
316         node: Node object to read from
317         propname: property name to read
318         datatype: Type to read (str or int)
319
320     Returns:
321         value read, or None if none
322
323     Raises:
324         ValueError if datatype is not str or int
325     """
326     if datatype == str:
327         return GetString(node, propname)
328     elif datatype == int:
329         return GetInt(node, propname)
330     raise ValueError("fdt_util internal error: Unknown data type '%s'" %
331                      datatype)