blob: d5ecc4207d85b850e807e0922d005b3cec4a14da [file] [log] [blame]
Simon Glassfa8974d2016-07-04 11:58:08 -06001#!/usr/bin/python
Tom Rini10e47792018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glassfa8974d2016-07-04 11:58:08 -06003#
4# Copyright (C) 2016 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
Simon Glassfa8974d2016-07-04 11:58:08 -06007
Simon Glassfe599c72018-07-17 13:25:31 -06008# 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
Simon Glassefc9bf62016-07-25 18:59:10 -060011import os
Simon Glassfa8974d2016-07-04 11:58:08 -060012import struct
Paul Burton307f1fa2016-09-27 16:03:57 +010013import sys
Simon Glassefc9bf62016-07-25 18:59:10 -060014import tempfile
15
Simon Glass131444f2023-02-23 18:18:04 -070016from u_boot_pylib import command
17from u_boot_pylib import tools
Simon Glassfa8974d2016-07-04 11:58:08 -060018
Simon Glassfa8974d2016-07-04 11:58:08 -060019def 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 """
Simon Glass29462c32016-07-25 18:59:17 -060028 return struct.unpack('>I', val)[0]
Simon Glassefc9bf62016-07-25 18:59:10 -060029
Simon Glass3b55e3f2021-11-23 11:03:39 -070030def 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
Simon Glassfc3ae9c2017-08-29 14:15:48 -060042def 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:
Simon Glassc69b4502019-05-17 22:00:42 -060049 A native-endian integer value
Simon Glassfc3ae9c2017-08-29 14:15:48 -060050 """
Simon Glass1b1fe412017-08-29 14:15:50 -060051 if not cells:
52 return 0
Simon Glassc69b4502019-05-17 22:00:42 -060053 out = int(fdt32_to_cpu(val[0]))
Simon Glassfc3ae9c2017-08-29 14:15:48 -060054 if cells == 2:
55 out = out << 32 | fdt32_to_cpu(val[1])
56 return out
57
Paul HENRYS8d222d32024-11-25 18:51:10 +010058def EnsureCompiled(fname, tmpdir=None, capture_stderr=False, indir=None):
Simon Glassefc9bf62016-07-25 18:59:10 -060059 """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
Simon Glassb8d2daa2019-07-20 12:23:49 -060064 tmpdir: Temporary directory for output files, or None to use the
65 tools-module output directory
Paul HENRYS8d222d32024-11-25 18:51:10 +010066 indir: List of directories where input files can be found
Simon Glassefc9bf62016-07-25 18:59:10 -060067
68 Returns:
69 Filename of resulting .dtb file
70 """
71 _, ext = os.path.splitext(fname)
72 if ext != '.dts':
73 return fname
74
Simon Glassb8d2daa2019-07-20 12:23:49 -060075 if tmpdir:
76 dts_input = os.path.join(tmpdir, 'source.dts')
77 dtb_output = os.path.join(tmpdir, 'source.dtb')
78 else:
Simon Glass80025522022-01-29 14:14:04 -070079 dts_input = tools.get_output_filename('source.dts')
80 dtb_output = tools.get_output_filename('source.dtb')
Simon Glassefc9bf62016-07-25 18:59:10 -060081
82 search_paths = [os.path.join(os.getcwd(), 'include')]
Paul HENRYS8d222d32024-11-25 18:51:10 +010083 if indir is not None:
84 search_paths += indir
Simon Glassefc9bf62016-07-25 18:59:10 -060085 root, _ = os.path.splitext(fname)
Simon Glass80025522022-01-29 14:14:04 -070086 cc, args = tools.get_target_compile_tool('cc')
Alper Nebi Yasak5cd321d2020-09-06 14:46:05 +030087 args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
Simon Glassefc9bf62016-07-25 18:59:10 -060088 args += ['-Ulinux']
89 for path in search_paths:
90 args.extend(['-I', path])
91 args += ['-o', dts_input, fname]
Simon Glass840be732022-01-29 14:14:05 -070092 command.run(cc, *args)
Simon Glassefc9bf62016-07-25 18:59:10 -060093
94 # If we don't have a directory, put it in the tools tempdir
95 search_list = []
96 for path in search_paths:
97 search_list.extend(['-i', path])
Simon Glass80025522022-01-29 14:14:04 -070098 dtc, args = tools.get_target_compile_tool('dtc')
Alper Nebi Yasak5cd321d2020-09-06 14:46:05 +030099 args += ['-I', 'dts', '-o', dtb_output, '-O', 'dtb',
Simon Glassc5c7b1a2017-11-12 21:52:09 -0700100 '-W', 'no-unit_address_vs_reg']
Simon Glassefc9bf62016-07-25 18:59:10 -0600101 args.extend(search_list)
102 args.append(dts_input)
Simon Glass840be732022-01-29 14:14:05 -0700103 command.run(dtc, *args, capture_stderr=capture_stderr)
Simon Glassefc9bf62016-07-25 18:59:10 -0600104 return dtb_output
Simon Glass4066b312016-07-25 18:59:18 -0600105
106def GetInt(node, propname, default=None):
Simon Glassfe599c72018-07-17 13:25:31 -0600107 """Get an integer from a property
108
109 Args:
110 node: Node object to read from
111 propname: property name to read
112 default: Default value to use if the node/property do not exist
113
114 Returns:
115 Integer value read, or default if none
116 """
Simon Glass4066b312016-07-25 18:59:18 -0600117 prop = node.props.get(propname)
118 if not prop:
119 return default
Simon Glass9c526332018-07-06 10:27:28 -0600120 if isinstance(prop.value, list):
121 raise ValueError("Node '%s' property '%s' has list value: expecting "
Simon Glass4066b312016-07-25 18:59:18 -0600122 "a single integer" % (node.name, propname))
Simon Glass9c526332018-07-06 10:27:28 -0600123 value = fdt32_to_cpu(prop.value)
Simon Glass4066b312016-07-25 18:59:18 -0600124 return value
125
Simon Glass3b55e3f2021-11-23 11:03:39 -0700126def GetInt64(node, propname, default=None):
127 """Get a 64-bit integer from a property
128
129 Args:
130 node (Node): Node object to read from
131 propname (str): property name to read
132 default (int): Default value to use if the node/property do not exist
133
134 Returns:
135 int: value read, or default if none
136
137 Raises:
138 ValueError: Property is not of the correct size
139 """
140 prop = node.props.get(propname)
141 if not prop:
142 return default
143 if not isinstance(prop.value, list) or len(prop.value) != 2:
144 raise ValueError("Node '%s' property '%s' should be a list with 2 items for 64-bit values" %
145 (node.name, propname))
146 value = fdt64_to_cpu(prop.value)
147 return value
148
Simon Glass4066b312016-07-25 18:59:18 -0600149def GetString(node, propname, default=None):
Simon Glassfe599c72018-07-17 13:25:31 -0600150 """Get a string from a property
151
152 Args:
153 node: Node object to read from
154 propname: property name to read
155 default: Default value to use if the node/property do not exist
156
157 Returns:
158 String value read, or default if none
159 """
Simon Glass4066b312016-07-25 18:59:18 -0600160 prop = node.props.get(propname)
161 if not prop:
162 return default
163 value = prop.value
Simon Glass120fa002022-03-05 20:18:56 -0700164 if not prop.bytes:
165 return ''
Simon Glass9c526332018-07-06 10:27:28 -0600166 if isinstance(value, list):
167 raise ValueError("Node '%s' property '%s' has list value: expecting "
Simon Glass4066b312016-07-25 18:59:18 -0600168 "a single string" % (node.name, propname))
169 return value
170
Simon Glassb2e88612021-11-23 21:09:51 -0700171def GetStringList(node, propname, default=None):
172 """Get a string list from a property
173
174 Args:
175 node (Node): Node object to read from
176 propname (str): property name to read
177 default (list of str): Default value to use if the node/property do not
178 exist, or None
179
180 Returns:
181 String value read, or default if none
182 """
183 prop = node.props.get(propname)
184 if not prop:
185 return default
186 value = prop.value
Simon Glass120fa002022-03-05 20:18:56 -0700187 if not prop.bytes:
188 return []
Simon Glassb2e88612021-11-23 21:09:51 -0700189 if not isinstance(value, list):
190 strval = GetString(node, propname)
191 return [strval]
192 return value
193
Simon Glass738a54d2022-02-08 11:49:53 -0700194def GetArgs(node, propname):
195 prop = node.props.get(propname)
196 if not prop:
197 raise ValueError(f"Node '{node.path}': Expected property '{propname}'")
198 if prop.bytes:
199 value = GetStringList(node, propname)
200 else:
201 value = []
Simon Glassc6b3cdc2022-03-05 20:18:52 -0700202 if not value:
203 args = []
204 elif len(value) == 1:
205 args = value[0].split()
206 else:
207 args = value
Simon Glass738a54d2022-02-08 11:49:53 -0700208 return args
209
Simon Glass4066b312016-07-25 18:59:18 -0600210def GetBool(node, propname, default=False):
Simon Glassfe599c72018-07-17 13:25:31 -0600211 """Get an boolean from a property
212
213 Args:
214 node: Node object to read from
215 propname: property name to read
216 default: Default value to use if the node/property do not exist
217
218 Returns:
219 Boolean value read, or default if none (if you set this to True the
220 function will always return True)
221 """
Simon Glass4066b312016-07-25 18:59:18 -0600222 if propname in node.props:
223 return True
224 return default
Simon Glass91710b32018-07-17 13:25:32 -0600225
Simon Glass53f53992018-07-17 13:25:40 -0600226def GetByte(node, propname, default=None):
227 """Get an byte from a property
228
229 Args:
230 node: Node object to read from
231 propname: property name to read
232 default: Default value to use if the node/property do not exist
233
234 Returns:
235 Byte value read, or default if none
236 """
237 prop = node.props.get(propname)
238 if not prop:
239 return default
240 value = prop.value
241 if isinstance(value, list):
242 raise ValueError("Node '%s' property '%s' has list value: expecting "
243 "a single byte" % (node.name, propname))
244 if len(value) != 1:
245 raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
246 (node.name, propname, len(value), 1))
247 return ord(value[0])
248
Simon Glass0e055bf2021-11-23 11:03:40 -0700249def GetBytes(node, propname, size, default=None):
250 """Get a set of bytes from a property
251
252 Args:
253 node (Node): Node object to read from
254 propname (str): property name to read
255 size (int): Number of bytes to expect
256 default (bytes): Default value or None
257
258 Returns:
259 bytes: Bytes value read, or default if none
260 """
261 prop = node.props.get(propname)
262 if not prop:
263 return default
264 if len(prop.bytes) != size:
265 raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
266 (node.name, propname, len(prop.bytes), size))
267 return prop.bytes
268
Simon Glasse2d65282018-07-17 13:25:46 -0600269def GetPhandleList(node, propname):
270 """Get a list of phandles from a property
271
272 Args:
273 node: Node object to read from
274 propname: property name to read
275
276 Returns:
277 List of phandles read, each an integer
278 """
279 prop = node.props.get(propname)
280 if not prop:
281 return None
282 value = prop.value
283 if not isinstance(value, list):
284 value = [value]
285 return [fdt32_to_cpu(v) for v in value]
286
Simon Glasse8cea0e2023-01-11 16:10:18 -0700287def GetPhandleNameOffset(node, propname):
288 """Get a <&phandle>, "string", <offset> value from a property
289
290 Args:
291 node: Node object to read from
292 propname: property name to read
293
294 Returns:
295 tuple:
296 Node object
297 str
298 int
299 or None if the property does not exist
300 """
301 prop = node.props.get(propname)
302 if not prop:
303 return None
304 value = prop.bytes
305 phandle = fdt32_to_cpu(value[:4])
306 node = node.GetFdt().LookupPhandle(phandle)
307 name = ''
308 for byte in value[4:]:
309 if not byte:
310 break
311 name += chr(byte)
312 val = fdt32_to_cpu(value[4 + len(name) + 1:])
313 return node, name, val
314
Simon Glass91710b32018-07-17 13:25:32 -0600315def GetDatatype(node, propname, datatype):
316 """Get a value of a given type from a property
317
318 Args:
319 node: Node object to read from
320 propname: property name to read
321 datatype: Type to read (str or int)
322
323 Returns:
324 value read, or None if none
325
326 Raises:
327 ValueError if datatype is not str or int
328 """
329 if datatype == str:
330 return GetString(node, propname)
331 elif datatype == int:
332 return GetInt(node, propname)
333 raise ValueError("fdt_util internal error: Unknown data type '%s'" %
334 datatype)