blob: e12aaa5399fcabe0801795f88a1bd09b78d36195 [file] [log] [blame]
Simon Glassd570dec2017-06-18 22:08:58 -06001#!/usr/bin/python
Tom Rini10e47792018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glassd570dec2017-06-18 22:08:58 -06003#
4# Copyright (C) 2017 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
Simon Glassd570dec2017-06-18 22:08:58 -06007
Simon Glass1f730c82017-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 Glass94ee3bd2020-11-08 20:36:21 -070012
13See doc/driver-model/of-plat.rst for more informaiton
Simon Glass1f730c82017-06-18 22:08:59 -060014"""
15
Simon Glassec3b5e42017-08-29 14:15:55 -060016import collections
Simon Glassd570dec2017-06-18 22:08:58 -060017import copy
Simon Glassc3a310a82020-12-28 20:34:51 -070018from enum import IntEnum
Walter Lozanoe675d962020-07-03 08:07:17 -030019import os
20import re
Simon Glass1f730c82017-06-18 22:08:59 -060021import sys
Simon Glassd570dec2017-06-18 22:08:58 -060022
Simon Glassa997ea52020-04-17 18:09:04 -060023from dtoc import fdt
24from dtoc import fdt_util
Simon Glassd570dec2017-06-18 22:08:58 -060025
Simon Glass94ee3bd2020-11-08 20:36:21 -070026# When we see these properties we ignore them - i.e. do not create a structure
27# member
Simon Glassd570dec2017-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 Glassc9a032c2020-11-08 20:36:17 -070041# C type declarations for the types we support
Simon Glassd570dec2017-06-18 22:08:58 -060042TYPE_NAMES = {
Simon Glassc9a032c2020-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 Glass1f730c82017-06-18 22:08:59 -060048}
Simon Glassd570dec2017-06-18 22:08:58 -060049
50STRUCT_PREFIX = 'dtd_'
51VAL_PREFIX = 'dtv_'
52
Simon Glassc3a310a82020-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)
59# fname: Filename excluding directory, e.g. 'dt-platdata.c'
60OutputFile = collections.namedtuple('OutputFile', ['ftype', 'fname'])
61
Simon Glassec3b5e42017-08-29 14:15:55 -060062# This holds information about a property which includes phandles.
63#
64# max_args: integer: Maximum number or arguments that any phandle uses (int).
65# args: Number of args for each phandle in the property. The total number of
66# phandles is len(args). This is a list of integers.
67PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
68
Simon Glassc1622112020-10-03 09:25:19 -060069# Holds a single phandle link, allowing a C struct value to be assigned to point
70# to a device
71#
72# var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
73# dev_name: Name of device to assign to (e.g. 'clock')
74PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
75
Simon Glassec3b5e42017-08-29 14:15:55 -060076
Simon Glassb42ed512020-12-23 08:11:23 -070077class Driver:
78 """Information about a driver in U-Boot
79
80 Attributes:
81 name: Name of driver. For U_BOOT_DRIVER(x) this is 'x'
82 """
83 def __init__(self, name):
84 self.name = name
85
86 def __eq__(self, other):
87 return self.name == other.name
88
89 def __repr__(self):
90 return "Driver(name='%s')" % self.name
91
92
Simon Glass1f730c82017-06-18 22:08:59 -060093def conv_name_to_c(name):
Simon Glassd570dec2017-06-18 22:08:58 -060094 """Convert a device-tree name to a C identifier
95
Simon Glass2e0bf3f2017-06-18 22:09:04 -060096 This uses multiple replace() calls instead of re.sub() since it is faster
97 (400ms for 1m calls versus 1000ms for the 're' version).
98
Simon Glassd570dec2017-06-18 22:08:58 -060099 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700100 name (str): Name to convert
Simon Glassd570dec2017-06-18 22:08:58 -0600101 Return:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700102 str: String containing the C version of this name
Simon Glassd570dec2017-06-18 22:08:58 -0600103 """
Simon Glass1f730c82017-06-18 22:08:59 -0600104 new = name.replace('@', '_at_')
105 new = new.replace('-', '_')
106 new = new.replace(',', '_')
107 new = new.replace('.', '_')
Simon Glass1f730c82017-06-18 22:08:59 -0600108 return new
Simon Glassd570dec2017-06-18 22:08:58 -0600109
Simon Glass1f730c82017-06-18 22:08:59 -0600110def tab_to(num_tabs, line):
111 """Append tabs to a line of text to reach a tab stop.
Simon Glassd570dec2017-06-18 22:08:58 -0600112
Simon Glass1f730c82017-06-18 22:08:59 -0600113 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700114 num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
115 line (str): Line of text to append to
Simon Glass1f730c82017-06-18 22:08:59 -0600116
117 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700118 str: line with the correct number of tabs appeneded. If the line already
Simon Glass1f730c82017-06-18 22:08:59 -0600119 extends past that tab stop then a single space is appended.
120 """
121 if len(line) >= num_tabs * 8:
122 return line + ' '
123 return line + '\t' * (num_tabs - len(line) // 8)
124
Simon Glass7a2add12017-06-18 22:09:02 -0600125def get_value(ftype, value):
126 """Get a value as a C expression
127
128 For integers this returns a byte-swapped (little-endian) hex string
129 For bytes this returns a hex string, e.g. 0x12
130 For strings this returns a literal string enclosed in quotes
131 For booleans this return 'true'
132
133 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700134 ftype (fdt.Type): Data type (fdt_util)
135 value (bytes): Data value, as a string of bytes
136
137 Returns:
138 str: String representation of the value
Simon Glass7a2add12017-06-18 22:09:02 -0600139 """
Simon Glassc9a032c2020-11-08 20:36:17 -0700140 if ftype == fdt.Type.INT:
Simon Glass27511232020-12-23 08:11:19 -0700141 val = '%#x' % fdt_util.fdt32_to_cpu(value)
Simon Glassc9a032c2020-11-08 20:36:17 -0700142 elif ftype == fdt.Type.BYTE:
Simon Glass93daa012020-12-03 16:55:16 -0700143 char = value[0]
Simon Glass27511232020-12-23 08:11:19 -0700144 val = '%#x' % (ord(char) if isinstance(char, str) else char)
Simon Glassc9a032c2020-11-08 20:36:17 -0700145 elif ftype == fdt.Type.STRING:
Simon Glass7f5e2262020-07-07 21:32:06 -0600146 # Handle evil ACPI backslashes by adding another backslash before them.
147 # So "\\_SB.GPO0" in the device tree effectively stays like that in C
Simon Glass27511232020-12-23 08:11:19 -0700148 val = '"%s"' % value.replace('\\', '\\\\')
Simon Glassc9a032c2020-11-08 20:36:17 -0700149 elif ftype == fdt.Type.BOOL:
Simon Glass27511232020-12-23 08:11:19 -0700150 val = 'true'
Simon Glass94ee3bd2020-11-08 20:36:21 -0700151 else: # ftype == fdt.Type.INT64:
Simon Glass27511232020-12-23 08:11:19 -0700152 val = '%#x' % value
153 return val
Simon Glass7a2add12017-06-18 22:09:02 -0600154
155def get_compat_name(node):
Walter Lozano5fe734c2020-07-23 00:22:03 -0300156 """Get the node's list of compatible string as a C identifiers
Simon Glass7a2add12017-06-18 22:09:02 -0600157
158 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700159 node (fdt.Node): Node object to check
Simon Glass7a2add12017-06-18 22:09:02 -0600160 Return:
Simon Glass27511232020-12-23 08:11:19 -0700161 list of str: List of C identifiers for all the compatible strings
Simon Glass7a2add12017-06-18 22:09:02 -0600162 """
163 compat = node.props['compatible'].value
Walter Lozano5fe734c2020-07-23 00:22:03 -0300164 if not isinstance(compat, list):
165 compat = [compat]
166 return [conv_name_to_c(c) for c in compat]
Simon Glass7a2add12017-06-18 22:09:02 -0600167
Simon Glass7a2add12017-06-18 22:09:02 -0600168
Simon Glass27511232020-12-23 08:11:19 -0700169class DtbPlatdata():
Simon Glassd570dec2017-06-18 22:08:58 -0600170 """Provide a means to convert device tree binary data to platform data
171
172 The output of this process is C structures which can be used in space-
173 constrained encvironments where the ~3KB code overhead of device tree
174 code is not affordable.
175
176 Properties:
Simon Glass1f730c82017-06-18 22:08:59 -0600177 _fdt: Fdt object, referencing the device tree
Simon Glassd570dec2017-06-18 22:08:58 -0600178 _dtb_fname: Filename of the input device tree binary file
Simon Glass192f8132020-10-03 11:31:25 -0600179 _valid_nodes: A list of Node object with compatible strings. The list
180 is ordered by conv_name_to_c(node.name)
Simon Glasseab3f622017-06-18 22:09:01 -0600181 _include_disabled: true to include nodes marked status = "disabled"
Simon Glassd570dec2017-06-18 22:08:58 -0600182 _outfile: The current output file (sys.stdout or a real file)
Walter Lozanoa324e412020-06-25 01:10:08 -0300183 _warning_disabled: true to disable warnings about driver names not found
Simon Glassd570dec2017-06-18 22:08:58 -0600184 _lines: Stashed list of output lines for outputting in the future
Simon Glassb42ed512020-12-23 08:11:23 -0700185 _drivers: Dict of valid driver names found in drivers/
186 key: Driver name
187 value: Driver for that driver
Walter Lozanoe675d962020-07-03 08:07:17 -0300188 _driver_aliases: Dict that holds aliases for driver names
189 key: Driver alias declared with
Simon Glassdf65db82020-12-28 20:34:57 -0700190 DM_DRIVER_ALIAS(driver_alias, driver_name)
Walter Lozanoe675d962020-07-03 08:07:17 -0300191 value: Driver name declared with U_BOOT_DRIVER(driver_name)
Walter Lozanod82062b2020-07-28 19:06:23 -0300192 _drivers_additional: List of additional drivers to use during scanning
Simon Glassc3a310a82020-12-28 20:34:51 -0700193 _dirname: Directory to hold output files, or None for none (all files
194 go to stdout)
Simon Glassd570dec2017-06-18 22:08:58 -0600195 """
Walter Lozanod82062b2020-07-28 19:06:23 -0300196 def __init__(self, dtb_fname, include_disabled, warning_disabled,
Simon Glass93daa012020-12-03 16:55:16 -0700197 drivers_additional=None):
Simon Glass1f730c82017-06-18 22:08:59 -0600198 self._fdt = None
Simon Glassd570dec2017-06-18 22:08:58 -0600199 self._dtb_fname = dtb_fname
200 self._valid_nodes = None
Simon Glasseab3f622017-06-18 22:09:01 -0600201 self._include_disabled = include_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600202 self._outfile = None
Walter Lozanoa324e412020-06-25 01:10:08 -0300203 self._warning_disabled = warning_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600204 self._lines = []
Simon Glassb42ed512020-12-23 08:11:23 -0700205 self._drivers = {}
Walter Lozanoe675d962020-07-03 08:07:17 -0300206 self._driver_aliases = {}
Simon Glass93daa012020-12-03 16:55:16 -0700207 self._drivers_additional = drivers_additional or []
Simon Glassc3a310a82020-12-28 20:34:51 -0700208 self._dirnames = [None] * len(Ftype)
Walter Lozanoe675d962020-07-03 08:07:17 -0300209
210 def get_normalized_compat_name(self, node):
211 """Get a node's normalized compat name
212
Walter Lozano5fe734c2020-07-23 00:22:03 -0300213 Returns a valid driver name by retrieving node's list of compatible
Walter Lozanoe675d962020-07-03 08:07:17 -0300214 string as a C identifier and performing a check against _drivers
215 and a lookup in driver_aliases printing a warning in case of failure.
216
217 Args:
Simon Glass27511232020-12-23 08:11:19 -0700218 node (Node): Node object to check
Walter Lozanoe675d962020-07-03 08:07:17 -0300219 Return:
220 Tuple:
221 Driver name associated with the first compatible string
222 List of C identifiers for all the other compatible strings
223 (possibly empty)
224 In case of no match found, the return will be the same as
225 get_compat_name()
226 """
Walter Lozano5fe734c2020-07-23 00:22:03 -0300227 compat_list_c = get_compat_name(node)
228
229 for compat_c in compat_list_c:
Simon Glassb42ed512020-12-23 08:11:23 -0700230 if not compat_c in self._drivers.keys():
Walter Lozano5fe734c2020-07-23 00:22:03 -0300231 compat_c = self._driver_aliases.get(compat_c)
232 if not compat_c:
233 continue
234
235 aliases_c = compat_list_c
236 if compat_c in aliases_c:
237 aliases_c.remove(compat_c)
238 return compat_c, aliases_c
239
240 if not self._warning_disabled:
241 print('WARNING: the driver %s was not found in the driver list'
242 % (compat_list_c[0]))
Walter Lozanoe675d962020-07-03 08:07:17 -0300243
Walter Lozano5fe734c2020-07-23 00:22:03 -0300244 return compat_list_c[0], compat_list_c[1:]
Simon Glassd570dec2017-06-18 22:08:58 -0600245
Simon Glassc3a310a82020-12-28 20:34:51 -0700246 def setup_output_dirs(self, output_dirs):
247 """Set up the output directories
248
249 This should be done before setup_output() is called
250
251 Args:
252 output_dirs (tuple of str):
253 Directory to use for C output files.
254 Use None to write files relative current directory
255 Directory to use for H output files.
256 Defaults to the C output dir
257 """
258 def process_dir(ftype, dirname):
259 if dirname:
260 os.makedirs(dirname, exist_ok=True)
261 self._dirnames[ftype] = dirname
262
263 if output_dirs:
264 c_dirname = output_dirs[0]
265 h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
266 process_dir(Ftype.SOURCE, c_dirname)
267 process_dir(Ftype.HEADER, h_dirname)
268
269 def setup_output(self, ftype, fname):
Simon Glassd570dec2017-06-18 22:08:58 -0600270 """Set up the output destination
271
Simon Glass1f730c82017-06-18 22:08:59 -0600272 Once this is done, future calls to self.out() will output to this
Simon Glassc3a310a82020-12-28 20:34:51 -0700273 file. The file used is as follows:
274
275 self._dirnames[ftype] is None: output to fname, or stdout if None
276 self._dirnames[ftype] is not None: output to fname in that directory
277
278 Calling this function multiple times will close the old file and open
279 the new one. If they are the same file, nothing happens and output will
280 continue to the same file.
Simon Glassd570dec2017-06-18 22:08:58 -0600281
282 Args:
Simon Glassc3a310a82020-12-28 20:34:51 -0700283 ftype (str): Type of file to create ('c' or 'h')
284 fname (str): Filename to send output to. If there is a directory in
285 self._dirnames for this file type, it will be put in that
286 directory
Simon Glassd570dec2017-06-18 22:08:58 -0600287 """
Simon Glassc3a310a82020-12-28 20:34:51 -0700288 dirname = self._dirnames[ftype]
289 if dirname:
290 pathname = os.path.join(dirname, fname)
291 if self._outfile:
292 self._outfile.close()
293 self._outfile = open(pathname, 'w')
294 elif fname:
295 if not self._outfile:
296 self._outfile = open(fname, 'w')
Simon Glass6ca0c7a2020-12-28 20:34:48 -0700297 else:
298 self._outfile = sys.stdout
Simon Glassd570dec2017-06-18 22:08:58 -0600299
Simon Glassc3a310a82020-12-28 20:34:51 -0700300 def finish_output(self):
301 """Finish outputing to a file
302
303 This closes the output file, if one is in use
304 """
305 if self._outfile != sys.stdout:
306 self._outfile.close()
307
Simon Glass1f730c82017-06-18 22:08:59 -0600308 def out(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600309 """Output a string to the output file
310
311 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700312 line (str): String to output
Simon Glassd570dec2017-06-18 22:08:58 -0600313 """
Simon Glass1f730c82017-06-18 22:08:59 -0600314 self._outfile.write(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600315
Simon Glass1f730c82017-06-18 22:08:59 -0600316 def buf(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600317 """Buffer up a string to send later
318
319 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700320 line (str): String to add to our 'buffer' list
Simon Glassd570dec2017-06-18 22:08:58 -0600321 """
Simon Glass1f730c82017-06-18 22:08:59 -0600322 self._lines.append(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600323
Simon Glass1f730c82017-06-18 22:08:59 -0600324 def get_buf(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600325 """Get the contents of the output buffer, and clear it
326
327 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700328 list(str): The output buffer, which is then cleared for future use
Simon Glassd570dec2017-06-18 22:08:58 -0600329 """
330 lines = self._lines
331 self._lines = []
332 return lines
333
Simon Glass68d32c72017-08-29 14:16:01 -0600334 def out_header(self):
335 """Output a message indicating that this is an auto-generated file"""
336 self.out('''/*
337 * DO NOT MODIFY
338 *
339 * This file was generated by dtoc from a .dtb (device tree binary) file.
340 */
341
342''')
343
Simon Glassec3b5e42017-08-29 14:15:55 -0600344 def get_phandle_argc(self, prop, node_name):
345 """Check if a node contains phandles
Simon Glassce5621d2017-08-29 14:15:54 -0600346
Simon Glassec3b5e42017-08-29 14:15:55 -0600347 We have no reliable way of detecting whether a node uses a phandle
348 or not. As an interim measure, use a list of known property names.
349
350 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700351 prop (fdt.Prop): Prop object to check
352 node_name (str): Node name, only used for raising an error
353 Returns:
354 int or None: Number of argument cells is this is a phandle,
355 else None
356 Raises:
357 ValueError: if the phandle cannot be parsed or the required property
358 is not present
Simon Glassec3b5e42017-08-29 14:15:55 -0600359 """
Walter Lozano179f0b62020-06-25 01:10:16 -0300360 if prop.name in ['clocks', 'cd-gpios']:
Simon Glass609e2b12018-07-06 10:27:31 -0600361 if not isinstance(prop.value, list):
362 prop.value = [prop.value]
Simon Glassec3b5e42017-08-29 14:15:55 -0600363 val = prop.value
Simon Glassec3b5e42017-08-29 14:15:55 -0600364 i = 0
Simon Glassce5621d2017-08-29 14:15:54 -0600365
Simon Glassec3b5e42017-08-29 14:15:55 -0600366 max_args = 0
367 args = []
368 while i < len(val):
369 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass609e2b12018-07-06 10:27:31 -0600370 # If we get to the end of the list, stop. This can happen
371 # since some nodes have more phandles in the list than others,
372 # but we allocate enough space for the largest list. So those
373 # nodes with shorter lists end up with zeroes at the end.
374 if not phandle:
375 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600376 target = self._fdt.phandle_to_node.get(phandle)
377 if not target:
378 raise ValueError("Cannot parse '%s' in node '%s'" %
379 (prop.name, node_name))
Walter Lozano179f0b62020-06-25 01:10:16 -0300380 cells = None
381 for prop_name in ['#clock-cells', '#gpio-cells']:
382 cells = target.props.get(prop_name)
383 if cells:
384 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600385 if not cells:
Walter Lozano179f0b62020-06-25 01:10:16 -0300386 raise ValueError("Node '%s' has no cells property" %
Simon Glass94ee3bd2020-11-08 20:36:21 -0700387 (target.name))
Simon Glassec3b5e42017-08-29 14:15:55 -0600388 num_args = fdt_util.fdt32_to_cpu(cells.value)
389 max_args = max(max_args, num_args)
390 args.append(num_args)
391 i += 1 + num_args
392 return PhandleInfo(max_args, args)
393 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600394
Simon Glass93daa012020-12-03 16:55:16 -0700395 def scan_driver(self, fname):
Walter Lozanoe675d962020-07-03 08:07:17 -0300396 """Scan a driver file to build a list of driver names and aliases
397
398 This procedure will populate self._drivers and self._driver_aliases
399
400 Args
Simon Glass93daa012020-12-03 16:55:16 -0700401 fname: Driver filename to scan
Walter Lozanoe675d962020-07-03 08:07:17 -0300402 """
Simon Glass93daa012020-12-03 16:55:16 -0700403 with open(fname, encoding='utf-8') as inf:
Walter Lozanoe675d962020-07-03 08:07:17 -0300404 try:
Simon Glass93daa012020-12-03 16:55:16 -0700405 buff = inf.read()
Walter Lozanoe675d962020-07-03 08:07:17 -0300406 except UnicodeDecodeError:
407 # This seems to happen on older Python versions
Simon Glass93daa012020-12-03 16:55:16 -0700408 print("Skipping file '%s' due to unicode error" % fname)
Walter Lozanoe675d962020-07-03 08:07:17 -0300409 return
410
411 # The following re will search for driver names declared as
412 # U_BOOT_DRIVER(driver_name)
Simon Glass27511232020-12-23 08:11:19 -0700413 drivers = re.findall(r'U_BOOT_DRIVER\((.*)\)', buff)
Walter Lozanoe675d962020-07-03 08:07:17 -0300414
415 for driver in drivers:
Simon Glassb42ed512020-12-23 08:11:23 -0700416 self._drivers[driver] = Driver(driver)
Walter Lozanoe675d962020-07-03 08:07:17 -0300417
418 # The following re will search for driver aliases declared as
Simon Glassdf65db82020-12-28 20:34:57 -0700419 # DM_DRIVER_ALIAS(alias, driver_name)
Simon Glass93daa012020-12-03 16:55:16 -0700420 driver_aliases = re.findall(
Simon Glassdf65db82020-12-28 20:34:57 -0700421 r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
Simon Glass93daa012020-12-03 16:55:16 -0700422 buff)
Walter Lozanoe675d962020-07-03 08:07:17 -0300423
424 for alias in driver_aliases: # pragma: no cover
425 if len(alias) != 2:
426 continue
427 self._driver_aliases[alias[1]] = alias[0]
428
429 def scan_drivers(self):
430 """Scan the driver folders to build a list of driver names and aliases
431
432 This procedure will populate self._drivers and self._driver_aliases
433
434 """
435 basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
436 if basedir == '':
437 basedir = './'
Simon Glass93daa012020-12-03 16:55:16 -0700438 for (dirpath, _, filenames) in os.walk(basedir):
439 for fname in filenames:
440 if not fname.endswith('.c'):
Walter Lozanoe675d962020-07-03 08:07:17 -0300441 continue
Simon Glass93daa012020-12-03 16:55:16 -0700442 self.scan_driver(dirpath + '/' + fname)
Walter Lozanoe675d962020-07-03 08:07:17 -0300443
Simon Glass93daa012020-12-03 16:55:16 -0700444 for fname in self._drivers_additional:
445 if not isinstance(fname, str) or len(fname) == 0:
Walter Lozanod82062b2020-07-28 19:06:23 -0300446 continue
Simon Glass93daa012020-12-03 16:55:16 -0700447 if fname[0] == '/':
448 self.scan_driver(fname)
Walter Lozanod82062b2020-07-28 19:06:23 -0300449 else:
Simon Glass93daa012020-12-03 16:55:16 -0700450 self.scan_driver(basedir + '/' + fname)
Walter Lozanod82062b2020-07-28 19:06:23 -0300451
Simon Glass1f730c82017-06-18 22:08:59 -0600452 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200453 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600454
Simon Glass1f730c82017-06-18 22:08:59 -0600455 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600456 device tree root node, and progress from there.
457 """
Simon Glass1f730c82017-06-18 22:08:59 -0600458 self._fdt = fdt.FdtScan(self._dtb_fname)
459
Simon Glass192f8132020-10-03 11:31:25 -0600460 def scan_node(self, root, valid_nodes):
Simon Glass1f730c82017-06-18 22:08:59 -0600461 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600462
Simon Glass17ffd622017-08-29 14:15:53 -0600463 This adds each node to self._valid_nodes.
Simon Glass1f730c82017-06-18 22:08:59 -0600464
465 Args:
Simon Glass27511232020-12-23 08:11:19 -0700466 root (Node): Root node for scan
467 valid_nodes (list of Node): List of Node objects to add to
Simon Glass1f730c82017-06-18 22:08:59 -0600468 """
Simon Glassd570dec2017-06-18 22:08:58 -0600469 for node in root.subnodes:
470 if 'compatible' in node.props:
471 status = node.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600472 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600473 status.value != 'disabled'):
Simon Glass192f8132020-10-03 11:31:25 -0600474 valid_nodes.append(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600475
476 # recurse to handle any subnodes
Simon Glass192f8132020-10-03 11:31:25 -0600477 self.scan_node(node, valid_nodes)
Simon Glassd570dec2017-06-18 22:08:58 -0600478
Simon Glass1f730c82017-06-18 22:08:59 -0600479 def scan_tree(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600480 """Scan the device tree for useful information
481
482 This fills in the following properties:
Simon Glassd570dec2017-06-18 22:08:58 -0600483 _valid_nodes: A list of nodes we wish to consider include in the
484 platform data
485 """
Simon Glass192f8132020-10-03 11:31:25 -0600486 valid_nodes = []
487 self.scan_node(self._fdt.GetRoot(), valid_nodes)
488 self._valid_nodes = sorted(valid_nodes,
489 key=lambda x: conv_name_to_c(x.name))
490 for idx, node in enumerate(self._valid_nodes):
491 node.idx = idx
Simon Glassd570dec2017-06-18 22:08:58 -0600492
Simon Glass1b1fe412017-08-29 14:15:50 -0600493 @staticmethod
494 def get_num_cells(node):
495 """Get the number of cells in addresses and sizes for this node
496
497 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700498 node (fdt.None): Node to check
Simon Glass1b1fe412017-08-29 14:15:50 -0600499
500 Returns:
501 Tuple:
502 Number of address cells for this node
503 Number of size cells for this node
504 """
505 parent = node.parent
Simon Glass93daa012020-12-03 16:55:16 -0700506 num_addr, num_size = 2, 2
Simon Glass1b1fe412017-08-29 14:15:50 -0600507 if parent:
Simon Glass93daa012020-12-03 16:55:16 -0700508 addr_prop = parent.props.get('#address-cells')
509 size_prop = parent.props.get('#size-cells')
510 if addr_prop:
511 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
512 if size_prop:
513 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
514 return num_addr, num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600515
516 def scan_reg_sizes(self):
517 """Scan for 64-bit 'reg' properties and update the values
518
519 This finds 'reg' properties with 64-bit data and converts the value to
520 an array of 64-values. This allows it to be output in a way that the
521 C code can read.
522 """
523 for node in self._valid_nodes:
524 reg = node.props.get('reg')
525 if not reg:
526 continue
Simon Glass93daa012020-12-03 16:55:16 -0700527 num_addr, num_size = self.get_num_cells(node)
528 total = num_addr + num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600529
Simon Glassc9a032c2020-11-08 20:36:17 -0700530 if reg.type != fdt.Type.INT:
Simon Glassc38fee042018-07-06 10:27:32 -0600531 raise ValueError("Node '%s' reg property is not an int" %
532 node.name)
Simon Glass1b1fe412017-08-29 14:15:50 -0600533 if len(reg.value) % total:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700534 raise ValueError(
535 "Node '%s' reg property has %d cells "
536 'which is not a multiple of na + ns = %d + %d)' %
Simon Glass93daa012020-12-03 16:55:16 -0700537 (node.name, len(reg.value), num_addr, num_size))
538 reg.num_addr = num_addr
539 reg.num_size = num_size
540 if num_addr != 1 or num_size != 1:
Simon Glassc9a032c2020-11-08 20:36:17 -0700541 reg.type = fdt.Type.INT64
Simon Glass1b1fe412017-08-29 14:15:50 -0600542 i = 0
543 new_value = []
544 val = reg.value
545 if not isinstance(val, list):
546 val = [val]
547 while i < len(val):
Simon Glass93daa012020-12-03 16:55:16 -0700548 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
549 i += num_addr
550 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
551 i += num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600552 new_value += [addr, size]
553 reg.value = new_value
554
Simon Glass1f730c82017-06-18 22:08:59 -0600555 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600556 """Scan the device tree building up the C structures we will use.
557
558 Build a dict keyed by C struct name containing a dict of Prop
559 object for each struct field (keyed by property name). Where the
560 same struct appears multiple times, try to use the 'widest'
561 property, i.e. the one with a type which can express all others.
562
563 Once the widest property is determined, all other properties are
564 updated to match that width.
Simon Glass941f8f02020-10-03 11:31:24 -0600565
566 Returns:
Simon Glass27511232020-12-23 08:11:19 -0700567 dict of dict: dict containing structures:
Simon Glass941f8f02020-10-03 11:31:24 -0600568 key (str): Node name, as a C identifier
569 value: dict containing structure fields:
570 key (str): Field name
571 value: Prop object with field information
Simon Glassd570dec2017-06-18 22:08:58 -0600572 """
Simon Glass192f8132020-10-03 11:31:25 -0600573 structs = collections.OrderedDict()
Simon Glassd570dec2017-06-18 22:08:58 -0600574 for node in self._valid_nodes:
Walter Lozanoe675d962020-07-03 08:07:17 -0300575 node_name, _ = self.get_normalized_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600576 fields = {}
577
578 # Get a list of all the valid properties in this node.
579 for name, prop in node.props.items():
580 if name not in PROP_IGNORE_LIST and name[0] != '#':
581 fields[name] = copy.deepcopy(prop)
582
583 # If we've seen this node_name before, update the existing struct.
584 if node_name in structs:
585 struct = structs[node_name]
586 for name, prop in fields.items():
587 oldprop = struct.get(name)
588 if oldprop:
589 oldprop.Widen(prop)
590 else:
591 struct[name] = prop
592
593 # Otherwise store this as a new struct.
594 else:
595 structs[node_name] = fields
596
Simon Glassd570dec2017-06-18 22:08:58 -0600597 for node in self._valid_nodes:
Walter Lozanoe675d962020-07-03 08:07:17 -0300598 node_name, _ = self.get_normalized_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600599 struct = structs[node_name]
600 for name, prop in node.props.items():
601 if name not in PROP_IGNORE_LIST and name[0] != '#':
602 prop.Widen(struct[name])
Simon Glassd570dec2017-06-18 22:08:58 -0600603
Simon Glassd570dec2017-06-18 22:08:58 -0600604 return structs
605
Simon Glass1f730c82017-06-18 22:08:59 -0600606 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600607 """Figure out what phandles each node uses
608
609 We need to be careful when outputing nodes that use phandles since
610 they must come after the declaration of the phandles in the C file.
611 Otherwise we get a compiler error since the phandle struct is not yet
612 declared.
613
614 This function adds to each node a list of phandle nodes that the node
615 depends on. This allows us to output things in the right order.
616 """
617 for node in self._valid_nodes:
618 node.phandles = set()
619 for pname, prop in node.props.items():
620 if pname in PROP_IGNORE_LIST or pname[0] == '#':
621 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600622 info = self.get_phandle_argc(prop, node.name)
623 if info:
Simon Glassec3b5e42017-08-29 14:15:55 -0600624 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600625 pos = 0
626 for args in info.args:
627 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600628 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
629 target_node = self._fdt.phandle_to_node[phandle]
630 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600631 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600632
633
Simon Glass1f730c82017-06-18 22:08:59 -0600634 def generate_structs(self, structs):
Simon Glassd570dec2017-06-18 22:08:58 -0600635 """Generate struct defintions for the platform data
636
637 This writes out the body of a header file consisting of structure
638 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100639 doc/driver-model/of-plat.rst for more information.
Simon Glass941f8f02020-10-03 11:31:24 -0600640
641 Args:
Simon Glass27511232020-12-23 08:11:19 -0700642 structs (dict): dict containing structures:
Simon Glass941f8f02020-10-03 11:31:24 -0600643 key (str): Node name, as a C identifier
644 value: dict containing structure fields:
645 key (str): Field name
646 value: Prop object with field information
647
Simon Glassd570dec2017-06-18 22:08:58 -0600648 """
Simon Glass68d32c72017-08-29 14:16:01 -0600649 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600650 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900651 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600652
653 # Output the struct definition
654 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600655 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600656 for pname in sorted(structs[name]):
657 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600658 info = self.get_phandle_argc(prop, structs[name])
659 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600660 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600661 struct_name = 'struct phandle_%d_arg' % info.max_args
662 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600663 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600664 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600665 else:
666 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600667 self.out('\t%s%s' % (tab_to(2, ptype),
668 conv_name_to_c(prop.name)))
669 if isinstance(prop.value, list):
670 self.out('[%d]' % len(prop.value))
671 self.out(';\n')
672 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600673
Simon Glass9d98b6e2020-12-23 08:11:20 -0700674 def _output_list(self, node, prop):
675 """Output the C code for a devicetree property that holds a list
Simon Glassd570dec2017-06-18 22:08:58 -0600676
677 Args:
Simon Glass9d98b6e2020-12-23 08:11:20 -0700678 node (fdt.Node): Node to output
679 prop (fdt.Prop): Prop to output
Simon Glassd570dec2017-06-18 22:08:58 -0600680 """
Simon Glass9d98b6e2020-12-23 08:11:20 -0700681 self.buf('{')
682 vals = []
683 # For phandles, output a reference to the platform data
684 # of the target node.
685 info = self.get_phandle_argc(prop, node.name)
686 if info:
687 # Process the list as pairs of (phandle, id)
688 pos = 0
689 for args in info.args:
690 phandle_cell = prop.value[pos]
691 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
692 target_node = self._fdt.phandle_to_node[phandle]
693 arg_values = []
694 for i in range(args):
695 arg_values.append(
696 str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
697 pos += 1 + args
698 vals.append('\t{%d, {%s}}' % (target_node.idx,
699 ', '.join(arg_values)))
700 for val in vals:
701 self.buf('\n\t\t%s,' % val)
702 else:
703 for val in prop.value:
704 vals.append(get_value(prop.type, val))
Simon Glassbc9e2682020-10-03 09:25:18 -0600705
Simon Glass9d98b6e2020-12-23 08:11:20 -0700706 # Put 8 values per line to avoid very long lines.
707 for i in range(0, len(vals), 8):
708 if i:
709 self.buf(',\n\t\t')
710 self.buf(', '.join(vals[i:i + 8]))
711 self.buf('}')
Simon Glassbc9e2682020-10-03 09:25:18 -0600712
Simon Glass9fdd0c32020-12-23 08:11:21 -0700713 def _declare_device(self, var_name, struct_name, node_parent):
714 """Add a device declaration to the output
715
Simon Glass1d8364a2020-12-28 20:34:54 -0700716 This declares a U_BOOT_DRVINFO() for the device being processed
Simon Glass9fdd0c32020-12-23 08:11:21 -0700717
718 Args:
719 var_name (str): C name for the node
720 struct_name (str): Name for the dt struct associated with the node
721 node_parent (Node): Parent of the node (or None if none)
722 """
Simon Glass1d8364a2020-12-28 20:34:54 -0700723 self.buf('U_BOOT_DRVINFO(%s) = {\n' % var_name)
Simon Glass9fdd0c32020-12-23 08:11:21 -0700724 self.buf('\t.name\t\t= "%s",\n' % struct_name)
725 self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, var_name))
726 self.buf('\t.plat_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
727 idx = -1
728 if node_parent and node_parent in self._valid_nodes:
729 idx = node_parent.idx
730 self.buf('\t.parent_idx\t= %d,\n' % idx)
731 self.buf('};\n')
732 self.buf('\n')
733
Simon Glass9829eea2020-12-23 08:11:22 -0700734 def _output_prop(self, node, prop):
735 """Output a line containing the value of a struct member
736
737 Args:
738 node (Node): Node being output
739 prop (Prop): Prop object to output
740 """
741 if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
742 return
743 member_name = conv_name_to_c(prop.name)
744 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
745
746 # Special handling for lists
747 if isinstance(prop.value, list):
748 self._output_list(node, prop)
749 else:
750 self.buf(get_value(prop.type, prop.value))
751 self.buf(',\n')
752
753 def _output_values(self, var_name, struct_name, node):
754 """Output the definition of a device's struct values
755
756 Args:
757 var_name (str): C name for the node
758 struct_name (str): Name for the dt struct associated with the node
759 node (Node): Node being output
760 """
761 self.buf('static struct %s%s %s%s = {\n' %
762 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
763 for pname in sorted(node.props):
764 self._output_prop(node, node.props[pname])
765 self.buf('};\n')
766
Simon Glass9d98b6e2020-12-23 08:11:20 -0700767 def output_node(self, node):
768 """Output the C code for a node
Simon Glassbc9e2682020-10-03 09:25:18 -0600769
Simon Glass9d98b6e2020-12-23 08:11:20 -0700770 Args:
771 node (fdt.Node): node to output
772 """
Walter Lozanoe675d962020-07-03 08:07:17 -0300773 struct_name, _ = self.get_normalized_compat_name(node)
Simon Glass1f730c82017-06-18 22:08:59 -0600774 var_name = conv_name_to_c(node.name)
Simon Glass192f8132020-10-03 11:31:25 -0600775 self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
Simon Glassd570dec2017-06-18 22:08:58 -0600776
Simon Glass9829eea2020-12-23 08:11:22 -0700777 self._output_values(var_name, struct_name, node)
Simon Glass9fdd0c32020-12-23 08:11:21 -0700778 self._declare_device(var_name, struct_name, node.parent)
Simon Glassd570dec2017-06-18 22:08:58 -0600779
Simon Glass1f730c82017-06-18 22:08:59 -0600780 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -0600781
Simon Glass1f730c82017-06-18 22:08:59 -0600782 def generate_tables(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600783 """Generate device defintions for the platform data
784
785 This writes out C platform data initialisation data and
Simon Glass1d8364a2020-12-28 20:34:54 -0700786 U_BOOT_DRVINFO() declarations for each valid node. Where a node has
Simon Glassd570dec2017-06-18 22:08:58 -0600787 multiple compatible strings, a #define is used to make them equivalent.
788
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100789 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glassd570dec2017-06-18 22:08:58 -0600790 information.
791 """
Simon Glass68d32c72017-08-29 14:16:01 -0600792 self.out_header()
Simon Glass1d8364a2020-12-28 20:34:54 -0700793 self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
Simon Glass4c73d7b2020-10-03 11:31:41 -0600794 self.out('#define DT_PLATDATA_C\n')
795 self.out('\n')
Simon Glass1f730c82017-06-18 22:08:59 -0600796 self.out('#include <common.h>\n')
797 self.out('#include <dm.h>\n')
798 self.out('#include <dt-structs.h>\n')
799 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600800 nodes_to_output = list(self._valid_nodes)
801
802 # Keep outputing nodes until there is none left
803 while nodes_to_output:
804 node = nodes_to_output[0]
805 # Output all the node's dependencies first
806 for req_node in node.phandles:
807 if req_node in nodes_to_output:
Simon Glass1f730c82017-06-18 22:08:59 -0600808 self.output_node(req_node)
Simon Glassd570dec2017-06-18 22:08:58 -0600809 nodes_to_output.remove(req_node)
Simon Glass1f730c82017-06-18 22:08:59 -0600810 self.output_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600811 nodes_to_output.remove(node)
Simon Glass3fa797a2017-06-18 22:09:03 -0600812
Walter Lozanodc5b4372020-06-25 01:10:13 -0300813 # Define dm_populate_phandle_data() which will add the linking between
Simon Glasse10c0ff2020-12-28 20:34:55 -0700814 # nodes using DM_DRVINFO_GET
815 # dtv_dmc_at_xxx.clocks[0].node = DM_DRVINFO_GET(clock_controller_at_xxx)
Walter Lozanodc5b4372020-06-25 01:10:13 -0300816 self.buf('void dm_populate_phandle_data(void) {\n')
Walter Lozanodc5b4372020-06-25 01:10:13 -0300817 self.buf('}\n')
818
819 self.out(''.join(self.get_buf()))
Simon Glass3fa797a2017-06-18 22:09:03 -0600820
Simon Glassc3a310a82020-12-28 20:34:51 -0700821
822# Types of output file we understand
823# key: Command used to generate this file
824# value: OutputFile for this command
825OUTPUT_FILES = {
826 'struct': OutputFile(Ftype.HEADER, 'dt-structs-gen.h'),
827 'platdata': OutputFile(Ftype.SOURCE, 'dt-platdata.c'),
828 }
829
Simon Glass6a65d8a2020-12-28 20:34:50 -0700830
831def run_steps(args, dtb_file, include_disabled, output, output_dirs,
832 warning_disabled=False, drivers_additional=None):
Simon Glass3fa797a2017-06-18 22:09:03 -0600833 """Run all the steps of the dtoc tool
834
835 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700836 args (list): List of non-option arguments provided to the problem
837 dtb_file (str): Filename of dtb file to process
838 include_disabled (bool): True to include disabled nodes
Simon Glass6ca0c7a2020-12-28 20:34:48 -0700839 output (str): Name of output file (None for stdout)
Simon Glass6a65d8a2020-12-28 20:34:50 -0700840 output_dirs (tuple of str):
841 Directory to put C output files
842 Directory to put H output files
Simon Glass93daa012020-12-03 16:55:16 -0700843 warning_disabled (bool): True to avoid showing warnings about missing
844 drivers
Simon Glass27511232020-12-23 08:11:19 -0700845 drivers_additional (list): List of additional drivers to use during
Simon Glass93daa012020-12-03 16:55:16 -0700846 scanning
Simon Glass94ee3bd2020-11-08 20:36:21 -0700847 Raises:
848 ValueError: if args has no command, or an unknown command
Simon Glass3fa797a2017-06-18 22:09:03 -0600849 """
850 if not args:
Simon Glassc3a310a82020-12-28 20:34:51 -0700851 raise ValueError('Please specify a command: struct, platdata, all')
852 if output and output_dirs and any(output_dirs):
853 raise ValueError('Must specify either output or output_dirs, not both')
Simon Glass3fa797a2017-06-18 22:09:03 -0600854
Simon Glass93daa012020-12-03 16:55:16 -0700855 plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled,
856 drivers_additional)
Walter Lozanoe675d962020-07-03 08:07:17 -0300857 plat.scan_drivers()
Simon Glass3fa797a2017-06-18 22:09:03 -0600858 plat.scan_dtb()
859 plat.scan_tree()
Simon Glass1b1fe412017-08-29 14:15:50 -0600860 plat.scan_reg_sizes()
Simon Glassc3a310a82020-12-28 20:34:51 -0700861 plat.setup_output_dirs(output_dirs)
Simon Glass3fa797a2017-06-18 22:09:03 -0600862 structs = plat.scan_structs()
863 plat.scan_phandles()
864
Simon Glass4e8e8462020-12-28 20:34:52 -0700865 cmds = args[0].split(',')
866 if 'all' in cmds:
867 cmds = sorted(OUTPUT_FILES.keys())
868 for cmd in cmds:
Simon Glassc3a310a82020-12-28 20:34:51 -0700869 outfile = OUTPUT_FILES.get(cmd)
870 if not outfile:
871 raise ValueError("Unknown command '%s': (use: %s)" %
Simon Glass4e8e8462020-12-28 20:34:52 -0700872 (cmd, ', '.join(sorted(OUTPUT_FILES.keys()))))
Simon Glassc3a310a82020-12-28 20:34:51 -0700873 plat.setup_output(outfile.ftype,
874 outfile.fname if output_dirs else output)
Simon Glass3fa797a2017-06-18 22:09:03 -0600875 if cmd == 'struct':
876 plat.generate_structs(structs)
877 elif cmd == 'platdata':
878 plat.generate_tables()
Simon Glassc3a310a82020-12-28 20:34:51 -0700879 plat.finish_output()