blob: 57550624bbf27d3a0527981b4b314371a8e8713f [file] [log] [blame]
Simon Glassec564b42016-07-04 11:58:08 -06001#!/usr/bin/python
Tom Rini83d290c2018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glassec564b42016-07-04 11:58:08 -06003#
4# Copyright (C) 2016 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
Simon Glassec564b42016-07-04 11:58:08 -06007
Simon Glassdc08ecc2018-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 Glass355c67c2016-07-25 18:59:10 -060011import os
Simon Glassec564b42016-07-04 11:58:08 -060012import struct
Paul Burtonc4c5f9e2016-09-27 16:03:57 +010013import sys
Simon Glass355c67c2016-07-25 18:59:10 -060014import tempfile
15
Simon Glassbf776672020-04-17 18:09:04 -060016from patman import command
17from patman import tools
Simon Glassec564b42016-07-04 11:58:08 -060018
Simon Glassec564b42016-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 Glass20024da2016-07-25 18:59:17 -060028 return struct.unpack('>I', val)[0]
Simon Glass355c67c2016-07-25 18:59:10 -060029
Simon Glassd866e622021-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 Glassfbdfd222017-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 Glass209a5592019-05-17 22:00:42 -060049 A native-endian integer value
Simon Glassfbdfd222017-08-29 14:15:48 -060050 """
Simon Glassc20ee0e2017-08-29 14:15:50 -060051 if not cells:
52 return 0
Simon Glass209a5592019-05-17 22:00:42 -060053 out = int(fdt32_to_cpu(val[0]))
Simon Glassfbdfd222017-08-29 14:15:48 -060054 if cells == 2:
55 out = out << 32 | fdt32_to_cpu(val[1])
56 return out
57
Simon Glassa004f292019-07-20 12:23:49 -060058def EnsureCompiled(fname, tmpdir=None, capture_stderr=False):
Simon Glass355c67c2016-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 Glassa004f292019-07-20 12:23:49 -060064 tmpdir: Temporary directory for output files, or None to use the
65 tools-module output directory
Simon Glass355c67c2016-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 Glassa004f292019-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 Glassc1aa66e2022-01-29 14:14:04 -070078 dts_input = tools.get_output_filename('source.dts')
79 dtb_output = tools.get_output_filename('source.dtb')
Simon Glass355c67c2016-07-25 18:59:10 -060080
81 search_paths = [os.path.join(os.getcwd(), 'include')]
82 root, _ = os.path.splitext(fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -070083 cc, args = tools.get_target_compile_tool('cc')
Alper Nebi Yasak1e4687a2020-09-06 14:46:05 +030084 args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
Simon Glass355c67c2016-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 Glassd9800692022-01-29 14:14:05 -070089 command.run(cc, *args)
Simon Glass355c67c2016-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 Glassc1aa66e2022-01-29 14:14:04 -070095 dtc, args = tools.get_target_compile_tool('dtc')
Alper Nebi Yasak1e4687a2020-09-06 14:46:05 +030096 args += ['-I', 'dts', '-o', dtb_output, '-O', 'dtb',
Simon Glassd09682e2017-11-12 21:52:09 -070097 '-W', 'no-unit_address_vs_reg']
Simon Glass355c67c2016-07-25 18:59:10 -060098 args.extend(search_list)
99 args.append(dts_input)
Simon Glassd9800692022-01-29 14:14:05 -0700100 command.run(dtc, *args, capture_stderr=capture_stderr)
Simon Glass355c67c2016-07-25 18:59:10 -0600101 return dtb_output
Simon Glass8f224b32016-07-25 18:59:18 -0600102
103def GetInt(node, propname, default=None):
Simon Glassdc08ecc2018-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 Glass8f224b32016-07-25 18:59:18 -0600114 prop = node.props.get(propname)
115 if not prop:
116 return default
Simon Glass2a2d91d2018-07-06 10:27:28 -0600117 if isinstance(prop.value, list):
118 raise ValueError("Node '%s' property '%s' has list value: expecting "
Simon Glass8f224b32016-07-25 18:59:18 -0600119 "a single integer" % (node.name, propname))
Simon Glass2a2d91d2018-07-06 10:27:28 -0600120 value = fdt32_to_cpu(prop.value)
Simon Glass8f224b32016-07-25 18:59:18 -0600121 return value
122
Simon Glassd866e622021-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 Glass8f224b32016-07-25 18:59:18 -0600146def GetString(node, propname, default=None):
Simon Glassdc08ecc2018-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 Glass8f224b32016-07-25 18:59:18 -0600157 prop = node.props.get(propname)
158 if not prop:
159 return default
160 value = prop.value
Simon Glass2a2d91d2018-07-06 10:27:28 -0600161 if isinstance(value, list):
162 raise ValueError("Node '%s' property '%s' has list value: expecting "
Simon Glass8f224b32016-07-25 18:59:18 -0600163 "a single string" % (node.name, propname))
164 return value
165
Simon Glass1b5a5332021-11-23 21:09:51 -0700166def GetStringList(node, propname, default=None):
167 """Get a string list from a property
168
169 Args:
170 node (Node): Node object to read from
171 propname (str): property name to read
172 default (list of str): Default value to use if the node/property do not
173 exist, or None
174
175 Returns:
176 String value read, or default if none
177 """
178 prop = node.props.get(propname)
179 if not prop:
180 return default
181 value = prop.value
182 if not isinstance(value, list):
183 strval = GetString(node, propname)
184 return [strval]
185 return value
186
Simon Glass7e4b66a2022-02-08 11:49:53 -0700187def GetArgs(node, propname):
188 prop = node.props.get(propname)
189 if not prop:
190 raise ValueError(f"Node '{node.path}': Expected property '{propname}'")
191 if prop.bytes:
192 value = GetStringList(node, propname)
193 else:
194 value = []
Simon Glass61012532022-03-05 20:18:52 -0700195 if not value:
196 args = []
197 elif len(value) == 1:
198 args = value[0].split()
199 else:
200 args = value
Simon Glass7e4b66a2022-02-08 11:49:53 -0700201 return args
202
Simon Glass8f224b32016-07-25 18:59:18 -0600203def GetBool(node, propname, default=False):
Simon Glassdc08ecc2018-07-17 13:25:31 -0600204 """Get an boolean from a property
205
206 Args:
207 node: Node object to read from
208 propname: property name to read
209 default: Default value to use if the node/property do not exist
210
211 Returns:
212 Boolean value read, or default if none (if you set this to True the
213 function will always return True)
214 """
Simon Glass8f224b32016-07-25 18:59:18 -0600215 if propname in node.props:
216 return True
217 return default
Simon Glass53af22a2018-07-17 13:25:32 -0600218
Simon Glass3af8e492018-07-17 13:25:40 -0600219def GetByte(node, propname, default=None):
220 """Get an byte from a property
221
222 Args:
223 node: Node object to read from
224 propname: property name to read
225 default: Default value to use if the node/property do not exist
226
227 Returns:
228 Byte value read, or default if none
229 """
230 prop = node.props.get(propname)
231 if not prop:
232 return default
233 value = prop.value
234 if isinstance(value, list):
235 raise ValueError("Node '%s' property '%s' has list value: expecting "
236 "a single byte" % (node.name, propname))
237 if len(value) != 1:
238 raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
239 (node.name, propname, len(value), 1))
240 return ord(value[0])
241
Simon Glass40b4d642021-11-23 11:03:40 -0700242def GetBytes(node, propname, size, default=None):
243 """Get a set of bytes from a property
244
245 Args:
246 node (Node): Node object to read from
247 propname (str): property name to read
248 size (int): Number of bytes to expect
249 default (bytes): Default value or None
250
251 Returns:
252 bytes: Bytes value read, or default if none
253 """
254 prop = node.props.get(propname)
255 if not prop:
256 return default
257 if len(prop.bytes) != size:
258 raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
259 (node.name, propname, len(prop.bytes), size))
260 return prop.bytes
261
Simon Glass94a7c602018-07-17 13:25:46 -0600262def GetPhandleList(node, propname):
263 """Get a list of phandles from a property
264
265 Args:
266 node: Node object to read from
267 propname: property name to read
268
269 Returns:
270 List of phandles read, each an integer
271 """
272 prop = node.props.get(propname)
273 if not prop:
274 return None
275 value = prop.value
276 if not isinstance(value, list):
277 value = [value]
278 return [fdt32_to_cpu(v) for v in value]
279
Simon Glass53af22a2018-07-17 13:25:32 -0600280def GetDatatype(node, propname, datatype):
281 """Get a value of a given type from a property
282
283 Args:
284 node: Node object to read from
285 propname: property name to read
286 datatype: Type to read (str or int)
287
288 Returns:
289 value read, or None if none
290
291 Raises:
292 ValueError if datatype is not str or int
293 """
294 if datatype == str:
295 return GetString(node, propname)
296 elif datatype == int:
297 return GetInt(node, propname)
298 raise ValueError("fdt_util internal error: Unknown data type '%s'" %
299 datatype)