blob: 2d42480a9a5a0a40f2353348fd5b73f240905f5b [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):
Simon Glassc7b4b832021-02-03 06:01:20 -0700827 self.out('\n')
828 self.out('#include <common.h>\n')
829 self.out('#include <dm.h>\n')
830 self.out('#include <dt-structs.h>\n')
831 self.out('\n')
832 self.buf('/*\n')
Simon Glassfea2f252021-02-03 06:01:21 -0700833 self.buf(
834 " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
Simon Glassc7b4b832021-02-03 06:01:20 -0700835 uclass_list = self._valid_uclasses
Simon Glassfea2f252021-02-03 06:01:21 -0700836 for seq, uclass in enumerate(uclass_list):
837 self.buf(' * %3d: %s\n' % (seq, uclass.name))
838 self.buf(' *\n')
839 self.buf(' * Sequence numbers allocated in each uclass:\n')
Simon Glassc7b4b832021-02-03 06:01:20 -0700840 for uclass in uclass_list:
841 if uclass.alias_num_to_node:
842 self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
843 for seq, node in uclass.alias_num_to_node.items():
844 self.buf(' * %d: %s\n' % (seq, node.path))
845 self.buf(' */\n')
846
847 uclass_node = {}
848 for seq, uclass in enumerate(uclass_list):
849 uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
850 uclass.name)
851 uclass_node[-1] = '&uclass_head'
852 uclass_node[len(uclass_list)] = '&uclass_head'
853 self.buf('\n')
854 self.buf('struct list_head %s = {\n' % 'uclass_head')
855 self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
856 self.buf('\t.next = %s,\n' % uclass_node[0])
857 self.buf('};\n')
858 self.buf('\n')
859
860 for seq, uclass in enumerate(uclass_list):
861 uc_drv = self._scan._uclass.get(uclass.uclass_id)
862
863 priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
864
865 self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
866 if priv_name:
867 self.buf('\t.priv_\t\t= %s,\n' % priv_name)
868 self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
869 self.list_node('sibling_node', uclass_node, seq)
870 self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
871 self.buf('};\n')
872 self.buf('\n')
873 self.out(''.join(self.get_buf()))
Simon Glass9829eea2020-12-23 08:11:22 -0700874
Simon Glassbe88d2f2021-02-03 06:01:07 -0700875 def read_aliases(self):
876 """Read the aliases and attach the information to self._alias
877
878 Raises:
879 ValueError: The alias path is not found
880 """
881 alias_node = self._fdt.GetNode('/aliases')
882 if not alias_node:
883 return
884 re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
885 for prop in alias_node.props.values():
886 m_alias = re_num.match(prop.name)
887 if not m_alias:
888 raise ValueError("Cannot decode alias '%s'" % prop.name)
889 name, num = m_alias.groups()
890 node = self._fdt.GetNode(prop.value)
891 result = self._scan.add_uclass_alias(name, num, node)
892 if result is None:
893 raise ValueError("Alias '%s' path '%s' not found" %
894 (prop.name, prop.value))
895 elif result is False:
896 print("Could not find uclass for alias '%s'" % prop.name)
897
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700898 def generate_decl(self):
899 nodes_to_output = list(self._valid_nodes)
900
901 self.buf('#include <dm/device-internal.h>\n')
902 self.buf('#include <dm/uclass-internal.h>\n')
903 self.buf('\n')
904 self.buf(
905 '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
906 for node in nodes_to_output:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300907 self.buf('extern U_BOOT_DRIVER(%s);\n' % node.struct_name);
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700908 self.buf('\n')
909
910 if self._instantiate:
911 self.buf(
912 '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
913 for node in nodes_to_output:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300914 self.buf('extern DM_DEVICE_INST(%s);\n' % node.var_name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700915 self.buf('\n')
916
917 uclass_list = self._valid_uclasses
918
919 self.buf(
920 '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
921 for uclass in uclass_list:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300922 self.buf('extern UCLASS_DRIVER(%s);\n' % uclass.name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700923
924 if self._instantiate:
925 self.buf('\n')
926 self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
927 for uclass in uclass_list:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300928 self.buf('extern DM_UCLASS_INST(%s);\n' % uclass.name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700929 self.out(''.join(self.get_buf()))
930
Simon Glass80d782c42021-02-03 06:01:10 -0700931 def assign_seqs(self):
Simon Glassdf56e0b2021-02-03 06:01:09 -0700932 """Assign a sequence number to each node"""
933 for node in self._valid_nodes_unsorted:
Simon Glass80d782c42021-02-03 06:01:10 -0700934 seq = self._scan.assign_seq(node)
935 if seq is not None:
936 node.seq = seq
Simon Glassdf56e0b2021-02-03 06:01:09 -0700937
Simon Glass047a4802021-02-03 06:01:00 -0700938 def process_nodes(self, need_drivers):
939 nodes_to_output = list(self._valid_nodes)
940
Simon Glasseb3c2492021-02-03 06:01:01 -0700941 # Figure out which drivers we actually use
942 self._scan.mark_used(nodes_to_output)
943
Simon Glass047a4802021-02-03 06:01:00 -0700944 for node in nodes_to_output:
945 node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
946 driver = self._scan.get_driver(node.struct_name)
947 if not driver:
948 if not need_drivers:
949 continue
950 raise ValueError("Cannot parse/find driver for '%s'" %
951 node.struct_name)
952 node.driver = driver
Simon Glass80d782c42021-02-03 06:01:10 -0700953 uclass = self._scan._uclass.get(driver.uclass_id)
954 if not uclass:
955 raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
956 (driver.uclass_id, node.struct_name))
957 node.uclass = uclass
958 node.uclass_seq = len(node.uclass.devs)
959 node.uclass.devs.append(node)
960 uclass.node_refs[node.uclass_seq] = \
961 '&%s->uclass_node' % node.dev_ref
962
Simon Glass047a4802021-02-03 06:01:00 -0700963 parent_driver = None
964 if node.parent in self._valid_nodes:
965 parent_driver = self._scan.get_driver(node.parent.struct_name)
966 if not parent_driver:
967 if not need_drivers:
968 continue
969 raise ValueError(
970 "Cannot parse/find parent driver '%s' for '%s'" %
971 (node.parent.struct_name, node.struct_name))
972 node.parent_seq = len(node.parent.child_devs)
973 node.parent.child_devs.append(node)
974 node.parent.child_refs[node.parent_seq] = \
975 '&%s->sibling_node' % node.dev_ref
976 node.parent_driver = parent_driver
977
978 for node in nodes_to_output:
979 ref = '&%s->child_head' % node.dev_ref
980 node.child_refs[-1] = ref
981 node.child_refs[len(node.child_devs)] = ref
982
Simon Glass80d782c42021-02-03 06:01:10 -0700983 uclass_set = set()
984 for driver in self._scan._drivers.values():
985 if driver.used and driver.uclass:
986 uclass_set.add(driver.uclass)
987 self._valid_uclasses = sorted(list(uclass_set),
988 key=lambda uc: uc.uclass_id)
989
990 for seq, uclass in enumerate(uclass_set):
991 ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
992 uclass.node_refs[-1] = ref
993 uclass.node_refs[len(uclass.devs)] = ref
994
Simon Glassbe749002021-02-03 06:01:15 -0700995 def output_node_plat(self, node):
Simon Glass9d98b6e2020-12-23 08:11:20 -0700996 """Output the C code for a node
Simon Glassbc9e2682020-10-03 09:25:18 -0600997
Simon Glass9d98b6e2020-12-23 08:11:20 -0700998 Args:
999 node (fdt.Node): node to output
1000 """
Simon Glassbe749002021-02-03 06:01:15 -07001001 driver = node.driver
1002 parent_driver = node.parent_driver
1003
1004 line1 = 'Node %s index %d' % (node.path, node.idx)
1005 if driver:
1006 self.buf('/*\n')
1007 self.buf(' * %s\n' % line1)
1008 self.buf(' * driver %s parent %s\n' % (driver.name,
1009 parent_driver.name if parent_driver else 'None'))
1010 self.buf(' */\n')
1011 else:
1012 self.buf('/* %s */\n' % line1)
Simon Glassd570dec2017-06-18 22:08:58 -06001013
Simon Glass62a95372021-02-03 06:00:59 -07001014 self._output_values(node)
1015 self._declare_device(node)
Simon Glassd570dec2017-06-18 22:08:58 -06001016
Simon Glass1f730c82017-06-18 22:08:59 -06001017 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -06001018
Simon Glassfea2f252021-02-03 06:01:21 -07001019 def output_node_instance(self, node):
1020 """Output the C code for a node
1021
1022 Args:
1023 node (fdt.Node): node to output
1024 """
1025 parent_driver = node.parent_driver
1026
1027 self.buf('/*\n')
1028 self.buf(' * Node %s index %d\n' % (node.path, node.idx))
1029 self.buf(' * driver %s parent %s\n' % (node.driver.name,
1030 parent_driver.name if parent_driver else 'None'))
1031 self.buf('*/\n')
1032
1033 if not node.driver.plat:
1034 self._output_values(node)
1035 self._declare_device_inst(node, parent_driver)
1036
1037 self.out(''.join(self.get_buf()))
1038
Simon Glass55526782020-12-28 20:35:02 -07001039 def generate_plat(self):
Simon Glassd570dec2017-06-18 22:08:58 -06001040 """Generate device defintions for the platform data
1041
1042 This writes out C platform data initialisation data and
Simon Glass1d8364a2020-12-28 20:34:54 -07001043 U_BOOT_DRVINFO() declarations for each valid node. Where a node has
Simon Glassd570dec2017-06-18 22:08:58 -06001044 multiple compatible strings, a #define is used to make them equivalent.
1045
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +01001046 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glassd570dec2017-06-18 22:08:58 -06001047 information.
1048 """
Simon Glass1d8364a2020-12-28 20:34:54 -07001049 self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
Simon Glassbeddd7a2020-12-28 20:35:01 -07001050 self.out('#define DT_PLAT_C\n')
Simon Glass4c73d7b2020-10-03 11:31:41 -06001051 self.out('\n')
Simon Glass1f730c82017-06-18 22:08:59 -06001052 self.out('#include <common.h>\n')
1053 self.out('#include <dm.h>\n')
1054 self.out('#include <dt-structs.h>\n')
1055 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -06001056
Simon Glasse2119082021-02-03 06:01:19 -07001057 if self._valid_nodes:
1058 self.out('/*\n')
1059 self.out(
1060 " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
1061 self.out(' *\n')
1062 self.out(' * idx %-20s %-s\n' % ('driver_info', 'driver'))
1063 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1064 for node in self._valid_nodes:
1065 self.out(' * %3d: %-20s %-s\n' %
1066 (node.idx, node.var_name, node.struct_name))
1067 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1068 self.out(' */\n')
1069 self.out('\n')
1070
1071 for node in self._valid_nodes:
1072 self.output_node_plat(node)
Simon Glass3fa797a2017-06-18 22:09:03 -06001073
Walter Lozanodc5b4372020-06-25 01:10:13 -03001074 self.out(''.join(self.get_buf()))
Simon Glass3fa797a2017-06-18 22:09:03 -06001075
Simon Glassfea2f252021-02-03 06:01:21 -07001076 def generate_device(self):
1077 """Generate device instances
1078
1079 This writes out DM_DEVICE_INST() records for each device in the
1080 build.
1081
1082 See the documentation in doc/driver-model/of-plat.rst for more
1083 information.
1084 """
Simon Glassfea2f252021-02-03 06:01:21 -07001085 self.out('#include <common.h>\n')
1086 self.out('#include <dm.h>\n')
1087 self.out('#include <dt-structs.h>\n')
1088 self.out('\n')
1089
1090 if self._valid_nodes:
1091 self.out('/*\n')
1092 self.out(
1093 " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
1094 self.out(' *\n')
1095 self.out(' * idx %-20s %-s\n' % ('udevice', 'driver'))
1096 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1097 for node in self._valid_nodes:
1098 self.out(' * %3d: %-20s %-s\n' %
1099 (node.idx, node.var_name, node.struct_name))
1100 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1101 self.out(' */\n')
1102 self.out('\n')
1103
1104 for node in self._valid_nodes:
1105 self.output_node_instance(node)
1106
1107 self.out(''.join(self.get_buf()))
1108
Simon Glassc3a310a82020-12-28 20:34:51 -07001109
1110# Types of output file we understand
1111# key: Command used to generate this file
1112# value: OutputFile for this command
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001113OUTPUT_FILES_COMMON = {
Simon Glass3fa3bbb2021-02-03 06:01:14 -07001114 'decl':
1115 OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
1116 'Declares externs for all device/uclass instances'),
Simon Glass6b208842020-12-28 20:35:00 -07001117 'struct':
1118 OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
Simon Glass55526782020-12-28 20:35:02 -07001119 DtbPlatdata.generate_structs,
Simon Glass6b208842020-12-28 20:35:00 -07001120 'Defines the structs used to hold devicetree data'),
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001121 }
1122
1123# File generated without instantiate
1124OUTPUT_FILES_NOINST = {
Simon Glass6b208842020-12-28 20:35:00 -07001125 'platdata':
Simon Glass55526782020-12-28 20:35:02 -07001126 OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
Simon Glass6b208842020-12-28 20:35:00 -07001127 'Declares the U_BOOT_DRIVER() records and platform data'),
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001128 }
1129
1130# File generated with instantiate
1131OUTPUT_FILES_INST = {
Simon Glassfea2f252021-02-03 06:01:21 -07001132 'device':
1133 OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
1134 'Declares the DM_DEVICE_INST() records'),
Simon Glassc7b4b832021-02-03 06:01:20 -07001135 'uclass':
1136 OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
1137 'Declares the uclass instances (struct uclass)'),
Simon Glassc3a310a82020-12-28 20:34:51 -07001138 }
1139
Simon Glass6a65d8a2020-12-28 20:34:50 -07001140
Simon Glassf303ee72021-02-03 06:01:02 -07001141def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
Simon Glass3809ad92021-02-03 06:01:12 -07001142 instantiate, warning_disabled=False, drivers_additional=None,
1143 basedir=None, scan=None):
Simon Glass3fa797a2017-06-18 22:09:03 -06001144 """Run all the steps of the dtoc tool
1145
1146 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -07001147 args (list): List of non-option arguments provided to the problem
1148 dtb_file (str): Filename of dtb file to process
1149 include_disabled (bool): True to include disabled nodes
Simon Glass6ca0c7a2020-12-28 20:34:48 -07001150 output (str): Name of output file (None for stdout)
Simon Glass6a65d8a2020-12-28 20:34:50 -07001151 output_dirs (tuple of str):
1152 Directory to put C output files
1153 Directory to put H output files
Simon Glassf303ee72021-02-03 06:01:02 -07001154 phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
1155 or 'tpl'. None if not known
Simon Glass3809ad92021-02-03 06:01:12 -07001156 instantiate: Instantiate devices so they don't need to be bound at
1157 run-time
Simon Glass93daa012020-12-03 16:55:16 -07001158 warning_disabled (bool): True to avoid showing warnings about missing
1159 drivers
Simon Glass27511232020-12-23 08:11:19 -07001160 drivers_additional (list): List of additional drivers to use during
Simon Glass93daa012020-12-03 16:55:16 -07001161 scanning
Simon Glass4f2059b2020-12-28 20:35:03 -07001162 basedir (str): Base directory of U-Boot source code. Defaults to the
1163 grandparent of this file's directory
Simon Glass768ff0a2021-02-03 06:00:51 -07001164 scan (src_src.Scanner): Scanner from a previous run. This can help speed
1165 up tests. Use None for normal operation
1166
Simon Glassbe88d2f2021-02-03 06:01:07 -07001167 Returns:
1168 DtbPlatdata object
1169
Simon Glass94ee3bd2020-11-08 20:36:21 -07001170 Raises:
1171 ValueError: if args has no command, or an unknown command
Simon Glass3fa797a2017-06-18 22:09:03 -06001172 """
1173 if not args:
Simon Glassc3a310a82020-12-28 20:34:51 -07001174 raise ValueError('Please specify a command: struct, platdata, all')
1175 if output and output_dirs and any(output_dirs):
1176 raise ValueError('Must specify either output or output_dirs, not both')
Simon Glass3fa797a2017-06-18 22:09:03 -06001177
Simon Glass768ff0a2021-02-03 06:00:51 -07001178 if not scan:
Simon Glass695077d2021-03-26 16:17:25 +13001179 scan = src_scan.Scanner(basedir, drivers_additional, phase)
Simon Glass768ff0a2021-02-03 06:00:51 -07001180 scan.scan_drivers()
Simon Glass047a4802021-02-03 06:01:00 -07001181 do_process = True
1182 else:
1183 do_process = False
Simon Glass3809ad92021-02-03 06:01:12 -07001184 plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
Simon Glass3fa797a2017-06-18 22:09:03 -06001185 plat.scan_dtb()
Simon Glass3809ad92021-02-03 06:01:12 -07001186 plat.scan_tree(add_root=instantiate)
Simon Glass44479782021-02-03 06:00:58 -07001187 plat.prepare_nodes()
Simon Glass1b1fe412017-08-29 14:15:50 -06001188 plat.scan_reg_sizes()
Simon Glassc3a310a82020-12-28 20:34:51 -07001189 plat.setup_output_dirs(output_dirs)
Simon Glass55526782020-12-28 20:35:02 -07001190 plat.scan_structs()
Simon Glass3fa797a2017-06-18 22:09:03 -06001191 plat.scan_phandles()
Simon Glass3809ad92021-02-03 06:01:12 -07001192 plat.process_nodes(instantiate)
Simon Glassbe88d2f2021-02-03 06:01:07 -07001193 plat.read_aliases()
Simon Glass80d782c42021-02-03 06:01:10 -07001194 plat.assign_seqs()
Simon Glass3fa797a2017-06-18 22:09:03 -06001195
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001196 # Figure out what output files we plan to generate
Simon Glass705b84b2021-04-27 08:19:48 +12001197 output_files = dict(OUTPUT_FILES_COMMON)
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001198 if instantiate:
1199 output_files.update(OUTPUT_FILES_INST)
1200 else:
1201 output_files.update(OUTPUT_FILES_NOINST)
1202
Simon Glass4e8e8462020-12-28 20:34:52 -07001203 cmds = args[0].split(',')
1204 if 'all' in cmds:
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001205 cmds = sorted(output_files.keys())
Simon Glass4e8e8462020-12-28 20:34:52 -07001206 for cmd in cmds:
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001207 outfile = output_files.get(cmd)
Simon Glassc3a310a82020-12-28 20:34:51 -07001208 if not outfile:
1209 raise ValueError("Unknown command '%s': (use: %s)" %
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001210 (cmd, ', '.join(sorted(output_files.keys()))))
Simon Glassc3a310a82020-12-28 20:34:51 -07001211 plat.setup_output(outfile.ftype,
1212 outfile.fname if output_dirs else output)
Simon Glass6b208842020-12-28 20:35:00 -07001213 plat.out_header(outfile)
Simon Glass55526782020-12-28 20:35:02 -07001214 outfile.method(plat)
Simon Glassc3a310a82020-12-28 20:34:51 -07001215 plat.finish_output()
Simon Glass695077d2021-03-26 16:17:25 +13001216
1217 if not warning_disabled:
1218 scan.show_warnings()
Simon Glassbe88d2f2021-02-03 06:01:07 -07001219 return plat