blob: 1374f01c707ff39bd9015d259ce5623bb8ef5a82 [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 Glass4e430a22021-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 Glassc3a310a82020-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 Glass6b208842020-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 Glass55526782020-12-28 20:35:02 -070078 ['ftype', 'fname', 'method', 'hdr_comment'])
Simon Glassc3a310a82020-12-28 20:34:51 -070079
Simon Glassec3b5e42017-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 Glassc1622112020-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 Glassec3b5e42017-08-29 14:15:55 -060094
Simon Glass1f730c82017-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 Glassd570dec2017-06-18 22:08:58 -060097
Simon Glass1f730c82017-06-18 22:08:59 -060098 Args:
Simon Glass94ee3bd2020-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 Glass1f730c82017-06-18 22:08:59 -0600101
102 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700103 str: line with the correct number of tabs appeneded. If the line already
Simon Glass1f730c82017-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 Glass7a2add12017-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 Glass94ee3bd2020-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 Glass7a2add12017-06-18 22:09:02 -0600124 """
Simon Glassc9a032c2020-11-08 20:36:17 -0700125 if ftype == fdt.Type.INT:
Simon Glass27511232020-12-23 08:11:19 -0700126 val = '%#x' % fdt_util.fdt32_to_cpu(value)
Simon Glassc9a032c2020-11-08 20:36:17 -0700127 elif ftype == fdt.Type.BYTE:
Simon Glass93daa012020-12-03 16:55:16 -0700128 char = value[0]
Simon Glass27511232020-12-23 08:11:19 -0700129 val = '%#x' % (ord(char) if isinstance(char, str) else char)
Simon Glassc9a032c2020-11-08 20:36:17 -0700130 elif ftype == fdt.Type.STRING:
Simon Glass7f5e2262020-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 Glass27511232020-12-23 08:11:19 -0700133 val = '"%s"' % value.replace('\\', '\\\\')
Simon Glassc9a032c2020-11-08 20:36:17 -0700134 elif ftype == fdt.Type.BOOL:
Simon Glass27511232020-12-23 08:11:19 -0700135 val = 'true'
Simon Glass94ee3bd2020-11-08 20:36:21 -0700136 else: # ftype == fdt.Type.INT64:
Simon Glass27511232020-12-23 08:11:19 -0700137 val = '%#x' % value
138 return val
Simon Glass7a2add12017-06-18 22:09:02 -0600139
Simon Glass7a2add12017-06-18 22:09:02 -0600140
Simon Glass27511232020-12-23 08:11:19 -0700141class DtbPlatdata():
Simon Glassd570dec2017-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 Glass9065bc92020-12-28 20:35:06 -0700149 _scan: Scan object, for scanning and reporting on useful information
150 from the U-Boot source code
Simon Glass1f730c82017-06-18 22:08:59 -0600151 _fdt: Fdt object, referencing the device tree
Simon Glassd570dec2017-06-18 22:08:58 -0600152 _dtb_fname: Filename of the input device tree binary file
Simon Glassdf56e0b2021-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 Glasseab3f622017-06-18 22:09:01 -0600157 _include_disabled: true to include nodes marked status = "disabled"
Simon Glassd570dec2017-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 Glassc3a310a82020-12-28 20:34:51 -0700160 _dirname: Directory to hold output files, or None for none (all files
161 go to stdout)
Simon Glass55526782020-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 Glass4f2059b2020-12-28 20:35:03 -0700167 _basedir (str): Base directory of source tree
Simon Glass80d782c42021-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 Glass3809ad92021-02-03 06:01:12 -0700170 _instantiate: Instantiate devices so they don't need to be bound at
171 run-time
Simon Glassd570dec2017-06-18 22:08:58 -0600172 """
Simon Glass3809ad92021-02-03 06:01:12 -0700173 def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
Simon Glass9065bc92020-12-28 20:35:06 -0700174 self._scan = scan
Simon Glass1f730c82017-06-18 22:08:59 -0600175 self._fdt = None
Simon Glassd570dec2017-06-18 22:08:58 -0600176 self._dtb_fname = dtb_fname
177 self._valid_nodes = None
Simon Glassdf56e0b2021-02-03 06:01:09 -0700178 self._valid_nodes_unsorted = None
Simon Glasseab3f622017-06-18 22:09:01 -0600179 self._include_disabled = include_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600180 self._outfile = None
181 self._lines = []
Simon Glassc3a310a82020-12-28 20:34:51 -0700182 self._dirnames = [None] * len(Ftype)
Simon Glass55526782020-12-28 20:35:02 -0700183 self._struct_data = collections.OrderedDict()
Simon Glass4f2059b2020-12-28 20:35:03 -0700184 self._basedir = None
Simon Glass80d782c42021-02-03 06:01:10 -0700185 self._valid_uclasses = None
Simon Glass3809ad92021-02-03 06:01:12 -0700186 self._instantiate = instantiate
Walter Lozanoe675d962020-07-03 08:07:17 -0300187
Simon Glassc3a310a82020-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 Glassd570dec2017-06-18 22:08:58 -0600212 """Set up the output destination
213
Simon Glass1f730c82017-06-18 22:08:59 -0600214 Once this is done, future calls to self.out() will output to this
Simon Glassc3a310a82020-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 Glassd570dec2017-06-18 22:08:58 -0600223
224 Args:
Simon Glassc3a310a82020-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 Glassd570dec2017-06-18 22:08:58 -0600229 """
Simon Glassc3a310a82020-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 Glass6ca0c7a2020-12-28 20:34:48 -0700239 else:
240 self._outfile = sys.stdout
Simon Glassd570dec2017-06-18 22:08:58 -0600241
Simon Glassc3a310a82020-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()
Simon Glassc7b4b832021-02-03 06:01:20 -0700249 self._outfile = None
Simon Glassc3a310a82020-12-28 20:34:51 -0700250
Simon Glass1f730c82017-06-18 22:08:59 -0600251 def out(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600252 """Output a string to the output file
253
254 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700255 line (str): String to output
Simon Glassd570dec2017-06-18 22:08:58 -0600256 """
Simon Glass1f730c82017-06-18 22:08:59 -0600257 self._outfile.write(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600258
Simon Glass1f730c82017-06-18 22:08:59 -0600259 def buf(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600260 """Buffer up a string to send later
261
262 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700263 line (str): String to add to our 'buffer' list
Simon Glassd570dec2017-06-18 22:08:58 -0600264 """
Simon Glass1f730c82017-06-18 22:08:59 -0600265 self._lines.append(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600266
Simon Glass1f730c82017-06-18 22:08:59 -0600267 def get_buf(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600268 """Get the contents of the output buffer, and clear it
269
270 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700271 list(str): The output buffer, which is then cleared for future use
Simon Glassd570dec2017-06-18 22:08:58 -0600272 """
273 lines = self._lines
274 self._lines = []
275 return lines
276
Simon Glass6b208842020-12-28 20:35:00 -0700277 def out_header(self, outfile):
278 """Output a message indicating that this is an auto-generated file
279
280 Args:
281 outfile: OutputFile describing the file being generated
282 """
Simon Glass68d32c72017-08-29 14:16:01 -0600283 self.out('''/*
284 * DO NOT MODIFY
285 *
Simon Glass6b208842020-12-28 20:35:00 -0700286 * %s.
287 * This was generated by dtoc from a .dtb (device tree binary) file.
Simon Glass68d32c72017-08-29 14:16:01 -0600288 */
289
Simon Glass6b208842020-12-28 20:35:00 -0700290''' % outfile.hdr_comment)
Simon Glass68d32c72017-08-29 14:16:01 -0600291
Simon Glassec3b5e42017-08-29 14:15:55 -0600292 def get_phandle_argc(self, prop, node_name):
293 """Check if a node contains phandles
Simon Glassce5621d2017-08-29 14:15:54 -0600294
Simon Glassec3b5e42017-08-29 14:15:55 -0600295 We have no reliable way of detecting whether a node uses a phandle
296 or not. As an interim measure, use a list of known property names.
297
298 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700299 prop (fdt.Prop): Prop object to check
300 node_name (str): Node name, only used for raising an error
301 Returns:
302 int or None: Number of argument cells is this is a phandle,
303 else None
304 Raises:
305 ValueError: if the phandle cannot be parsed or the required property
306 is not present
Simon Glassec3b5e42017-08-29 14:15:55 -0600307 """
Simon Glass4e430a22021-02-03 06:01:18 -0700308 cells_prop = None
309 for name, cprop in PHANDLE_PROPS.items():
310 if prop.name.endswith(name):
311 cells_prop = cprop
312 if cells_prop:
Simon Glass609e2b12018-07-06 10:27:31 -0600313 if not isinstance(prop.value, list):
314 prop.value = [prop.value]
Simon Glassec3b5e42017-08-29 14:15:55 -0600315 val = prop.value
Simon Glassec3b5e42017-08-29 14:15:55 -0600316 i = 0
Simon Glassce5621d2017-08-29 14:15:54 -0600317
Simon Glassec3b5e42017-08-29 14:15:55 -0600318 max_args = 0
319 args = []
320 while i < len(val):
321 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass609e2b12018-07-06 10:27:31 -0600322 # If we get to the end of the list, stop. This can happen
323 # since some nodes have more phandles in the list than others,
324 # but we allocate enough space for the largest list. So those
325 # nodes with shorter lists end up with zeroes at the end.
326 if not phandle:
327 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600328 target = self._fdt.phandle_to_node.get(phandle)
329 if not target:
330 raise ValueError("Cannot parse '%s' in node '%s'" %
331 (prop.name, node_name))
Simon Glass4e430a22021-02-03 06:01:18 -0700332 cells = target.props.get(cells_prop)
Simon Glassec3b5e42017-08-29 14:15:55 -0600333 if not cells:
Walter Lozano179f0b62020-06-25 01:10:16 -0300334 raise ValueError("Node '%s' has no cells property" %
Simon Glass4e430a22021-02-03 06:01:18 -0700335 target.name)
Simon Glassec3b5e42017-08-29 14:15:55 -0600336 num_args = fdt_util.fdt32_to_cpu(cells.value)
337 max_args = max(max_args, num_args)
338 args.append(num_args)
339 i += 1 + num_args
340 return PhandleInfo(max_args, args)
341 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600342
Simon Glass1f730c82017-06-18 22:08:59 -0600343 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200344 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600345
Simon Glass1f730c82017-06-18 22:08:59 -0600346 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600347 device tree root node, and progress from there.
348 """
Simon Glass1f730c82017-06-18 22:08:59 -0600349 self._fdt = fdt.FdtScan(self._dtb_fname)
350
Simon Glassdf56e0b2021-02-03 06:01:09 -0700351 def scan_node(self, node, valid_nodes):
Simon Glass1f730c82017-06-18 22:08:59 -0600352 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600353
Simon Glassdf56e0b2021-02-03 06:01:09 -0700354 This adds each subnode to self._valid_nodes if it is enabled and has a
355 compatible string.
Simon Glass1f730c82017-06-18 22:08:59 -0600356
357 Args:
Simon Glassdf56e0b2021-02-03 06:01:09 -0700358 node (Node): Node for scan for subnodes
Simon Glass27511232020-12-23 08:11:19 -0700359 valid_nodes (list of Node): List of Node objects to add to
Simon Glass1f730c82017-06-18 22:08:59 -0600360 """
Simon Glassdf56e0b2021-02-03 06:01:09 -0700361 for subnode in node.subnodes:
362 if 'compatible' in subnode.props:
363 status = subnode.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600364 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600365 status.value != 'disabled'):
Simon Glassdf56e0b2021-02-03 06:01:09 -0700366 valid_nodes.append(subnode)
Simon Glassd570dec2017-06-18 22:08:58 -0600367
368 # recurse to handle any subnodes
Simon Glassdf56e0b2021-02-03 06:01:09 -0700369 self.scan_node(subnode, valid_nodes)
Simon Glassd570dec2017-06-18 22:08:58 -0600370
Simon Glassc14fd0c2021-02-03 06:01:11 -0700371 def scan_tree(self, add_root):
Simon Glassd570dec2017-06-18 22:08:58 -0600372 """Scan the device tree for useful information
373
374 This fills in the following properties:
Simon Glassdf56e0b2021-02-03 06:01:09 -0700375 _valid_nodes_unsorted: A list of nodes we wish to consider include
376 in the platform data (in devicetree node order)
377 _valid_nodes: Sorted version of _valid_nodes_unsorted
Simon Glassc14fd0c2021-02-03 06:01:11 -0700378
379 Args:
380 add_root: True to add the root node also (which wouldn't normally
381 be added as it may not have a compatible string)
Simon Glassd570dec2017-06-18 22:08:58 -0600382 """
Simon Glassdf56e0b2021-02-03 06:01:09 -0700383 root = self._fdt.GetRoot()
Simon Glass192f8132020-10-03 11:31:25 -0600384 valid_nodes = []
Simon Glassc14fd0c2021-02-03 06:01:11 -0700385 if add_root:
386 valid_nodes.append(root)
Simon Glassdf56e0b2021-02-03 06:01:09 -0700387 self.scan_node(root, valid_nodes)
388 self._valid_nodes_unsorted = valid_nodes
Simon Glass192f8132020-10-03 11:31:25 -0600389 self._valid_nodes = sorted(valid_nodes,
390 key=lambda x: conv_name_to_c(x.name))
Simon Glass44479782021-02-03 06:00:58 -0700391
392 def prepare_nodes(self):
393 """Add extra properties to the nodes we are using
394
395 The following properties are added for use by dtoc:
396 idx: Index number of this node (0=first, etc.)
397 struct_name: Name of the struct dtd used by this node
398 var_name: C name for this node
399 child_devs: List of child devices for this node, each a None
400 child_refs: Dict of references for each child:
401 key: Position in child list (-1=head, 0=first, 1=second, ...
402 n-1=last, n=head)
403 seq: Sequence number of the device (unique within its uclass), or
404 -1 not not known yet
405 dev_ref: Reference to this device, e.g. 'DM_DEVICE_REF(serial)'
406 driver: Driver record for this node, or None if not known
407 uclass: Uclass record for this node, or None if not known
408 uclass_seq: Position of this device within the uclass list (0=first,
409 n-1=last)
410 parent_seq: Position of this device within it siblings (0=first,
411 n-1=last)
412 parent_driver: Driver record of the node's parent, or None if none.
413 We don't use node.parent.driver since node.parent may not be in
414 the list of valid nodes
415 """
Simon Glass192f8132020-10-03 11:31:25 -0600416 for idx, node in enumerate(self._valid_nodes):
417 node.idx = idx
Simon Glass44479782021-02-03 06:00:58 -0700418 node.struct_name, _ = self._scan.get_normalized_compat_name(node)
419 node.var_name = conv_name_to_c(node.name)
420 node.child_devs = []
421 node.child_refs = {}
422 node.seq = -1
423 node.dev_ref = None
424 node.driver = None
425 node.uclass = None
426 node.uclass_seq = None
427 node.parent_seq = None
428 node.parent_driver = None
Simon Glassd570dec2017-06-18 22:08:58 -0600429
Simon Glass1b1fe412017-08-29 14:15:50 -0600430 @staticmethod
431 def get_num_cells(node):
432 """Get the number of cells in addresses and sizes for this node
433
434 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700435 node (fdt.None): Node to check
Simon Glass1b1fe412017-08-29 14:15:50 -0600436
437 Returns:
438 Tuple:
439 Number of address cells for this node
440 Number of size cells for this node
441 """
442 parent = node.parent
Simon Glass4415dc12021-03-26 16:17:27 +1300443 if parent and not parent.props:
444 raise ValueError("Parent node '%s' has no properties - do you need u-boot,dm-spl or similar?" %
445 parent.path)
Simon Glass93daa012020-12-03 16:55:16 -0700446 num_addr, num_size = 2, 2
Simon Glass1b1fe412017-08-29 14:15:50 -0600447 if parent:
Simon Glass93daa012020-12-03 16:55:16 -0700448 addr_prop = parent.props.get('#address-cells')
449 size_prop = parent.props.get('#size-cells')
450 if addr_prop:
451 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
452 if size_prop:
453 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
454 return num_addr, num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600455
456 def scan_reg_sizes(self):
457 """Scan for 64-bit 'reg' properties and update the values
458
459 This finds 'reg' properties with 64-bit data and converts the value to
460 an array of 64-values. This allows it to be output in a way that the
461 C code can read.
462 """
463 for node in self._valid_nodes:
464 reg = node.props.get('reg')
465 if not reg:
466 continue
Simon Glass93daa012020-12-03 16:55:16 -0700467 num_addr, num_size = self.get_num_cells(node)
468 total = num_addr + num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600469
Simon Glassc9a032c2020-11-08 20:36:17 -0700470 if reg.type != fdt.Type.INT:
Simon Glassc38fee042018-07-06 10:27:32 -0600471 raise ValueError("Node '%s' reg property is not an int" %
472 node.name)
Simon Glass94ba59e2021-03-26 16:17:26 +1300473 if not isinstance(reg.value, list):
474 reg.value = [reg.value]
Simon Glass1b1fe412017-08-29 14:15:50 -0600475 if len(reg.value) % total:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700476 raise ValueError(
Simon Glass4415dc12021-03-26 16:17:27 +1300477 "Node '%s' (parent '%s') reg property has %d cells "
Simon Glass94ee3bd2020-11-08 20:36:21 -0700478 'which is not a multiple of na + ns = %d + %d)' %
Simon Glass4415dc12021-03-26 16:17:27 +1300479 (node.name, node.parent.name, len(reg.value), num_addr,
480 num_size))
Simon Glass93daa012020-12-03 16:55:16 -0700481 reg.num_addr = num_addr
482 reg.num_size = num_size
Simon Glass94ba59e2021-03-26 16:17:26 +1300483 if num_addr > 1 or num_size > 1:
Simon Glassc9a032c2020-11-08 20:36:17 -0700484 reg.type = fdt.Type.INT64
Simon Glass1b1fe412017-08-29 14:15:50 -0600485 i = 0
486 new_value = []
487 val = reg.value
Simon Glass1b1fe412017-08-29 14:15:50 -0600488 while i < len(val):
Simon Glass93daa012020-12-03 16:55:16 -0700489 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
490 i += num_addr
491 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
492 i += num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600493 new_value += [addr, size]
494 reg.value = new_value
495
Simon Glass1f730c82017-06-18 22:08:59 -0600496 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600497 """Scan the device tree building up the C structures we will use.
498
499 Build a dict keyed by C struct name containing a dict of Prop
500 object for each struct field (keyed by property name). Where the
501 same struct appears multiple times, try to use the 'widest'
502 property, i.e. the one with a type which can express all others.
503
504 Once the widest property is determined, all other properties are
505 updated to match that width.
Simon Glass941f8f02020-10-03 11:31:24 -0600506
Simon Glass55526782020-12-28 20:35:02 -0700507 The results are written to self._struct_data
Simon Glassd570dec2017-06-18 22:08:58 -0600508 """
Simon Glass55526782020-12-28 20:35:02 -0700509 structs = self._struct_data
Simon Glassd570dec2017-06-18 22:08:58 -0600510 for node in self._valid_nodes:
Simon Glassd570dec2017-06-18 22:08:58 -0600511 fields = {}
512
513 # Get a list of all the valid properties in this node.
514 for name, prop in node.props.items():
515 if name not in PROP_IGNORE_LIST and name[0] != '#':
516 fields[name] = copy.deepcopy(prop)
517
Simon Glass62a95372021-02-03 06:00:59 -0700518 # If we've seen this struct_name before, update the existing struct
519 if node.struct_name in structs:
520 struct = structs[node.struct_name]
Simon Glassd570dec2017-06-18 22:08:58 -0600521 for name, prop in fields.items():
522 oldprop = struct.get(name)
523 if oldprop:
524 oldprop.Widen(prop)
525 else:
526 struct[name] = prop
527
528 # Otherwise store this as a new struct.
529 else:
Simon Glass62a95372021-02-03 06:00:59 -0700530 structs[node.struct_name] = fields
Simon Glassd570dec2017-06-18 22:08:58 -0600531
Simon Glassd570dec2017-06-18 22:08:58 -0600532 for node in self._valid_nodes:
Simon Glass62a95372021-02-03 06:00:59 -0700533 struct = structs[node.struct_name]
Simon Glassd570dec2017-06-18 22:08:58 -0600534 for name, prop in node.props.items():
535 if name not in PROP_IGNORE_LIST and name[0] != '#':
536 prop.Widen(struct[name])
Simon Glassd570dec2017-06-18 22:08:58 -0600537
Simon Glass1f730c82017-06-18 22:08:59 -0600538 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600539 """Figure out what phandles each node uses
540
541 We need to be careful when outputing nodes that use phandles since
542 they must come after the declaration of the phandles in the C file.
543 Otherwise we get a compiler error since the phandle struct is not yet
544 declared.
545
546 This function adds to each node a list of phandle nodes that the node
547 depends on. This allows us to output things in the right order.
548 """
549 for node in self._valid_nodes:
550 node.phandles = set()
551 for pname, prop in node.props.items():
552 if pname in PROP_IGNORE_LIST or pname[0] == '#':
553 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600554 info = self.get_phandle_argc(prop, node.name)
555 if info:
Simon Glassec3b5e42017-08-29 14:15:55 -0600556 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600557 pos = 0
558 for args in info.args:
559 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600560 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
561 target_node = self._fdt.phandle_to_node[phandle]
562 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600563 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600564
565
Simon Glass55526782020-12-28 20:35:02 -0700566 def generate_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600567 """Generate struct defintions for the platform data
568
569 This writes out the body of a header file consisting of structure
570 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100571 doc/driver-model/of-plat.rst for more information.
Simon Glassd570dec2017-06-18 22:08:58 -0600572 """
Simon Glass55526782020-12-28 20:35:02 -0700573 structs = self._struct_data
Simon Glass1f730c82017-06-18 22:08:59 -0600574 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900575 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600576
577 # Output the struct definition
578 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600579 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600580 for pname in sorted(structs[name]):
581 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600582 info = self.get_phandle_argc(prop, structs[name])
583 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600584 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600585 struct_name = 'struct phandle_%d_arg' % info.max_args
586 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600587 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600588 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600589 else:
590 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600591 self.out('\t%s%s' % (tab_to(2, ptype),
592 conv_name_to_c(prop.name)))
593 if isinstance(prop.value, list):
594 self.out('[%d]' % len(prop.value))
595 self.out(';\n')
596 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600597
Simon Glass9d98b6e2020-12-23 08:11:20 -0700598 def _output_list(self, node, prop):
599 """Output the C code for a devicetree property that holds a list
Simon Glassd570dec2017-06-18 22:08:58 -0600600
601 Args:
Simon Glass9d98b6e2020-12-23 08:11:20 -0700602 node (fdt.Node): Node to output
603 prop (fdt.Prop): Prop to output
Simon Glassd570dec2017-06-18 22:08:58 -0600604 """
Simon Glass9d98b6e2020-12-23 08:11:20 -0700605 self.buf('{')
606 vals = []
607 # For phandles, output a reference to the platform data
608 # of the target node.
609 info = self.get_phandle_argc(prop, node.name)
610 if info:
611 # Process the list as pairs of (phandle, id)
612 pos = 0
613 for args in info.args:
614 phandle_cell = prop.value[pos]
615 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
616 target_node = self._fdt.phandle_to_node[phandle]
617 arg_values = []
618 for i in range(args):
619 arg_values.append(
620 str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
621 pos += 1 + args
622 vals.append('\t{%d, {%s}}' % (target_node.idx,
623 ', '.join(arg_values)))
624 for val in vals:
625 self.buf('\n\t\t%s,' % val)
626 else:
627 for val in prop.value:
628 vals.append(get_value(prop.type, val))
Simon Glassbc9e2682020-10-03 09:25:18 -0600629
Simon Glass9d98b6e2020-12-23 08:11:20 -0700630 # Put 8 values per line to avoid very long lines.
631 for i in range(0, len(vals), 8):
632 if i:
633 self.buf(',\n\t\t')
634 self.buf(', '.join(vals[i:i + 8]))
635 self.buf('}')
Simon Glassbc9e2682020-10-03 09:25:18 -0600636
Simon Glass62a95372021-02-03 06:00:59 -0700637 def _declare_device(self, node):
Simon Glass9fdd0c32020-12-23 08:11:21 -0700638 """Add a device declaration to the output
639
Simon Glass1d8364a2020-12-28 20:34:54 -0700640 This declares a U_BOOT_DRVINFO() for the device being processed
Simon Glass9fdd0c32020-12-23 08:11:21 -0700641
642 Args:
Simon Glass62a95372021-02-03 06:00:59 -0700643 node: Node to process
Simon Glass9fdd0c32020-12-23 08:11:21 -0700644 """
Simon Glass62a95372021-02-03 06:00:59 -0700645 self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
646 self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
Simon Glasse2119082021-02-03 06:01:19 -0700647 self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
Simon Glass62a95372021-02-03 06:00:59 -0700648 self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
649 (VAL_PREFIX, node.var_name))
Simon Glass9fdd0c32020-12-23 08:11:21 -0700650 idx = -1
Simon Glass62a95372021-02-03 06:00:59 -0700651 if node.parent and node.parent in self._valid_nodes:
652 idx = node.parent.idx
Simon Glass9fdd0c32020-12-23 08:11:21 -0700653 self.buf('\t.parent_idx\t= %d,\n' % idx)
654 self.buf('};\n')
655 self.buf('\n')
656
Simon Glassc7b4b832021-02-03 06:01:20 -0700657 def prep_priv(self, struc, name, suffix, section='.priv_data'):
658 if not struc:
659 return None
660 var_name = '_%s%s' % (name, suffix)
661 hdr = self._scan._structs.get(struc)
662 if hdr:
663 self.buf('#include <%s>\n' % hdr.fname)
664 else:
665 print('Warning: Cannot find header file for struct %s' % struc)
666 attr = '__attribute__ ((section ("%s")))' % section
667 return var_name, struc, attr
668
669 def alloc_priv(self, info, name, extra, suffix='_priv'):
670 result = self.prep_priv(info, name, suffix)
671 if not result:
672 return None
673 var_name, struc, section = result
674 self.buf('u8 %s_%s[sizeof(struct %s)]\n\t%s;\n' %
675 (var_name, extra, struc.strip(), section))
676 return '%s_%s' % (var_name, extra)
677
Simon Glassfea2f252021-02-03 06:01:21 -0700678 def alloc_plat(self, info, name, extra, node):
679 result = self.prep_priv(info, name, '_plat')
680 if not result:
681 return None
682 var_name, struc, section = result
683 self.buf('struct %s %s\n\t%s_%s = {\n' %
684 (struc.strip(), section, var_name, extra))
685 self.buf('\t.dtplat = {\n')
686 for pname in sorted(node.props):
687 self._output_prop(node, node.props[pname], 2)
688 self.buf('\t},\n')
689 self.buf('};\n')
690 return '&%s_%s' % (var_name, extra)
691
692 def _declare_device_inst(self, node, parent_driver):
693 """Add a device instance declaration to the output
694
695 This declares a DM_DEVICE_INST() for the device being processed
696
697 Args:
698 node: Node to output
699 """
700 driver = node.driver
701 uclass = node.uclass
702 self.buf('\n')
703 num_lines = len(self._lines)
704 plat_name = self.alloc_plat(driver.plat, driver.name, node.var_name,
705 node)
706 priv_name = self.alloc_priv(driver.priv, driver.name, node.var_name)
707 parent_plat_name = None
708 parent_priv_name = None
709 if parent_driver:
710 # TODO: deal with uclass providing these values
711 parent_plat_name = self.alloc_priv(
712 parent_driver.child_plat, driver.name, node.var_name,
713 '_parent_plat')
714 parent_priv_name = self.alloc_priv(
715 parent_driver.child_priv, driver.name, node.var_name,
716 '_parent_priv')
717 uclass_plat_name = self.alloc_priv(
718 uclass.per_dev_plat, driver.name + '_uc', node.var_name, 'plat')
719 uclass_priv_name = self.alloc_priv(uclass.per_dev_priv,
720 driver.name + '_uc', node.var_name)
721 for hdr in driver.headers:
722 self.buf('#include %s\n' % hdr)
723
724 # Add a blank line if we emitted any stuff above, for readability
725 if num_lines != len(self._lines):
726 self.buf('\n')
727
728 self.buf('DM_DEVICE_INST(%s) = {\n' % node.var_name)
729 self.buf('\t.driver\t\t= DM_DRIVER_REF(%s),\n' % node.struct_name)
730 self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
731 if plat_name:
732 self.buf('\t.plat_\t\t= %s,\n' % plat_name)
733 else:
734 self.buf('\t.plat_\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
735 if parent_plat_name:
736 self.buf('\t.parent_plat_\t= %s,\n' % parent_plat_name)
737 if uclass_plat_name:
738 self.buf('\t.uclass_plat_\t= %s,\n' % uclass_plat_name)
739 driver_date = None
740
741 if node != self._fdt.GetRoot():
742 compat_list = node.props['compatible'].value
743 if not isinstance(compat_list, list):
744 compat_list = [compat_list]
745 for compat in compat_list:
746 driver_data = driver.compat.get(compat)
747 if driver_data:
748 self.buf('\t.driver_data\t= %s,\n' % driver_data)
749 break
750
751 if node.parent and node.parent.parent:
752 self.buf('\t.parent\t\t= DM_DEVICE_REF(%s),\n' %
753 node.parent.var_name)
754 if priv_name:
755 self.buf('\t.priv_\t\t= %s,\n' % priv_name)
756 self.buf('\t.uclass\t\t= DM_UCLASS_REF(%s),\n' % uclass.name)
757
758 if uclass_priv_name:
759 self.buf('\t.uclass_priv_ = %s,\n' % uclass_priv_name)
760 if parent_priv_name:
761 self.buf('\t.parent_priv_\t= %s,\n' % parent_priv_name)
762 self.list_node('uclass_node', uclass.node_refs, node.uclass_seq)
763 self.list_head('child_head', 'sibling_node', node.child_devs, node.var_name)
764 if node.parent in self._valid_nodes:
765 self.list_node('sibling_node', node.parent.child_refs,
766 node.parent_seq)
767 # flags is left as 0
768
769 self.buf('\t.seq_ = %d,\n' % node.seq)
770
771 self.buf('};\n')
772 self.buf('\n')
773 return parent_plat_name
774
775 def _output_prop(self, node, prop, tabs=1):
Simon Glass9829eea2020-12-23 08:11:22 -0700776 """Output a line containing the value of a struct member
777
778 Args:
779 node (Node): Node being output
780 prop (Prop): Prop object to output
781 """
782 if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
783 return
784 member_name = conv_name_to_c(prop.name)
Simon Glassfea2f252021-02-03 06:01:21 -0700785 self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
Simon Glass9829eea2020-12-23 08:11:22 -0700786
787 # Special handling for lists
788 if isinstance(prop.value, list):
789 self._output_list(node, prop)
790 else:
791 self.buf(get_value(prop.type, prop.value))
792 self.buf(',\n')
793
Simon Glass62a95372021-02-03 06:00:59 -0700794 def _output_values(self, node):
Simon Glass9829eea2020-12-23 08:11:22 -0700795 """Output the definition of a device's struct values
796
797 Args:
Simon Glass62a95372021-02-03 06:00:59 -0700798 node (Node): Node to output
Simon Glass9829eea2020-12-23 08:11:22 -0700799 """
800 self.buf('static struct %s%s %s%s = {\n' %
Simon Glass62a95372021-02-03 06:00:59 -0700801 (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
Simon Glass9829eea2020-12-23 08:11:22 -0700802 for pname in sorted(node.props):
803 self._output_prop(node, node.props[pname])
804 self.buf('};\n')
Simon Glassc7b4b832021-02-03 06:01:20 -0700805
806 def list_head(self, head_member, node_member, node_refs, var_name):
807 self.buf('\t.%s\t= {\n' % head_member)
808 if node_refs:
809 last = node_refs[-1].dev_ref
810 first = node_refs[0].dev_ref
811 member = node_member
812 else:
813 last = 'DM_DEVICE_REF(%s)' % var_name
814 first = last
815 member = head_member
816 self.buf('\t\t.prev = &%s->%s,\n' % (last, member))
817 self.buf('\t\t.next = &%s->%s,\n' % (first, member))
818 self.buf('\t},\n')
819
820 def list_node(self, member, node_refs, seq):
821 self.buf('\t.%s\t= {\n' % member)
822 self.buf('\t\t.prev = %s,\n' % node_refs[seq - 1])
823 self.buf('\t\t.next = %s,\n' % node_refs[seq + 1])
824 self.buf('\t},\n')
825
826 def generate_uclasses(self):
827 if not self.check_instantiate(True):
828 return
829 self.out('\n')
830 self.out('#include <common.h>\n')
831 self.out('#include <dm.h>\n')
832 self.out('#include <dt-structs.h>\n')
833 self.out('\n')
834 self.buf('/*\n')
Simon Glassfea2f252021-02-03 06:01:21 -0700835 self.buf(
836 " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
Simon Glassc7b4b832021-02-03 06:01:20 -0700837 uclass_list = self._valid_uclasses
Simon Glassfea2f252021-02-03 06:01:21 -0700838 for seq, uclass in enumerate(uclass_list):
839 self.buf(' * %3d: %s\n' % (seq, uclass.name))
840 self.buf(' *\n')
841 self.buf(' * Sequence numbers allocated in each uclass:\n')
Simon Glassc7b4b832021-02-03 06:01:20 -0700842 for uclass in uclass_list:
843 if uclass.alias_num_to_node:
844 self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
845 for seq, node in uclass.alias_num_to_node.items():
846 self.buf(' * %d: %s\n' % (seq, node.path))
847 self.buf(' */\n')
848
849 uclass_node = {}
850 for seq, uclass in enumerate(uclass_list):
851 uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
852 uclass.name)
853 uclass_node[-1] = '&uclass_head'
854 uclass_node[len(uclass_list)] = '&uclass_head'
855 self.buf('\n')
856 self.buf('struct list_head %s = {\n' % 'uclass_head')
857 self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
858 self.buf('\t.next = %s,\n' % uclass_node[0])
859 self.buf('};\n')
860 self.buf('\n')
861
862 for seq, uclass in enumerate(uclass_list):
863 uc_drv = self._scan._uclass.get(uclass.uclass_id)
864
865 priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
866
867 self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
868 if priv_name:
869 self.buf('\t.priv_\t\t= %s,\n' % priv_name)
870 self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
871 self.list_node('sibling_node', uclass_node, seq)
872 self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
873 self.buf('};\n')
874 self.buf('\n')
875 self.out(''.join(self.get_buf()))
Simon Glass9829eea2020-12-23 08:11:22 -0700876
Simon Glassbe88d2f2021-02-03 06:01:07 -0700877 def read_aliases(self):
878 """Read the aliases and attach the information to self._alias
879
880 Raises:
881 ValueError: The alias path is not found
882 """
883 alias_node = self._fdt.GetNode('/aliases')
884 if not alias_node:
885 return
886 re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
887 for prop in alias_node.props.values():
888 m_alias = re_num.match(prop.name)
889 if not m_alias:
890 raise ValueError("Cannot decode alias '%s'" % prop.name)
891 name, num = m_alias.groups()
892 node = self._fdt.GetNode(prop.value)
893 result = self._scan.add_uclass_alias(name, num, node)
894 if result is None:
895 raise ValueError("Alias '%s' path '%s' not found" %
896 (prop.name, prop.value))
897 elif result is False:
898 print("Could not find uclass for alias '%s'" % prop.name)
899
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700900 def generate_decl(self):
901 nodes_to_output = list(self._valid_nodes)
902
903 self.buf('#include <dm/device-internal.h>\n')
904 self.buf('#include <dm/uclass-internal.h>\n')
905 self.buf('\n')
906 self.buf(
907 '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
908 for node in nodes_to_output:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300909 self.buf('extern U_BOOT_DRIVER(%s);\n' % node.struct_name);
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700910 self.buf('\n')
911
912 if self._instantiate:
913 self.buf(
914 '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
915 for node in nodes_to_output:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300916 self.buf('extern DM_DEVICE_INST(%s);\n' % node.var_name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700917 self.buf('\n')
918
919 uclass_list = self._valid_uclasses
920
921 self.buf(
922 '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
923 for uclass in uclass_list:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300924 self.buf('extern UCLASS_DRIVER(%s);\n' % uclass.name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700925
926 if self._instantiate:
927 self.buf('\n')
928 self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
929 for uclass in uclass_list:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300930 self.buf('extern DM_UCLASS_INST(%s);\n' % uclass.name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700931 self.out(''.join(self.get_buf()))
932
Simon Glass80d782c42021-02-03 06:01:10 -0700933 def assign_seqs(self):
Simon Glassdf56e0b2021-02-03 06:01:09 -0700934 """Assign a sequence number to each node"""
935 for node in self._valid_nodes_unsorted:
Simon Glass80d782c42021-02-03 06:01:10 -0700936 seq = self._scan.assign_seq(node)
937 if seq is not None:
938 node.seq = seq
Simon Glassdf56e0b2021-02-03 06:01:09 -0700939
Simon Glass047a4802021-02-03 06:01:00 -0700940 def process_nodes(self, need_drivers):
941 nodes_to_output = list(self._valid_nodes)
942
Simon Glasseb3c2492021-02-03 06:01:01 -0700943 # Figure out which drivers we actually use
944 self._scan.mark_used(nodes_to_output)
945
Simon Glass047a4802021-02-03 06:01:00 -0700946 for node in nodes_to_output:
947 node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
948 driver = self._scan.get_driver(node.struct_name)
949 if not driver:
950 if not need_drivers:
951 continue
952 raise ValueError("Cannot parse/find driver for '%s'" %
953 node.struct_name)
954 node.driver = driver
Simon Glass80d782c42021-02-03 06:01:10 -0700955 uclass = self._scan._uclass.get(driver.uclass_id)
956 if not uclass:
957 raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
958 (driver.uclass_id, node.struct_name))
959 node.uclass = uclass
960 node.uclass_seq = len(node.uclass.devs)
961 node.uclass.devs.append(node)
962 uclass.node_refs[node.uclass_seq] = \
963 '&%s->uclass_node' % node.dev_ref
964
Simon Glass047a4802021-02-03 06:01:00 -0700965 parent_driver = None
966 if node.parent in self._valid_nodes:
967 parent_driver = self._scan.get_driver(node.parent.struct_name)
968 if not parent_driver:
969 if not need_drivers:
970 continue
971 raise ValueError(
972 "Cannot parse/find parent driver '%s' for '%s'" %
973 (node.parent.struct_name, node.struct_name))
974 node.parent_seq = len(node.parent.child_devs)
975 node.parent.child_devs.append(node)
976 node.parent.child_refs[node.parent_seq] = \
977 '&%s->sibling_node' % node.dev_ref
978 node.parent_driver = parent_driver
979
980 for node in nodes_to_output:
981 ref = '&%s->child_head' % node.dev_ref
982 node.child_refs[-1] = ref
983 node.child_refs[len(node.child_devs)] = ref
984
Simon Glass80d782c42021-02-03 06:01:10 -0700985 uclass_set = set()
986 for driver in self._scan._drivers.values():
987 if driver.used and driver.uclass:
988 uclass_set.add(driver.uclass)
989 self._valid_uclasses = sorted(list(uclass_set),
990 key=lambda uc: uc.uclass_id)
991
992 for seq, uclass in enumerate(uclass_set):
993 ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
994 uclass.node_refs[-1] = ref
995 uclass.node_refs[len(uclass.devs)] = ref
996
Simon Glassbe749002021-02-03 06:01:15 -0700997 def output_node_plat(self, node):
Simon Glass9d98b6e2020-12-23 08:11:20 -0700998 """Output the C code for a node
Simon Glassbc9e2682020-10-03 09:25:18 -0600999
Simon Glass9d98b6e2020-12-23 08:11:20 -07001000 Args:
1001 node (fdt.Node): node to output
1002 """
Simon Glassbe749002021-02-03 06:01:15 -07001003 driver = node.driver
1004 parent_driver = node.parent_driver
1005
1006 line1 = 'Node %s index %d' % (node.path, node.idx)
1007 if driver:
1008 self.buf('/*\n')
1009 self.buf(' * %s\n' % line1)
1010 self.buf(' * driver %s parent %s\n' % (driver.name,
1011 parent_driver.name if parent_driver else 'None'))
1012 self.buf(' */\n')
1013 else:
1014 self.buf('/* %s */\n' % line1)
Simon Glassd570dec2017-06-18 22:08:58 -06001015
Simon Glass62a95372021-02-03 06:00:59 -07001016 self._output_values(node)
1017 self._declare_device(node)
Simon Glassd570dec2017-06-18 22:08:58 -06001018
Simon Glass1f730c82017-06-18 22:08:59 -06001019 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -06001020
Simon Glassfea2f252021-02-03 06:01:21 -07001021 def output_node_instance(self, node):
1022 """Output the C code for a node
1023
1024 Args:
1025 node (fdt.Node): node to output
1026 """
1027 parent_driver = node.parent_driver
1028
1029 self.buf('/*\n')
1030 self.buf(' * Node %s index %d\n' % (node.path, node.idx))
1031 self.buf(' * driver %s parent %s\n' % (node.driver.name,
1032 parent_driver.name if parent_driver else 'None'))
1033 self.buf('*/\n')
1034
1035 if not node.driver.plat:
1036 self._output_values(node)
1037 self._declare_device_inst(node, parent_driver)
1038
1039 self.out(''.join(self.get_buf()))
1040
Simon Glassbe749002021-02-03 06:01:15 -07001041 def check_instantiate(self, require):
1042 """Check if self._instantiate is set to the required value
1043
1044 If not, this outputs a message into the current file
1045
1046 Args:
1047 require: True to require --instantiate, False to require that it not
1048 be enabled
1049 """
1050 if require != self._instantiate:
1051 self.out(
1052 '/* This file is not used: --instantiate was %senabled */\n' %
1053 ('not ' if require else ''))
1054 return False
1055 return True
1056
Simon Glass55526782020-12-28 20:35:02 -07001057 def generate_plat(self):
Simon Glassd570dec2017-06-18 22:08:58 -06001058 """Generate device defintions for the platform data
1059
1060 This writes out C platform data initialisation data and
Simon Glass1d8364a2020-12-28 20:34:54 -07001061 U_BOOT_DRVINFO() declarations for each valid node. Where a node has
Simon Glassd570dec2017-06-18 22:08:58 -06001062 multiple compatible strings, a #define is used to make them equivalent.
1063
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +01001064 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glassd570dec2017-06-18 22:08:58 -06001065 information.
1066 """
Simon Glassbe749002021-02-03 06:01:15 -07001067 if not self.check_instantiate(False):
1068 return
Simon Glass1d8364a2020-12-28 20:34:54 -07001069 self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
Simon Glassbeddd7a2020-12-28 20:35:01 -07001070 self.out('#define DT_PLAT_C\n')
Simon Glass4c73d7b2020-10-03 11:31:41 -06001071 self.out('\n')
Simon Glass1f730c82017-06-18 22:08:59 -06001072 self.out('#include <common.h>\n')
1073 self.out('#include <dm.h>\n')
1074 self.out('#include <dt-structs.h>\n')
1075 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -06001076
Simon Glasse2119082021-02-03 06:01:19 -07001077 if self._valid_nodes:
1078 self.out('/*\n')
1079 self.out(
1080 " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
1081 self.out(' *\n')
1082 self.out(' * idx %-20s %-s\n' % ('driver_info', 'driver'))
1083 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1084 for node in self._valid_nodes:
1085 self.out(' * %3d: %-20s %-s\n' %
1086 (node.idx, node.var_name, node.struct_name))
1087 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1088 self.out(' */\n')
1089 self.out('\n')
1090
1091 for node in self._valid_nodes:
1092 self.output_node_plat(node)
Simon Glass3fa797a2017-06-18 22:09:03 -06001093
Walter Lozanodc5b4372020-06-25 01:10:13 -03001094 self.out(''.join(self.get_buf()))
Simon Glass3fa797a2017-06-18 22:09:03 -06001095
Simon Glassfea2f252021-02-03 06:01:21 -07001096 def generate_device(self):
1097 """Generate device instances
1098
1099 This writes out DM_DEVICE_INST() records for each device in the
1100 build.
1101
1102 See the documentation in doc/driver-model/of-plat.rst for more
1103 information.
1104 """
1105 if not self.check_instantiate(True):
1106 return
1107 self.out('#include <common.h>\n')
1108 self.out('#include <dm.h>\n')
1109 self.out('#include <dt-structs.h>\n')
1110 self.out('\n')
1111
1112 if self._valid_nodes:
1113 self.out('/*\n')
1114 self.out(
1115 " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
1116 self.out(' *\n')
1117 self.out(' * idx %-20s %-s\n' % ('udevice', 'driver'))
1118 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1119 for node in self._valid_nodes:
1120 self.out(' * %3d: %-20s %-s\n' %
1121 (node.idx, node.var_name, node.struct_name))
1122 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1123 self.out(' */\n')
1124 self.out('\n')
1125
1126 for node in self._valid_nodes:
1127 self.output_node_instance(node)
1128
1129 self.out(''.join(self.get_buf()))
1130
Simon Glassc3a310a82020-12-28 20:34:51 -07001131
1132# Types of output file we understand
1133# key: Command used to generate this file
1134# value: OutputFile for this command
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001135OUTPUT_FILES_COMMON = {
Simon Glass3fa3bbb2021-02-03 06:01:14 -07001136 'decl':
1137 OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
1138 'Declares externs for all device/uclass instances'),
Simon Glass6b208842020-12-28 20:35:00 -07001139 'struct':
1140 OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
Simon Glass55526782020-12-28 20:35:02 -07001141 DtbPlatdata.generate_structs,
Simon Glass6b208842020-12-28 20:35:00 -07001142 'Defines the structs used to hold devicetree data'),
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001143 }
1144
1145# File generated without instantiate
1146OUTPUT_FILES_NOINST = {
Simon Glass6b208842020-12-28 20:35:00 -07001147 'platdata':
Simon Glass55526782020-12-28 20:35:02 -07001148 OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
Simon Glass6b208842020-12-28 20:35:00 -07001149 'Declares the U_BOOT_DRIVER() records and platform data'),
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001150 }
1151
1152# File generated with instantiate
1153OUTPUT_FILES_INST = {
Simon Glassfea2f252021-02-03 06:01:21 -07001154 'device':
1155 OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
1156 'Declares the DM_DEVICE_INST() records'),
Simon Glassc7b4b832021-02-03 06:01:20 -07001157 'uclass':
1158 OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
1159 'Declares the uclass instances (struct uclass)'),
Simon Glassc3a310a82020-12-28 20:34:51 -07001160 }
1161
Simon Glass6a65d8a2020-12-28 20:34:50 -07001162
Simon Glassf303ee72021-02-03 06:01:02 -07001163def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
Simon Glass3809ad92021-02-03 06:01:12 -07001164 instantiate, warning_disabled=False, drivers_additional=None,
1165 basedir=None, scan=None):
Simon Glass3fa797a2017-06-18 22:09:03 -06001166 """Run all the steps of the dtoc tool
1167
1168 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -07001169 args (list): List of non-option arguments provided to the problem
1170 dtb_file (str): Filename of dtb file to process
1171 include_disabled (bool): True to include disabled nodes
Simon Glass6ca0c7a2020-12-28 20:34:48 -07001172 output (str): Name of output file (None for stdout)
Simon Glass6a65d8a2020-12-28 20:34:50 -07001173 output_dirs (tuple of str):
1174 Directory to put C output files
1175 Directory to put H output files
Simon Glassf303ee72021-02-03 06:01:02 -07001176 phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
1177 or 'tpl'. None if not known
Simon Glass3809ad92021-02-03 06:01:12 -07001178 instantiate: Instantiate devices so they don't need to be bound at
1179 run-time
Simon Glass93daa012020-12-03 16:55:16 -07001180 warning_disabled (bool): True to avoid showing warnings about missing
1181 drivers
Simon Glass27511232020-12-23 08:11:19 -07001182 drivers_additional (list): List of additional drivers to use during
Simon Glass93daa012020-12-03 16:55:16 -07001183 scanning
Simon Glass4f2059b2020-12-28 20:35:03 -07001184 basedir (str): Base directory of U-Boot source code. Defaults to the
1185 grandparent of this file's directory
Simon Glass768ff0a2021-02-03 06:00:51 -07001186 scan (src_src.Scanner): Scanner from a previous run. This can help speed
1187 up tests. Use None for normal operation
1188
Simon Glassbe88d2f2021-02-03 06:01:07 -07001189 Returns:
1190 DtbPlatdata object
1191
Simon Glass94ee3bd2020-11-08 20:36:21 -07001192 Raises:
1193 ValueError: if args has no command, or an unknown command
Simon Glass3fa797a2017-06-18 22:09:03 -06001194 """
1195 if not args:
Simon Glassc3a310a82020-12-28 20:34:51 -07001196 raise ValueError('Please specify a command: struct, platdata, all')
1197 if output and output_dirs and any(output_dirs):
1198 raise ValueError('Must specify either output or output_dirs, not both')
Simon Glass3fa797a2017-06-18 22:09:03 -06001199
Simon Glass768ff0a2021-02-03 06:00:51 -07001200 if not scan:
Simon Glass695077d2021-03-26 16:17:25 +13001201 scan = src_scan.Scanner(basedir, drivers_additional, phase)
Simon Glass768ff0a2021-02-03 06:00:51 -07001202 scan.scan_drivers()
Simon Glass047a4802021-02-03 06:01:00 -07001203 do_process = True
1204 else:
1205 do_process = False
Simon Glass3809ad92021-02-03 06:01:12 -07001206 plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
Simon Glass3fa797a2017-06-18 22:09:03 -06001207 plat.scan_dtb()
Simon Glass3809ad92021-02-03 06:01:12 -07001208 plat.scan_tree(add_root=instantiate)
Simon Glass44479782021-02-03 06:00:58 -07001209 plat.prepare_nodes()
Simon Glass1b1fe412017-08-29 14:15:50 -06001210 plat.scan_reg_sizes()
Simon Glassc3a310a82020-12-28 20:34:51 -07001211 plat.setup_output_dirs(output_dirs)
Simon Glass55526782020-12-28 20:35:02 -07001212 plat.scan_structs()
Simon Glass3fa797a2017-06-18 22:09:03 -06001213 plat.scan_phandles()
Simon Glass3809ad92021-02-03 06:01:12 -07001214 plat.process_nodes(instantiate)
Simon Glassbe88d2f2021-02-03 06:01:07 -07001215 plat.read_aliases()
Simon Glass80d782c42021-02-03 06:01:10 -07001216 plat.assign_seqs()
Simon Glass3fa797a2017-06-18 22:09:03 -06001217
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001218 # Figure out what output files we plan to generate
1219 output_files = OUTPUT_FILES_COMMON
1220 if instantiate:
1221 output_files.update(OUTPUT_FILES_INST)
1222 else:
1223 output_files.update(OUTPUT_FILES_NOINST)
1224
Simon Glass4e8e8462020-12-28 20:34:52 -07001225 cmds = args[0].split(',')
1226 if 'all' in cmds:
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001227 cmds = sorted(output_files.keys())
Simon Glass4e8e8462020-12-28 20:34:52 -07001228 for cmd in cmds:
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001229 outfile = output_files.get(cmd)
Simon Glassc3a310a82020-12-28 20:34:51 -07001230 if not outfile:
1231 raise ValueError("Unknown command '%s': (use: %s)" %
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001232 (cmd, ', '.join(sorted(output_files.keys()))))
Simon Glassc3a310a82020-12-28 20:34:51 -07001233 plat.setup_output(outfile.ftype,
1234 outfile.fname if output_dirs else output)
Simon Glass6b208842020-12-28 20:35:00 -07001235 plat.out_header(outfile)
Simon Glass55526782020-12-28 20:35:02 -07001236 outfile.method(plat)
Simon Glassc3a310a82020-12-28 20:34:51 -07001237 plat.finish_output()
Simon Glass695077d2021-03-26 16:17:25 +13001238
1239 if not warning_disabled:
1240 scan.show_warnings()
Simon Glassbe88d2f2021-02-03 06:01:07 -07001241 return plat