blob: ab26c4adca5342e0d678dd0f47ebf0616aec7934 [file] [log] [blame]
Simon Glass7581c012017-06-18 22:08:58 -06001#!/usr/bin/python
Tom Rini83d290c2018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glass7581c012017-06-18 22:08:58 -06003#
4# Copyright (C) 2017 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
Simon Glass7581c012017-06-18 22:08:58 -06007
Simon Glass2be282c2017-06-18 22:08:59 -06008"""Device tree to platform data class
9
10This supports converting device tree data to C structures definitions and
11static data.
Simon Glass9b330382020-11-08 20:36:21 -070012
13See doc/driver-model/of-plat.rst for more informaiton
Simon Glass2be282c2017-06-18 22:08:59 -060014"""
15
Simon Glass8fed2eb2017-08-29 14:15:55 -060016import collections
Simon Glass7581c012017-06-18 22:08:58 -060017import copy
Simon Glassbe44f272020-12-28 20:34:51 -070018from enum import IntEnum
Walter Lozanodac82282020-07-03 08:07:17 -030019import os
20import re
Simon Glass2be282c2017-06-18 22:08:59 -060021import sys
Simon Glass7581c012017-06-18 22:08:58 -060022
Simon Glassbf776672020-04-17 18:09:04 -060023from dtoc import fdt
24from dtoc import fdt_util
Simon Glassa542a702020-12-28 20:35:06 -070025from dtoc import src_scan
26from dtoc.src_scan import conv_name_to_c
Simon Glass7581c012017-06-18 22:08:58 -060027
Simon Glass9b330382020-11-08 20:36:21 -070028# When we see these properties we ignore them - i.e. do not create a structure
29# member
Simon Glass7581c012017-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 Glass5ea9dcc2020-11-08 20:36:17 -070043# C type declarations for the types we support
Simon Glass7581c012017-06-18 22:08:58 -060044TYPE_NAMES = {
Simon Glass5ea9dcc2020-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 Glass2be282c2017-06-18 22:08:59 -060050}
Simon Glass7581c012017-06-18 22:08:58 -060051
52STRUCT_PREFIX = 'dtd_'
53VAL_PREFIX = 'dtv_'
54
Simon Glass8840bc52021-02-03 06:01:18 -070055# Properties which are considered to be phandles
56# key: property name
57# value: name of associated #cells property in the target node
58#
59# New phandle properties must be added here; otherwise they will come through as
60# simple integers and finding devices by phandle will not work.
61# Any property that ends with one of these (e.g. 'cd-gpios') will be considered
62# a phandle property.
63PHANDLE_PROPS = {
64 'clocks': '#clock-cells',
65 'gpios': '#gpio-cells',
66 'sandbox,emul': '#emul-cells',
67 }
68
Simon Glassbe44f272020-12-28 20:34:51 -070069class Ftype(IntEnum):
70 SOURCE, HEADER = range(2)
71
72
73# This holds information about each type of output file dtoc can create
74# type: Type of file (Ftype)
Simon Glassd1055d62020-12-28 20:35:00 -070075# fname: Filename excluding directory, e.g. 'dt-plat.c'
76# hdr_comment: Comment explaining the purpose of the file
77OutputFile = collections.namedtuple('OutputFile',
Simon Glassa7d5f962020-12-28 20:35:02 -070078 ['ftype', 'fname', 'method', 'hdr_comment'])
Simon Glassbe44f272020-12-28 20:34:51 -070079
Simon Glass8fed2eb2017-08-29 14:15:55 -060080# This holds information about a property which includes phandles.
81#
82# max_args: integer: Maximum number or arguments that any phandle uses (int).
83# args: Number of args for each phandle in the property. The total number of
84# phandles is len(args). This is a list of integers.
85PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
86
Simon Glass97136eb2020-10-03 09:25:19 -060087# Holds a single phandle link, allowing a C struct value to be assigned to point
88# to a device
89#
90# var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
91# dev_name: Name of device to assign to (e.g. 'clock')
92PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
93
Simon Glass8fed2eb2017-08-29 14:15:55 -060094
Simon Glass2be282c2017-06-18 22:08:59 -060095def tab_to(num_tabs, line):
96 """Append tabs to a line of text to reach a tab stop.
Simon Glass7581c012017-06-18 22:08:58 -060097
Simon Glass2be282c2017-06-18 22:08:59 -060098 Args:
Simon Glass9b330382020-11-08 20:36:21 -070099 num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
100 line (str): Line of text to append to
Simon Glass2be282c2017-06-18 22:08:59 -0600101
102 Returns:
Simon Glass9b330382020-11-08 20:36:21 -0700103 str: line with the correct number of tabs appeneded. If the line already
Simon Glass2be282c2017-06-18 22:08:59 -0600104 extends past that tab stop then a single space is appended.
105 """
106 if len(line) >= num_tabs * 8:
107 return line + ' '
108 return line + '\t' * (num_tabs - len(line) // 8)
109
Simon Glass56e0bbe2017-06-18 22:09:02 -0600110def get_value(ftype, value):
111 """Get a value as a C expression
112
113 For integers this returns a byte-swapped (little-endian) hex string
114 For bytes this returns a hex string, e.g. 0x12
115 For strings this returns a literal string enclosed in quotes
116 For booleans this return 'true'
117
118 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700119 ftype (fdt.Type): Data type (fdt_util)
120 value (bytes): Data value, as a string of bytes
121
122 Returns:
123 str: String representation of the value
Simon Glass56e0bbe2017-06-18 22:09:02 -0600124 """
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700125 if ftype == fdt.Type.INT:
Simon Glassccc3da72020-12-23 08:11:19 -0700126 val = '%#x' % fdt_util.fdt32_to_cpu(value)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700127 elif ftype == fdt.Type.BYTE:
Simon Glass78128d52020-12-03 16:55:16 -0700128 char = value[0]
Simon Glassccc3da72020-12-23 08:11:19 -0700129 val = '%#x' % (ord(char) if isinstance(char, str) else char)
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700130 elif ftype == fdt.Type.STRING:
Simon Glassf02d0eb2020-07-07 21:32:06 -0600131 # Handle evil ACPI backslashes by adding another backslash before them.
132 # So "\\_SB.GPO0" in the device tree effectively stays like that in C
Simon Glassccc3da72020-12-23 08:11:19 -0700133 val = '"%s"' % value.replace('\\', '\\\\')
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700134 elif ftype == fdt.Type.BOOL:
Simon Glassccc3da72020-12-23 08:11:19 -0700135 val = 'true'
Simon Glass9b330382020-11-08 20:36:21 -0700136 else: # ftype == fdt.Type.INT64:
Simon Glassccc3da72020-12-23 08:11:19 -0700137 val = '%#x' % value
138 return val
Simon Glass56e0bbe2017-06-18 22:09:02 -0600139
Simon Glass56e0bbe2017-06-18 22:09:02 -0600140
Simon Glassccc3da72020-12-23 08:11:19 -0700141class DtbPlatdata():
Simon Glass7581c012017-06-18 22:08:58 -0600142 """Provide a means to convert device tree binary data to platform data
143
144 The output of this process is C structures which can be used in space-
145 constrained encvironments where the ~3KB code overhead of device tree
146 code is not affordable.
147
148 Properties:
Simon Glassa542a702020-12-28 20:35:06 -0700149 _scan: Scan object, for scanning and reporting on useful information
150 from the U-Boot source code
Simon Glass2be282c2017-06-18 22:08:59 -0600151 _fdt: Fdt object, referencing the device tree
Simon Glass7581c012017-06-18 22:08:58 -0600152 _dtb_fname: Filename of the input device tree binary file
Simon Glass074197a2021-02-03 06:01:09 -0700153 _valid_nodes_unsorted: A list of Node object with compatible strings,
154 ordered by devicetree node order
155 _valid_nodes: A list of Node object with compatible strings, ordered by
156 conv_name_to_c(node.name)
Simon Glasse36024b2017-06-18 22:09:01 -0600157 _include_disabled: true to include nodes marked status = "disabled"
Simon Glass7581c012017-06-18 22:08:58 -0600158 _outfile: The current output file (sys.stdout or a real file)
159 _lines: Stashed list of output lines for outputting in the future
Simon Glassbe44f272020-12-28 20:34:51 -0700160 _dirname: Directory to hold output files, or None for none (all files
161 go to stdout)
Simon Glassa7d5f962020-12-28 20:35:02 -0700162 _struct_data (dict): OrderedDict of dtplat structures to output
163 key (str): Node name, as a C identifier
164 value: dict containing structure fields:
165 key (str): Field name
166 value: Prop object with field information
Simon Glass1e0f3f42020-12-28 20:35:03 -0700167 _basedir (str): Base directory of source tree
Simon Glass337d6972021-02-03 06:01:10 -0700168 _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
169 the selected devices (see _valid_node), in alphabetical order
Simon Glass4a092352021-02-03 06:01:12 -0700170 _instantiate: Instantiate devices so they don't need to be bound at
171 run-time
Simon Glass7581c012017-06-18 22:08:58 -0600172 """
Simon Glass4a092352021-02-03 06:01:12 -0700173 def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
Simon Glassa542a702020-12-28 20:35:06 -0700174 self._scan = scan
Simon Glass2be282c2017-06-18 22:08:59 -0600175 self._fdt = None
Simon Glass7581c012017-06-18 22:08:58 -0600176 self._dtb_fname = dtb_fname
177 self._valid_nodes = None
Simon Glass074197a2021-02-03 06:01:09 -0700178 self._valid_nodes_unsorted = None
Simon Glasse36024b2017-06-18 22:09:01 -0600179 self._include_disabled = include_disabled
Simon Glass7581c012017-06-18 22:08:58 -0600180 self._outfile = None
181 self._lines = []
Simon Glassbe44f272020-12-28 20:34:51 -0700182 self._dirnames = [None] * len(Ftype)
Simon Glassa7d5f962020-12-28 20:35:02 -0700183 self._struct_data = collections.OrderedDict()
Simon Glass1e0f3f42020-12-28 20:35:03 -0700184 self._basedir = None
Simon Glass337d6972021-02-03 06:01:10 -0700185 self._valid_uclasses = None
Simon Glass4a092352021-02-03 06:01:12 -0700186 self._instantiate = instantiate
Walter Lozanodac82282020-07-03 08:07:17 -0300187
Simon Glassbe44f272020-12-28 20:34:51 -0700188 def setup_output_dirs(self, output_dirs):
189 """Set up the output directories
190
191 This should be done before setup_output() is called
192
193 Args:
194 output_dirs (tuple of str):
195 Directory to use for C output files.
196 Use None to write files relative current directory
197 Directory to use for H output files.
198 Defaults to the C output dir
199 """
200 def process_dir(ftype, dirname):
201 if dirname:
202 os.makedirs(dirname, exist_ok=True)
203 self._dirnames[ftype] = dirname
204
205 if output_dirs:
206 c_dirname = output_dirs[0]
207 h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
208 process_dir(Ftype.SOURCE, c_dirname)
209 process_dir(Ftype.HEADER, h_dirname)
210
211 def setup_output(self, ftype, fname):
Simon Glass7581c012017-06-18 22:08:58 -0600212 """Set up the output destination
213
Simon Glass2be282c2017-06-18 22:08:59 -0600214 Once this is done, future calls to self.out() will output to this
Simon Glassbe44f272020-12-28 20:34:51 -0700215 file. The file used is as follows:
216
217 self._dirnames[ftype] is None: output to fname, or stdout if None
218 self._dirnames[ftype] is not None: output to fname in that directory
219
220 Calling this function multiple times will close the old file and open
221 the new one. If they are the same file, nothing happens and output will
222 continue to the same file.
Simon Glass7581c012017-06-18 22:08:58 -0600223
224 Args:
Simon Glassbe44f272020-12-28 20:34:51 -0700225 ftype (str): Type of file to create ('c' or 'h')
226 fname (str): Filename to send output to. If there is a directory in
227 self._dirnames for this file type, it will be put in that
228 directory
Simon Glass7581c012017-06-18 22:08:58 -0600229 """
Simon Glassbe44f272020-12-28 20:34:51 -0700230 dirname = self._dirnames[ftype]
231 if dirname:
232 pathname = os.path.join(dirname, fname)
233 if self._outfile:
234 self._outfile.close()
235 self._outfile = open(pathname, 'w')
236 elif fname:
237 if not self._outfile:
238 self._outfile = open(fname, 'w')
Simon Glassf62cea02020-12-28 20:34:48 -0700239 else:
240 self._outfile = sys.stdout
Simon Glass7581c012017-06-18 22:08:58 -0600241
Simon Glassbe44f272020-12-28 20:34:51 -0700242 def finish_output(self):
243 """Finish outputing to a file
244
245 This closes the output file, if one is in use
246 """
247 if self._outfile != sys.stdout:
248 self._outfile.close()
249
Simon Glass2be282c2017-06-18 22:08:59 -0600250 def out(self, line):
Simon Glass7581c012017-06-18 22:08:58 -0600251 """Output a string to the output file
252
253 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700254 line (str): String to output
Simon Glass7581c012017-06-18 22:08:58 -0600255 """
Simon Glass2be282c2017-06-18 22:08:59 -0600256 self._outfile.write(line)
Simon Glass7581c012017-06-18 22:08:58 -0600257
Simon Glass2be282c2017-06-18 22:08:59 -0600258 def buf(self, line):
Simon Glass7581c012017-06-18 22:08:58 -0600259 """Buffer up a string to send later
260
261 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700262 line (str): String to add to our 'buffer' list
Simon Glass7581c012017-06-18 22:08:58 -0600263 """
Simon Glass2be282c2017-06-18 22:08:59 -0600264 self._lines.append(line)
Simon Glass7581c012017-06-18 22:08:58 -0600265
Simon Glass2be282c2017-06-18 22:08:59 -0600266 def get_buf(self):
Simon Glass7581c012017-06-18 22:08:58 -0600267 """Get the contents of the output buffer, and clear it
268
269 Returns:
Simon Glass9b330382020-11-08 20:36:21 -0700270 list(str): The output buffer, which is then cleared for future use
Simon Glass7581c012017-06-18 22:08:58 -0600271 """
272 lines = self._lines
273 self._lines = []
274 return lines
275
Simon Glassd1055d62020-12-28 20:35:00 -0700276 def out_header(self, outfile):
277 """Output a message indicating that this is an auto-generated file
278
279 Args:
280 outfile: OutputFile describing the file being generated
281 """
Simon Glassd5031142017-08-29 14:16:01 -0600282 self.out('''/*
283 * DO NOT MODIFY
284 *
Simon Glassd1055d62020-12-28 20:35:00 -0700285 * %s.
286 * This was generated by dtoc from a .dtb (device tree binary) file.
Simon Glassd5031142017-08-29 14:16:01 -0600287 */
288
Simon Glassd1055d62020-12-28 20:35:00 -0700289''' % outfile.hdr_comment)
Simon Glassd5031142017-08-29 14:16:01 -0600290
Simon Glass8fed2eb2017-08-29 14:15:55 -0600291 def get_phandle_argc(self, prop, node_name):
292 """Check if a node contains phandles
Simon Glass2925c262017-08-29 14:15:54 -0600293
Simon Glass8fed2eb2017-08-29 14:15:55 -0600294 We have no reliable way of detecting whether a node uses a phandle
295 or not. As an interim measure, use a list of known property names.
Simon Glass2925c262017-08-29 14:15:54 -0600296
Simon Glass8fed2eb2017-08-29 14:15:55 -0600297 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700298 prop (fdt.Prop): Prop object to check
299 node_name (str): Node name, only used for raising an error
300 Returns:
301 int or None: Number of argument cells is this is a phandle,
302 else None
303 Raises:
304 ValueError: if the phandle cannot be parsed or the required property
305 is not present
Simon Glass8fed2eb2017-08-29 14:15:55 -0600306 """
Simon Glass8840bc52021-02-03 06:01:18 -0700307 cells_prop = None
308 for name, cprop in PHANDLE_PROPS.items():
309 if prop.name.endswith(name):
310 cells_prop = cprop
311 if cells_prop:
Simon Glass760b7172018-07-06 10:27:31 -0600312 if not isinstance(prop.value, list):
313 prop.value = [prop.value]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600314 val = prop.value
Simon Glass8fed2eb2017-08-29 14:15:55 -0600315 i = 0
316
317 max_args = 0
318 args = []
319 while i < len(val):
320 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass760b7172018-07-06 10:27:31 -0600321 # If we get to the end of the list, stop. This can happen
322 # since some nodes have more phandles in the list than others,
323 # but we allocate enough space for the largest list. So those
324 # nodes with shorter lists end up with zeroes at the end.
325 if not phandle:
326 break
Simon Glass8fed2eb2017-08-29 14:15:55 -0600327 target = self._fdt.phandle_to_node.get(phandle)
328 if not target:
329 raise ValueError("Cannot parse '%s' in node '%s'" %
330 (prop.name, node_name))
Simon Glass8840bc52021-02-03 06:01:18 -0700331 cells = target.props.get(cells_prop)
Simon Glass8fed2eb2017-08-29 14:15:55 -0600332 if not cells:
Walter Lozanoad340172020-06-25 01:10:16 -0300333 raise ValueError("Node '%s' has no cells property" %
Simon Glass8840bc52021-02-03 06:01:18 -0700334 target.name)
Simon Glass8fed2eb2017-08-29 14:15:55 -0600335 num_args = fdt_util.fdt32_to_cpu(cells.value)
336 max_args = max(max_args, num_args)
337 args.append(num_args)
338 i += 1 + num_args
339 return PhandleInfo(max_args, args)
340 return None
Simon Glass2925c262017-08-29 14:15:54 -0600341
Simon Glass2be282c2017-06-18 22:08:59 -0600342 def scan_dtb(self):
Anatolij Gustschinf1a7ba12017-08-18 17:58:51 +0200343 """Scan the device tree to obtain a tree of nodes and properties
Simon Glass7581c012017-06-18 22:08:58 -0600344
Simon Glass2be282c2017-06-18 22:08:59 -0600345 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glass7581c012017-06-18 22:08:58 -0600346 device tree root node, and progress from there.
347 """
Simon Glass2be282c2017-06-18 22:08:59 -0600348 self._fdt = fdt.FdtScan(self._dtb_fname)
Simon Glass7581c012017-06-18 22:08:58 -0600349
Simon Glass074197a2021-02-03 06:01:09 -0700350 def scan_node(self, node, valid_nodes):
Simon Glass2be282c2017-06-18 22:08:59 -0600351 """Scan a node and subnodes to build a tree of node and phandle info
352
Simon Glass074197a2021-02-03 06:01:09 -0700353 This adds each subnode to self._valid_nodes if it is enabled and has a
354 compatible string.
Simon Glass2be282c2017-06-18 22:08:59 -0600355
356 Args:
Simon Glass074197a2021-02-03 06:01:09 -0700357 node (Node): Node for scan for subnodes
Simon Glassccc3da72020-12-23 08:11:19 -0700358 valid_nodes (list of Node): List of Node objects to add to
Simon Glass2be282c2017-06-18 22:08:59 -0600359 """
Simon Glass074197a2021-02-03 06:01:09 -0700360 for subnode in node.subnodes:
361 if 'compatible' in subnode.props:
362 status = subnode.props.get('status')
Simon Glasse36024b2017-06-18 22:09:01 -0600363 if (not self._include_disabled and not status or
Simon Glass2be282c2017-06-18 22:08:59 -0600364 status.value != 'disabled'):
Simon Glass074197a2021-02-03 06:01:09 -0700365 valid_nodes.append(subnode)
Simon Glass7581c012017-06-18 22:08:58 -0600366
367 # recurse to handle any subnodes
Simon Glass074197a2021-02-03 06:01:09 -0700368 self.scan_node(subnode, valid_nodes)
Simon Glass7581c012017-06-18 22:08:58 -0600369
Simon Glass50aae3e2021-02-03 06:01:11 -0700370 def scan_tree(self, add_root):
Simon Glass7581c012017-06-18 22:08:58 -0600371 """Scan the device tree for useful information
372
373 This fills in the following properties:
Simon Glass074197a2021-02-03 06:01:09 -0700374 _valid_nodes_unsorted: A list of nodes we wish to consider include
375 in the platform data (in devicetree node order)
376 _valid_nodes: Sorted version of _valid_nodes_unsorted
Simon Glass50aae3e2021-02-03 06:01:11 -0700377
378 Args:
379 add_root: True to add the root node also (which wouldn't normally
380 be added as it may not have a compatible string)
Simon Glass7581c012017-06-18 22:08:58 -0600381 """
Simon Glass074197a2021-02-03 06:01:09 -0700382 root = self._fdt.GetRoot()
Simon Glass1b272732020-10-03 11:31:25 -0600383 valid_nodes = []
Simon Glass50aae3e2021-02-03 06:01:11 -0700384 if add_root:
385 valid_nodes.append(root)
Simon Glass074197a2021-02-03 06:01:09 -0700386 self.scan_node(root, valid_nodes)
387 self._valid_nodes_unsorted = valid_nodes
Simon Glass1b272732020-10-03 11:31:25 -0600388 self._valid_nodes = sorted(valid_nodes,
389 key=lambda x: conv_name_to_c(x.name))
Simon Glass51d5d052021-02-03 06:00:58 -0700390
391 def prepare_nodes(self):
392 """Add extra properties to the nodes we are using
393
394 The following properties are added for use by dtoc:
395 idx: Index number of this node (0=first, etc.)
396 struct_name: Name of the struct dtd used by this node
397 var_name: C name for this node
398 child_devs: List of child devices for this node, each a None
399 child_refs: Dict of references for each child:
400 key: Position in child list (-1=head, 0=first, 1=second, ...
401 n-1=last, n=head)
402 seq: Sequence number of the device (unique within its uclass), or
403 -1 not not known yet
404 dev_ref: Reference to this device, e.g. 'DM_DEVICE_REF(serial)'
405 driver: Driver record for this node, or None if not known
406 uclass: Uclass record for this node, or None if not known
407 uclass_seq: Position of this device within the uclass list (0=first,
408 n-1=last)
409 parent_seq: Position of this device within it siblings (0=first,
410 n-1=last)
411 parent_driver: Driver record of the node's parent, or None if none.
412 We don't use node.parent.driver since node.parent may not be in
413 the list of valid nodes
414 """
Simon Glass1b272732020-10-03 11:31:25 -0600415 for idx, node in enumerate(self._valid_nodes):
416 node.idx = idx
Simon Glass51d5d052021-02-03 06:00:58 -0700417 node.struct_name, _ = self._scan.get_normalized_compat_name(node)
418 node.var_name = conv_name_to_c(node.name)
419 node.child_devs = []
420 node.child_refs = {}
421 node.seq = -1
422 node.dev_ref = None
423 node.driver = None
424 node.uclass = None
425 node.uclass_seq = None
426 node.parent_seq = None
427 node.parent_driver = None
Simon Glass7581c012017-06-18 22:08:58 -0600428
Simon Glassc20ee0e2017-08-29 14:15:50 -0600429 @staticmethod
430 def get_num_cells(node):
431 """Get the number of cells in addresses and sizes for this node
432
433 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700434 node (fdt.None): Node to check
Simon Glassc20ee0e2017-08-29 14:15:50 -0600435
436 Returns:
437 Tuple:
438 Number of address cells for this node
439 Number of size cells for this node
440 """
441 parent = node.parent
Simon Glass78128d52020-12-03 16:55:16 -0700442 num_addr, num_size = 2, 2
Simon Glassc20ee0e2017-08-29 14:15:50 -0600443 if parent:
Simon Glass78128d52020-12-03 16:55:16 -0700444 addr_prop = parent.props.get('#address-cells')
445 size_prop = parent.props.get('#size-cells')
446 if addr_prop:
447 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
448 if size_prop:
449 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
450 return num_addr, num_size
Simon Glassc20ee0e2017-08-29 14:15:50 -0600451
452 def scan_reg_sizes(self):
453 """Scan for 64-bit 'reg' properties and update the values
454
455 This finds 'reg' properties with 64-bit data and converts the value to
456 an array of 64-values. This allows it to be output in a way that the
457 C code can read.
458 """
459 for node in self._valid_nodes:
460 reg = node.props.get('reg')
461 if not reg:
462 continue
Simon Glass78128d52020-12-03 16:55:16 -0700463 num_addr, num_size = self.get_num_cells(node)
464 total = num_addr + num_size
Simon Glassc20ee0e2017-08-29 14:15:50 -0600465
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700466 if reg.type != fdt.Type.INT:
Simon Glassdfe5f5b2018-07-06 10:27:32 -0600467 raise ValueError("Node '%s' reg property is not an int" %
468 node.name)
Simon Glassc20ee0e2017-08-29 14:15:50 -0600469 if len(reg.value) % total:
Simon Glass9b330382020-11-08 20:36:21 -0700470 raise ValueError(
471 "Node '%s' reg property has %d cells "
472 'which is not a multiple of na + ns = %d + %d)' %
Simon Glass78128d52020-12-03 16:55:16 -0700473 (node.name, len(reg.value), num_addr, num_size))
474 reg.num_addr = num_addr
475 reg.num_size = num_size
476 if num_addr != 1 or num_size != 1:
Simon Glass5ea9dcc2020-11-08 20:36:17 -0700477 reg.type = fdt.Type.INT64
Simon Glassc20ee0e2017-08-29 14:15:50 -0600478 i = 0
479 new_value = []
480 val = reg.value
481 if not isinstance(val, list):
482 val = [val]
483 while i < len(val):
Simon Glass78128d52020-12-03 16:55:16 -0700484 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
485 i += num_addr
486 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
487 i += num_size
Simon Glassc20ee0e2017-08-29 14:15:50 -0600488 new_value += [addr, size]
489 reg.value = new_value
490
Simon Glass2be282c2017-06-18 22:08:59 -0600491 def scan_structs(self):
Simon Glass7581c012017-06-18 22:08:58 -0600492 """Scan the device tree building up the C structures we will use.
493
494 Build a dict keyed by C struct name containing a dict of Prop
495 object for each struct field (keyed by property name). Where the
496 same struct appears multiple times, try to use the 'widest'
497 property, i.e. the one with a type which can express all others.
498
499 Once the widest property is determined, all other properties are
500 updated to match that width.
Simon Glasse4fb5fa2020-10-03 11:31:24 -0600501
Simon Glassa7d5f962020-12-28 20:35:02 -0700502 The results are written to self._struct_data
Simon Glass7581c012017-06-18 22:08:58 -0600503 """
Simon Glassa7d5f962020-12-28 20:35:02 -0700504 structs = self._struct_data
Simon Glass7581c012017-06-18 22:08:58 -0600505 for node in self._valid_nodes:
Simon Glass7581c012017-06-18 22:08:58 -0600506 fields = {}
507
508 # Get a list of all the valid properties in this node.
509 for name, prop in node.props.items():
510 if name not in PROP_IGNORE_LIST and name[0] != '#':
511 fields[name] = copy.deepcopy(prop)
512
Simon Glasse525fea2021-02-03 06:00:59 -0700513 # If we've seen this struct_name before, update the existing struct
514 if node.struct_name in structs:
515 struct = structs[node.struct_name]
Simon Glass7581c012017-06-18 22:08:58 -0600516 for name, prop in fields.items():
517 oldprop = struct.get(name)
518 if oldprop:
519 oldprop.Widen(prop)
520 else:
521 struct[name] = prop
522
523 # Otherwise store this as a new struct.
524 else:
Simon Glasse525fea2021-02-03 06:00:59 -0700525 structs[node.struct_name] = fields
Simon Glass7581c012017-06-18 22:08:58 -0600526
Simon Glass7581c012017-06-18 22:08:58 -0600527 for node in self._valid_nodes:
Simon Glasse525fea2021-02-03 06:00:59 -0700528 struct = structs[node.struct_name]
Simon Glass7581c012017-06-18 22:08:58 -0600529 for name, prop in node.props.items():
530 if name not in PROP_IGNORE_LIST and name[0] != '#':
531 prop.Widen(struct[name])
Simon Glass7581c012017-06-18 22:08:58 -0600532
Simon Glass2be282c2017-06-18 22:08:59 -0600533 def scan_phandles(self):
Simon Glass7581c012017-06-18 22:08:58 -0600534 """Figure out what phandles each node uses
535
536 We need to be careful when outputing nodes that use phandles since
537 they must come after the declaration of the phandles in the C file.
538 Otherwise we get a compiler error since the phandle struct is not yet
539 declared.
540
541 This function adds to each node a list of phandle nodes that the node
542 depends on. This allows us to output things in the right order.
543 """
544 for node in self._valid_nodes:
545 node.phandles = set()
546 for pname, prop in node.props.items():
547 if pname in PROP_IGNORE_LIST or pname[0] == '#':
548 continue
Simon Glass8fed2eb2017-08-29 14:15:55 -0600549 info = self.get_phandle_argc(prop, node.name)
550 if info:
Simon Glass8fed2eb2017-08-29 14:15:55 -0600551 # Process the list as pairs of (phandle, id)
Simon Glass634eba42017-08-29 14:15:59 -0600552 pos = 0
553 for args in info.args:
554 phandle_cell = prop.value[pos]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600555 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
556 target_node = self._fdt.phandle_to_node[phandle]
557 node.phandles.add(target_node)
Simon Glass634eba42017-08-29 14:15:59 -0600558 pos += 1 + args
Simon Glass7581c012017-06-18 22:08:58 -0600559
560
Simon Glassa7d5f962020-12-28 20:35:02 -0700561 def generate_structs(self):
Simon Glass7581c012017-06-18 22:08:58 -0600562 """Generate struct defintions for the platform data
563
564 This writes out the body of a header file consisting of structure
565 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardt2799a692020-02-25 21:35:39 +0100566 doc/driver-model/of-plat.rst for more information.
Simon Glass7581c012017-06-18 22:08:58 -0600567 """
Simon Glassa7d5f962020-12-28 20:35:02 -0700568 structs = self._struct_data
Simon Glass2be282c2017-06-18 22:08:59 -0600569 self.out('#include <stdbool.h>\n')
Masahiro Yamadab08c8c42018-03-05 01:20:11 +0900570 self.out('#include <linux/libfdt.h>\n')
Simon Glass7581c012017-06-18 22:08:58 -0600571
572 # Output the struct definition
573 for name in sorted(structs):
Simon Glass2be282c2017-06-18 22:08:59 -0600574 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glass7581c012017-06-18 22:08:58 -0600575 for pname in sorted(structs[name]):
576 prop = structs[name][pname]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600577 info = self.get_phandle_argc(prop, structs[name])
578 if info:
Simon Glass7581c012017-06-18 22:08:58 -0600579 # For phandles, include a reference to the target
Simon Glass0d154632017-08-29 14:15:56 -0600580 struct_name = 'struct phandle_%d_arg' % info.max_args
581 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass2be282c2017-06-18 22:08:59 -0600582 conv_name_to_c(prop.name),
Simon Glass634eba42017-08-29 14:15:59 -0600583 len(info.args)))
Simon Glass7581c012017-06-18 22:08:58 -0600584 else:
585 ptype = TYPE_NAMES[prop.type]
Simon Glass2be282c2017-06-18 22:08:59 -0600586 self.out('\t%s%s' % (tab_to(2, ptype),
587 conv_name_to_c(prop.name)))
588 if isinstance(prop.value, list):
589 self.out('[%d]' % len(prop.value))
590 self.out(';\n')
591 self.out('};\n')
Simon Glass7581c012017-06-18 22:08:58 -0600592
Simon Glassabf0c802020-12-23 08:11:20 -0700593 def _output_list(self, node, prop):
594 """Output the C code for a devicetree property that holds a list
595
596 Args:
597 node (fdt.Node): Node to output
598 prop (fdt.Prop): Prop to output
599 """
600 self.buf('{')
601 vals = []
602 # For phandles, output a reference to the platform data
603 # of the target node.
604 info = self.get_phandle_argc(prop, node.name)
605 if info:
606 # Process the list as pairs of (phandle, id)
607 pos = 0
608 for args in info.args:
609 phandle_cell = prop.value[pos]
610 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
611 target_node = self._fdt.phandle_to_node[phandle]
612 arg_values = []
613 for i in range(args):
614 arg_values.append(
615 str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
616 pos += 1 + args
617 vals.append('\t{%d, {%s}}' % (target_node.idx,
618 ', '.join(arg_values)))
619 for val in vals:
620 self.buf('\n\t\t%s,' % val)
621 else:
622 for val in prop.value:
623 vals.append(get_value(prop.type, val))
624
625 # Put 8 values per line to avoid very long lines.
626 for i in range(0, len(vals), 8):
627 if i:
628 self.buf(',\n\t\t')
629 self.buf(', '.join(vals[i:i + 8]))
630 self.buf('}')
631
Simon Glasse525fea2021-02-03 06:00:59 -0700632 def _declare_device(self, node):
Simon Glass221ddc12020-12-23 08:11:21 -0700633 """Add a device declaration to the output
634
Simon Glass20e442a2020-12-28 20:34:54 -0700635 This declares a U_BOOT_DRVINFO() for the device being processed
Simon Glass221ddc12020-12-23 08:11:21 -0700636
637 Args:
Simon Glasse525fea2021-02-03 06:00:59 -0700638 node: Node to process
Simon Glass221ddc12020-12-23 08:11:21 -0700639 """
Simon Glasse525fea2021-02-03 06:00:59 -0700640 self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
641 self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
Simon Glass9763e4e2021-02-03 06:01:19 -0700642 self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
Simon Glasse525fea2021-02-03 06:00:59 -0700643 self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
644 (VAL_PREFIX, node.var_name))
Simon Glass221ddc12020-12-23 08:11:21 -0700645 idx = -1
Simon Glasse525fea2021-02-03 06:00:59 -0700646 if node.parent and node.parent in self._valid_nodes:
647 idx = node.parent.idx
Simon Glass221ddc12020-12-23 08:11:21 -0700648 self.buf('\t.parent_idx\t= %d,\n' % idx)
649 self.buf('};\n')
650 self.buf('\n')
651
Simon Glass161dac12020-12-23 08:11:22 -0700652 def _output_prop(self, node, prop):
653 """Output a line containing the value of a struct member
654
655 Args:
656 node (Node): Node being output
657 prop (Prop): Prop object to output
658 """
659 if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
660 return
661 member_name = conv_name_to_c(prop.name)
662 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
663
664 # Special handling for lists
665 if isinstance(prop.value, list):
666 self._output_list(node, prop)
667 else:
668 self.buf(get_value(prop.type, prop.value))
669 self.buf(',\n')
670
Simon Glasse525fea2021-02-03 06:00:59 -0700671 def _output_values(self, node):
Simon Glass161dac12020-12-23 08:11:22 -0700672 """Output the definition of a device's struct values
673
674 Args:
Simon Glasse525fea2021-02-03 06:00:59 -0700675 node (Node): Node to output
Simon Glass161dac12020-12-23 08:11:22 -0700676 """
677 self.buf('static struct %s%s %s%s = {\n' %
Simon Glasse525fea2021-02-03 06:00:59 -0700678 (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
Simon Glass161dac12020-12-23 08:11:22 -0700679 for pname in sorted(node.props):
680 self._output_prop(node, node.props[pname])
681 self.buf('};\n')
682
Simon Glass05953522021-02-03 06:01:07 -0700683 def read_aliases(self):
684 """Read the aliases and attach the information to self._alias
685
686 Raises:
687 ValueError: The alias path is not found
688 """
689 alias_node = self._fdt.GetNode('/aliases')
690 if not alias_node:
691 return
692 re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
693 for prop in alias_node.props.values():
694 m_alias = re_num.match(prop.name)
695 if not m_alias:
696 raise ValueError("Cannot decode alias '%s'" % prop.name)
697 name, num = m_alias.groups()
698 node = self._fdt.GetNode(prop.value)
699 result = self._scan.add_uclass_alias(name, num, node)
700 if result is None:
701 raise ValueError("Alias '%s' path '%s' not found" %
702 (prop.name, prop.value))
703 elif result is False:
704 print("Could not find uclass for alias '%s'" % prop.name)
705
Simon Glass426d12f2021-02-03 06:01:14 -0700706 def generate_decl(self):
707 nodes_to_output = list(self._valid_nodes)
708
709 self.buf('#include <dm/device-internal.h>\n')
710 self.buf('#include <dm/uclass-internal.h>\n')
711 self.buf('\n')
712 self.buf(
713 '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
714 for node in nodes_to_output:
715 self.buf('DM_DRIVER_DECL(%s);\n' % node.struct_name);
716 self.buf('\n')
717
718 if self._instantiate:
719 self.buf(
720 '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
721 for node in nodes_to_output:
722 self.buf('DM_DEVICE_DECL(%s);\n' % node.var_name)
723 self.buf('\n')
724
725 uclass_list = self._valid_uclasses
726
727 self.buf(
728 '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
729 for uclass in uclass_list:
730 self.buf('DM_UCLASS_DRIVER_DECL(%s);\n' % uclass.name)
731
732 if self._instantiate:
733 self.buf('\n')
734 self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
735 for uclass in uclass_list:
736 self.buf('DM_UCLASS_DECL(%s);\n' % uclass.name)
737 self.out(''.join(self.get_buf()))
738
Simon Glass337d6972021-02-03 06:01:10 -0700739 def assign_seqs(self):
Simon Glass074197a2021-02-03 06:01:09 -0700740 """Assign a sequence number to each node"""
741 for node in self._valid_nodes_unsorted:
Simon Glass337d6972021-02-03 06:01:10 -0700742 seq = self._scan.assign_seq(node)
743 if seq is not None:
744 node.seq = seq
Simon Glass074197a2021-02-03 06:01:09 -0700745
Simon Glassfd471e22021-02-03 06:01:00 -0700746 def process_nodes(self, need_drivers):
747 nodes_to_output = list(self._valid_nodes)
748
Simon Glassb9319c42021-02-03 06:01:01 -0700749 # Figure out which drivers we actually use
750 self._scan.mark_used(nodes_to_output)
751
Simon Glassfd471e22021-02-03 06:01:00 -0700752 for node in nodes_to_output:
753 node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
754 driver = self._scan.get_driver(node.struct_name)
755 if not driver:
756 if not need_drivers:
757 continue
758 raise ValueError("Cannot parse/find driver for '%s'" %
759 node.struct_name)
760 node.driver = driver
Simon Glass337d6972021-02-03 06:01:10 -0700761 uclass = self._scan._uclass.get(driver.uclass_id)
762 if not uclass:
763 raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
764 (driver.uclass_id, node.struct_name))
765 node.uclass = uclass
766 node.uclass_seq = len(node.uclass.devs)
767 node.uclass.devs.append(node)
768 uclass.node_refs[node.uclass_seq] = \
769 '&%s->uclass_node' % node.dev_ref
770
Simon Glassfd471e22021-02-03 06:01:00 -0700771 parent_driver = None
772 if node.parent in self._valid_nodes:
773 parent_driver = self._scan.get_driver(node.parent.struct_name)
774 if not parent_driver:
775 if not need_drivers:
776 continue
777 raise ValueError(
778 "Cannot parse/find parent driver '%s' for '%s'" %
779 (node.parent.struct_name, node.struct_name))
780 node.parent_seq = len(node.parent.child_devs)
781 node.parent.child_devs.append(node)
782 node.parent.child_refs[node.parent_seq] = \
783 '&%s->sibling_node' % node.dev_ref
784 node.parent_driver = parent_driver
785
786 for node in nodes_to_output:
787 ref = '&%s->child_head' % node.dev_ref
788 node.child_refs[-1] = ref
789 node.child_refs[len(node.child_devs)] = ref
790
Simon Glass337d6972021-02-03 06:01:10 -0700791 uclass_set = set()
792 for driver in self._scan._drivers.values():
793 if driver.used and driver.uclass:
794 uclass_set.add(driver.uclass)
795 self._valid_uclasses = sorted(list(uclass_set),
796 key=lambda uc: uc.uclass_id)
797
798 for seq, uclass in enumerate(uclass_set):
799 ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
800 uclass.node_refs[-1] = ref
801 uclass.node_refs[len(uclass.devs)] = ref
802
Simon Glass4b91be22021-02-03 06:01:15 -0700803 def output_node_plat(self, node):
Simon Glass7581c012017-06-18 22:08:58 -0600804 """Output the C code for a node
805
806 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700807 node (fdt.Node): node to output
Simon Glass7581c012017-06-18 22:08:58 -0600808 """
Simon Glass4b91be22021-02-03 06:01:15 -0700809 driver = node.driver
810 parent_driver = node.parent_driver
811
812 line1 = 'Node %s index %d' % (node.path, node.idx)
813 if driver:
814 self.buf('/*\n')
815 self.buf(' * %s\n' % line1)
816 self.buf(' * driver %s parent %s\n' % (driver.name,
817 parent_driver.name if parent_driver else 'None'))
818 self.buf(' */\n')
819 else:
820 self.buf('/* %s */\n' % line1)
Simon Glass7581c012017-06-18 22:08:58 -0600821
Simon Glasse525fea2021-02-03 06:00:59 -0700822 self._output_values(node)
823 self._declare_device(node)
Simon Glass7581c012017-06-18 22:08:58 -0600824
Simon Glass2be282c2017-06-18 22:08:59 -0600825 self.out(''.join(self.get_buf()))
Simon Glass7581c012017-06-18 22:08:58 -0600826
Simon Glass4b91be22021-02-03 06:01:15 -0700827 def check_instantiate(self, require):
828 """Check if self._instantiate is set to the required value
829
830 If not, this outputs a message into the current file
831
832 Args:
833 require: True to require --instantiate, False to require that it not
834 be enabled
835 """
836 if require != self._instantiate:
837 self.out(
838 '/* This file is not used: --instantiate was %senabled */\n' %
839 ('not ' if require else ''))
840 return False
841 return True
842
Simon Glassa7d5f962020-12-28 20:35:02 -0700843 def generate_plat(self):
Simon Glass7581c012017-06-18 22:08:58 -0600844 """Generate device defintions for the platform data
845
846 This writes out C platform data initialisation data and
Simon Glass20e442a2020-12-28 20:34:54 -0700847 U_BOOT_DRVINFO() declarations for each valid node. Where a node has
Simon Glass7581c012017-06-18 22:08:58 -0600848 multiple compatible strings, a #define is used to make them equivalent.
849
Heinrich Schuchardt2799a692020-02-25 21:35:39 +0100850 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glass7581c012017-06-18 22:08:58 -0600851 information.
852 """
Simon Glass4b91be22021-02-03 06:01:15 -0700853 if not self.check_instantiate(False):
854 return
Simon Glass20e442a2020-12-28 20:34:54 -0700855 self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
Simon Glassf31fa992020-12-28 20:35:01 -0700856 self.out('#define DT_PLAT_C\n')
Simon Glasscb43ac12020-10-03 11:31:41 -0600857 self.out('\n')
Simon Glass2be282c2017-06-18 22:08:59 -0600858 self.out('#include <common.h>\n')
859 self.out('#include <dm.h>\n')
860 self.out('#include <dt-structs.h>\n')
861 self.out('\n')
Simon Glass7581c012017-06-18 22:08:58 -0600862
Simon Glass9763e4e2021-02-03 06:01:19 -0700863 if self._valid_nodes:
864 self.out('/*\n')
865 self.out(
866 " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
867 self.out(' *\n')
868 self.out(' * idx %-20s %-s\n' % ('driver_info', 'driver'))
869 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
870 for node in self._valid_nodes:
871 self.out(' * %3d: %-20s %-s\n' %
872 (node.idx, node.var_name, node.struct_name))
873 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
874 self.out(' */\n')
875 self.out('\n')
876
877 for node in self._valid_nodes:
878 self.output_node_plat(node)
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600879
Walter Lozano51f12632020-06-25 01:10:13 -0300880 self.out(''.join(self.get_buf()))
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600881
Simon Glass192c1112020-12-28 20:34:50 -0700882
Simon Glassbe44f272020-12-28 20:34:51 -0700883# Types of output file we understand
884# key: Command used to generate this file
885# value: OutputFile for this command
886OUTPUT_FILES = {
Simon Glass426d12f2021-02-03 06:01:14 -0700887 'decl':
888 OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
889 'Declares externs for all device/uclass instances'),
Simon Glassd1055d62020-12-28 20:35:00 -0700890 'struct':
891 OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
Simon Glassa7d5f962020-12-28 20:35:02 -0700892 DtbPlatdata.generate_structs,
Simon Glassd1055d62020-12-28 20:35:00 -0700893 'Defines the structs used to hold devicetree data'),
894 'platdata':
Simon Glassa7d5f962020-12-28 20:35:02 -0700895 OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
Simon Glassd1055d62020-12-28 20:35:00 -0700896 'Declares the U_BOOT_DRIVER() records and platform data'),
Simon Glassbe44f272020-12-28 20:34:51 -0700897 }
898
899
Simon Glassb00f0062021-02-03 06:01:02 -0700900def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
Simon Glass4a092352021-02-03 06:01:12 -0700901 instantiate, warning_disabled=False, drivers_additional=None,
902 basedir=None, scan=None):
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600903 """Run all the steps of the dtoc tool
904
905 Args:
Simon Glass9b330382020-11-08 20:36:21 -0700906 args (list): List of non-option arguments provided to the problem
907 dtb_file (str): Filename of dtb file to process
908 include_disabled (bool): True to include disabled nodes
Simon Glassf62cea02020-12-28 20:34:48 -0700909 output (str): Name of output file (None for stdout)
Simon Glass192c1112020-12-28 20:34:50 -0700910 output_dirs (tuple of str):
911 Directory to put C output files
912 Directory to put H output files
Simon Glassb00f0062021-02-03 06:01:02 -0700913 phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
914 or 'tpl'. None if not known
Simon Glass4a092352021-02-03 06:01:12 -0700915 instantiate: Instantiate devices so they don't need to be bound at
916 run-time
Simon Glass78128d52020-12-03 16:55:16 -0700917 warning_disabled (bool): True to avoid showing warnings about missing
918 drivers
Simon Glassccc3da72020-12-23 08:11:19 -0700919 drivers_additional (list): List of additional drivers to use during
Simon Glass78128d52020-12-03 16:55:16 -0700920 scanning
Simon Glass1e0f3f42020-12-28 20:35:03 -0700921 basedir (str): Base directory of U-Boot source code. Defaults to the
922 grandparent of this file's directory
Simon Glassa32eb7d2021-02-03 06:00:51 -0700923 scan (src_src.Scanner): Scanner from a previous run. This can help speed
924 up tests. Use None for normal operation
925
Simon Glass05953522021-02-03 06:01:07 -0700926 Returns:
927 DtbPlatdata object
928
Simon Glass9b330382020-11-08 20:36:21 -0700929 Raises:
930 ValueError: if args has no command, or an unknown command
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600931 """
932 if not args:
Simon Glassbe44f272020-12-28 20:34:51 -0700933 raise ValueError('Please specify a command: struct, platdata, all')
934 if output and output_dirs and any(output_dirs):
935 raise ValueError('Must specify either output or output_dirs, not both')
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600936
Simon Glassa32eb7d2021-02-03 06:00:51 -0700937 if not scan:
Simon Glassb00f0062021-02-03 06:01:02 -0700938 scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional,
939 phase)
Simon Glassa32eb7d2021-02-03 06:00:51 -0700940 scan.scan_drivers()
Simon Glassfd471e22021-02-03 06:01:00 -0700941 do_process = True
942 else:
943 do_process = False
Simon Glass4a092352021-02-03 06:01:12 -0700944 plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600945 plat.scan_dtb()
Simon Glass4a092352021-02-03 06:01:12 -0700946 plat.scan_tree(add_root=instantiate)
Simon Glass51d5d052021-02-03 06:00:58 -0700947 plat.prepare_nodes()
Simon Glassc20ee0e2017-08-29 14:15:50 -0600948 plat.scan_reg_sizes()
Simon Glassbe44f272020-12-28 20:34:51 -0700949 plat.setup_output_dirs(output_dirs)
Simon Glassa7d5f962020-12-28 20:35:02 -0700950 plat.scan_structs()
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600951 plat.scan_phandles()
Simon Glass4a092352021-02-03 06:01:12 -0700952 plat.process_nodes(instantiate)
Simon Glass05953522021-02-03 06:01:07 -0700953 plat.read_aliases()
Simon Glass337d6972021-02-03 06:01:10 -0700954 plat.assign_seqs()
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600955
Simon Glass10cbd3b2020-12-28 20:34:52 -0700956 cmds = args[0].split(',')
957 if 'all' in cmds:
958 cmds = sorted(OUTPUT_FILES.keys())
959 for cmd in cmds:
Simon Glassbe44f272020-12-28 20:34:51 -0700960 outfile = OUTPUT_FILES.get(cmd)
961 if not outfile:
962 raise ValueError("Unknown command '%s': (use: %s)" %
Simon Glass10cbd3b2020-12-28 20:34:52 -0700963 (cmd, ', '.join(sorted(OUTPUT_FILES.keys()))))
Simon Glassbe44f272020-12-28 20:34:51 -0700964 plat.setup_output(outfile.ftype,
965 outfile.fname if output_dirs else output)
Simon Glassd1055d62020-12-28 20:35:00 -0700966 plat.out_header(outfile)
Simon Glassa7d5f962020-12-28 20:35:02 -0700967 outfile.method(plat)
Simon Glassbe44f272020-12-28 20:34:51 -0700968 plat.finish_output()
Simon Glass05953522021-02-03 06:01:07 -0700969 return plat