dtoc: Add support for reading 64-bit ints
[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 GetBool(node, propname, default=False):
167     """Get an boolean from a property
168
169     Args:
170         node: Node object to read from
171         propname: property name to read
172         default: Default value to use if the node/property do not exist
173
174     Returns:
175         Boolean value read, or default if none (if you set this to True the
176             function will always return True)
177     """
178     if propname in node.props:
179         return True
180     return default
181
182 def GetByte(node, propname, default=None):
183     """Get an byte from a property
184
185     Args:
186         node: Node object to read from
187         propname: property name to read
188         default: Default value to use if the node/property do not exist
189
190     Returns:
191         Byte value read, or default if none
192     """
193     prop = node.props.get(propname)
194     if not prop:
195         return default
196     value = prop.value
197     if isinstance(value, list):
198         raise ValueError("Node '%s' property '%s' has list value: expecting "
199                          "a single byte" % (node.name, propname))
200     if len(value) != 1:
201         raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
202                          (node.name, propname, len(value), 1))
203     return ord(value[0])
204
205 def GetPhandleList(node, propname):
206     """Get a list of phandles from a property
207
208     Args:
209         node: Node object to read from
210         propname: property name to read
211
212     Returns:
213         List of phandles read, each an integer
214     """
215     prop = node.props.get(propname)
216     if not prop:
217         return None
218     value = prop.value
219     if not isinstance(value, list):
220         value = [value]
221     return [fdt32_to_cpu(v) for v in value]
222
223 def GetDatatype(node, propname, datatype):
224     """Get a value of a given type from a property
225
226     Args:
227         node: Node object to read from
228         propname: property name to read
229         datatype: Type to read (str or int)
230
231     Returns:
232         value read, or None if none
233
234     Raises:
235         ValueError if datatype is not str or int
236     """
237     if datatype == str:
238         return GetString(node, propname)
239     elif datatype == int:
240         return GetInt(node, propname)
241     raise ValueError("fdt_util internal error: Unknown data type '%s'" %
242                      datatype)