Merge tag 'v2022.01-rc4' into next
[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 patman import command
17 from patman 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.GetOutputFilename('source.dts')
79         dtb_output = tools.GetOutputFilename('source.dtb')
80
81     search_paths = [os.path.join(os.getcwd(), 'include')]
82     root, _ = os.path.splitext(fname)
83     cc, args = tools.GetTargetCompileTool('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.GetTargetCompileTool('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 isinstance(value, list):
162         raise ValueError("Node '%s' property '%s' has list value: expecting "
163                          "a single string" % (node.name, propname))
164     return value
165
166 def 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
187 def GetBool(node, propname, default=False):
188     """Get an boolean from a property
189
190     Args:
191         node: Node object to read from
192         propname: property name to read
193         default: Default value to use if the node/property do not exist
194
195     Returns:
196         Boolean value read, or default if none (if you set this to True the
197             function will always return True)
198     """
199     if propname in node.props:
200         return True
201     return default
202
203 def GetByte(node, propname, default=None):
204     """Get an byte 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         Byte value read, or default if none
213     """
214     prop = node.props.get(propname)
215     if not prop:
216         return default
217     value = prop.value
218     if isinstance(value, list):
219         raise ValueError("Node '%s' property '%s' has list value: expecting "
220                          "a single byte" % (node.name, propname))
221     if len(value) != 1:
222         raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
223                          (node.name, propname, len(value), 1))
224     return ord(value[0])
225
226 def GetBytes(node, propname, size, default=None):
227     """Get a set of bytes from a property
228
229     Args:
230         node (Node): Node object to read from
231         propname (str): property name to read
232         size (int): Number of bytes to expect
233         default (bytes): Default value or None
234
235     Returns:
236         bytes: Bytes value read, or default if none
237     """
238     prop = node.props.get(propname)
239     if not prop:
240         return default
241     if len(prop.bytes) != size:
242         raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
243                          (node.name, propname, len(prop.bytes), size))
244     return prop.bytes
245
246 def GetPhandleList(node, propname):
247     """Get a list of phandles from a property
248
249     Args:
250         node: Node object to read from
251         propname: property name to read
252
253     Returns:
254         List of phandles read, each an integer
255     """
256     prop = node.props.get(propname)
257     if not prop:
258         return None
259     value = prop.value
260     if not isinstance(value, list):
261         value = [value]
262     return [fdt32_to_cpu(v) for v in value]
263
264 def GetDatatype(node, propname, datatype):
265     """Get a value of a given type from a property
266
267     Args:
268         node: Node object to read from
269         propname: property name to read
270         datatype: Type to read (str or int)
271
272     Returns:
273         value read, or None if none
274
275     Raises:
276         ValueError if datatype is not str or int
277     """
278     if datatype == str:
279         return GetString(node, propname)
280     elif datatype == int:
281         return GetInt(node, propname)
282     raise ValueError("fdt_util internal error: Unknown data type '%s'" %
283                      datatype)