blob: befe7c1490110384f7ea29ac808905bf8c1f81a9 [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 Glass9065bc92020-12-28 20:35:06 -070025from dtoc import src_scan
26from dtoc.src_scan import conv_name_to_c
Simon Glassd570dec2017-06-18 22:08:58 -060027
Simon Glass94ee3bd2020-11-08 20:36:21 -070028# When we see these properties we ignore them - i.e. do not create a structure
29# member
Simon Glassd570dec2017-06-18 22:08:58 -060030PROP_IGNORE_LIST = [
31 '#address-cells',
32 '#gpio-cells',
33 '#size-cells',
34 'compatible',
35 'linux,phandle',
36 "status",
37 'phandle',
38 'u-boot,dm-pre-reloc',
39 'u-boot,dm-tpl',
40 'u-boot,dm-spl',
41]
42
Simon Glassc9a032c2020-11-08 20:36:17 -070043# C type declarations for the types we support
Simon Glassd570dec2017-06-18 22:08:58 -060044TYPE_NAMES = {
Simon Glassc9a032c2020-11-08 20:36:17 -070045 fdt.Type.INT: 'fdt32_t',
46 fdt.Type.BYTE: 'unsigned char',
47 fdt.Type.STRING: 'const char *',
48 fdt.Type.BOOL: 'bool',
49 fdt.Type.INT64: 'fdt64_t',
Simon Glass1f730c82017-06-18 22:08:59 -060050}
Simon Glassd570dec2017-06-18 22:08:58 -060051
52STRUCT_PREFIX = 'dtd_'
53VAL_PREFIX = 'dtv_'
54
Simon Glassc3a310a82020-12-28 20:34:51 -070055class Ftype(IntEnum):
56 SOURCE, HEADER = range(2)
57
58
59# This holds information about each type of output file dtoc can create
60# type: Type of file (Ftype)
Simon Glass6b208842020-12-28 20:35:00 -070061# fname: Filename excluding directory, e.g. 'dt-plat.c'
62# hdr_comment: Comment explaining the purpose of the file
63OutputFile = collections.namedtuple('OutputFile',
Simon Glass55526782020-12-28 20:35:02 -070064 ['ftype', 'fname', 'method', 'hdr_comment'])
Simon Glassc3a310a82020-12-28 20:34:51 -070065
Simon Glassec3b5e42017-08-29 14:15:55 -060066# This holds information about a property which includes phandles.
67#
68# max_args: integer: Maximum number or arguments that any phandle uses (int).
69# args: Number of args for each phandle in the property. The total number of
70# phandles is len(args). This is a list of integers.
71PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
72
Simon Glassc1622112020-10-03 09:25:19 -060073# Holds a single phandle link, allowing a C struct value to be assigned to point
74# to a device
75#
76# var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
77# dev_name: Name of device to assign to (e.g. 'clock')
78PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
79
Simon Glassec3b5e42017-08-29 14:15:55 -060080
Simon Glass1f730c82017-06-18 22:08:59 -060081def tab_to(num_tabs, line):
82 """Append tabs to a line of text to reach a tab stop.
Simon Glassd570dec2017-06-18 22:08:58 -060083
Simon Glass1f730c82017-06-18 22:08:59 -060084 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -070085 num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
86 line (str): Line of text to append to
Simon Glass1f730c82017-06-18 22:08:59 -060087
88 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -070089 str: line with the correct number of tabs appeneded. If the line already
Simon Glass1f730c82017-06-18 22:08:59 -060090 extends past that tab stop then a single space is appended.
91 """
92 if len(line) >= num_tabs * 8:
93 return line + ' '
94 return line + '\t' * (num_tabs - len(line) // 8)
95
Simon Glass7a2add12017-06-18 22:09:02 -060096def get_value(ftype, value):
97 """Get a value as a C expression
98
99 For integers this returns a byte-swapped (little-endian) hex string
100 For bytes this returns a hex string, e.g. 0x12
101 For strings this returns a literal string enclosed in quotes
102 For booleans this return 'true'
103
104 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700105 ftype (fdt.Type): Data type (fdt_util)
106 value (bytes): Data value, as a string of bytes
107
108 Returns:
109 str: String representation of the value
Simon Glass7a2add12017-06-18 22:09:02 -0600110 """
Simon Glassc9a032c2020-11-08 20:36:17 -0700111 if ftype == fdt.Type.INT:
Simon Glass27511232020-12-23 08:11:19 -0700112 val = '%#x' % fdt_util.fdt32_to_cpu(value)
Simon Glassc9a032c2020-11-08 20:36:17 -0700113 elif ftype == fdt.Type.BYTE:
Simon Glass93daa012020-12-03 16:55:16 -0700114 char = value[0]
Simon Glass27511232020-12-23 08:11:19 -0700115 val = '%#x' % (ord(char) if isinstance(char, str) else char)
Simon Glassc9a032c2020-11-08 20:36:17 -0700116 elif ftype == fdt.Type.STRING:
Simon Glass7f5e2262020-07-07 21:32:06 -0600117 # Handle evil ACPI backslashes by adding another backslash before them.
118 # So "\\_SB.GPO0" in the device tree effectively stays like that in C
Simon Glass27511232020-12-23 08:11:19 -0700119 val = '"%s"' % value.replace('\\', '\\\\')
Simon Glassc9a032c2020-11-08 20:36:17 -0700120 elif ftype == fdt.Type.BOOL:
Simon Glass27511232020-12-23 08:11:19 -0700121 val = 'true'
Simon Glass94ee3bd2020-11-08 20:36:21 -0700122 else: # ftype == fdt.Type.INT64:
Simon Glass27511232020-12-23 08:11:19 -0700123 val = '%#x' % value
124 return val
Simon Glass7a2add12017-06-18 22:09:02 -0600125
Simon Glass7a2add12017-06-18 22:09:02 -0600126
Simon Glass27511232020-12-23 08:11:19 -0700127class DtbPlatdata():
Simon Glassd570dec2017-06-18 22:08:58 -0600128 """Provide a means to convert device tree binary data to platform data
129
130 The output of this process is C structures which can be used in space-
131 constrained encvironments where the ~3KB code overhead of device tree
132 code is not affordable.
133
134 Properties:
Simon Glass9065bc92020-12-28 20:35:06 -0700135 _scan: Scan object, for scanning and reporting on useful information
136 from the U-Boot source code
Simon Glass1f730c82017-06-18 22:08:59 -0600137 _fdt: Fdt object, referencing the device tree
Simon Glassd570dec2017-06-18 22:08:58 -0600138 _dtb_fname: Filename of the input device tree binary file
Simon Glassdf56e0b2021-02-03 06:01:09 -0700139 _valid_nodes_unsorted: A list of Node object with compatible strings,
140 ordered by devicetree node order
141 _valid_nodes: A list of Node object with compatible strings, ordered by
142 conv_name_to_c(node.name)
Simon Glasseab3f622017-06-18 22:09:01 -0600143 _include_disabled: true to include nodes marked status = "disabled"
Simon Glassd570dec2017-06-18 22:08:58 -0600144 _outfile: The current output file (sys.stdout or a real file)
145 _lines: Stashed list of output lines for outputting in the future
Simon Glassc3a310a82020-12-28 20:34:51 -0700146 _dirname: Directory to hold output files, or None for none (all files
147 go to stdout)
Simon Glass55526782020-12-28 20:35:02 -0700148 _struct_data (dict): OrderedDict of dtplat structures to output
149 key (str): Node name, as a C identifier
150 value: dict containing structure fields:
151 key (str): Field name
152 value: Prop object with field information
Simon Glass4f2059b2020-12-28 20:35:03 -0700153 _basedir (str): Base directory of source tree
Simon Glass80d782c42021-02-03 06:01:10 -0700154 _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
155 the selected devices (see _valid_node), in alphabetical order
Simon Glass3809ad92021-02-03 06:01:12 -0700156 _instantiate: Instantiate devices so they don't need to be bound at
157 run-time
Simon Glassd570dec2017-06-18 22:08:58 -0600158 """
Simon Glass3809ad92021-02-03 06:01:12 -0700159 def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
Simon Glass9065bc92020-12-28 20:35:06 -0700160 self._scan = scan
Simon Glass1f730c82017-06-18 22:08:59 -0600161 self._fdt = None
Simon Glassd570dec2017-06-18 22:08:58 -0600162 self._dtb_fname = dtb_fname
163 self._valid_nodes = None
Simon Glassdf56e0b2021-02-03 06:01:09 -0700164 self._valid_nodes_unsorted = None
Simon Glasseab3f622017-06-18 22:09:01 -0600165 self._include_disabled = include_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600166 self._outfile = None
167 self._lines = []
Simon Glassc3a310a82020-12-28 20:34:51 -0700168 self._dirnames = [None] * len(Ftype)
Simon Glass55526782020-12-28 20:35:02 -0700169 self._struct_data = collections.OrderedDict()
Simon Glass4f2059b2020-12-28 20:35:03 -0700170 self._basedir = None
Simon Glass80d782c42021-02-03 06:01:10 -0700171 self._valid_uclasses = None
Simon Glass3809ad92021-02-03 06:01:12 -0700172 self._instantiate = instantiate
Walter Lozanoe675d962020-07-03 08:07:17 -0300173
Simon Glassc3a310a82020-12-28 20:34:51 -0700174 def setup_output_dirs(self, output_dirs):
175 """Set up the output directories
176
177 This should be done before setup_output() is called
178
179 Args:
180 output_dirs (tuple of str):
181 Directory to use for C output files.
182 Use None to write files relative current directory
183 Directory to use for H output files.
184 Defaults to the C output dir
185 """
186 def process_dir(ftype, dirname):
187 if dirname:
188 os.makedirs(dirname, exist_ok=True)
189 self._dirnames[ftype] = dirname
190
191 if output_dirs:
192 c_dirname = output_dirs[0]
193 h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
194 process_dir(Ftype.SOURCE, c_dirname)
195 process_dir(Ftype.HEADER, h_dirname)
196
197 def setup_output(self, ftype, fname):
Simon Glassd570dec2017-06-18 22:08:58 -0600198 """Set up the output destination
199
Simon Glass1f730c82017-06-18 22:08:59 -0600200 Once this is done, future calls to self.out() will output to this
Simon Glassc3a310a82020-12-28 20:34:51 -0700201 file. The file used is as follows:
202
203 self._dirnames[ftype] is None: output to fname, or stdout if None
204 self._dirnames[ftype] is not None: output to fname in that directory
205
206 Calling this function multiple times will close the old file and open
207 the new one. If they are the same file, nothing happens and output will
208 continue to the same file.
Simon Glassd570dec2017-06-18 22:08:58 -0600209
210 Args:
Simon Glassc3a310a82020-12-28 20:34:51 -0700211 ftype (str): Type of file to create ('c' or 'h')
212 fname (str): Filename to send output to. If there is a directory in
213 self._dirnames for this file type, it will be put in that
214 directory
Simon Glassd570dec2017-06-18 22:08:58 -0600215 """
Simon Glassc3a310a82020-12-28 20:34:51 -0700216 dirname = self._dirnames[ftype]
217 if dirname:
218 pathname = os.path.join(dirname, fname)
219 if self._outfile:
220 self._outfile.close()
221 self._outfile = open(pathname, 'w')
222 elif fname:
223 if not self._outfile:
224 self._outfile = open(fname, 'w')
Simon Glass6ca0c7a2020-12-28 20:34:48 -0700225 else:
226 self._outfile = sys.stdout
Simon Glassd570dec2017-06-18 22:08:58 -0600227
Simon Glassc3a310a82020-12-28 20:34:51 -0700228 def finish_output(self):
229 """Finish outputing to a file
230
231 This closes the output file, if one is in use
232 """
233 if self._outfile != sys.stdout:
234 self._outfile.close()
235
Simon Glass1f730c82017-06-18 22:08:59 -0600236 def out(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600237 """Output a string to the output file
238
239 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700240 line (str): String to output
Simon Glassd570dec2017-06-18 22:08:58 -0600241 """
Simon Glass1f730c82017-06-18 22:08:59 -0600242 self._outfile.write(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600243
Simon Glass1f730c82017-06-18 22:08:59 -0600244 def buf(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600245 """Buffer up a string to send later
246
247 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700248 line (str): String to add to our 'buffer' list
Simon Glassd570dec2017-06-18 22:08:58 -0600249 """
Simon Glass1f730c82017-06-18 22:08:59 -0600250 self._lines.append(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600251
Simon Glass1f730c82017-06-18 22:08:59 -0600252 def get_buf(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600253 """Get the contents of the output buffer, and clear it
254
255 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700256 list(str): The output buffer, which is then cleared for future use
Simon Glassd570dec2017-06-18 22:08:58 -0600257 """
258 lines = self._lines
259 self._lines = []
260 return lines
261
Simon Glass6b208842020-12-28 20:35:00 -0700262 def out_header(self, outfile):
263 """Output a message indicating that this is an auto-generated file
264
265 Args:
266 outfile: OutputFile describing the file being generated
267 """
Simon Glass68d32c72017-08-29 14:16:01 -0600268 self.out('''/*
269 * DO NOT MODIFY
270 *
Simon Glass6b208842020-12-28 20:35:00 -0700271 * %s.
272 * This was generated by dtoc from a .dtb (device tree binary) file.
Simon Glass68d32c72017-08-29 14:16:01 -0600273 */
274
Simon Glass6b208842020-12-28 20:35:00 -0700275''' % outfile.hdr_comment)
Simon Glass68d32c72017-08-29 14:16:01 -0600276
Simon Glassec3b5e42017-08-29 14:15:55 -0600277 def get_phandle_argc(self, prop, node_name):
278 """Check if a node contains phandles
Simon Glassce5621d2017-08-29 14:15:54 -0600279
Simon Glassec3b5e42017-08-29 14:15:55 -0600280 We have no reliable way of detecting whether a node uses a phandle
281 or not. As an interim measure, use a list of known property names.
282
283 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700284 prop (fdt.Prop): Prop object to check
285 node_name (str): Node name, only used for raising an error
286 Returns:
287 int or None: Number of argument cells is this is a phandle,
288 else None
289 Raises:
290 ValueError: if the phandle cannot be parsed or the required property
291 is not present
Simon Glassec3b5e42017-08-29 14:15:55 -0600292 """
Walter Lozano179f0b62020-06-25 01:10:16 -0300293 if prop.name in ['clocks', 'cd-gpios']:
Simon Glass609e2b12018-07-06 10:27:31 -0600294 if not isinstance(prop.value, list):
295 prop.value = [prop.value]
Simon Glassec3b5e42017-08-29 14:15:55 -0600296 val = prop.value
Simon Glassec3b5e42017-08-29 14:15:55 -0600297 i = 0
Simon Glassce5621d2017-08-29 14:15:54 -0600298
Simon Glassec3b5e42017-08-29 14:15:55 -0600299 max_args = 0
300 args = []
301 while i < len(val):
302 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass609e2b12018-07-06 10:27:31 -0600303 # If we get to the end of the list, stop. This can happen
304 # since some nodes have more phandles in the list than others,
305 # but we allocate enough space for the largest list. So those
306 # nodes with shorter lists end up with zeroes at the end.
307 if not phandle:
308 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600309 target = self._fdt.phandle_to_node.get(phandle)
310 if not target:
311 raise ValueError("Cannot parse '%s' in node '%s'" %
312 (prop.name, node_name))
Walter Lozano179f0b62020-06-25 01:10:16 -0300313 cells = None
314 for prop_name in ['#clock-cells', '#gpio-cells']:
315 cells = target.props.get(prop_name)
316 if cells:
317 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600318 if not cells:
Walter Lozano179f0b62020-06-25 01:10:16 -0300319 raise ValueError("Node '%s' has no cells property" %
Simon Glass94ee3bd2020-11-08 20:36:21 -0700320 (target.name))
Simon Glassec3b5e42017-08-29 14:15:55 -0600321 num_args = fdt_util.fdt32_to_cpu(cells.value)
322 max_args = max(max_args, num_args)
323 args.append(num_args)
324 i += 1 + num_args
325 return PhandleInfo(max_args, args)
326 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600327
Simon Glass1f730c82017-06-18 22:08:59 -0600328 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200329 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600330
Simon Glass1f730c82017-06-18 22:08:59 -0600331 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600332 device tree root node, and progress from there.
333 """
Simon Glass1f730c82017-06-18 22:08:59 -0600334 self._fdt = fdt.FdtScan(self._dtb_fname)
335
Simon Glassdf56e0b2021-02-03 06:01:09 -0700336 def scan_node(self, node, valid_nodes):
Simon Glass1f730c82017-06-18 22:08:59 -0600337 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600338
Simon Glassdf56e0b2021-02-03 06:01:09 -0700339 This adds each subnode to self._valid_nodes if it is enabled and has a
340 compatible string.
Simon Glass1f730c82017-06-18 22:08:59 -0600341
342 Args:
Simon Glassdf56e0b2021-02-03 06:01:09 -0700343 node (Node): Node for scan for subnodes
Simon Glass27511232020-12-23 08:11:19 -0700344 valid_nodes (list of Node): List of Node objects to add to
Simon Glass1f730c82017-06-18 22:08:59 -0600345 """
Simon Glassdf56e0b2021-02-03 06:01:09 -0700346 for subnode in node.subnodes:
347 if 'compatible' in subnode.props:
348 status = subnode.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600349 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600350 status.value != 'disabled'):
Simon Glassdf56e0b2021-02-03 06:01:09 -0700351 valid_nodes.append(subnode)
Simon Glassd570dec2017-06-18 22:08:58 -0600352
353 # recurse to handle any subnodes
Simon Glassdf56e0b2021-02-03 06:01:09 -0700354 self.scan_node(subnode, valid_nodes)
Simon Glassd570dec2017-06-18 22:08:58 -0600355
Simon Glassc14fd0c2021-02-03 06:01:11 -0700356 def scan_tree(self, add_root):
Simon Glassd570dec2017-06-18 22:08:58 -0600357 """Scan the device tree for useful information
358
359 This fills in the following properties:
Simon Glassdf56e0b2021-02-03 06:01:09 -0700360 _valid_nodes_unsorted: A list of nodes we wish to consider include
361 in the platform data (in devicetree node order)
362 _valid_nodes: Sorted version of _valid_nodes_unsorted
Simon Glassc14fd0c2021-02-03 06:01:11 -0700363
364 Args:
365 add_root: True to add the root node also (which wouldn't normally
366 be added as it may not have a compatible string)
Simon Glassd570dec2017-06-18 22:08:58 -0600367 """
Simon Glassdf56e0b2021-02-03 06:01:09 -0700368 root = self._fdt.GetRoot()
Simon Glass192f8132020-10-03 11:31:25 -0600369 valid_nodes = []
Simon Glassc14fd0c2021-02-03 06:01:11 -0700370 if add_root:
371 valid_nodes.append(root)
Simon Glassdf56e0b2021-02-03 06:01:09 -0700372 self.scan_node(root, valid_nodes)
373 self._valid_nodes_unsorted = valid_nodes
Simon Glass192f8132020-10-03 11:31:25 -0600374 self._valid_nodes = sorted(valid_nodes,
375 key=lambda x: conv_name_to_c(x.name))
Simon Glass44479782021-02-03 06:00:58 -0700376
377 def prepare_nodes(self):
378 """Add extra properties to the nodes we are using
379
380 The following properties are added for use by dtoc:
381 idx: Index number of this node (0=first, etc.)
382 struct_name: Name of the struct dtd used by this node
383 var_name: C name for this node
384 child_devs: List of child devices for this node, each a None
385 child_refs: Dict of references for each child:
386 key: Position in child list (-1=head, 0=first, 1=second, ...
387 n-1=last, n=head)
388 seq: Sequence number of the device (unique within its uclass), or
389 -1 not not known yet
390 dev_ref: Reference to this device, e.g. 'DM_DEVICE_REF(serial)'
391 driver: Driver record for this node, or None if not known
392 uclass: Uclass record for this node, or None if not known
393 uclass_seq: Position of this device within the uclass list (0=first,
394 n-1=last)
395 parent_seq: Position of this device within it siblings (0=first,
396 n-1=last)
397 parent_driver: Driver record of the node's parent, or None if none.
398 We don't use node.parent.driver since node.parent may not be in
399 the list of valid nodes
400 """
Simon Glass192f8132020-10-03 11:31:25 -0600401 for idx, node in enumerate(self._valid_nodes):
402 node.idx = idx
Simon Glass44479782021-02-03 06:00:58 -0700403 node.struct_name, _ = self._scan.get_normalized_compat_name(node)
404 node.var_name = conv_name_to_c(node.name)
405 node.child_devs = []
406 node.child_refs = {}
407 node.seq = -1
408 node.dev_ref = None
409 node.driver = None
410 node.uclass = None
411 node.uclass_seq = None
412 node.parent_seq = None
413 node.parent_driver = None
Simon Glassd570dec2017-06-18 22:08:58 -0600414
Simon Glass1b1fe412017-08-29 14:15:50 -0600415 @staticmethod
416 def get_num_cells(node):
417 """Get the number of cells in addresses and sizes for this node
418
419 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700420 node (fdt.None): Node to check
Simon Glass1b1fe412017-08-29 14:15:50 -0600421
422 Returns:
423 Tuple:
424 Number of address cells for this node
425 Number of size cells for this node
426 """
427 parent = node.parent
Simon Glass93daa012020-12-03 16:55:16 -0700428 num_addr, num_size = 2, 2
Simon Glass1b1fe412017-08-29 14:15:50 -0600429 if parent:
Simon Glass93daa012020-12-03 16:55:16 -0700430 addr_prop = parent.props.get('#address-cells')
431 size_prop = parent.props.get('#size-cells')
432 if addr_prop:
433 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
434 if size_prop:
435 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
436 return num_addr, num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600437
438 def scan_reg_sizes(self):
439 """Scan for 64-bit 'reg' properties and update the values
440
441 This finds 'reg' properties with 64-bit data and converts the value to
442 an array of 64-values. This allows it to be output in a way that the
443 C code can read.
444 """
445 for node in self._valid_nodes:
446 reg = node.props.get('reg')
447 if not reg:
448 continue
Simon Glass93daa012020-12-03 16:55:16 -0700449 num_addr, num_size = self.get_num_cells(node)
450 total = num_addr + num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600451
Simon Glassc9a032c2020-11-08 20:36:17 -0700452 if reg.type != fdt.Type.INT:
Simon Glassc38fee042018-07-06 10:27:32 -0600453 raise ValueError("Node '%s' reg property is not an int" %
454 node.name)
Simon Glass1b1fe412017-08-29 14:15:50 -0600455 if len(reg.value) % total:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700456 raise ValueError(
457 "Node '%s' reg property has %d cells "
458 'which is not a multiple of na + ns = %d + %d)' %
Simon Glass93daa012020-12-03 16:55:16 -0700459 (node.name, len(reg.value), num_addr, num_size))
460 reg.num_addr = num_addr
461 reg.num_size = num_size
462 if num_addr != 1 or num_size != 1:
Simon Glassc9a032c2020-11-08 20:36:17 -0700463 reg.type = fdt.Type.INT64
Simon Glass1b1fe412017-08-29 14:15:50 -0600464 i = 0
465 new_value = []
466 val = reg.value
467 if not isinstance(val, list):
468 val = [val]
469 while i < len(val):
Simon Glass93daa012020-12-03 16:55:16 -0700470 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
471 i += num_addr
472 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
473 i += num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600474 new_value += [addr, size]
475 reg.value = new_value
476
Simon Glass1f730c82017-06-18 22:08:59 -0600477 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600478 """Scan the device tree building up the C structures we will use.
479
480 Build a dict keyed by C struct name containing a dict of Prop
481 object for each struct field (keyed by property name). Where the
482 same struct appears multiple times, try to use the 'widest'
483 property, i.e. the one with a type which can express all others.
484
485 Once the widest property is determined, all other properties are
486 updated to match that width.
Simon Glass941f8f02020-10-03 11:31:24 -0600487
Simon Glass55526782020-12-28 20:35:02 -0700488 The results are written to self._struct_data
Simon Glassd570dec2017-06-18 22:08:58 -0600489 """
Simon Glass55526782020-12-28 20:35:02 -0700490 structs = self._struct_data
Simon Glassd570dec2017-06-18 22:08:58 -0600491 for node in self._valid_nodes:
Simon Glassd570dec2017-06-18 22:08:58 -0600492 fields = {}
493
494 # Get a list of all the valid properties in this node.
495 for name, prop in node.props.items():
496 if name not in PROP_IGNORE_LIST and name[0] != '#':
497 fields[name] = copy.deepcopy(prop)
498
Simon Glass62a95372021-02-03 06:00:59 -0700499 # If we've seen this struct_name before, update the existing struct
500 if node.struct_name in structs:
501 struct = structs[node.struct_name]
Simon Glassd570dec2017-06-18 22:08:58 -0600502 for name, prop in fields.items():
503 oldprop = struct.get(name)
504 if oldprop:
505 oldprop.Widen(prop)
506 else:
507 struct[name] = prop
508
509 # Otherwise store this as a new struct.
510 else:
Simon Glass62a95372021-02-03 06:00:59 -0700511 structs[node.struct_name] = fields
Simon Glassd570dec2017-06-18 22:08:58 -0600512
Simon Glassd570dec2017-06-18 22:08:58 -0600513 for node in self._valid_nodes:
Simon Glass62a95372021-02-03 06:00:59 -0700514 struct = structs[node.struct_name]
Simon Glassd570dec2017-06-18 22:08:58 -0600515 for name, prop in node.props.items():
516 if name not in PROP_IGNORE_LIST and name[0] != '#':
517 prop.Widen(struct[name])
Simon Glassd570dec2017-06-18 22:08:58 -0600518
Simon Glass1f730c82017-06-18 22:08:59 -0600519 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600520 """Figure out what phandles each node uses
521
522 We need to be careful when outputing nodes that use phandles since
523 they must come after the declaration of the phandles in the C file.
524 Otherwise we get a compiler error since the phandle struct is not yet
525 declared.
526
527 This function adds to each node a list of phandle nodes that the node
528 depends on. This allows us to output things in the right order.
529 """
530 for node in self._valid_nodes:
531 node.phandles = set()
532 for pname, prop in node.props.items():
533 if pname in PROP_IGNORE_LIST or pname[0] == '#':
534 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600535 info = self.get_phandle_argc(prop, node.name)
536 if info:
Simon Glassec3b5e42017-08-29 14:15:55 -0600537 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600538 pos = 0
539 for args in info.args:
540 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600541 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
542 target_node = self._fdt.phandle_to_node[phandle]
543 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600544 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600545
546
Simon Glass55526782020-12-28 20:35:02 -0700547 def generate_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600548 """Generate struct defintions for the platform data
549
550 This writes out the body of a header file consisting of structure
551 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100552 doc/driver-model/of-plat.rst for more information.
Simon Glassd570dec2017-06-18 22:08:58 -0600553 """
Simon Glass55526782020-12-28 20:35:02 -0700554 structs = self._struct_data
Simon Glass1f730c82017-06-18 22:08:59 -0600555 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900556 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600557
558 # Output the struct definition
559 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600560 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600561 for pname in sorted(structs[name]):
562 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600563 info = self.get_phandle_argc(prop, structs[name])
564 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600565 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600566 struct_name = 'struct phandle_%d_arg' % info.max_args
567 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600568 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600569 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600570 else:
571 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600572 self.out('\t%s%s' % (tab_to(2, ptype),
573 conv_name_to_c(prop.name)))
574 if isinstance(prop.value, list):
575 self.out('[%d]' % len(prop.value))
576 self.out(';\n')
577 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600578
Simon Glass9d98b6e2020-12-23 08:11:20 -0700579 def _output_list(self, node, prop):
580 """Output the C code for a devicetree property that holds a list
Simon Glassd570dec2017-06-18 22:08:58 -0600581
582 Args:
Simon Glass9d98b6e2020-12-23 08:11:20 -0700583 node (fdt.Node): Node to output
584 prop (fdt.Prop): Prop to output
Simon Glassd570dec2017-06-18 22:08:58 -0600585 """
Simon Glass9d98b6e2020-12-23 08:11:20 -0700586 self.buf('{')
587 vals = []
588 # For phandles, output a reference to the platform data
589 # of the target node.
590 info = self.get_phandle_argc(prop, node.name)
591 if info:
592 # Process the list as pairs of (phandle, id)
593 pos = 0
594 for args in info.args:
595 phandle_cell = prop.value[pos]
596 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
597 target_node = self._fdt.phandle_to_node[phandle]
598 arg_values = []
599 for i in range(args):
600 arg_values.append(
601 str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
602 pos += 1 + args
603 vals.append('\t{%d, {%s}}' % (target_node.idx,
604 ', '.join(arg_values)))
605 for val in vals:
606 self.buf('\n\t\t%s,' % val)
607 else:
608 for val in prop.value:
609 vals.append(get_value(prop.type, val))
Simon Glassbc9e2682020-10-03 09:25:18 -0600610
Simon Glass9d98b6e2020-12-23 08:11:20 -0700611 # Put 8 values per line to avoid very long lines.
612 for i in range(0, len(vals), 8):
613 if i:
614 self.buf(',\n\t\t')
615 self.buf(', '.join(vals[i:i + 8]))
616 self.buf('}')
Simon Glassbc9e2682020-10-03 09:25:18 -0600617
Simon Glass62a95372021-02-03 06:00:59 -0700618 def _declare_device(self, node):
Simon Glass9fdd0c32020-12-23 08:11:21 -0700619 """Add a device declaration to the output
620
Simon Glass1d8364a2020-12-28 20:34:54 -0700621 This declares a U_BOOT_DRVINFO() for the device being processed
Simon Glass9fdd0c32020-12-23 08:11:21 -0700622
623 Args:
Simon Glass62a95372021-02-03 06:00:59 -0700624 node: Node to process
Simon Glass9fdd0c32020-12-23 08:11:21 -0700625 """
Simon Glass62a95372021-02-03 06:00:59 -0700626 self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
627 self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
628 self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
629 self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
630 (VAL_PREFIX, node.var_name))
Simon Glass9fdd0c32020-12-23 08:11:21 -0700631 idx = -1
Simon Glass62a95372021-02-03 06:00:59 -0700632 if node.parent and node.parent in self._valid_nodes:
633 idx = node.parent.idx
Simon Glass9fdd0c32020-12-23 08:11:21 -0700634 self.buf('\t.parent_idx\t= %d,\n' % idx)
635 self.buf('};\n')
636 self.buf('\n')
637
Simon Glass9829eea2020-12-23 08:11:22 -0700638 def _output_prop(self, node, prop):
639 """Output a line containing the value of a struct member
640
641 Args:
642 node (Node): Node being output
643 prop (Prop): Prop object to output
644 """
645 if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
646 return
647 member_name = conv_name_to_c(prop.name)
648 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
649
650 # Special handling for lists
651 if isinstance(prop.value, list):
652 self._output_list(node, prop)
653 else:
654 self.buf(get_value(prop.type, prop.value))
655 self.buf(',\n')
656
Simon Glass62a95372021-02-03 06:00:59 -0700657 def _output_values(self, node):
Simon Glass9829eea2020-12-23 08:11:22 -0700658 """Output the definition of a device's struct values
659
660 Args:
Simon Glass62a95372021-02-03 06:00:59 -0700661 node (Node): Node to output
Simon Glass9829eea2020-12-23 08:11:22 -0700662 """
663 self.buf('static struct %s%s %s%s = {\n' %
Simon Glass62a95372021-02-03 06:00:59 -0700664 (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
Simon Glass9829eea2020-12-23 08:11:22 -0700665 for pname in sorted(node.props):
666 self._output_prop(node, node.props[pname])
667 self.buf('};\n')
668
Simon Glassbe88d2f2021-02-03 06:01:07 -0700669 def read_aliases(self):
670 """Read the aliases and attach the information to self._alias
671
672 Raises:
673 ValueError: The alias path is not found
674 """
675 alias_node = self._fdt.GetNode('/aliases')
676 if not alias_node:
677 return
678 re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
679 for prop in alias_node.props.values():
680 m_alias = re_num.match(prop.name)
681 if not m_alias:
682 raise ValueError("Cannot decode alias '%s'" % prop.name)
683 name, num = m_alias.groups()
684 node = self._fdt.GetNode(prop.value)
685 result = self._scan.add_uclass_alias(name, num, node)
686 if result is None:
687 raise ValueError("Alias '%s' path '%s' not found" %
688 (prop.name, prop.value))
689 elif result is False:
690 print("Could not find uclass for alias '%s'" % prop.name)
691
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700692 def generate_decl(self):
693 nodes_to_output = list(self._valid_nodes)
694
695 self.buf('#include <dm/device-internal.h>\n')
696 self.buf('#include <dm/uclass-internal.h>\n')
697 self.buf('\n')
698 self.buf(
699 '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
700 for node in nodes_to_output:
701 self.buf('DM_DRIVER_DECL(%s);\n' % node.struct_name);
702 self.buf('\n')
703
704 if self._instantiate:
705 self.buf(
706 '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
707 for node in nodes_to_output:
708 self.buf('DM_DEVICE_DECL(%s);\n' % node.var_name)
709 self.buf('\n')
710
711 uclass_list = self._valid_uclasses
712
713 self.buf(
714 '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
715 for uclass in uclass_list:
716 self.buf('DM_UCLASS_DRIVER_DECL(%s);\n' % uclass.name)
717
718 if self._instantiate:
719 self.buf('\n')
720 self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
721 for uclass in uclass_list:
722 self.buf('DM_UCLASS_DECL(%s);\n' % uclass.name)
723 self.out(''.join(self.get_buf()))
724
Simon Glass80d782c42021-02-03 06:01:10 -0700725 def assign_seqs(self):
Simon Glassdf56e0b2021-02-03 06:01:09 -0700726 """Assign a sequence number to each node"""
727 for node in self._valid_nodes_unsorted:
Simon Glass80d782c42021-02-03 06:01:10 -0700728 seq = self._scan.assign_seq(node)
729 if seq is not None:
730 node.seq = seq
Simon Glassdf56e0b2021-02-03 06:01:09 -0700731
Simon Glass047a4802021-02-03 06:01:00 -0700732 def process_nodes(self, need_drivers):
733 nodes_to_output = list(self._valid_nodes)
734
Simon Glasseb3c2492021-02-03 06:01:01 -0700735 # Figure out which drivers we actually use
736 self._scan.mark_used(nodes_to_output)
737
Simon Glass047a4802021-02-03 06:01:00 -0700738 for node in nodes_to_output:
739 node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
740 driver = self._scan.get_driver(node.struct_name)
741 if not driver:
742 if not need_drivers:
743 continue
744 raise ValueError("Cannot parse/find driver for '%s'" %
745 node.struct_name)
746 node.driver = driver
Simon Glass80d782c42021-02-03 06:01:10 -0700747 uclass = self._scan._uclass.get(driver.uclass_id)
748 if not uclass:
749 raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
750 (driver.uclass_id, node.struct_name))
751 node.uclass = uclass
752 node.uclass_seq = len(node.uclass.devs)
753 node.uclass.devs.append(node)
754 uclass.node_refs[node.uclass_seq] = \
755 '&%s->uclass_node' % node.dev_ref
756
Simon Glass047a4802021-02-03 06:01:00 -0700757 parent_driver = None
758 if node.parent in self._valid_nodes:
759 parent_driver = self._scan.get_driver(node.parent.struct_name)
760 if not parent_driver:
761 if not need_drivers:
762 continue
763 raise ValueError(
764 "Cannot parse/find parent driver '%s' for '%s'" %
765 (node.parent.struct_name, node.struct_name))
766 node.parent_seq = len(node.parent.child_devs)
767 node.parent.child_devs.append(node)
768 node.parent.child_refs[node.parent_seq] = \
769 '&%s->sibling_node' % node.dev_ref
770 node.parent_driver = parent_driver
771
772 for node in nodes_to_output:
773 ref = '&%s->child_head' % node.dev_ref
774 node.child_refs[-1] = ref
775 node.child_refs[len(node.child_devs)] = ref
776
Simon Glass80d782c42021-02-03 06:01:10 -0700777 uclass_set = set()
778 for driver in self._scan._drivers.values():
779 if driver.used and driver.uclass:
780 uclass_set.add(driver.uclass)
781 self._valid_uclasses = sorted(list(uclass_set),
782 key=lambda uc: uc.uclass_id)
783
784 for seq, uclass in enumerate(uclass_set):
785 ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
786 uclass.node_refs[-1] = ref
787 uclass.node_refs[len(uclass.devs)] = ref
788
Simon Glassbe749002021-02-03 06:01:15 -0700789 def output_node_plat(self, node):
Simon Glass9d98b6e2020-12-23 08:11:20 -0700790 """Output the C code for a node
Simon Glassbc9e2682020-10-03 09:25:18 -0600791
Simon Glass9d98b6e2020-12-23 08:11:20 -0700792 Args:
793 node (fdt.Node): node to output
794 """
Simon Glassbe749002021-02-03 06:01:15 -0700795 driver = node.driver
796 parent_driver = node.parent_driver
797
798 line1 = 'Node %s index %d' % (node.path, node.idx)
799 if driver:
800 self.buf('/*\n')
801 self.buf(' * %s\n' % line1)
802 self.buf(' * driver %s parent %s\n' % (driver.name,
803 parent_driver.name if parent_driver else 'None'))
804 self.buf(' */\n')
805 else:
806 self.buf('/* %s */\n' % line1)
Simon Glassd570dec2017-06-18 22:08:58 -0600807
Simon Glass62a95372021-02-03 06:00:59 -0700808 self._output_values(node)
809 self._declare_device(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600810
Simon Glass1f730c82017-06-18 22:08:59 -0600811 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -0600812
Simon Glassbe749002021-02-03 06:01:15 -0700813 def check_instantiate(self, require):
814 """Check if self._instantiate is set to the required value
815
816 If not, this outputs a message into the current file
817
818 Args:
819 require: True to require --instantiate, False to require that it not
820 be enabled
821 """
822 if require != self._instantiate:
823 self.out(
824 '/* This file is not used: --instantiate was %senabled */\n' %
825 ('not ' if require else ''))
826 return False
827 return True
828
Simon Glass55526782020-12-28 20:35:02 -0700829 def generate_plat(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600830 """Generate device defintions for the platform data
831
832 This writes out C platform data initialisation data and
Simon Glass1d8364a2020-12-28 20:34:54 -0700833 U_BOOT_DRVINFO() declarations for each valid node. Where a node has
Simon Glassd570dec2017-06-18 22:08:58 -0600834 multiple compatible strings, a #define is used to make them equivalent.
835
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100836 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glassd570dec2017-06-18 22:08:58 -0600837 information.
838 """
Simon Glassbe749002021-02-03 06:01:15 -0700839 if not self.check_instantiate(False):
840 return
Simon Glass1d8364a2020-12-28 20:34:54 -0700841 self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
Simon Glassbeddd7a2020-12-28 20:35:01 -0700842 self.out('#define DT_PLAT_C\n')
Simon Glass4c73d7b2020-10-03 11:31:41 -0600843 self.out('\n')
Simon Glass1f730c82017-06-18 22:08:59 -0600844 self.out('#include <common.h>\n')
845 self.out('#include <dm.h>\n')
846 self.out('#include <dt-structs.h>\n')
847 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600848
Simon Glass16382ce2020-12-28 20:35:04 -0700849 for node in self._valid_nodes:
Simon Glassbe749002021-02-03 06:01:15 -0700850 self.output_node_plat(node)
Simon Glass3fa797a2017-06-18 22:09:03 -0600851
Walter Lozanodc5b4372020-06-25 01:10:13 -0300852 self.out(''.join(self.get_buf()))
Simon Glass3fa797a2017-06-18 22:09:03 -0600853
Simon Glassc3a310a82020-12-28 20:34:51 -0700854
855# Types of output file we understand
856# key: Command used to generate this file
857# value: OutputFile for this command
858OUTPUT_FILES = {
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700859 'decl':
860 OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
861 'Declares externs for all device/uclass instances'),
Simon Glass6b208842020-12-28 20:35:00 -0700862 'struct':
863 OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
Simon Glass55526782020-12-28 20:35:02 -0700864 DtbPlatdata.generate_structs,
Simon Glass6b208842020-12-28 20:35:00 -0700865 'Defines the structs used to hold devicetree data'),
866 'platdata':
Simon Glass55526782020-12-28 20:35:02 -0700867 OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
Simon Glass6b208842020-12-28 20:35:00 -0700868 'Declares the U_BOOT_DRIVER() records and platform data'),
Simon Glassc3a310a82020-12-28 20:34:51 -0700869 }
870
Simon Glass6a65d8a2020-12-28 20:34:50 -0700871
Simon Glassf303ee72021-02-03 06:01:02 -0700872def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
Simon Glass3809ad92021-02-03 06:01:12 -0700873 instantiate, warning_disabled=False, drivers_additional=None,
874 basedir=None, scan=None):
Simon Glass3fa797a2017-06-18 22:09:03 -0600875 """Run all the steps of the dtoc tool
876
877 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700878 args (list): List of non-option arguments provided to the problem
879 dtb_file (str): Filename of dtb file to process
880 include_disabled (bool): True to include disabled nodes
Simon Glass6ca0c7a2020-12-28 20:34:48 -0700881 output (str): Name of output file (None for stdout)
Simon Glass6a65d8a2020-12-28 20:34:50 -0700882 output_dirs (tuple of str):
883 Directory to put C output files
884 Directory to put H output files
Simon Glassf303ee72021-02-03 06:01:02 -0700885 phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
886 or 'tpl'. None if not known
Simon Glass3809ad92021-02-03 06:01:12 -0700887 instantiate: Instantiate devices so they don't need to be bound at
888 run-time
Simon Glass93daa012020-12-03 16:55:16 -0700889 warning_disabled (bool): True to avoid showing warnings about missing
890 drivers
Simon Glass27511232020-12-23 08:11:19 -0700891 drivers_additional (list): List of additional drivers to use during
Simon Glass93daa012020-12-03 16:55:16 -0700892 scanning
Simon Glass4f2059b2020-12-28 20:35:03 -0700893 basedir (str): Base directory of U-Boot source code. Defaults to the
894 grandparent of this file's directory
Simon Glass768ff0a2021-02-03 06:00:51 -0700895 scan (src_src.Scanner): Scanner from a previous run. This can help speed
896 up tests. Use None for normal operation
897
Simon Glassbe88d2f2021-02-03 06:01:07 -0700898 Returns:
899 DtbPlatdata object
900
Simon Glass94ee3bd2020-11-08 20:36:21 -0700901 Raises:
902 ValueError: if args has no command, or an unknown command
Simon Glass3fa797a2017-06-18 22:09:03 -0600903 """
904 if not args:
Simon Glassc3a310a82020-12-28 20:34:51 -0700905 raise ValueError('Please specify a command: struct, platdata, all')
906 if output and output_dirs and any(output_dirs):
907 raise ValueError('Must specify either output or output_dirs, not both')
Simon Glass3fa797a2017-06-18 22:09:03 -0600908
Simon Glass768ff0a2021-02-03 06:00:51 -0700909 if not scan:
Simon Glassf303ee72021-02-03 06:01:02 -0700910 scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional,
911 phase)
Simon Glass768ff0a2021-02-03 06:00:51 -0700912 scan.scan_drivers()
Simon Glass047a4802021-02-03 06:01:00 -0700913 do_process = True
914 else:
915 do_process = False
Simon Glass3809ad92021-02-03 06:01:12 -0700916 plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
Simon Glass3fa797a2017-06-18 22:09:03 -0600917 plat.scan_dtb()
Simon Glass3809ad92021-02-03 06:01:12 -0700918 plat.scan_tree(add_root=instantiate)
Simon Glass44479782021-02-03 06:00:58 -0700919 plat.prepare_nodes()
Simon Glass1b1fe412017-08-29 14:15:50 -0600920 plat.scan_reg_sizes()
Simon Glassc3a310a82020-12-28 20:34:51 -0700921 plat.setup_output_dirs(output_dirs)
Simon Glass55526782020-12-28 20:35:02 -0700922 plat.scan_structs()
Simon Glass3fa797a2017-06-18 22:09:03 -0600923 plat.scan_phandles()
Simon Glass3809ad92021-02-03 06:01:12 -0700924 plat.process_nodes(instantiate)
Simon Glassbe88d2f2021-02-03 06:01:07 -0700925 plat.read_aliases()
Simon Glass80d782c42021-02-03 06:01:10 -0700926 plat.assign_seqs()
Simon Glass3fa797a2017-06-18 22:09:03 -0600927
Simon Glass4e8e8462020-12-28 20:34:52 -0700928 cmds = args[0].split(',')
929 if 'all' in cmds:
930 cmds = sorted(OUTPUT_FILES.keys())
931 for cmd in cmds:
Simon Glassc3a310a82020-12-28 20:34:51 -0700932 outfile = OUTPUT_FILES.get(cmd)
933 if not outfile:
934 raise ValueError("Unknown command '%s': (use: %s)" %
Simon Glass4e8e8462020-12-28 20:34:52 -0700935 (cmd, ', '.join(sorted(OUTPUT_FILES.keys()))))
Simon Glassc3a310a82020-12-28 20:34:51 -0700936 plat.setup_output(outfile.ftype,
937 outfile.fname if output_dirs else output)
Simon Glass6b208842020-12-28 20:35:00 -0700938 plat.out_header(outfile)
Simon Glass55526782020-12-28 20:35:02 -0700939 outfile.method(plat)
Simon Glassc3a310a82020-12-28 20:34:51 -0700940 plat.finish_output()
Simon Glassbe88d2f2021-02-03 06:01:07 -0700941 return plat