blob: 4cdbd60c9ae00ab890630927f464cccbbea9a288 [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)
Simon Glass6b208842020-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',
Simon Glass55526782020-12-28 20:35:02 -070062 ['ftype', 'fname', 'method', 'hdr_comment'])
Simon Glassc3a310a82020-12-28 20:34:51 -070063
Simon Glassec3b5e42017-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 Glassc1622112020-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 Glassec3b5e42017-08-29 14:15:55 -060078
Simon Glassb42ed512020-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 Glass1f730c82017-06-18 22:08:59 -060095def conv_name_to_c(name):
Simon Glassd570dec2017-06-18 22:08:58 -060096 """Convert a device-tree name to a C identifier
97
Simon Glass2e0bf3f2017-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 Glassd570dec2017-06-18 22:08:58 -0600101 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700102 name (str): Name to convert
Simon Glassd570dec2017-06-18 22:08:58 -0600103 Return:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700104 str: String containing the C version of this name
Simon Glassd570dec2017-06-18 22:08:58 -0600105 """
Simon Glass1f730c82017-06-18 22:08:59 -0600106 new = name.replace('@', '_at_')
107 new = new.replace('-', '_')
108 new = new.replace(',', '_')
109 new = new.replace('.', '_')
Simon Glass1f730c82017-06-18 22:08:59 -0600110 return new
Simon Glassd570dec2017-06-18 22:08:58 -0600111
Simon Glass1f730c82017-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 Glassd570dec2017-06-18 22:08:58 -0600114
Simon Glass1f730c82017-06-18 22:08:59 -0600115 Args:
Simon Glass94ee3bd2020-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 Glass1f730c82017-06-18 22:08:59 -0600118
119 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700120 str: line with the correct number of tabs appeneded. If the line already
Simon Glass1f730c82017-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 Glass7a2add12017-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 Glass94ee3bd2020-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 Glass7a2add12017-06-18 22:09:02 -0600141 """
Simon Glassc9a032c2020-11-08 20:36:17 -0700142 if ftype == fdt.Type.INT:
Simon Glass27511232020-12-23 08:11:19 -0700143 val = '%#x' % fdt_util.fdt32_to_cpu(value)
Simon Glassc9a032c2020-11-08 20:36:17 -0700144 elif ftype == fdt.Type.BYTE:
Simon Glass93daa012020-12-03 16:55:16 -0700145 char = value[0]
Simon Glass27511232020-12-23 08:11:19 -0700146 val = '%#x' % (ord(char) if isinstance(char, str) else char)
Simon Glassc9a032c2020-11-08 20:36:17 -0700147 elif ftype == fdt.Type.STRING:
Simon Glass7f5e2262020-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 Glass27511232020-12-23 08:11:19 -0700150 val = '"%s"' % value.replace('\\', '\\\\')
Simon Glassc9a032c2020-11-08 20:36:17 -0700151 elif ftype == fdt.Type.BOOL:
Simon Glass27511232020-12-23 08:11:19 -0700152 val = 'true'
Simon Glass94ee3bd2020-11-08 20:36:21 -0700153 else: # ftype == fdt.Type.INT64:
Simon Glass27511232020-12-23 08:11:19 -0700154 val = '%#x' % value
155 return val
Simon Glass7a2add12017-06-18 22:09:02 -0600156
157def get_compat_name(node):
Walter Lozano5fe734c2020-07-23 00:22:03 -0300158 """Get the node's list of compatible string as a C identifiers
Simon Glass7a2add12017-06-18 22:09:02 -0600159
160 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700161 node (fdt.Node): Node object to check
Simon Glass7a2add12017-06-18 22:09:02 -0600162 Return:
Simon Glass27511232020-12-23 08:11:19 -0700163 list of str: List of C identifiers for all the compatible strings
Simon Glass7a2add12017-06-18 22:09:02 -0600164 """
165 compat = node.props['compatible'].value
Walter Lozano5fe734c2020-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 Glass7a2add12017-06-18 22:09:02 -0600169
Simon Glass7a2add12017-06-18 22:09:02 -0600170
Simon Glass27511232020-12-23 08:11:19 -0700171class DtbPlatdata():
Simon Glassd570dec2017-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 Glass1f730c82017-06-18 22:08:59 -0600179 _fdt: Fdt object, referencing the device tree
Simon Glassd570dec2017-06-18 22:08:58 -0600180 _dtb_fname: Filename of the input device tree binary file
Simon Glass192f8132020-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 Glasseab3f622017-06-18 22:09:01 -0600183 _include_disabled: true to include nodes marked status = "disabled"
Simon Glassd570dec2017-06-18 22:08:58 -0600184 _outfile: The current output file (sys.stdout or a real file)
Walter Lozanoa324e412020-06-25 01:10:08 -0300185 _warning_disabled: true to disable warnings about driver names not found
Simon Glassd570dec2017-06-18 22:08:58 -0600186 _lines: Stashed list of output lines for outputting in the future
Simon Glassb42ed512020-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 Lozanoe675d962020-07-03 08:07:17 -0300190 _driver_aliases: Dict that holds aliases for driver names
191 key: Driver alias declared with
Simon Glassdf65db82020-12-28 20:34:57 -0700192 DM_DRIVER_ALIAS(driver_alias, driver_name)
Walter Lozanoe675d962020-07-03 08:07:17 -0300193 value: Driver name declared with U_BOOT_DRIVER(driver_name)
Walter Lozanod82062b2020-07-28 19:06:23 -0300194 _drivers_additional: List of additional drivers to use during scanning
Simon Glassc3a310a82020-12-28 20:34:51 -0700195 _dirname: Directory to hold output files, or None for none (all files
196 go to stdout)
Simon Glass55526782020-12-28 20:35:02 -0700197 _struct_data (dict): OrderedDict of dtplat structures to output
198 key (str): Node name, as a C identifier
199 value: dict containing structure fields:
200 key (str): Field name
201 value: Prop object with field information
Simon Glass4f2059b2020-12-28 20:35:03 -0700202 _basedir (str): Base directory of source tree
Simon Glassd570dec2017-06-18 22:08:58 -0600203 """
Walter Lozanod82062b2020-07-28 19:06:23 -0300204 def __init__(self, dtb_fname, include_disabled, warning_disabled,
Simon Glass93daa012020-12-03 16:55:16 -0700205 drivers_additional=None):
Simon Glass1f730c82017-06-18 22:08:59 -0600206 self._fdt = None
Simon Glassd570dec2017-06-18 22:08:58 -0600207 self._dtb_fname = dtb_fname
208 self._valid_nodes = None
Simon Glasseab3f622017-06-18 22:09:01 -0600209 self._include_disabled = include_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600210 self._outfile = None
Walter Lozanoa324e412020-06-25 01:10:08 -0300211 self._warning_disabled = warning_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600212 self._lines = []
Simon Glassb42ed512020-12-23 08:11:23 -0700213 self._drivers = {}
Walter Lozanoe675d962020-07-03 08:07:17 -0300214 self._driver_aliases = {}
Simon Glass93daa012020-12-03 16:55:16 -0700215 self._drivers_additional = drivers_additional or []
Simon Glassc3a310a82020-12-28 20:34:51 -0700216 self._dirnames = [None] * len(Ftype)
Simon Glass55526782020-12-28 20:35:02 -0700217 self._struct_data = collections.OrderedDict()
Simon Glass4f2059b2020-12-28 20:35:03 -0700218 self._basedir = None
Walter Lozanoe675d962020-07-03 08:07:17 -0300219
220 def get_normalized_compat_name(self, node):
221 """Get a node's normalized compat name
222
Walter Lozano5fe734c2020-07-23 00:22:03 -0300223 Returns a valid driver name by retrieving node's list of compatible
Walter Lozanoe675d962020-07-03 08:07:17 -0300224 string as a C identifier and performing a check against _drivers
225 and a lookup in driver_aliases printing a warning in case of failure.
226
227 Args:
Simon Glass27511232020-12-23 08:11:19 -0700228 node (Node): Node object to check
Walter Lozanoe675d962020-07-03 08:07:17 -0300229 Return:
230 Tuple:
231 Driver name associated with the first compatible string
232 List of C identifiers for all the other compatible strings
233 (possibly empty)
234 In case of no match found, the return will be the same as
235 get_compat_name()
236 """
Walter Lozano5fe734c2020-07-23 00:22:03 -0300237 compat_list_c = get_compat_name(node)
238
239 for compat_c in compat_list_c:
Simon Glassb42ed512020-12-23 08:11:23 -0700240 if not compat_c in self._drivers.keys():
Walter Lozano5fe734c2020-07-23 00:22:03 -0300241 compat_c = self._driver_aliases.get(compat_c)
242 if not compat_c:
243 continue
244
245 aliases_c = compat_list_c
246 if compat_c in aliases_c:
247 aliases_c.remove(compat_c)
248 return compat_c, aliases_c
249
250 if not self._warning_disabled:
251 print('WARNING: the driver %s was not found in the driver list'
252 % (compat_list_c[0]))
Walter Lozanoe675d962020-07-03 08:07:17 -0300253
Walter Lozano5fe734c2020-07-23 00:22:03 -0300254 return compat_list_c[0], compat_list_c[1:]
Simon Glassd570dec2017-06-18 22:08:58 -0600255
Simon Glassc3a310a82020-12-28 20:34:51 -0700256 def setup_output_dirs(self, output_dirs):
257 """Set up the output directories
258
259 This should be done before setup_output() is called
260
261 Args:
262 output_dirs (tuple of str):
263 Directory to use for C output files.
264 Use None to write files relative current directory
265 Directory to use for H output files.
266 Defaults to the C output dir
267 """
268 def process_dir(ftype, dirname):
269 if dirname:
270 os.makedirs(dirname, exist_ok=True)
271 self._dirnames[ftype] = dirname
272
273 if output_dirs:
274 c_dirname = output_dirs[0]
275 h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
276 process_dir(Ftype.SOURCE, c_dirname)
277 process_dir(Ftype.HEADER, h_dirname)
278
279 def setup_output(self, ftype, fname):
Simon Glassd570dec2017-06-18 22:08:58 -0600280 """Set up the output destination
281
Simon Glass1f730c82017-06-18 22:08:59 -0600282 Once this is done, future calls to self.out() will output to this
Simon Glassc3a310a82020-12-28 20:34:51 -0700283 file. The file used is as follows:
284
285 self._dirnames[ftype] is None: output to fname, or stdout if None
286 self._dirnames[ftype] is not None: output to fname in that directory
287
288 Calling this function multiple times will close the old file and open
289 the new one. If they are the same file, nothing happens and output will
290 continue to the same file.
Simon Glassd570dec2017-06-18 22:08:58 -0600291
292 Args:
Simon Glassc3a310a82020-12-28 20:34:51 -0700293 ftype (str): Type of file to create ('c' or 'h')
294 fname (str): Filename to send output to. If there is a directory in
295 self._dirnames for this file type, it will be put in that
296 directory
Simon Glassd570dec2017-06-18 22:08:58 -0600297 """
Simon Glassc3a310a82020-12-28 20:34:51 -0700298 dirname = self._dirnames[ftype]
299 if dirname:
300 pathname = os.path.join(dirname, fname)
301 if self._outfile:
302 self._outfile.close()
303 self._outfile = open(pathname, 'w')
304 elif fname:
305 if not self._outfile:
306 self._outfile = open(fname, 'w')
Simon Glass6ca0c7a2020-12-28 20:34:48 -0700307 else:
308 self._outfile = sys.stdout
Simon Glassd570dec2017-06-18 22:08:58 -0600309
Simon Glassc3a310a82020-12-28 20:34:51 -0700310 def finish_output(self):
311 """Finish outputing to a file
312
313 This closes the output file, if one is in use
314 """
315 if self._outfile != sys.stdout:
316 self._outfile.close()
317
Simon Glass1f730c82017-06-18 22:08:59 -0600318 def out(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600319 """Output a string to the output file
320
321 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700322 line (str): String to output
Simon Glassd570dec2017-06-18 22:08:58 -0600323 """
Simon Glass1f730c82017-06-18 22:08:59 -0600324 self._outfile.write(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600325
Simon Glass1f730c82017-06-18 22:08:59 -0600326 def buf(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600327 """Buffer up a string to send later
328
329 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700330 line (str): String to add to our 'buffer' list
Simon Glassd570dec2017-06-18 22:08:58 -0600331 """
Simon Glass1f730c82017-06-18 22:08:59 -0600332 self._lines.append(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600333
Simon Glass1f730c82017-06-18 22:08:59 -0600334 def get_buf(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600335 """Get the contents of the output buffer, and clear it
336
337 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700338 list(str): The output buffer, which is then cleared for future use
Simon Glassd570dec2017-06-18 22:08:58 -0600339 """
340 lines = self._lines
341 self._lines = []
342 return lines
343
Simon Glass6b208842020-12-28 20:35:00 -0700344 def out_header(self, outfile):
345 """Output a message indicating that this is an auto-generated file
346
347 Args:
348 outfile: OutputFile describing the file being generated
349 """
Simon Glass68d32c72017-08-29 14:16:01 -0600350 self.out('''/*
351 * DO NOT MODIFY
352 *
Simon Glass6b208842020-12-28 20:35:00 -0700353 * %s.
354 * This was generated by dtoc from a .dtb (device tree binary) file.
Simon Glass68d32c72017-08-29 14:16:01 -0600355 */
356
Simon Glass6b208842020-12-28 20:35:00 -0700357''' % outfile.hdr_comment)
Simon Glass68d32c72017-08-29 14:16:01 -0600358
Simon Glassec3b5e42017-08-29 14:15:55 -0600359 def get_phandle_argc(self, prop, node_name):
360 """Check if a node contains phandles
Simon Glassce5621d2017-08-29 14:15:54 -0600361
Simon Glassec3b5e42017-08-29 14:15:55 -0600362 We have no reliable way of detecting whether a node uses a phandle
363 or not. As an interim measure, use a list of known property names.
364
365 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700366 prop (fdt.Prop): Prop object to check
367 node_name (str): Node name, only used for raising an error
368 Returns:
369 int or None: Number of argument cells is this is a phandle,
370 else None
371 Raises:
372 ValueError: if the phandle cannot be parsed or the required property
373 is not present
Simon Glassec3b5e42017-08-29 14:15:55 -0600374 """
Walter Lozano179f0b62020-06-25 01:10:16 -0300375 if prop.name in ['clocks', 'cd-gpios']:
Simon Glass609e2b12018-07-06 10:27:31 -0600376 if not isinstance(prop.value, list):
377 prop.value = [prop.value]
Simon Glassec3b5e42017-08-29 14:15:55 -0600378 val = prop.value
Simon Glassec3b5e42017-08-29 14:15:55 -0600379 i = 0
Simon Glassce5621d2017-08-29 14:15:54 -0600380
Simon Glassec3b5e42017-08-29 14:15:55 -0600381 max_args = 0
382 args = []
383 while i < len(val):
384 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass609e2b12018-07-06 10:27:31 -0600385 # If we get to the end of the list, stop. This can happen
386 # since some nodes have more phandles in the list than others,
387 # but we allocate enough space for the largest list. So those
388 # nodes with shorter lists end up with zeroes at the end.
389 if not phandle:
390 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600391 target = self._fdt.phandle_to_node.get(phandle)
392 if not target:
393 raise ValueError("Cannot parse '%s' in node '%s'" %
394 (prop.name, node_name))
Walter Lozano179f0b62020-06-25 01:10:16 -0300395 cells = None
396 for prop_name in ['#clock-cells', '#gpio-cells']:
397 cells = target.props.get(prop_name)
398 if cells:
399 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600400 if not cells:
Walter Lozano179f0b62020-06-25 01:10:16 -0300401 raise ValueError("Node '%s' has no cells property" %
Simon Glass94ee3bd2020-11-08 20:36:21 -0700402 (target.name))
Simon Glassec3b5e42017-08-29 14:15:55 -0600403 num_args = fdt_util.fdt32_to_cpu(cells.value)
404 max_args = max(max_args, num_args)
405 args.append(num_args)
406 i += 1 + num_args
407 return PhandleInfo(max_args, args)
408 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600409
Simon Glass93daa012020-12-03 16:55:16 -0700410 def scan_driver(self, fname):
Walter Lozanoe675d962020-07-03 08:07:17 -0300411 """Scan a driver file to build a list of driver names and aliases
412
413 This procedure will populate self._drivers and self._driver_aliases
414
415 Args
Simon Glass93daa012020-12-03 16:55:16 -0700416 fname: Driver filename to scan
Walter Lozanoe675d962020-07-03 08:07:17 -0300417 """
Simon Glass93daa012020-12-03 16:55:16 -0700418 with open(fname, encoding='utf-8') as inf:
Walter Lozanoe675d962020-07-03 08:07:17 -0300419 try:
Simon Glass93daa012020-12-03 16:55:16 -0700420 buff = inf.read()
Walter Lozanoe675d962020-07-03 08:07:17 -0300421 except UnicodeDecodeError:
422 # This seems to happen on older Python versions
Simon Glass93daa012020-12-03 16:55:16 -0700423 print("Skipping file '%s' due to unicode error" % fname)
Walter Lozanoe675d962020-07-03 08:07:17 -0300424 return
425
426 # The following re will search for driver names declared as
427 # U_BOOT_DRIVER(driver_name)
Simon Glass27511232020-12-23 08:11:19 -0700428 drivers = re.findall(r'U_BOOT_DRIVER\((.*)\)', buff)
Walter Lozanoe675d962020-07-03 08:07:17 -0300429
430 for driver in drivers:
Simon Glassb42ed512020-12-23 08:11:23 -0700431 self._drivers[driver] = Driver(driver)
Walter Lozanoe675d962020-07-03 08:07:17 -0300432
433 # The following re will search for driver aliases declared as
Simon Glassdf65db82020-12-28 20:34:57 -0700434 # DM_DRIVER_ALIAS(alias, driver_name)
Simon Glass93daa012020-12-03 16:55:16 -0700435 driver_aliases = re.findall(
Simon Glassdf65db82020-12-28 20:34:57 -0700436 r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
Simon Glass93daa012020-12-03 16:55:16 -0700437 buff)
Walter Lozanoe675d962020-07-03 08:07:17 -0300438
439 for alias in driver_aliases: # pragma: no cover
440 if len(alias) != 2:
441 continue
442 self._driver_aliases[alias[1]] = alias[0]
443
Simon Glass4f2059b2020-12-28 20:35:03 -0700444 def scan_drivers(self, basedir=None):
Walter Lozanoe675d962020-07-03 08:07:17 -0300445 """Scan the driver folders to build a list of driver names and aliases
446
447 This procedure will populate self._drivers and self._driver_aliases
448
449 """
Simon Glass4f2059b2020-12-28 20:35:03 -0700450 if not basedir:
451 basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
452 if basedir == '':
453 basedir = './'
454 self._basedir = basedir
Simon Glass93daa012020-12-03 16:55:16 -0700455 for (dirpath, _, filenames) in os.walk(basedir):
456 for fname in filenames:
457 if not fname.endswith('.c'):
Walter Lozanoe675d962020-07-03 08:07:17 -0300458 continue
Simon Glass93daa012020-12-03 16:55:16 -0700459 self.scan_driver(dirpath + '/' + fname)
Walter Lozanoe675d962020-07-03 08:07:17 -0300460
Simon Glass93daa012020-12-03 16:55:16 -0700461 for fname in self._drivers_additional:
462 if not isinstance(fname, str) or len(fname) == 0:
Walter Lozanod82062b2020-07-28 19:06:23 -0300463 continue
Simon Glass93daa012020-12-03 16:55:16 -0700464 if fname[0] == '/':
465 self.scan_driver(fname)
Walter Lozanod82062b2020-07-28 19:06:23 -0300466 else:
Simon Glass93daa012020-12-03 16:55:16 -0700467 self.scan_driver(basedir + '/' + fname)
Walter Lozanod82062b2020-07-28 19:06:23 -0300468
Simon Glass1f730c82017-06-18 22:08:59 -0600469 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200470 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600471
Simon Glass1f730c82017-06-18 22:08:59 -0600472 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600473 device tree root node, and progress from there.
474 """
Simon Glass1f730c82017-06-18 22:08:59 -0600475 self._fdt = fdt.FdtScan(self._dtb_fname)
476
Simon Glass192f8132020-10-03 11:31:25 -0600477 def scan_node(self, root, valid_nodes):
Simon Glass1f730c82017-06-18 22:08:59 -0600478 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600479
Simon Glass17ffd622017-08-29 14:15:53 -0600480 This adds each node to self._valid_nodes.
Simon Glass1f730c82017-06-18 22:08:59 -0600481
482 Args:
Simon Glass27511232020-12-23 08:11:19 -0700483 root (Node): Root node for scan
484 valid_nodes (list of Node): List of Node objects to add to
Simon Glass1f730c82017-06-18 22:08:59 -0600485 """
Simon Glassd570dec2017-06-18 22:08:58 -0600486 for node in root.subnodes:
487 if 'compatible' in node.props:
488 status = node.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600489 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600490 status.value != 'disabled'):
Simon Glass192f8132020-10-03 11:31:25 -0600491 valid_nodes.append(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600492
493 # recurse to handle any subnodes
Simon Glass192f8132020-10-03 11:31:25 -0600494 self.scan_node(node, valid_nodes)
Simon Glassd570dec2017-06-18 22:08:58 -0600495
Simon Glass1f730c82017-06-18 22:08:59 -0600496 def scan_tree(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600497 """Scan the device tree for useful information
498
499 This fills in the following properties:
Simon Glassd570dec2017-06-18 22:08:58 -0600500 _valid_nodes: A list of nodes we wish to consider include in the
501 platform data
502 """
Simon Glass192f8132020-10-03 11:31:25 -0600503 valid_nodes = []
504 self.scan_node(self._fdt.GetRoot(), valid_nodes)
505 self._valid_nodes = sorted(valid_nodes,
506 key=lambda x: conv_name_to_c(x.name))
507 for idx, node in enumerate(self._valid_nodes):
508 node.idx = idx
Simon Glassd570dec2017-06-18 22:08:58 -0600509
Simon Glass1b1fe412017-08-29 14:15:50 -0600510 @staticmethod
511 def get_num_cells(node):
512 """Get the number of cells in addresses and sizes for this node
513
514 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700515 node (fdt.None): Node to check
Simon Glass1b1fe412017-08-29 14:15:50 -0600516
517 Returns:
518 Tuple:
519 Number of address cells for this node
520 Number of size cells for this node
521 """
522 parent = node.parent
Simon Glass93daa012020-12-03 16:55:16 -0700523 num_addr, num_size = 2, 2
Simon Glass1b1fe412017-08-29 14:15:50 -0600524 if parent:
Simon Glass93daa012020-12-03 16:55:16 -0700525 addr_prop = parent.props.get('#address-cells')
526 size_prop = parent.props.get('#size-cells')
527 if addr_prop:
528 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
529 if size_prop:
530 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
531 return num_addr, num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600532
533 def scan_reg_sizes(self):
534 """Scan for 64-bit 'reg' properties and update the values
535
536 This finds 'reg' properties with 64-bit data and converts the value to
537 an array of 64-values. This allows it to be output in a way that the
538 C code can read.
539 """
540 for node in self._valid_nodes:
541 reg = node.props.get('reg')
542 if not reg:
543 continue
Simon Glass93daa012020-12-03 16:55:16 -0700544 num_addr, num_size = self.get_num_cells(node)
545 total = num_addr + num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600546
Simon Glassc9a032c2020-11-08 20:36:17 -0700547 if reg.type != fdt.Type.INT:
Simon Glassc38fee042018-07-06 10:27:32 -0600548 raise ValueError("Node '%s' reg property is not an int" %
549 node.name)
Simon Glass1b1fe412017-08-29 14:15:50 -0600550 if len(reg.value) % total:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700551 raise ValueError(
552 "Node '%s' reg property has %d cells "
553 'which is not a multiple of na + ns = %d + %d)' %
Simon Glass93daa012020-12-03 16:55:16 -0700554 (node.name, len(reg.value), num_addr, num_size))
555 reg.num_addr = num_addr
556 reg.num_size = num_size
557 if num_addr != 1 or num_size != 1:
Simon Glassc9a032c2020-11-08 20:36:17 -0700558 reg.type = fdt.Type.INT64
Simon Glass1b1fe412017-08-29 14:15:50 -0600559 i = 0
560 new_value = []
561 val = reg.value
562 if not isinstance(val, list):
563 val = [val]
564 while i < len(val):
Simon Glass93daa012020-12-03 16:55:16 -0700565 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
566 i += num_addr
567 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
568 i += num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600569 new_value += [addr, size]
570 reg.value = new_value
571
Simon Glass1f730c82017-06-18 22:08:59 -0600572 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600573 """Scan the device tree building up the C structures we will use.
574
575 Build a dict keyed by C struct name containing a dict of Prop
576 object for each struct field (keyed by property name). Where the
577 same struct appears multiple times, try to use the 'widest'
578 property, i.e. the one with a type which can express all others.
579
580 Once the widest property is determined, all other properties are
581 updated to match that width.
Simon Glass941f8f02020-10-03 11:31:24 -0600582
Simon Glass55526782020-12-28 20:35:02 -0700583 The results are written to self._struct_data
Simon Glassd570dec2017-06-18 22:08:58 -0600584 """
Simon Glass55526782020-12-28 20:35:02 -0700585 structs = self._struct_data
Simon Glassd570dec2017-06-18 22:08:58 -0600586 for node in self._valid_nodes:
Walter Lozanoe675d962020-07-03 08:07:17 -0300587 node_name, _ = self.get_normalized_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600588 fields = {}
589
590 # Get a list of all the valid properties in this node.
591 for name, prop in node.props.items():
592 if name not in PROP_IGNORE_LIST and name[0] != '#':
593 fields[name] = copy.deepcopy(prop)
594
595 # If we've seen this node_name before, update the existing struct.
596 if node_name in structs:
597 struct = structs[node_name]
598 for name, prop in fields.items():
599 oldprop = struct.get(name)
600 if oldprop:
601 oldprop.Widen(prop)
602 else:
603 struct[name] = prop
604
605 # Otherwise store this as a new struct.
606 else:
607 structs[node_name] = fields
608
Simon Glassd570dec2017-06-18 22:08:58 -0600609 for node in self._valid_nodes:
Walter Lozanoe675d962020-07-03 08:07:17 -0300610 node_name, _ = self.get_normalized_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600611 struct = structs[node_name]
612 for name, prop in node.props.items():
613 if name not in PROP_IGNORE_LIST and name[0] != '#':
614 prop.Widen(struct[name])
Simon Glassd570dec2017-06-18 22:08:58 -0600615
Simon Glass1f730c82017-06-18 22:08:59 -0600616 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600617 """Figure out what phandles each node uses
618
619 We need to be careful when outputing nodes that use phandles since
620 they must come after the declaration of the phandles in the C file.
621 Otherwise we get a compiler error since the phandle struct is not yet
622 declared.
623
624 This function adds to each node a list of phandle nodes that the node
625 depends on. This allows us to output things in the right order.
626 """
627 for node in self._valid_nodes:
628 node.phandles = set()
629 for pname, prop in node.props.items():
630 if pname in PROP_IGNORE_LIST or pname[0] == '#':
631 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600632 info = self.get_phandle_argc(prop, node.name)
633 if info:
Simon Glassec3b5e42017-08-29 14:15:55 -0600634 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600635 pos = 0
636 for args in info.args:
637 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600638 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
639 target_node = self._fdt.phandle_to_node[phandle]
640 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600641 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600642
643
Simon Glass55526782020-12-28 20:35:02 -0700644 def generate_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600645 """Generate struct defintions for the platform data
646
647 This writes out the body of a header file consisting of structure
648 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100649 doc/driver-model/of-plat.rst for more information.
Simon Glassd570dec2017-06-18 22:08:58 -0600650 """
Simon Glass55526782020-12-28 20:35:02 -0700651 structs = self._struct_data
Simon Glass1f730c82017-06-18 22:08:59 -0600652 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900653 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600654
655 # Output the struct definition
656 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600657 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600658 for pname in sorted(structs[name]):
659 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600660 info = self.get_phandle_argc(prop, structs[name])
661 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600662 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600663 struct_name = 'struct phandle_%d_arg' % info.max_args
664 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600665 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600666 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600667 else:
668 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600669 self.out('\t%s%s' % (tab_to(2, ptype),
670 conv_name_to_c(prop.name)))
671 if isinstance(prop.value, list):
672 self.out('[%d]' % len(prop.value))
673 self.out(';\n')
674 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600675
Simon Glass9d98b6e2020-12-23 08:11:20 -0700676 def _output_list(self, node, prop):
677 """Output the C code for a devicetree property that holds a list
Simon Glassd570dec2017-06-18 22:08:58 -0600678
679 Args:
Simon Glass9d98b6e2020-12-23 08:11:20 -0700680 node (fdt.Node): Node to output
681 prop (fdt.Prop): Prop to output
Simon Glassd570dec2017-06-18 22:08:58 -0600682 """
Simon Glass9d98b6e2020-12-23 08:11:20 -0700683 self.buf('{')
684 vals = []
685 # For phandles, output a reference to the platform data
686 # of the target node.
687 info = self.get_phandle_argc(prop, node.name)
688 if info:
689 # Process the list as pairs of (phandle, id)
690 pos = 0
691 for args in info.args:
692 phandle_cell = prop.value[pos]
693 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
694 target_node = self._fdt.phandle_to_node[phandle]
695 arg_values = []
696 for i in range(args):
697 arg_values.append(
698 str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
699 pos += 1 + args
700 vals.append('\t{%d, {%s}}' % (target_node.idx,
701 ', '.join(arg_values)))
702 for val in vals:
703 self.buf('\n\t\t%s,' % val)
704 else:
705 for val in prop.value:
706 vals.append(get_value(prop.type, val))
Simon Glassbc9e2682020-10-03 09:25:18 -0600707
Simon Glass9d98b6e2020-12-23 08:11:20 -0700708 # Put 8 values per line to avoid very long lines.
709 for i in range(0, len(vals), 8):
710 if i:
711 self.buf(',\n\t\t')
712 self.buf(', '.join(vals[i:i + 8]))
713 self.buf('}')
Simon Glassbc9e2682020-10-03 09:25:18 -0600714
Simon Glass9fdd0c32020-12-23 08:11:21 -0700715 def _declare_device(self, var_name, struct_name, node_parent):
716 """Add a device declaration to the output
717
Simon Glass1d8364a2020-12-28 20:34:54 -0700718 This declares a U_BOOT_DRVINFO() for the device being processed
Simon Glass9fdd0c32020-12-23 08:11:21 -0700719
720 Args:
721 var_name (str): C name for the node
722 struct_name (str): Name for the dt struct associated with the node
723 node_parent (Node): Parent of the node (or None if none)
724 """
Simon Glass1d8364a2020-12-28 20:34:54 -0700725 self.buf('U_BOOT_DRVINFO(%s) = {\n' % var_name)
Simon Glass9fdd0c32020-12-23 08:11:21 -0700726 self.buf('\t.name\t\t= "%s",\n' % struct_name)
727 self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, var_name))
728 self.buf('\t.plat_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
729 idx = -1
730 if node_parent and node_parent in self._valid_nodes:
731 idx = node_parent.idx
732 self.buf('\t.parent_idx\t= %d,\n' % idx)
733 self.buf('};\n')
734 self.buf('\n')
735
Simon Glass9829eea2020-12-23 08:11:22 -0700736 def _output_prop(self, node, prop):
737 """Output a line containing the value of a struct member
738
739 Args:
740 node (Node): Node being output
741 prop (Prop): Prop object to output
742 """
743 if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
744 return
745 member_name = conv_name_to_c(prop.name)
746 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
747
748 # Special handling for lists
749 if isinstance(prop.value, list):
750 self._output_list(node, prop)
751 else:
752 self.buf(get_value(prop.type, prop.value))
753 self.buf(',\n')
754
755 def _output_values(self, var_name, struct_name, node):
756 """Output the definition of a device's struct values
757
758 Args:
759 var_name (str): C name for the node
760 struct_name (str): Name for the dt struct associated with the node
761 node (Node): Node being output
762 """
763 self.buf('static struct %s%s %s%s = {\n' %
764 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
765 for pname in sorted(node.props):
766 self._output_prop(node, node.props[pname])
767 self.buf('};\n')
768
Simon Glass9d98b6e2020-12-23 08:11:20 -0700769 def output_node(self, node):
770 """Output the C code for a node
Simon Glassbc9e2682020-10-03 09:25:18 -0600771
Simon Glass9d98b6e2020-12-23 08:11:20 -0700772 Args:
773 node (fdt.Node): node to output
774 """
Walter Lozanoe675d962020-07-03 08:07:17 -0300775 struct_name, _ = self.get_normalized_compat_name(node)
Simon Glass1f730c82017-06-18 22:08:59 -0600776 var_name = conv_name_to_c(node.name)
Simon Glass192f8132020-10-03 11:31:25 -0600777 self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
Simon Glassd570dec2017-06-18 22:08:58 -0600778
Simon Glass9829eea2020-12-23 08:11:22 -0700779 self._output_values(var_name, struct_name, node)
Simon Glass9fdd0c32020-12-23 08:11:21 -0700780 self._declare_device(var_name, struct_name, node.parent)
Simon Glassd570dec2017-06-18 22:08:58 -0600781
Simon Glass1f730c82017-06-18 22:08:59 -0600782 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -0600783
Simon Glass55526782020-12-28 20:35:02 -0700784 def generate_plat(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600785 """Generate device defintions for the platform data
786
787 This writes out C platform data initialisation data and
Simon Glass1d8364a2020-12-28 20:34:54 -0700788 U_BOOT_DRVINFO() declarations for each valid node. Where a node has
Simon Glassd570dec2017-06-18 22:08:58 -0600789 multiple compatible strings, a #define is used to make them equivalent.
790
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100791 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glassd570dec2017-06-18 22:08:58 -0600792 information.
793 """
Simon Glass1d8364a2020-12-28 20:34:54 -0700794 self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
Simon Glassbeddd7a2020-12-28 20:35:01 -0700795 self.out('#define DT_PLAT_C\n')
Simon Glass4c73d7b2020-10-03 11:31:41 -0600796 self.out('\n')
Simon Glass1f730c82017-06-18 22:08:59 -0600797 self.out('#include <common.h>\n')
798 self.out('#include <dm.h>\n')
799 self.out('#include <dt-structs.h>\n')
800 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600801
Simon Glass16382ce2020-12-28 20:35:04 -0700802 for node in self._valid_nodes:
Simon Glass1f730c82017-06-18 22:08:59 -0600803 self.output_node(node)
Simon Glass3fa797a2017-06-18 22:09:03 -0600804
Walter Lozanodc5b4372020-06-25 01:10:13 -0300805 # Define dm_populate_phandle_data() which will add the linking between
Simon Glasse10c0ff2020-12-28 20:34:55 -0700806 # nodes using DM_DRVINFO_GET
807 # dtv_dmc_at_xxx.clocks[0].node = DM_DRVINFO_GET(clock_controller_at_xxx)
Walter Lozanodc5b4372020-06-25 01:10:13 -0300808 self.buf('void dm_populate_phandle_data(void) {\n')
Walter Lozanodc5b4372020-06-25 01:10:13 -0300809 self.buf('}\n')
810
811 self.out(''.join(self.get_buf()))
Simon Glass3fa797a2017-06-18 22:09:03 -0600812
Simon Glassc3a310a82020-12-28 20:34:51 -0700813
814# Types of output file we understand
815# key: Command used to generate this file
816# value: OutputFile for this command
817OUTPUT_FILES = {
Simon Glass6b208842020-12-28 20:35:00 -0700818 'struct':
819 OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
Simon Glass55526782020-12-28 20:35:02 -0700820 DtbPlatdata.generate_structs,
Simon Glass6b208842020-12-28 20:35:00 -0700821 'Defines the structs used to hold devicetree data'),
822 'platdata':
Simon Glass55526782020-12-28 20:35:02 -0700823 OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
Simon Glass6b208842020-12-28 20:35:00 -0700824 'Declares the U_BOOT_DRIVER() records and platform data'),
Simon Glassc3a310a82020-12-28 20:34:51 -0700825 }
826
Simon Glass6a65d8a2020-12-28 20:34:50 -0700827
828def run_steps(args, dtb_file, include_disabled, output, output_dirs,
Simon Glass4f2059b2020-12-28 20:35:03 -0700829 warning_disabled=False, drivers_additional=None, basedir=None):
Simon Glass3fa797a2017-06-18 22:09:03 -0600830 """Run all the steps of the dtoc tool
831
832 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700833 args (list): List of non-option arguments provided to the problem
834 dtb_file (str): Filename of dtb file to process
835 include_disabled (bool): True to include disabled nodes
Simon Glass6ca0c7a2020-12-28 20:34:48 -0700836 output (str): Name of output file (None for stdout)
Simon Glass6a65d8a2020-12-28 20:34:50 -0700837 output_dirs (tuple of str):
838 Directory to put C output files
839 Directory to put H output files
Simon Glass93daa012020-12-03 16:55:16 -0700840 warning_disabled (bool): True to avoid showing warnings about missing
841 drivers
Simon Glass27511232020-12-23 08:11:19 -0700842 drivers_additional (list): List of additional drivers to use during
Simon Glass93daa012020-12-03 16:55:16 -0700843 scanning
Simon Glass4f2059b2020-12-28 20:35:03 -0700844 basedir (str): Base directory of U-Boot source code. Defaults to the
845 grandparent of this file's directory
Simon Glass94ee3bd2020-11-08 20:36:21 -0700846 Raises:
847 ValueError: if args has no command, or an unknown command
Simon Glass3fa797a2017-06-18 22:09:03 -0600848 """
849 if not args:
Simon Glassc3a310a82020-12-28 20:34:51 -0700850 raise ValueError('Please specify a command: struct, platdata, all')
851 if output and output_dirs and any(output_dirs):
852 raise ValueError('Must specify either output or output_dirs, not both')
Simon Glass3fa797a2017-06-18 22:09:03 -0600853
Simon Glass93daa012020-12-03 16:55:16 -0700854 plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled,
855 drivers_additional)
Simon Glass4f2059b2020-12-28 20:35:03 -0700856 plat.scan_drivers(basedir)
Simon Glass3fa797a2017-06-18 22:09:03 -0600857 plat.scan_dtb()
858 plat.scan_tree()
Simon Glass1b1fe412017-08-29 14:15:50 -0600859 plat.scan_reg_sizes()
Simon Glassc3a310a82020-12-28 20:34:51 -0700860 plat.setup_output_dirs(output_dirs)
Simon Glass55526782020-12-28 20:35:02 -0700861 plat.scan_structs()
Simon Glass3fa797a2017-06-18 22:09:03 -0600862 plat.scan_phandles()
863
Simon Glass4e8e8462020-12-28 20:34:52 -0700864 cmds = args[0].split(',')
865 if 'all' in cmds:
866 cmds = sorted(OUTPUT_FILES.keys())
867 for cmd in cmds:
Simon Glassc3a310a82020-12-28 20:34:51 -0700868 outfile = OUTPUT_FILES.get(cmd)
869 if not outfile:
870 raise ValueError("Unknown command '%s': (use: %s)" %
Simon Glass4e8e8462020-12-28 20:34:52 -0700871 (cmd, ', '.join(sorted(OUTPUT_FILES.keys()))))
Simon Glassc3a310a82020-12-28 20:34:51 -0700872 plat.setup_output(outfile.ftype,
873 outfile.fname if output_dirs else output)
Simon Glass6b208842020-12-28 20:35:00 -0700874 plat.out_header(outfile)
Simon Glass55526782020-12-28 20:35:02 -0700875 outfile.method(plat)
Simon Glassc3a310a82020-12-28 20:34:51 -0700876 plat.finish_output()