blob: f1f70568cfef4e8fe268180f95371bb413e52eb1 [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
Simon Glassb8d2daa2019-07-20 12:23:49 -060058def EnsureCompiled(fname, tmpdir=None, capture_stderr=False):
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
Simon Glassefc9bf62016-07-25 18:59:10 -060066
67 Returns:
68 Filename of resulting .dtb file
69 """
70 _, ext = os.path.splitext(fname)
71 if ext != '.dts':
72 return fname
73
Simon Glassb8d2daa2019-07-20 12:23:49 -060074 if tmpdir:
75 dts_input = os.path.join(tmpdir, 'source.dts')
76 dtb_output = os.path.join(tmpdir, 'source.dtb')
77 else:
Simon Glass80025522022-01-29 14:14:04 -070078 dts_input = tools.get_output_filename('source.dts')
79 dtb_output = tools.get_output_filename('source.dtb')
Simon Glassefc9bf62016-07-25 18:59:10 -060080
81 search_paths = [os.path.join(os.getcwd(), 'include')]
82 root, _ = os.path.splitext(fname)
Simon Glass80025522022-01-29 14:14:04 -070083 cc, args = tools.get_target_compile_tool('cc')
Alper Nebi Yasak5cd321d2020-09-06 14:46:05 +030084 args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
Simon Glassefc9bf62016-07-25 18:59:10 -060085 args += ['-Ulinux']
86 for path in search_paths:
87 args.extend(['-I', path])
88 args += ['-o', dts_input, fname]
Simon Glass840be732022-01-29 14:14:05 -070089 command.run(cc, *args)
Simon Glassefc9bf62016-07-25 18:59:10 -060090
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])
Simon Glass80025522022-01-29 14:14:04 -070095 dtc, args = tools.get_target_compile_tool('dtc')
Alper Nebi Yasak5cd321d2020-09-06 14:46:05 +030096 args += ['-I', 'dts', '-o', dtb_output, '-O', 'dtb',
Simon Glassc5c7b1a2017-11-12 21:52:09 -070097 '-W', 'no-unit_address_vs_reg']
Simon Glassefc9bf62016-07-25 18:59:10 -060098 args.extend(search_list)
99 args.append(dts_input)
Simon Glass840be732022-01-29 14:14:05 -0700100 command.run(dtc, *args, capture_stderr=capture_stderr)
Simon Glassefc9bf62016-07-25 18:59:10 -0600101 return dtb_output
Simon Glass4066b312016-07-25 18:59:18 -0600102
103def GetInt(node, propname, default=None):
Simon Glassfe599c72018-07-17 13:25:31 -0600104 """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 """
Simon Glass4066b312016-07-25 18:59:18 -0600114 prop = node.props.get(propname)
115 if not prop:
116 return default
Simon Glass9c526332018-07-06 10:27:28 -0600117 if isinstance(prop.value, list):
118 raise ValueError("Node '%s' property '%s' has list value: expecting "
Simon Glass4066b312016-07-25 18:59:18 -0600119 "a single integer" % (node.name, propname))
Simon Glass9c526332018-07-06 10:27:28 -0600120 value = fdt32_to_cpu(prop.value)
Simon Glass4066b312016-07-25 18:59:18 -0600121 return value
122
Simon Glass3b55e3f2021-11-23 11:03:39 -0700123def 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
Simon Glass4066b312016-07-25 18:59:18 -0600146def GetString(node, propname, default=None):
Simon Glassfe599c72018-07-17 13:25:31 -0600147 """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 """
Simon Glass4066b312016-07-25 18:59:18 -0600157 prop = node.props.get(propname)
158 if not prop:
159 return default
160 value = prop.value
Simon Glass120fa002022-03-05 20:18:56 -0700161 if not prop.bytes:
162 return ''
Simon Glass9c526332018-07-06 10:27:28 -0600163 if isinstance(value, list):
164 raise ValueError("Node '%s' property '%s' has list value: expecting "
Simon Glass4066b312016-07-25 18:59:18 -0600165 "a single string" % (node.name, propname))
166 return value
167
Simon Glassb2e88612021-11-23 21:09:51 -0700168def 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
Simon Glass120fa002022-03-05 20:18:56 -0700184 if not prop.bytes:
185 return []
Simon Glassb2e88612021-11-23 21:09:51 -0700186 if not isinstance(value, list):
187 strval = GetString(node, propname)
188 return [strval]
189 return value
190
Simon Glass738a54d2022-02-08 11:49:53 -0700191def 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 = []
Simon Glassc6b3cdc2022-03-05 20:18:52 -0700199 if not value:
200 args = []
201 elif len(value) == 1:
202 args = value[0].split()
203 else:
204 args = value
Simon Glass738a54d2022-02-08 11:49:53 -0700205 return args
206
Simon Glass4066b312016-07-25 18:59:18 -0600207def GetBool(node, propname, default=False):
Simon Glassfe599c72018-07-17 13:25:31 -0600208 """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 """
Simon Glass4066b312016-07-25 18:59:18 -0600219 if propname in node.props:
220 return True
221 return default
Simon Glass91710b32018-07-17 13:25:32 -0600222
Simon Glass53f53992018-07-17 13:25:40 -0600223def 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
Simon Glass0e055bf2021-11-23 11:03:40 -0700246def 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
Simon Glasse2d65282018-07-17 13:25:46 -0600266def 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
Simon Glasse8cea0e2023-01-11 16:10:18 -0700284def 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
Simon Glass91710b32018-07-17 13:25:32 -0600312def 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)