blob: c82e7747aa3d1b259b478f7b947a212c44b48a4d [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 = []
195 lists = [v.split() for v in value]
196 args = [x for l in lists for x in l]
197 return args
198
Simon Glass8f224b32016-07-25 18:59:18 -0600199def GetBool(node, propname, default=False):
Simon Glassdc08ecc2018-07-17 13:25:31 -0600200 """Get an boolean from a property
201
202 Args:
203 node: Node object to read from
204 propname: property name to read
205 default: Default value to use if the node/property do not exist
206
207 Returns:
208 Boolean value read, or default if none (if you set this to True the
209 function will always return True)
210 """
Simon Glass8f224b32016-07-25 18:59:18 -0600211 if propname in node.props:
212 return True
213 return default
Simon Glass53af22a2018-07-17 13:25:32 -0600214
Simon Glass3af8e492018-07-17 13:25:40 -0600215def GetByte(node, propname, default=None):
216 """Get an byte from a property
217
218 Args:
219 node: Node object to read from
220 propname: property name to read
221 default: Default value to use if the node/property do not exist
222
223 Returns:
224 Byte value read, or default if none
225 """
226 prop = node.props.get(propname)
227 if not prop:
228 return default
229 value = prop.value
230 if isinstance(value, list):
231 raise ValueError("Node '%s' property '%s' has list value: expecting "
232 "a single byte" % (node.name, propname))
233 if len(value) != 1:
234 raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
235 (node.name, propname, len(value), 1))
236 return ord(value[0])
237
Simon Glass40b4d642021-11-23 11:03:40 -0700238def GetBytes(node, propname, size, default=None):
239 """Get a set of bytes from a property
240
241 Args:
242 node (Node): Node object to read from
243 propname (str): property name to read
244 size (int): Number of bytes to expect
245 default (bytes): Default value or None
246
247 Returns:
248 bytes: Bytes value read, or default if none
249 """
250 prop = node.props.get(propname)
251 if not prop:
252 return default
253 if len(prop.bytes) != size:
254 raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
255 (node.name, propname, len(prop.bytes), size))
256 return prop.bytes
257
Simon Glass94a7c602018-07-17 13:25:46 -0600258def GetPhandleList(node, propname):
259 """Get a list of phandles from a property
260
261 Args:
262 node: Node object to read from
263 propname: property name to read
264
265 Returns:
266 List of phandles read, each an integer
267 """
268 prop = node.props.get(propname)
269 if not prop:
270 return None
271 value = prop.value
272 if not isinstance(value, list):
273 value = [value]
274 return [fdt32_to_cpu(v) for v in value]
275
Simon Glass53af22a2018-07-17 13:25:32 -0600276def GetDatatype(node, propname, datatype):
277 """Get a value of a given type from a property
278
279 Args:
280 node: Node object to read from
281 propname: property name to read
282 datatype: Type to read (str or int)
283
284 Returns:
285 value read, or None if none
286
287 Raises:
288 ValueError if datatype is not str or int
289 """
290 if datatype == str:
291 return GetString(node, propname)
292 elif datatype == int:
293 return GetInt(node, propname)
294 raise ValueError("fdt_util internal error: Unknown data type '%s'" %
295 datatype)