blob: b3d777e0c5e595269580d4bfafa6ffb7e2f76a12 [file] [log] [blame]
Simon Glass7581c012017-06-18 22:08:58 -06001#!/usr/bin/python
Tom Rini83d290c2018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glass7581c012017-06-18 22:08:58 -06003#
4# Copyright (C) 2017 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
Simon Glass7581c012017-06-18 22:08:58 -06007
Simon Glass2be282c2017-06-18 22:08:59 -06008"""Device tree to platform data class
9
10This supports converting device tree data to C structures definitions and
11static data.
Simon Glass9b330382020-11-08 20:36:21 -070012
13See doc/driver-model/of-plat.rst for more informaiton
Simon Glass2be282c2017-06-18 22:08:59 -060014"""
15
Simon Glass8fed2eb2017-08-29 14:15:55 -060016import collections
Simon Glass7581c012017-06-18 22:08:58 -060017import copy
Simon Glassbe44f272020-12-28 20:34:51 -070018from enum import IntEnum
Walter Lozanodac82282020-07-03 08:07:17 -030019import os
20import re
Simon Glass2be282c2017-06-18 22:08:59 -060021import sys
Simon Glass7581c012017-06-18 22:08:58 -060022
Simon Glassbf776672020-04-17 18:09:04 -060023from dtoc import fdt
24from dtoc import fdt_util
Simon Glass7581c012017-06-18 22:08:58 -060025
Simon Glass9b330382020-11-08 20:36:21 -070026# When we see these properties we ignore them - i.e. do not create a structure
27# member
Simon Glass7581c012017-06-18 22:08:58 -060028PROP_IGNORE_LIST = [
29 '#address-cells',
30 '#gpio-cells',
31 '#size-cells',
32 'compatible',
33 'linux,phandle',
34 "status",
35 'phandle',
36 'u-boot,dm-pre-reloc',
37 'u-boot,dm-tpl',
38 'u-boot,dm-spl',
39]
40
Simon Glass5ea9dcc2020-11-08 20:36:17 -070041# C type declarations for the types we support
Simon Glass7581c012017-06-18 22:08:58 -060042TYPE_NAMES = {
Simon Glass5ea9dcc2020-11-08 20:36:17 -070043 fdt.Type.INT: 'fdt32_t',
44 fdt.Type.BYTE: 'unsigned char',
45 fdt.Type.STRING: 'const char *',
46 fdt.Type.BOOL: 'bool',
47 fdt.Type.INT64: 'fdt64_t',
Simon Glass2be282c2017-06-18 22:08:59 -060048}
Simon Glass7581c012017-06-18 22:08:58 -060049
50STRUCT_PREFIX = 'dtd_'
51VAL_PREFIX = 'dtv_'
52
Simon Glassbe44f272020-12-28 20:34:51 -070053class Ftype(IntEnum):
54 SOURCE, HEADER = range(2)
55
56
57# This holds information about each type of output file dtoc can create
58# type: Type of file (Ftype)
Simon Glassd1055d62020-12-28 20:35:00 -070059# fname: Filename excluding directory, e.g. 'dt-plat.c'
60# hdr_comment: Comment explaining the purpose of the file
61OutputFile = collections.namedtuple('OutputFile',
62 ['ftype', 'fname', 'hdr_comment'])
Simon Glassbe44f272020-12-28 20:34:51 -070063
Simon Glass8fed2eb2017-08-29 14:15:55 -060064# This holds information about a property which includes phandles.
65#
66# max_args: integer: Maximum number or arguments that any phandle uses (int).
67# args: Number of args for each phandle in the property. The total number of
68# phandles is len(args). This is a list of integers.
69PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
70
Simon Glass97136eb2020-10-03 09:25:19 -060071# Holds a single phandle link, allowing a C struct value to be assigned to point
72# to a device
73#
74# var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
75# dev_name: Name of device to assign to (e.g. 'clock')
76PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
77
Simon Glass8fed2eb2017-08-29 14:15:55 -060078
Simon Glass7d637c12020-12-23 08:11:23 -070079class Driver:
80 """Information about a driver in U-Boot
81
82 Attributes:
83 name: Name of driver. For U_BOOT_DRIVER(x) this is 'x'
84 """
85 def __init__(self, name):
86 self.name = name
87
88 def __eq__(self, other):
89 return self.name == other.name
90
91 def __repr__(self):
92 return "Driver(name='%s')" % self.name
93
94
Simon Glass2be282c2017-06-18 22:08:59 -060095def conv_name_to_c(name):
Simon Glass7581c012017-06-18 22:08:58 -060096 """Convert a device-tree name to a C identifier
97
Simon Glass30107b02017-06-18 22:09:04 -060098 This uses multiple replace() calls instead of re.sub() since it is faster
99 (400ms for 1m calls versus 1000ms for the 're' version).
100
Simon Glass7581c012017-06-18 22:08:58 -0600101 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700102 name (str): Name to convert
Simon Glass7581c012017-06-18 22:08:58 -0600103 Return:
Simon Glass9b330382020-11-08 20:36:21 -0700104 str: String containing the C version of this name
Simon Glass7581c012017-06-18 22:08:58 -0600105 """
Simon Glass2be282c2017-06-18 22:08:59 -0600106 new = name.replace('@', '_at_')
107 new = new.replace('-', '_')
108 new = new.replace(',', '_')
109 new = new.replace('.', '_')
Simon Glass2be282c2017-06-18 22:08:59 -0600110 return new
Simon Glass7581c012017-06-18 22:08:58 -0600111
Simon Glass2be282c2017-06-18 22:08:59 -0600112def tab_to(num_tabs, line):
113 """Append tabs to a line of text to reach a tab stop.
Simon Glass7581c012017-06-18 22:08:58 -0600114
Simon Glass2be282c2017-06-18 22:08:59 -0600115 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700116 num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
117 line (str): Line of text to append to
Simon Glass2be282c2017-06-18 22:08:59 -0600118
119 Returns:
Simon Glass9b330382020-11-08 20:36:21 -0700120 str: line with the correct number of tabs appeneded. If the line already
Simon Glass2be282c2017-06-18 22:08:59 -0600121 extends past that tab stop then a single space is appended.
122 """
123 if len(line) >= num_tabs * 8:
124 return line + ' '
125 return line + '\t' * (num_tabs - len(line) // 8)
126
Simon Glass56e0bbe2017-06-18 22:09:02 -0600127def get_value(ftype, value):
128 """Get a value as a C expression
129
130 For integers this returns a byte-swapped (little-endian) hex string
131 For bytes this returns a hex string, e.g. 0x12
132 For strings this returns a literal string enclosed in quotes
133 For booleans this return 'true'
134
135 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700136 ftype (fdt.Type): Data type (fdt_util)
137 value (bytes): Data value, as a string of bytes
138
139 Returns:
140 str: String representation of the value
Simon Glass56e0bbe2017-06-18 22:09:02 -0600141 """
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700142 if ftype == fdt.Type.INT:
Simon Glassccc3da72020-12-23 08:11:19 -0700143 val = '%#x' % fdt_util.fdt32_to_cpu(value)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700144 elif ftype == fdt.Type.BYTE:
Simon Glass78128d52020-12-03 16:55:16 -0700145 char = value[0]
Simon Glassccc3da72020-12-23 08:11:19 -0700146 val = '%#x' % (ord(char) if isinstance(char, str) else char)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700147 elif ftype == fdt.Type.STRING:
Simon Glassf02d0eb2020-07-07 21:32:06 -0600148 # Handle evil ACPI backslashes by adding another backslash before them.
149 # So "\\_SB.GPO0" in the device tree effectively stays like that in C
Simon Glassccc3da72020-12-23 08:11:19 -0700150 val = '"%s"' % value.replace('\\', '\\\\')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700151 elif ftype == fdt.Type.BOOL:
Simon Glassccc3da72020-12-23 08:11:19 -0700152 val = 'true'
Simon Glass9b330382020-11-08 20:36:21 -0700153 else: # ftype == fdt.Type.INT64:
Simon Glassccc3da72020-12-23 08:11:19 -0700154 val = '%#x' % value
155 return val
Simon Glass56e0bbe2017-06-18 22:09:02 -0600156
157def get_compat_name(node):
Walter Lozanodcb3ed62020-07-23 00:22:03 -0300158 """Get the node's list of compatible string as a C identifiers
Simon Glass56e0bbe2017-06-18 22:09:02 -0600159
160 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700161 node (fdt.Node): Node object to check
Simon Glass56e0bbe2017-06-18 22:09:02 -0600162 Return:
Simon Glassccc3da72020-12-23 08:11:19 -0700163 list of str: List of C identifiers for all the compatible strings
Simon Glass56e0bbe2017-06-18 22:09:02 -0600164 """
165 compat = node.props['compatible'].value
Walter Lozanodcb3ed62020-07-23 00:22:03 -0300166 if not isinstance(compat, list):
167 compat = [compat]
168 return [conv_name_to_c(c) for c in compat]
Simon Glass56e0bbe2017-06-18 22:09:02 -0600169
Simon Glass56e0bbe2017-06-18 22:09:02 -0600170
Simon Glassccc3da72020-12-23 08:11:19 -0700171class DtbPlatdata():
Simon Glass7581c012017-06-18 22:08:58 -0600172 """Provide a means to convert device tree binary data to platform data
173
174 The output of this process is C structures which can be used in space-
175 constrained encvironments where the ~3KB code overhead of device tree
176 code is not affordable.
177
178 Properties:
Simon Glass2be282c2017-06-18 22:08:59 -0600179 _fdt: Fdt object, referencing the device tree
Simon Glass7581c012017-06-18 22:08:58 -0600180 _dtb_fname: Filename of the input device tree binary file
Simon Glass1b272732020-10-03 11:31:25 -0600181 _valid_nodes: A list of Node object with compatible strings. The list
182 is ordered by conv_name_to_c(node.name)
Simon Glasse36024b2017-06-18 22:09:01 -0600183 _include_disabled: true to include nodes marked status = "disabled"
Simon Glass7581c012017-06-18 22:08:58 -0600184 _outfile: The current output file (sys.stdout or a real file)
Walter Lozano361e7332020-06-25 01:10:08 -0300185 _warning_disabled: true to disable warnings about driver names not found
Simon Glass7581c012017-06-18 22:08:58 -0600186 _lines: Stashed list of output lines for outputting in the future
Simon Glass7d637c12020-12-23 08:11:23 -0700187 _drivers: Dict of valid driver names found in drivers/
188 key: Driver name
189 value: Driver for that driver
Walter Lozanodac82282020-07-03 08:07:17 -0300190 _driver_aliases: Dict that holds aliases for driver names
191 key: Driver alias declared with
Simon Glassbdf8fd72020-12-28 20:34:57 -0700192 DM_DRIVER_ALIAS(driver_alias, driver_name)
Walter Lozanodac82282020-07-03 08:07:17 -0300193 value: Driver name declared with U_BOOT_DRIVER(driver_name)
Walter Lozano6c74d1b2020-07-28 19:06:23 -0300194 _drivers_additional: List of additional drivers to use during scanning
Simon Glassbe44f272020-12-28 20:34:51 -0700195 _dirname: Directory to hold output files, or None for none (all files
196 go to stdout)
Simon Glass7581c012017-06-18 22:08:58 -0600197 """
Walter Lozano6c74d1b2020-07-28 19:06:23 -0300198 def __init__(self, dtb_fname, include_disabled, warning_disabled,
Simon Glass78128d52020-12-03 16:55:16 -0700199 drivers_additional=None):
Simon Glass2be282c2017-06-18 22:08:59 -0600200 self._fdt = None
Simon Glass7581c012017-06-18 22:08:58 -0600201 self._dtb_fname = dtb_fname
202 self._valid_nodes = None
Simon Glasse36024b2017-06-18 22:09:01 -0600203 self._include_disabled = include_disabled
Simon Glass7581c012017-06-18 22:08:58 -0600204 self._outfile = None
Walter Lozano361e7332020-06-25 01:10:08 -0300205 self._warning_disabled = warning_disabled
Simon Glass7581c012017-06-18 22:08:58 -0600206 self._lines = []
Simon Glass7d637c12020-12-23 08:11:23 -0700207 self._drivers = {}
Walter Lozanodac82282020-07-03 08:07:17 -0300208 self._driver_aliases = {}
Simon Glass78128d52020-12-03 16:55:16 -0700209 self._drivers_additional = drivers_additional or []
Simon Glassbe44f272020-12-28 20:34:51 -0700210 self._dirnames = [None] * len(Ftype)
Walter Lozanodac82282020-07-03 08:07:17 -0300211
212 def get_normalized_compat_name(self, node):
213 """Get a node's normalized compat name
214
Walter Lozanodcb3ed62020-07-23 00:22:03 -0300215 Returns a valid driver name by retrieving node's list of compatible
Walter Lozanodac82282020-07-03 08:07:17 -0300216 string as a C identifier and performing a check against _drivers
217 and a lookup in driver_aliases printing a warning in case of failure.
218
219 Args:
Simon Glassccc3da72020-12-23 08:11:19 -0700220 node (Node): Node object to check
Walter Lozanodac82282020-07-03 08:07:17 -0300221 Return:
222 Tuple:
223 Driver name associated with the first compatible string
224 List of C identifiers for all the other compatible strings
225 (possibly empty)
226 In case of no match found, the return will be the same as
227 get_compat_name()
228 """
Walter Lozanodcb3ed62020-07-23 00:22:03 -0300229 compat_list_c = get_compat_name(node)
Walter Lozanodac82282020-07-03 08:07:17 -0300230
Walter Lozanodcb3ed62020-07-23 00:22:03 -0300231 for compat_c in compat_list_c:
Simon Glass7d637c12020-12-23 08:11:23 -0700232 if not compat_c in self._drivers.keys():
Walter Lozanodcb3ed62020-07-23 00:22:03 -0300233 compat_c = self._driver_aliases.get(compat_c)
234 if not compat_c:
235 continue
236
237 aliases_c = compat_list_c
238 if compat_c in aliases_c:
239 aliases_c.remove(compat_c)
240 return compat_c, aliases_c
241
242 if not self._warning_disabled:
243 print('WARNING: the driver %s was not found in the driver list'
244 % (compat_list_c[0]))
245
246 return compat_list_c[0], compat_list_c[1:]
Simon Glass7581c012017-06-18 22:08:58 -0600247
Simon Glassbe44f272020-12-28 20:34:51 -0700248 def setup_output_dirs(self, output_dirs):
249 """Set up the output directories
250
251 This should be done before setup_output() is called
252
253 Args:
254 output_dirs (tuple of str):
255 Directory to use for C output files.
256 Use None to write files relative current directory
257 Directory to use for H output files.
258 Defaults to the C output dir
259 """
260 def process_dir(ftype, dirname):
261 if dirname:
262 os.makedirs(dirname, exist_ok=True)
263 self._dirnames[ftype] = dirname
264
265 if output_dirs:
266 c_dirname = output_dirs[0]
267 h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
268 process_dir(Ftype.SOURCE, c_dirname)
269 process_dir(Ftype.HEADER, h_dirname)
270
271 def setup_output(self, ftype, fname):
Simon Glass7581c012017-06-18 22:08:58 -0600272 """Set up the output destination
273
Simon Glass2be282c2017-06-18 22:08:59 -0600274 Once this is done, future calls to self.out() will output to this
Simon Glassbe44f272020-12-28 20:34:51 -0700275 file. The file used is as follows:
276
277 self._dirnames[ftype] is None: output to fname, or stdout if None
278 self._dirnames[ftype] is not None: output to fname in that directory
279
280 Calling this function multiple times will close the old file and open
281 the new one. If they are the same file, nothing happens and output will
282 continue to the same file.
Simon Glass7581c012017-06-18 22:08:58 -0600283
284 Args:
Simon Glassbe44f272020-12-28 20:34:51 -0700285 ftype (str): Type of file to create ('c' or 'h')
286 fname (str): Filename to send output to. If there is a directory in
287 self._dirnames for this file type, it will be put in that
288 directory
Simon Glass7581c012017-06-18 22:08:58 -0600289 """
Simon Glassbe44f272020-12-28 20:34:51 -0700290 dirname = self._dirnames[ftype]
291 if dirname:
292 pathname = os.path.join(dirname, fname)
293 if self._outfile:
294 self._outfile.close()
295 self._outfile = open(pathname, 'w')
296 elif fname:
297 if not self._outfile:
298 self._outfile = open(fname, 'w')
Simon Glassf62cea02020-12-28 20:34:48 -0700299 else:
300 self._outfile = sys.stdout
Simon Glass7581c012017-06-18 22:08:58 -0600301
Simon Glassbe44f272020-12-28 20:34:51 -0700302 def finish_output(self):
303 """Finish outputing to a file
304
305 This closes the output file, if one is in use
306 """
307 if self._outfile != sys.stdout:
308 self._outfile.close()
309
Simon Glass2be282c2017-06-18 22:08:59 -0600310 def out(self, line):
Simon Glass7581c012017-06-18 22:08:58 -0600311 """Output a string to the output file
312
313 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700314 line (str): String to output
Simon Glass7581c012017-06-18 22:08:58 -0600315 """
Simon Glass2be282c2017-06-18 22:08:59 -0600316 self._outfile.write(line)
Simon Glass7581c012017-06-18 22:08:58 -0600317
Simon Glass2be282c2017-06-18 22:08:59 -0600318 def buf(self, line):
Simon Glass7581c012017-06-18 22:08:58 -0600319 """Buffer up a string to send later
320
321 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700322 line (str): String to add to our 'buffer' list
Simon Glass7581c012017-06-18 22:08:58 -0600323 """
Simon Glass2be282c2017-06-18 22:08:59 -0600324 self._lines.append(line)
Simon Glass7581c012017-06-18 22:08:58 -0600325
Simon Glass2be282c2017-06-18 22:08:59 -0600326 def get_buf(self):
Simon Glass7581c012017-06-18 22:08:58 -0600327 """Get the contents of the output buffer, and clear it
328
329 Returns:
Simon Glass9b330382020-11-08 20:36:21 -0700330 list(str): The output buffer, which is then cleared for future use
Simon Glass7581c012017-06-18 22:08:58 -0600331 """
332 lines = self._lines
333 self._lines = []
334 return lines
335
Simon Glassd1055d62020-12-28 20:35:00 -0700336 def out_header(self, outfile):
337 """Output a message indicating that this is an auto-generated file
338
339 Args:
340 outfile: OutputFile describing the file being generated
341 """
Simon Glassd5031142017-08-29 14:16:01 -0600342 self.out('''/*
343 * DO NOT MODIFY
344 *
Simon Glassd1055d62020-12-28 20:35:00 -0700345 * %s.
346 * This was generated by dtoc from a .dtb (device tree binary) file.
Simon Glassd5031142017-08-29 14:16:01 -0600347 */
348
Simon Glassd1055d62020-12-28 20:35:00 -0700349''' % outfile.hdr_comment)
Simon Glassd5031142017-08-29 14:16:01 -0600350
Simon Glass8fed2eb2017-08-29 14:15:55 -0600351 def get_phandle_argc(self, prop, node_name):
352 """Check if a node contains phandles
Simon Glass2925c262017-08-29 14:15:54 -0600353
Simon Glass8fed2eb2017-08-29 14:15:55 -0600354 We have no reliable way of detecting whether a node uses a phandle
355 or not. As an interim measure, use a list of known property names.
Simon Glass2925c262017-08-29 14:15:54 -0600356
Simon Glass8fed2eb2017-08-29 14:15:55 -0600357 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700358 prop (fdt.Prop): Prop object to check
359 node_name (str): Node name, only used for raising an error
360 Returns:
361 int or None: Number of argument cells is this is a phandle,
362 else None
363 Raises:
364 ValueError: if the phandle cannot be parsed or the required property
365 is not present
Simon Glass8fed2eb2017-08-29 14:15:55 -0600366 """
Walter Lozanoad340172020-06-25 01:10:16 -0300367 if prop.name in ['clocks', 'cd-gpios']:
Simon Glass760b7172018-07-06 10:27:31 -0600368 if not isinstance(prop.value, list):
369 prop.value = [prop.value]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600370 val = prop.value
Simon Glass8fed2eb2017-08-29 14:15:55 -0600371 i = 0
372
373 max_args = 0
374 args = []
375 while i < len(val):
376 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass760b7172018-07-06 10:27:31 -0600377 # If we get to the end of the list, stop. This can happen
378 # since some nodes have more phandles in the list than others,
379 # but we allocate enough space for the largest list. So those
380 # nodes with shorter lists end up with zeroes at the end.
381 if not phandle:
382 break
Simon Glass8fed2eb2017-08-29 14:15:55 -0600383 target = self._fdt.phandle_to_node.get(phandle)
384 if not target:
385 raise ValueError("Cannot parse '%s' in node '%s'" %
386 (prop.name, node_name))
Walter Lozanoad340172020-06-25 01:10:16 -0300387 cells = None
388 for prop_name in ['#clock-cells', '#gpio-cells']:
389 cells = target.props.get(prop_name)
390 if cells:
391 break
Simon Glass8fed2eb2017-08-29 14:15:55 -0600392 if not cells:
Walter Lozanoad340172020-06-25 01:10:16 -0300393 raise ValueError("Node '%s' has no cells property" %
Simon Glass9b330382020-11-08 20:36:21 -0700394 (target.name))
Simon Glass8fed2eb2017-08-29 14:15:55 -0600395 num_args = fdt_util.fdt32_to_cpu(cells.value)
396 max_args = max(max_args, num_args)
397 args.append(num_args)
398 i += 1 + num_args
399 return PhandleInfo(max_args, args)
400 return None
Simon Glass2925c262017-08-29 14:15:54 -0600401
Simon Glass78128d52020-12-03 16:55:16 -0700402 def scan_driver(self, fname):
Walter Lozanodac82282020-07-03 08:07:17 -0300403 """Scan a driver file to build a list of driver names and aliases
404
405 This procedure will populate self._drivers and self._driver_aliases
406
407 Args
Simon Glass78128d52020-12-03 16:55:16 -0700408 fname: Driver filename to scan
Walter Lozanodac82282020-07-03 08:07:17 -0300409 """
Simon Glass78128d52020-12-03 16:55:16 -0700410 with open(fname, encoding='utf-8') as inf:
Walter Lozanodac82282020-07-03 08:07:17 -0300411 try:
Simon Glass78128d52020-12-03 16:55:16 -0700412 buff = inf.read()
Walter Lozanodac82282020-07-03 08:07:17 -0300413 except UnicodeDecodeError:
414 # This seems to happen on older Python versions
Simon Glass78128d52020-12-03 16:55:16 -0700415 print("Skipping file '%s' due to unicode error" % fname)
Walter Lozanodac82282020-07-03 08:07:17 -0300416 return
417
418 # The following re will search for driver names declared as
419 # U_BOOT_DRIVER(driver_name)
Simon Glassccc3da72020-12-23 08:11:19 -0700420 drivers = re.findall(r'U_BOOT_DRIVER\((.*)\)', buff)
Walter Lozanodac82282020-07-03 08:07:17 -0300421
422 for driver in drivers:
Simon Glass7d637c12020-12-23 08:11:23 -0700423 self._drivers[driver] = Driver(driver)
Walter Lozanodac82282020-07-03 08:07:17 -0300424
425 # The following re will search for driver aliases declared as
Simon Glassbdf8fd72020-12-28 20:34:57 -0700426 # DM_DRIVER_ALIAS(alias, driver_name)
Simon Glass78128d52020-12-03 16:55:16 -0700427 driver_aliases = re.findall(
Simon Glassbdf8fd72020-12-28 20:34:57 -0700428 r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
Simon Glass78128d52020-12-03 16:55:16 -0700429 buff)
Walter Lozanodac82282020-07-03 08:07:17 -0300430
431 for alias in driver_aliases: # pragma: no cover
432 if len(alias) != 2:
433 continue
434 self._driver_aliases[alias[1]] = alias[0]
435
436 def scan_drivers(self):
437 """Scan the driver folders to build a list of driver names and aliases
438
439 This procedure will populate self._drivers and self._driver_aliases
440
441 """
442 basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
443 if basedir == '':
444 basedir = './'
Simon Glass78128d52020-12-03 16:55:16 -0700445 for (dirpath, _, filenames) in os.walk(basedir):
446 for fname in filenames:
447 if not fname.endswith('.c'):
Walter Lozanodac82282020-07-03 08:07:17 -0300448 continue
Simon Glass78128d52020-12-03 16:55:16 -0700449 self.scan_driver(dirpath + '/' + fname)
Walter Lozanodac82282020-07-03 08:07:17 -0300450
Simon Glass78128d52020-12-03 16:55:16 -0700451 for fname in self._drivers_additional:
452 if not isinstance(fname, str) or len(fname) == 0:
Walter Lozano6c74d1b2020-07-28 19:06:23 -0300453 continue
Simon Glass78128d52020-12-03 16:55:16 -0700454 if fname[0] == '/':
455 self.scan_driver(fname)
Walter Lozano6c74d1b2020-07-28 19:06:23 -0300456 else:
Simon Glass78128d52020-12-03 16:55:16 -0700457 self.scan_driver(basedir + '/' + fname)
Walter Lozano6c74d1b2020-07-28 19:06:23 -0300458
Simon Glass2be282c2017-06-18 22:08:59 -0600459 def scan_dtb(self):
Anatolij Gustschinf1a7ba12017-08-18 17:58:51 +0200460 """Scan the device tree to obtain a tree of nodes and properties
Simon Glass7581c012017-06-18 22:08:58 -0600461
Simon Glass2be282c2017-06-18 22:08:59 -0600462 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glass7581c012017-06-18 22:08:58 -0600463 device tree root node, and progress from there.
464 """
Simon Glass2be282c2017-06-18 22:08:59 -0600465 self._fdt = fdt.FdtScan(self._dtb_fname)
Simon Glass7581c012017-06-18 22:08:58 -0600466
Simon Glass1b272732020-10-03 11:31:25 -0600467 def scan_node(self, root, valid_nodes):
Simon Glass2be282c2017-06-18 22:08:59 -0600468 """Scan a node and subnodes to build a tree of node and phandle info
469
Simon Glass72ab7c52017-08-29 14:15:53 -0600470 This adds each node to self._valid_nodes.
Simon Glass2be282c2017-06-18 22:08:59 -0600471
472 Args:
Simon Glassccc3da72020-12-23 08:11:19 -0700473 root (Node): Root node for scan
474 valid_nodes (list of Node): List of Node objects to add to
Simon Glass2be282c2017-06-18 22:08:59 -0600475 """
Simon Glass7581c012017-06-18 22:08:58 -0600476 for node in root.subnodes:
477 if 'compatible' in node.props:
478 status = node.props.get('status')
Simon Glasse36024b2017-06-18 22:09:01 -0600479 if (not self._include_disabled and not status or
Simon Glass2be282c2017-06-18 22:08:59 -0600480 status.value != 'disabled'):
Simon Glass1b272732020-10-03 11:31:25 -0600481 valid_nodes.append(node)
Simon Glass7581c012017-06-18 22:08:58 -0600482
483 # recurse to handle any subnodes
Simon Glass1b272732020-10-03 11:31:25 -0600484 self.scan_node(node, valid_nodes)
Simon Glass7581c012017-06-18 22:08:58 -0600485
Simon Glass2be282c2017-06-18 22:08:59 -0600486 def scan_tree(self):
Simon Glass7581c012017-06-18 22:08:58 -0600487 """Scan the device tree for useful information
488
489 This fills in the following properties:
Simon Glass7581c012017-06-18 22:08:58 -0600490 _valid_nodes: A list of nodes we wish to consider include in the
491 platform data
492 """
Simon Glass1b272732020-10-03 11:31:25 -0600493 valid_nodes = []
494 self.scan_node(self._fdt.GetRoot(), valid_nodes)
495 self._valid_nodes = sorted(valid_nodes,
496 key=lambda x: conv_name_to_c(x.name))
497 for idx, node in enumerate(self._valid_nodes):
498 node.idx = idx
Simon Glass7581c012017-06-18 22:08:58 -0600499
Simon Glassc20ee0e2017-08-29 14:15:50 -0600500 @staticmethod
501 def get_num_cells(node):
502 """Get the number of cells in addresses and sizes for this node
503
504 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700505 node (fdt.None): Node to check
Simon Glassc20ee0e2017-08-29 14:15:50 -0600506
507 Returns:
508 Tuple:
509 Number of address cells for this node
510 Number of size cells for this node
511 """
512 parent = node.parent
Simon Glass78128d52020-12-03 16:55:16 -0700513 num_addr, num_size = 2, 2
Simon Glassc20ee0e2017-08-29 14:15:50 -0600514 if parent:
Simon Glass78128d52020-12-03 16:55:16 -0700515 addr_prop = parent.props.get('#address-cells')
516 size_prop = parent.props.get('#size-cells')
517 if addr_prop:
518 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
519 if size_prop:
520 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
521 return num_addr, num_size
Simon Glassc20ee0e2017-08-29 14:15:50 -0600522
523 def scan_reg_sizes(self):
524 """Scan for 64-bit 'reg' properties and update the values
525
526 This finds 'reg' properties with 64-bit data and converts the value to
527 an array of 64-values. This allows it to be output in a way that the
528 C code can read.
529 """
530 for node in self._valid_nodes:
531 reg = node.props.get('reg')
532 if not reg:
533 continue
Simon Glass78128d52020-12-03 16:55:16 -0700534 num_addr, num_size = self.get_num_cells(node)
535 total = num_addr + num_size
Simon Glassc20ee0e2017-08-29 14:15:50 -0600536
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700537 if reg.type != fdt.Type.INT:
Simon Glassdfe5f5b2018-07-06 10:27:32 -0600538 raise ValueError("Node '%s' reg property is not an int" %
539 node.name)
Simon Glassc20ee0e2017-08-29 14:15:50 -0600540 if len(reg.value) % total:
Simon Glass9b330382020-11-08 20:36:21 -0700541 raise ValueError(
542 "Node '%s' reg property has %d cells "
543 'which is not a multiple of na + ns = %d + %d)' %
Simon Glass78128d52020-12-03 16:55:16 -0700544 (node.name, len(reg.value), num_addr, num_size))
545 reg.num_addr = num_addr
546 reg.num_size = num_size
547 if num_addr != 1 or num_size != 1:
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700548 reg.type = fdt.Type.INT64
Simon Glassc20ee0e2017-08-29 14:15:50 -0600549 i = 0
550 new_value = []
551 val = reg.value
552 if not isinstance(val, list):
553 val = [val]
554 while i < len(val):
Simon Glass78128d52020-12-03 16:55:16 -0700555 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
556 i += num_addr
557 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
558 i += num_size
Simon Glassc20ee0e2017-08-29 14:15:50 -0600559 new_value += [addr, size]
560 reg.value = new_value
561
Simon Glass2be282c2017-06-18 22:08:59 -0600562 def scan_structs(self):
Simon Glass7581c012017-06-18 22:08:58 -0600563 """Scan the device tree building up the C structures we will use.
564
565 Build a dict keyed by C struct name containing a dict of Prop
566 object for each struct field (keyed by property name). Where the
567 same struct appears multiple times, try to use the 'widest'
568 property, i.e. the one with a type which can express all others.
569
570 Once the widest property is determined, all other properties are
571 updated to match that width.
Simon Glasse4fb5fa2020-10-03 11:31:24 -0600572
573 Returns:
Simon Glassccc3da72020-12-23 08:11:19 -0700574 dict of dict: dict containing structures:
Simon Glasse4fb5fa2020-10-03 11:31:24 -0600575 key (str): Node name, as a C identifier
576 value: dict containing structure fields:
577 key (str): Field name
578 value: Prop object with field information
Simon Glass7581c012017-06-18 22:08:58 -0600579 """
Simon Glass1b272732020-10-03 11:31:25 -0600580 structs = collections.OrderedDict()
Simon Glass7581c012017-06-18 22:08:58 -0600581 for node in self._valid_nodes:
Walter Lozanodac82282020-07-03 08:07:17 -0300582 node_name, _ = self.get_normalized_compat_name(node)
Simon Glass7581c012017-06-18 22:08:58 -0600583 fields = {}
584
585 # Get a list of all the valid properties in this node.
586 for name, prop in node.props.items():
587 if name not in PROP_IGNORE_LIST and name[0] != '#':
588 fields[name] = copy.deepcopy(prop)
589
590 # If we've seen this node_name before, update the existing struct.
591 if node_name in structs:
592 struct = structs[node_name]
593 for name, prop in fields.items():
594 oldprop = struct.get(name)
595 if oldprop:
596 oldprop.Widen(prop)
597 else:
598 struct[name] = prop
599
600 # Otherwise store this as a new struct.
601 else:
602 structs[node_name] = fields
603
Simon Glass7581c012017-06-18 22:08:58 -0600604 for node in self._valid_nodes:
Walter Lozanodac82282020-07-03 08:07:17 -0300605 node_name, _ = self.get_normalized_compat_name(node)
Simon Glass7581c012017-06-18 22:08:58 -0600606 struct = structs[node_name]
607 for name, prop in node.props.items():
608 if name not in PROP_IGNORE_LIST and name[0] != '#':
609 prop.Widen(struct[name])
Simon Glass7581c012017-06-18 22:08:58 -0600610
Simon Glass7581c012017-06-18 22:08:58 -0600611 return structs
612
Simon Glass2be282c2017-06-18 22:08:59 -0600613 def scan_phandles(self):
Simon Glass7581c012017-06-18 22:08:58 -0600614 """Figure out what phandles each node uses
615
616 We need to be careful when outputing nodes that use phandles since
617 they must come after the declaration of the phandles in the C file.
618 Otherwise we get a compiler error since the phandle struct is not yet
619 declared.
620
621 This function adds to each node a list of phandle nodes that the node
622 depends on. This allows us to output things in the right order.
623 """
624 for node in self._valid_nodes:
625 node.phandles = set()
626 for pname, prop in node.props.items():
627 if pname in PROP_IGNORE_LIST or pname[0] == '#':
628 continue
Simon Glass8fed2eb2017-08-29 14:15:55 -0600629 info = self.get_phandle_argc(prop, node.name)
630 if info:
Simon Glass8fed2eb2017-08-29 14:15:55 -0600631 # Process the list as pairs of (phandle, id)
Simon Glass634eba42017-08-29 14:15:59 -0600632 pos = 0
633 for args in info.args:
634 phandle_cell = prop.value[pos]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600635 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
636 target_node = self._fdt.phandle_to_node[phandle]
637 node.phandles.add(target_node)
Simon Glass634eba42017-08-29 14:15:59 -0600638 pos += 1 + args
Simon Glass7581c012017-06-18 22:08:58 -0600639
640
Simon Glass2be282c2017-06-18 22:08:59 -0600641 def generate_structs(self, structs):
Simon Glass7581c012017-06-18 22:08:58 -0600642 """Generate struct defintions for the platform data
643
644 This writes out the body of a header file consisting of structure
645 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardt2799a692020-02-25 21:35:39 +0100646 doc/driver-model/of-plat.rst for more information.
Simon Glasse4fb5fa2020-10-03 11:31:24 -0600647
648 Args:
Simon Glassccc3da72020-12-23 08:11:19 -0700649 structs (dict): dict containing structures:
Simon Glasse4fb5fa2020-10-03 11:31:24 -0600650 key (str): Node name, as a C identifier
651 value: dict containing structure fields:
652 key (str): Field name
653 value: Prop object with field information
654
Simon Glass7581c012017-06-18 22:08:58 -0600655 """
Simon Glass2be282c2017-06-18 22:08:59 -0600656 self.out('#include <stdbool.h>\n')
Masahiro Yamadab08c8c42018-03-05 01:20:11 +0900657 self.out('#include <linux/libfdt.h>\n')
Simon Glass7581c012017-06-18 22:08:58 -0600658
659 # Output the struct definition
660 for name in sorted(structs):
Simon Glass2be282c2017-06-18 22:08:59 -0600661 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glass7581c012017-06-18 22:08:58 -0600662 for pname in sorted(structs[name]):
663 prop = structs[name][pname]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600664 info = self.get_phandle_argc(prop, structs[name])
665 if info:
Simon Glass7581c012017-06-18 22:08:58 -0600666 # For phandles, include a reference to the target
Simon Glass0d154632017-08-29 14:15:56 -0600667 struct_name = 'struct phandle_%d_arg' % info.max_args
668 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass2be282c2017-06-18 22:08:59 -0600669 conv_name_to_c(prop.name),
Simon Glass634eba42017-08-29 14:15:59 -0600670 len(info.args)))
Simon Glass7581c012017-06-18 22:08:58 -0600671 else:
672 ptype = TYPE_NAMES[prop.type]
Simon Glass2be282c2017-06-18 22:08:59 -0600673 self.out('\t%s%s' % (tab_to(2, ptype),
674 conv_name_to_c(prop.name)))
675 if isinstance(prop.value, list):
676 self.out('[%d]' % len(prop.value))
677 self.out(';\n')
678 self.out('};\n')
Simon Glass7581c012017-06-18 22:08:58 -0600679
Simon Glassabf0c802020-12-23 08:11:20 -0700680 def _output_list(self, node, prop):
681 """Output the C code for a devicetree property that holds a list
682
683 Args:
684 node (fdt.Node): Node to output
685 prop (fdt.Prop): Prop to output
686 """
687 self.buf('{')
688 vals = []
689 # For phandles, output a reference to the platform data
690 # of the target node.
691 info = self.get_phandle_argc(prop, node.name)
692 if info:
693 # Process the list as pairs of (phandle, id)
694 pos = 0
695 for args in info.args:
696 phandle_cell = prop.value[pos]
697 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
698 target_node = self._fdt.phandle_to_node[phandle]
699 arg_values = []
700 for i in range(args):
701 arg_values.append(
702 str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
703 pos += 1 + args
704 vals.append('\t{%d, {%s}}' % (target_node.idx,
705 ', '.join(arg_values)))
706 for val in vals:
707 self.buf('\n\t\t%s,' % val)
708 else:
709 for val in prop.value:
710 vals.append(get_value(prop.type, val))
711
712 # Put 8 values per line to avoid very long lines.
713 for i in range(0, len(vals), 8):
714 if i:
715 self.buf(',\n\t\t')
716 self.buf(', '.join(vals[i:i + 8]))
717 self.buf('}')
718
Simon Glass221ddc12020-12-23 08:11:21 -0700719 def _declare_device(self, var_name, struct_name, node_parent):
720 """Add a device declaration to the output
721
Simon Glass20e442a2020-12-28 20:34:54 -0700722 This declares a U_BOOT_DRVINFO() for the device being processed
Simon Glass221ddc12020-12-23 08:11:21 -0700723
724 Args:
725 var_name (str): C name for the node
726 struct_name (str): Name for the dt struct associated with the node
727 node_parent (Node): Parent of the node (or None if none)
728 """
Simon Glass20e442a2020-12-28 20:34:54 -0700729 self.buf('U_BOOT_DRVINFO(%s) = {\n' % var_name)
Simon Glass221ddc12020-12-23 08:11:21 -0700730 self.buf('\t.name\t\t= "%s",\n' % struct_name)
731 self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, var_name))
732 self.buf('\t.plat_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
733 idx = -1
734 if node_parent and node_parent in self._valid_nodes:
735 idx = node_parent.idx
736 self.buf('\t.parent_idx\t= %d,\n' % idx)
737 self.buf('};\n')
738 self.buf('\n')
739
Simon Glass161dac12020-12-23 08:11:22 -0700740 def _output_prop(self, node, prop):
741 """Output a line containing the value of a struct member
742
743 Args:
744 node (Node): Node being output
745 prop (Prop): Prop object to output
746 """
747 if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
748 return
749 member_name = conv_name_to_c(prop.name)
750 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
751
752 # Special handling for lists
753 if isinstance(prop.value, list):
754 self._output_list(node, prop)
755 else:
756 self.buf(get_value(prop.type, prop.value))
757 self.buf(',\n')
758
759 def _output_values(self, var_name, struct_name, node):
760 """Output the definition of a device's struct values
761
762 Args:
763 var_name (str): C name for the node
764 struct_name (str): Name for the dt struct associated with the node
765 node (Node): Node being output
766 """
767 self.buf('static struct %s%s %s%s = {\n' %
768 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
769 for pname in sorted(node.props):
770 self._output_prop(node, node.props[pname])
771 self.buf('};\n')
772
Simon Glass2be282c2017-06-18 22:08:59 -0600773 def output_node(self, node):
Simon Glass7581c012017-06-18 22:08:58 -0600774 """Output the C code for a node
775
776 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700777 node (fdt.Node): node to output
Simon Glass7581c012017-06-18 22:08:58 -0600778 """
Walter Lozanodac82282020-07-03 08:07:17 -0300779 struct_name, _ = self.get_normalized_compat_name(node)
Simon Glass2be282c2017-06-18 22:08:59 -0600780 var_name = conv_name_to_c(node.name)
Simon Glass1b272732020-10-03 11:31:25 -0600781 self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
Simon Glass7581c012017-06-18 22:08:58 -0600782
Simon Glass161dac12020-12-23 08:11:22 -0700783 self._output_values(var_name, struct_name, node)
Simon Glass221ddc12020-12-23 08:11:21 -0700784 self._declare_device(var_name, struct_name, node.parent)
Simon Glass7581c012017-06-18 22:08:58 -0600785
Simon Glass2be282c2017-06-18 22:08:59 -0600786 self.out(''.join(self.get_buf()))
Simon Glass7581c012017-06-18 22:08:58 -0600787
Simon Glass2be282c2017-06-18 22:08:59 -0600788 def generate_tables(self):
Simon Glass7581c012017-06-18 22:08:58 -0600789 """Generate device defintions for the platform data
790
791 This writes out C platform data initialisation data and
Simon Glass20e442a2020-12-28 20:34:54 -0700792 U_BOOT_DRVINFO() declarations for each valid node. Where a node has
Simon Glass7581c012017-06-18 22:08:58 -0600793 multiple compatible strings, a #define is used to make them equivalent.
794
Heinrich Schuchardt2799a692020-02-25 21:35:39 +0100795 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glass7581c012017-06-18 22:08:58 -0600796 information.
797 """
Simon Glass20e442a2020-12-28 20:34:54 -0700798 self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
Simon Glasscb43ac12020-10-03 11:31:41 -0600799 self.out('#define DT_PLATDATA_C\n')
800 self.out('\n')
Simon Glass2be282c2017-06-18 22:08:59 -0600801 self.out('#include <common.h>\n')
802 self.out('#include <dm.h>\n')
803 self.out('#include <dt-structs.h>\n')
804 self.out('\n')
Simon Glass7581c012017-06-18 22:08:58 -0600805 nodes_to_output = list(self._valid_nodes)
806
807 # Keep outputing nodes until there is none left
808 while nodes_to_output:
809 node = nodes_to_output[0]
810 # Output all the node's dependencies first
811 for req_node in node.phandles:
812 if req_node in nodes_to_output:
Simon Glass2be282c2017-06-18 22:08:59 -0600813 self.output_node(req_node)
Simon Glass7581c012017-06-18 22:08:58 -0600814 nodes_to_output.remove(req_node)
Simon Glass2be282c2017-06-18 22:08:59 -0600815 self.output_node(node)
Simon Glass7581c012017-06-18 22:08:58 -0600816 nodes_to_output.remove(node)
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600817
Walter Lozano51f12632020-06-25 01:10:13 -0300818 # Define dm_populate_phandle_data() which will add the linking between
Simon Glass8629d302020-12-28 20:34:55 -0700819 # nodes using DM_DRVINFO_GET
820 # dtv_dmc_at_xxx.clocks[0].node = DM_DRVINFO_GET(clock_controller_at_xxx)
Walter Lozano51f12632020-06-25 01:10:13 -0300821 self.buf('void dm_populate_phandle_data(void) {\n')
Walter Lozano51f12632020-06-25 01:10:13 -0300822 self.buf('}\n')
823
824 self.out(''.join(self.get_buf()))
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600825
Simon Glass192c1112020-12-28 20:34:50 -0700826
Simon Glassbe44f272020-12-28 20:34:51 -0700827# Types of output file we understand
828# key: Command used to generate this file
829# value: OutputFile for this command
830OUTPUT_FILES = {
Simon Glassd1055d62020-12-28 20:35:00 -0700831 'struct':
832 OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
833 'Defines the structs used to hold devicetree data'),
834 'platdata':
835 OutputFile(Ftype.SOURCE, 'dt-platdata.c',
836 'Declares the U_BOOT_DRIVER() records and platform data'),
Simon Glassbe44f272020-12-28 20:34:51 -0700837 }
838
839
Simon Glass192c1112020-12-28 20:34:50 -0700840def run_steps(args, dtb_file, include_disabled, output, output_dirs,
841 warning_disabled=False, drivers_additional=None):
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600842 """Run all the steps of the dtoc tool
843
844 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700845 args (list): List of non-option arguments provided to the problem
846 dtb_file (str): Filename of dtb file to process
847 include_disabled (bool): True to include disabled nodes
Simon Glassf62cea02020-12-28 20:34:48 -0700848 output (str): Name of output file (None for stdout)
Simon Glass192c1112020-12-28 20:34:50 -0700849 output_dirs (tuple of str):
850 Directory to put C output files
851 Directory to put H output files
Simon Glass78128d52020-12-03 16:55:16 -0700852 warning_disabled (bool): True to avoid showing warnings about missing
853 drivers
Simon Glassccc3da72020-12-23 08:11:19 -0700854 drivers_additional (list): List of additional drivers to use during
Simon Glass78128d52020-12-03 16:55:16 -0700855 scanning
Simon Glass9b330382020-11-08 20:36:21 -0700856 Raises:
857 ValueError: if args has no command, or an unknown command
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600858 """
859 if not args:
Simon Glassbe44f272020-12-28 20:34:51 -0700860 raise ValueError('Please specify a command: struct, platdata, all')
861 if output and output_dirs and any(output_dirs):
862 raise ValueError('Must specify either output or output_dirs, not both')
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600863
Simon Glass78128d52020-12-03 16:55:16 -0700864 plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled,
865 drivers_additional)
Walter Lozanodac82282020-07-03 08:07:17 -0300866 plat.scan_drivers()
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600867 plat.scan_dtb()
868 plat.scan_tree()
Simon Glassc20ee0e2017-08-29 14:15:50 -0600869 plat.scan_reg_sizes()
Simon Glassbe44f272020-12-28 20:34:51 -0700870 plat.setup_output_dirs(output_dirs)
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600871 structs = plat.scan_structs()
872 plat.scan_phandles()
873
Simon Glass10cbd3b2020-12-28 20:34:52 -0700874 cmds = args[0].split(',')
875 if 'all' in cmds:
876 cmds = sorted(OUTPUT_FILES.keys())
877 for cmd in cmds:
Simon Glassbe44f272020-12-28 20:34:51 -0700878 outfile = OUTPUT_FILES.get(cmd)
879 if not outfile:
880 raise ValueError("Unknown command '%s': (use: %s)" %
Simon Glass10cbd3b2020-12-28 20:34:52 -0700881 (cmd, ', '.join(sorted(OUTPUT_FILES.keys()))))
Simon Glassbe44f272020-12-28 20:34:51 -0700882 plat.setup_output(outfile.ftype,
883 outfile.fname if output_dirs else output)
Simon Glassd1055d62020-12-28 20:35:00 -0700884 plat.out_header(outfile)
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600885 if cmd == 'struct':
886 plat.generate_structs(structs)
887 elif cmd == 'platdata':
888 plat.generate_tables()
Simon Glassbe44f272020-12-28 20:34:51 -0700889 plat.finish_output()