dtoc: Update fdt_util for Python 3
[oweals/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 import command
17 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 fdt_cells_to_cpu(val, cells):
31     """Convert one or two cells to a long integer
32
33     Args:
34         Value to convert (array of one or more 4-character strings)
35
36     Return:
37         A native-endian integer value
38     """
39     if not cells:
40         return 0
41     out = int(fdt32_to_cpu(val[0]))
42     if cells == 2:
43         out = out << 32 | fdt32_to_cpu(val[1])
44     return out
45
46 def EnsureCompiled(fname, capture_stderr=False):
47     """Compile an fdt .dts source file into a .dtb binary blob if needed.
48
49     Args:
50         fname: Filename (if .dts it will be compiled). It not it will be
51             left alone
52
53     Returns:
54         Filename of resulting .dtb file
55     """
56     _, ext = os.path.splitext(fname)
57     if ext != '.dts':
58         return fname
59
60     dts_input = tools.GetOutputFilename('source.dts')
61     dtb_output = tools.GetOutputFilename('source.dtb')
62
63     search_paths = [os.path.join(os.getcwd(), 'include')]
64     root, _ = os.path.splitext(fname)
65     args = ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
66     args += ['-Ulinux']
67     for path in search_paths:
68         args.extend(['-I', path])
69     args += ['-o', dts_input, fname]
70     command.Run('cc', *args)
71
72     # If we don't have a directory, put it in the tools tempdir
73     search_list = []
74     for path in search_paths:
75         search_list.extend(['-i', path])
76     args = ['-I', 'dts', '-o', dtb_output, '-O', 'dtb',
77             '-W', 'no-unit_address_vs_reg']
78     args.extend(search_list)
79     args.append(dts_input)
80     dtc = os.environ.get('DTC') or 'dtc'
81     command.Run(dtc, *args, capture_stderr=capture_stderr)
82     return dtb_output
83
84 def GetInt(node, propname, default=None):
85     """Get an integer from a property
86
87     Args:
88         node: Node object to read from
89         propname: property name to read
90         default: Default value to use if the node/property do not exist
91
92     Returns:
93         Integer value read, or default if none
94     """
95     prop = node.props.get(propname)
96     if not prop:
97         return default
98     if isinstance(prop.value, list):
99         raise ValueError("Node '%s' property '%s' has list value: expecting "
100                          "a single integer" % (node.name, propname))
101     value = fdt32_to_cpu(prop.value)
102     return value
103
104 def GetString(node, propname, default=None):
105     """Get a string from a property
106
107     Args:
108         node: Node object to read from
109         propname: property name to read
110         default: Default value to use if the node/property do not exist
111
112     Returns:
113         String value read, or default if none
114     """
115     prop = node.props.get(propname)
116     if not prop:
117         return default
118     value = prop.value
119     if isinstance(value, list):
120         raise ValueError("Node '%s' property '%s' has list value: expecting "
121                          "a single string" % (node.name, propname))
122     return value
123
124 def GetBool(node, propname, default=False):
125     """Get an boolean from a property
126
127     Args:
128         node: Node object to read from
129         propname: property name to read
130         default: Default value to use if the node/property do not exist
131
132     Returns:
133         Boolean value read, or default if none (if you set this to True the
134             function will always return True)
135     """
136     if propname in node.props:
137         return True
138     return default
139
140 def GetByte(node, propname, default=None):
141     """Get an byte from a property
142
143     Args:
144         node: Node object to read from
145         propname: property name to read
146         default: Default value to use if the node/property do not exist
147
148     Returns:
149         Byte value read, or default if none
150     """
151     prop = node.props.get(propname)
152     if not prop:
153         return default
154     value = prop.value
155     if isinstance(value, list):
156         raise ValueError("Node '%s' property '%s' has list value: expecting "
157                          "a single byte" % (node.name, propname))
158     if len(value) != 1:
159         raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
160                          (node.name, propname, len(value), 1))
161     return ord(value[0])
162
163 def GetPhandleList(node, propname):
164     """Get a list of phandles from a property
165
166     Args:
167         node: Node object to read from
168         propname: property name to read
169
170     Returns:
171         List of phandles read, each an integer
172     """
173     prop = node.props.get(propname)
174     if not prop:
175         return None
176     value = prop.value
177     if not isinstance(value, list):
178         value = [value]
179     return [fdt32_to_cpu(v) for v in value]
180
181 def GetDatatype(node, propname, datatype):
182     """Get a value of a given type from a property
183
184     Args:
185         node: Node object to read from
186         propname: property name to read
187         datatype: Type to read (str or int)
188
189     Returns:
190         value read, or None if none
191
192     Raises:
193         ValueError if datatype is not str or int
194     """
195     if datatype == str:
196         return GetString(node, propname)
197     elif datatype == int:
198         return GetInt(node, propname)
199     raise ValueError("fdt_util internal error: Unknown data type '%s'" %
200                      datatype)