blob: 89066e6403fcc8243946eb4110d67f7195ffe6b4 [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',
Simon Glass9dbf90e2023-02-13 08:56:37 -070038 'bootph-all',
39 'bootph-pre-sram',
40 'bootph-pre-ram',
Simon Glassd570dec2017-06-18 22:08:58 -060041]
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',
Simon Glasse7995f72021-08-07 07:24:11 -060065 'interrupts-extended': '#interrupt-cells',
Simon Glass4e430a22021-02-03 06:01:18 -070066 'gpios': '#gpio-cells',
67 'sandbox,emul': '#emul-cells',
68 }
69
Simon Glassc3a310a82020-12-28 20:34:51 -070070class Ftype(IntEnum):
71 SOURCE, HEADER = range(2)
72
73
74# This holds information about each type of output file dtoc can create
Simon Glass0d925392021-11-21 20:48:37 -070075# ftype: Type of file (Ftype)
Simon Glass6b208842020-12-28 20:35:00 -070076# fname: Filename excluding directory, e.g. 'dt-plat.c'
77# hdr_comment: Comment explaining the purpose of the file
78OutputFile = collections.namedtuple('OutputFile',
Simon Glass55526782020-12-28 20:35:02 -070079 ['ftype', 'fname', 'method', 'hdr_comment'])
Simon Glassc3a310a82020-12-28 20:34:51 -070080
Simon Glassec3b5e42017-08-29 14:15:55 -060081# This holds information about a property which includes phandles.
82#
83# max_args: integer: Maximum number or arguments that any phandle uses (int).
84# args: Number of args for each phandle in the property. The total number of
85# phandles is len(args). This is a list of integers.
86PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
87
Simon Glassc1622112020-10-03 09:25:19 -060088# Holds a single phandle link, allowing a C struct value to be assigned to point
89# to a device
90#
91# var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
92# dev_name: Name of device to assign to (e.g. 'clock')
93PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
94
Simon Glassec3b5e42017-08-29 14:15:55 -060095
Simon Glass1f730c82017-06-18 22:08:59 -060096def tab_to(num_tabs, line):
97 """Append tabs to a line of text to reach a tab stop.
Simon Glassd570dec2017-06-18 22:08:58 -060098
Simon Glass1f730c82017-06-18 22:08:59 -060099 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700100 num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
101 line (str): Line of text to append to
Simon Glass1f730c82017-06-18 22:08:59 -0600102
103 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700104 str: line with the correct number of tabs appeneded. If the line already
Simon Glass1f730c82017-06-18 22:08:59 -0600105 extends past that tab stop then a single space is appended.
106 """
107 if len(line) >= num_tabs * 8:
108 return line + ' '
109 return line + '\t' * (num_tabs - len(line) // 8)
110
Simon Glass7a2add12017-06-18 22:09:02 -0600111def get_value(ftype, value):
112 """Get a value as a C expression
113
114 For integers this returns a byte-swapped (little-endian) hex string
115 For bytes this returns a hex string, e.g. 0x12
116 For strings this returns a literal string enclosed in quotes
117 For booleans this return 'true'
118
119 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700120 ftype (fdt.Type): Data type (fdt_util)
121 value (bytes): Data value, as a string of bytes
122
123 Returns:
124 str: String representation of the value
Simon Glass7a2add12017-06-18 22:09:02 -0600125 """
Simon Glassc9a032c2020-11-08 20:36:17 -0700126 if ftype == fdt.Type.INT:
Simon Glass27511232020-12-23 08:11:19 -0700127 val = '%#x' % fdt_util.fdt32_to_cpu(value)
Simon Glassc9a032c2020-11-08 20:36:17 -0700128 elif ftype == fdt.Type.BYTE:
Simon Glass93daa012020-12-03 16:55:16 -0700129 char = value[0]
Simon Glass27511232020-12-23 08:11:19 -0700130 val = '%#x' % (ord(char) if isinstance(char, str) else char)
Simon Glassc9a032c2020-11-08 20:36:17 -0700131 elif ftype == fdt.Type.STRING:
Simon Glass7f5e2262020-07-07 21:32:06 -0600132 # Handle evil ACPI backslashes by adding another backslash before them.
133 # So "\\_SB.GPO0" in the device tree effectively stays like that in C
Simon Glass27511232020-12-23 08:11:19 -0700134 val = '"%s"' % value.replace('\\', '\\\\')
Simon Glassc9a032c2020-11-08 20:36:17 -0700135 elif ftype == fdt.Type.BOOL:
Simon Glass27511232020-12-23 08:11:19 -0700136 val = 'true'
Simon Glass94ee3bd2020-11-08 20:36:21 -0700137 else: # ftype == fdt.Type.INT64:
Simon Glass27511232020-12-23 08:11:19 -0700138 val = '%#x' % value
139 return val
Simon Glass7a2add12017-06-18 22:09:02 -0600140
Simon Glass7a2add12017-06-18 22:09:02 -0600141
Simon Glass27511232020-12-23 08:11:19 -0700142class DtbPlatdata():
Simon Glassd570dec2017-06-18 22:08:58 -0600143 """Provide a means to convert device tree binary data to platform data
144
145 The output of this process is C structures which can be used in space-
146 constrained encvironments where the ~3KB code overhead of device tree
147 code is not affordable.
148
149 Properties:
Simon Glass9065bc92020-12-28 20:35:06 -0700150 _scan: Scan object, for scanning and reporting on useful information
151 from the U-Boot source code
Simon Glass1f730c82017-06-18 22:08:59 -0600152 _fdt: Fdt object, referencing the device tree
Simon Glassd570dec2017-06-18 22:08:58 -0600153 _dtb_fname: Filename of the input device tree binary file
Simon Glassdf56e0b2021-02-03 06:01:09 -0700154 _valid_nodes_unsorted: A list of Node object with compatible strings,
155 ordered by devicetree node order
156 _valid_nodes: A list of Node object with compatible strings, ordered by
157 conv_name_to_c(node.name)
Simon Glasseab3f622017-06-18 22:09:01 -0600158 _include_disabled: true to include nodes marked status = "disabled"
Simon Glassd570dec2017-06-18 22:08:58 -0600159 _outfile: The current output file (sys.stdout or a real file)
160 _lines: Stashed list of output lines for outputting in the future
Simon Glassc3a310a82020-12-28 20:34:51 -0700161 _dirname: Directory to hold output files, or None for none (all files
162 go to stdout)
Simon Glass55526782020-12-28 20:35:02 -0700163 _struct_data (dict): OrderedDict of dtplat structures to output
164 key (str): Node name, as a C identifier
165 value: dict containing structure fields:
166 key (str): Field name
167 value: Prop object with field information
Simon Glass4f2059b2020-12-28 20:35:03 -0700168 _basedir (str): Base directory of source tree
Simon Glass80d782c42021-02-03 06:01:10 -0700169 _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
170 the selected devices (see _valid_node), in alphabetical order
Simon Glass3809ad92021-02-03 06:01:12 -0700171 _instantiate: Instantiate devices so they don't need to be bound at
172 run-time
Simon Glassd570dec2017-06-18 22:08:58 -0600173 """
Simon Glass3809ad92021-02-03 06:01:12 -0700174 def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
Simon Glass9065bc92020-12-28 20:35:06 -0700175 self._scan = scan
Simon Glass1f730c82017-06-18 22:08:59 -0600176 self._fdt = None
Simon Glassd570dec2017-06-18 22:08:58 -0600177 self._dtb_fname = dtb_fname
178 self._valid_nodes = None
Simon Glassdf56e0b2021-02-03 06:01:09 -0700179 self._valid_nodes_unsorted = None
Simon Glasseab3f622017-06-18 22:09:01 -0600180 self._include_disabled = include_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600181 self._outfile = None
182 self._lines = []
Simon Glassc3a310a82020-12-28 20:34:51 -0700183 self._dirnames = [None] * len(Ftype)
Simon Glass55526782020-12-28 20:35:02 -0700184 self._struct_data = collections.OrderedDict()
Simon Glass4f2059b2020-12-28 20:35:03 -0700185 self._basedir = None
Simon Glass80d782c42021-02-03 06:01:10 -0700186 self._valid_uclasses = None
Simon Glass3809ad92021-02-03 06:01:12 -0700187 self._instantiate = instantiate
Walter Lozanoe675d962020-07-03 08:07:17 -0300188
Simon Glassc3a310a82020-12-28 20:34:51 -0700189 def setup_output_dirs(self, output_dirs):
190 """Set up the output directories
191
192 This should be done before setup_output() is called
193
194 Args:
195 output_dirs (tuple of str):
196 Directory to use for C output files.
197 Use None to write files relative current directory
198 Directory to use for H output files.
199 Defaults to the C output dir
200 """
201 def process_dir(ftype, dirname):
202 if dirname:
203 os.makedirs(dirname, exist_ok=True)
204 self._dirnames[ftype] = dirname
205
206 if output_dirs:
207 c_dirname = output_dirs[0]
208 h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
209 process_dir(Ftype.SOURCE, c_dirname)
210 process_dir(Ftype.HEADER, h_dirname)
211
212 def setup_output(self, ftype, fname):
Simon Glassd570dec2017-06-18 22:08:58 -0600213 """Set up the output destination
214
Simon Glass1f730c82017-06-18 22:08:59 -0600215 Once this is done, future calls to self.out() will output to this
Simon Glassc3a310a82020-12-28 20:34:51 -0700216 file. The file used is as follows:
217
218 self._dirnames[ftype] is None: output to fname, or stdout if None
219 self._dirnames[ftype] is not None: output to fname in that directory
220
221 Calling this function multiple times will close the old file and open
222 the new one. If they are the same file, nothing happens and output will
223 continue to the same file.
Simon Glassd570dec2017-06-18 22:08:58 -0600224
225 Args:
Simon Glassc3a310a82020-12-28 20:34:51 -0700226 ftype (str): Type of file to create ('c' or 'h')
227 fname (str): Filename to send output to. If there is a directory in
228 self._dirnames for this file type, it will be put in that
229 directory
Simon Glassd570dec2017-06-18 22:08:58 -0600230 """
Simon Glassc3a310a82020-12-28 20:34:51 -0700231 dirname = self._dirnames[ftype]
232 if dirname:
233 pathname = os.path.join(dirname, fname)
234 if self._outfile:
235 self._outfile.close()
236 self._outfile = open(pathname, 'w')
237 elif fname:
238 if not self._outfile:
239 self._outfile = open(fname, 'w')
Simon Glass6ca0c7a2020-12-28 20:34:48 -0700240 else:
241 self._outfile = sys.stdout
Simon Glassd570dec2017-06-18 22:08:58 -0600242
Simon Glassc3a310a82020-12-28 20:34:51 -0700243 def finish_output(self):
244 """Finish outputing to a file
245
246 This closes the output file, if one is in use
247 """
248 if self._outfile != sys.stdout:
249 self._outfile.close()
Simon Glassc7b4b832021-02-03 06:01:20 -0700250 self._outfile = None
Simon Glassc3a310a82020-12-28 20:34:51 -0700251
Simon Glass1f730c82017-06-18 22:08:59 -0600252 def out(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600253 """Output a string to the output file
254
255 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700256 line (str): String to output
Simon Glassd570dec2017-06-18 22:08:58 -0600257 """
Simon Glass1f730c82017-06-18 22:08:59 -0600258 self._outfile.write(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600259
Simon Glass1f730c82017-06-18 22:08:59 -0600260 def buf(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600261 """Buffer up a string to send later
262
263 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700264 line (str): String to add to our 'buffer' list
Simon Glassd570dec2017-06-18 22:08:58 -0600265 """
Simon Glass1f730c82017-06-18 22:08:59 -0600266 self._lines.append(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600267
Simon Glass1f730c82017-06-18 22:08:59 -0600268 def get_buf(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600269 """Get the contents of the output buffer, and clear it
270
271 Returns:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700272 list(str): The output buffer, which is then cleared for future use
Simon Glassd570dec2017-06-18 22:08:58 -0600273 """
274 lines = self._lines
275 self._lines = []
276 return lines
277
Simon Glass6b208842020-12-28 20:35:00 -0700278 def out_header(self, outfile):
279 """Output a message indicating that this is an auto-generated file
280
281 Args:
282 outfile: OutputFile describing the file being generated
283 """
Simon Glass68d32c72017-08-29 14:16:01 -0600284 self.out('''/*
285 * DO NOT MODIFY
286 *
Simon Glass6b208842020-12-28 20:35:00 -0700287 * %s.
288 * This was generated by dtoc from a .dtb (device tree binary) file.
Simon Glass68d32c72017-08-29 14:16:01 -0600289 */
290
Simon Glass6b208842020-12-28 20:35:00 -0700291''' % outfile.hdr_comment)
Simon Glass68d32c72017-08-29 14:16:01 -0600292
Simon Glassec3b5e42017-08-29 14:15:55 -0600293 def get_phandle_argc(self, prop, node_name):
294 """Check if a node contains phandles
Simon Glassce5621d2017-08-29 14:15:54 -0600295
Simon Glassec3b5e42017-08-29 14:15:55 -0600296 We have no reliable way of detecting whether a node uses a phandle
297 or not. As an interim measure, use a list of known property names.
298
299 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700300 prop (fdt.Prop): Prop object to check
301 node_name (str): Node name, only used for raising an error
302 Returns:
303 int or None: Number of argument cells is this is a phandle,
304 else None
305 Raises:
306 ValueError: if the phandle cannot be parsed or the required property
307 is not present
Simon Glassec3b5e42017-08-29 14:15:55 -0600308 """
Simon Glass4e430a22021-02-03 06:01:18 -0700309 cells_prop = None
310 for name, cprop in PHANDLE_PROPS.items():
311 if prop.name.endswith(name):
312 cells_prop = cprop
313 if cells_prop:
Simon Glass609e2b12018-07-06 10:27:31 -0600314 if not isinstance(prop.value, list):
315 prop.value = [prop.value]
Simon Glassec3b5e42017-08-29 14:15:55 -0600316 val = prop.value
Simon Glassec3b5e42017-08-29 14:15:55 -0600317 i = 0
Simon Glassce5621d2017-08-29 14:15:54 -0600318
Simon Glassec3b5e42017-08-29 14:15:55 -0600319 max_args = 0
320 args = []
321 while i < len(val):
322 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass609e2b12018-07-06 10:27:31 -0600323 # If we get to the end of the list, stop. This can happen
324 # since some nodes have more phandles in the list than others,
325 # but we allocate enough space for the largest list. So those
326 # nodes with shorter lists end up with zeroes at the end.
327 if not phandle:
328 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600329 target = self._fdt.phandle_to_node.get(phandle)
330 if not target:
331 raise ValueError("Cannot parse '%s' in node '%s'" %
332 (prop.name, node_name))
Simon Glass4e430a22021-02-03 06:01:18 -0700333 cells = target.props.get(cells_prop)
Simon Glassec3b5e42017-08-29 14:15:55 -0600334 if not cells:
Walter Lozano179f0b62020-06-25 01:10:16 -0300335 raise ValueError("Node '%s' has no cells property" %
Simon Glass4e430a22021-02-03 06:01:18 -0700336 target.name)
Simon Glassec3b5e42017-08-29 14:15:55 -0600337 num_args = fdt_util.fdt32_to_cpu(cells.value)
338 max_args = max(max_args, num_args)
339 args.append(num_args)
340 i += 1 + num_args
341 return PhandleInfo(max_args, args)
342 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600343
Simon Glass1f730c82017-06-18 22:08:59 -0600344 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200345 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600346
Simon Glass1f730c82017-06-18 22:08:59 -0600347 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600348 device tree root node, and progress from there.
349 """
Simon Glass1f730c82017-06-18 22:08:59 -0600350 self._fdt = fdt.FdtScan(self._dtb_fname)
351
Simon Glassdf56e0b2021-02-03 06:01:09 -0700352 def scan_node(self, node, valid_nodes):
Simon Glass1f730c82017-06-18 22:08:59 -0600353 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600354
Simon Glassdf56e0b2021-02-03 06:01:09 -0700355 This adds each subnode to self._valid_nodes if it is enabled and has a
356 compatible string.
Simon Glass1f730c82017-06-18 22:08:59 -0600357
358 Args:
Simon Glassdf56e0b2021-02-03 06:01:09 -0700359 node (Node): Node for scan for subnodes
Simon Glass27511232020-12-23 08:11:19 -0700360 valid_nodes (list of Node): List of Node objects to add to
Simon Glass1f730c82017-06-18 22:08:59 -0600361 """
Simon Glassdf56e0b2021-02-03 06:01:09 -0700362 for subnode in node.subnodes:
363 if 'compatible' in subnode.props:
364 status = subnode.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600365 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600366 status.value != 'disabled'):
Simon Glassdf56e0b2021-02-03 06:01:09 -0700367 valid_nodes.append(subnode)
Simon Glassd570dec2017-06-18 22:08:58 -0600368
369 # recurse to handle any subnodes
Simon Glassdf56e0b2021-02-03 06:01:09 -0700370 self.scan_node(subnode, valid_nodes)
Simon Glassd570dec2017-06-18 22:08:58 -0600371
Simon Glassc14fd0c2021-02-03 06:01:11 -0700372 def scan_tree(self, add_root):
Simon Glassd570dec2017-06-18 22:08:58 -0600373 """Scan the device tree for useful information
374
375 This fills in the following properties:
Simon Glassdf56e0b2021-02-03 06:01:09 -0700376 _valid_nodes_unsorted: A list of nodes we wish to consider include
377 in the platform data (in devicetree node order)
378 _valid_nodes: Sorted version of _valid_nodes_unsorted
Simon Glassc14fd0c2021-02-03 06:01:11 -0700379
380 Args:
381 add_root: True to add the root node also (which wouldn't normally
382 be added as it may not have a compatible string)
Simon Glassd570dec2017-06-18 22:08:58 -0600383 """
Simon Glassdf56e0b2021-02-03 06:01:09 -0700384 root = self._fdt.GetRoot()
Simon Glass192f8132020-10-03 11:31:25 -0600385 valid_nodes = []
Simon Glassc14fd0c2021-02-03 06:01:11 -0700386 if add_root:
387 valid_nodes.append(root)
Simon Glassdf56e0b2021-02-03 06:01:09 -0700388 self.scan_node(root, valid_nodes)
389 self._valid_nodes_unsorted = valid_nodes
Simon Glass192f8132020-10-03 11:31:25 -0600390 self._valid_nodes = sorted(valid_nodes,
391 key=lambda x: conv_name_to_c(x.name))
Simon Glass44479782021-02-03 06:00:58 -0700392
393 def prepare_nodes(self):
394 """Add extra properties to the nodes we are using
395
396 The following properties are added for use by dtoc:
397 idx: Index number of this node (0=first, etc.)
398 struct_name: Name of the struct dtd used by this node
399 var_name: C name for this node
400 child_devs: List of child devices for this node, each a None
401 child_refs: Dict of references for each child:
402 key: Position in child list (-1=head, 0=first, 1=second, ...
403 n-1=last, n=head)
404 seq: Sequence number of the device (unique within its uclass), or
405 -1 not not known yet
406 dev_ref: Reference to this device, e.g. 'DM_DEVICE_REF(serial)'
407 driver: Driver record for this node, or None if not known
408 uclass: Uclass record for this node, or None if not known
409 uclass_seq: Position of this device within the uclass list (0=first,
410 n-1=last)
411 parent_seq: Position of this device within it siblings (0=first,
412 n-1=last)
413 parent_driver: Driver record of the node's parent, or None if none.
414 We don't use node.parent.driver since node.parent may not be in
415 the list of valid nodes
416 """
Simon Glass192f8132020-10-03 11:31:25 -0600417 for idx, node in enumerate(self._valid_nodes):
418 node.idx = idx
Simon Glass44479782021-02-03 06:00:58 -0700419 node.struct_name, _ = self._scan.get_normalized_compat_name(node)
420 node.var_name = conv_name_to_c(node.name)
421 node.child_devs = []
422 node.child_refs = {}
423 node.seq = -1
424 node.dev_ref = None
425 node.driver = None
426 node.uclass = None
427 node.uclass_seq = None
428 node.parent_seq = None
429 node.parent_driver = None
Simon Glassd570dec2017-06-18 22:08:58 -0600430
Simon Glass1b1fe412017-08-29 14:15:50 -0600431 @staticmethod
432 def get_num_cells(node):
433 """Get the number of cells in addresses and sizes for this node
434
435 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700436 node (fdt.None): Node to check
Simon Glass1b1fe412017-08-29 14:15:50 -0600437
438 Returns:
439 Tuple:
440 Number of address cells for this node
441 Number of size cells for this node
442 """
443 parent = node.parent
Simon Glass4415dc12021-03-26 16:17:27 +1300444 if parent and not parent.props:
Simon Glass9dbf90e2023-02-13 08:56:37 -0700445 raise ValueError("Parent node '%s' has no properties - do you need bootph-pre-ram or similar?" %
Simon Glass4415dc12021-03-26 16:17:27 +1300446 parent.path)
Simon Glass93daa012020-12-03 16:55:16 -0700447 num_addr, num_size = 2, 2
Simon Glass1b1fe412017-08-29 14:15:50 -0600448 if parent:
Simon Glass93daa012020-12-03 16:55:16 -0700449 addr_prop = parent.props.get('#address-cells')
450 size_prop = parent.props.get('#size-cells')
451 if addr_prop:
452 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
453 if size_prop:
454 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
455 return num_addr, num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600456
457 def scan_reg_sizes(self):
458 """Scan for 64-bit 'reg' properties and update the values
459
460 This finds 'reg' properties with 64-bit data and converts the value to
461 an array of 64-values. This allows it to be output in a way that the
462 C code can read.
463 """
464 for node in self._valid_nodes:
465 reg = node.props.get('reg')
466 if not reg:
467 continue
Simon Glass93daa012020-12-03 16:55:16 -0700468 num_addr, num_size = self.get_num_cells(node)
469 total = num_addr + num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600470
Simon Glassc9a032c2020-11-08 20:36:17 -0700471 if reg.type != fdt.Type.INT:
Simon Glassc38fee042018-07-06 10:27:32 -0600472 raise ValueError("Node '%s' reg property is not an int" %
473 node.name)
Simon Glass94ba59e2021-03-26 16:17:26 +1300474 if not isinstance(reg.value, list):
475 reg.value = [reg.value]
Simon Glass1b1fe412017-08-29 14:15:50 -0600476 if len(reg.value) % total:
Simon Glass94ee3bd2020-11-08 20:36:21 -0700477 raise ValueError(
Simon Glass4415dc12021-03-26 16:17:27 +1300478 "Node '%s' (parent '%s') reg property has %d cells "
Simon Glass94ee3bd2020-11-08 20:36:21 -0700479 'which is not a multiple of na + ns = %d + %d)' %
Simon Glass4415dc12021-03-26 16:17:27 +1300480 (node.name, node.parent.name, len(reg.value), num_addr,
481 num_size))
Simon Glass93daa012020-12-03 16:55:16 -0700482 reg.num_addr = num_addr
483 reg.num_size = num_size
Simon Glass94ba59e2021-03-26 16:17:26 +1300484 if num_addr > 1 or num_size > 1:
Simon Glassc9a032c2020-11-08 20:36:17 -0700485 reg.type = fdt.Type.INT64
Simon Glass1b1fe412017-08-29 14:15:50 -0600486 i = 0
487 new_value = []
488 val = reg.value
Simon Glass1b1fe412017-08-29 14:15:50 -0600489 while i < len(val):
Simon Glass93daa012020-12-03 16:55:16 -0700490 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
491 i += num_addr
492 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
493 i += num_size
Simon Glass1b1fe412017-08-29 14:15:50 -0600494 new_value += [addr, size]
495 reg.value = new_value
496
Simon Glass1f730c82017-06-18 22:08:59 -0600497 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600498 """Scan the device tree building up the C structures we will use.
499
500 Build a dict keyed by C struct name containing a dict of Prop
501 object for each struct field (keyed by property name). Where the
502 same struct appears multiple times, try to use the 'widest'
503 property, i.e. the one with a type which can express all others.
504
505 Once the widest property is determined, all other properties are
506 updated to match that width.
Simon Glass941f8f02020-10-03 11:31:24 -0600507
Simon Glass55526782020-12-28 20:35:02 -0700508 The results are written to self._struct_data
Simon Glassd570dec2017-06-18 22:08:58 -0600509 """
Simon Glass55526782020-12-28 20:35:02 -0700510 structs = self._struct_data
Simon Glassd570dec2017-06-18 22:08:58 -0600511 for node in self._valid_nodes:
Simon Glassd570dec2017-06-18 22:08:58 -0600512 fields = {}
513
514 # Get a list of all the valid properties in this node.
515 for name, prop in node.props.items():
516 if name not in PROP_IGNORE_LIST and name[0] != '#':
517 fields[name] = copy.deepcopy(prop)
518
Simon Glass62a95372021-02-03 06:00:59 -0700519 # If we've seen this struct_name before, update the existing struct
520 if node.struct_name in structs:
521 struct = structs[node.struct_name]
Simon Glassd570dec2017-06-18 22:08:58 -0600522 for name, prop in fields.items():
523 oldprop = struct.get(name)
524 if oldprop:
525 oldprop.Widen(prop)
526 else:
527 struct[name] = prop
528
529 # Otherwise store this as a new struct.
530 else:
Simon Glass62a95372021-02-03 06:00:59 -0700531 structs[node.struct_name] = fields
Simon Glassd570dec2017-06-18 22:08:58 -0600532
Simon Glassd570dec2017-06-18 22:08:58 -0600533 for node in self._valid_nodes:
Simon Glass62a95372021-02-03 06:00:59 -0700534 struct = structs[node.struct_name]
Simon Glassd570dec2017-06-18 22:08:58 -0600535 for name, prop in node.props.items():
536 if name not in PROP_IGNORE_LIST and name[0] != '#':
537 prop.Widen(struct[name])
Simon Glassd570dec2017-06-18 22:08:58 -0600538
Simon Glass1f730c82017-06-18 22:08:59 -0600539 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600540 """Figure out what phandles each node uses
541
542 We need to be careful when outputing nodes that use phandles since
543 they must come after the declaration of the phandles in the C file.
544 Otherwise we get a compiler error since the phandle struct is not yet
545 declared.
546
547 This function adds to each node a list of phandle nodes that the node
548 depends on. This allows us to output things in the right order.
549 """
550 for node in self._valid_nodes:
551 node.phandles = set()
552 for pname, prop in node.props.items():
553 if pname in PROP_IGNORE_LIST or pname[0] == '#':
554 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600555 info = self.get_phandle_argc(prop, node.name)
556 if info:
Simon Glassec3b5e42017-08-29 14:15:55 -0600557 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600558 pos = 0
559 for args in info.args:
560 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600561 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
562 target_node = self._fdt.phandle_to_node[phandle]
563 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600564 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600565
566
Simon Glass55526782020-12-28 20:35:02 -0700567 def generate_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600568 """Generate struct defintions for the platform data
569
570 This writes out the body of a header file consisting of structure
571 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100572 doc/driver-model/of-plat.rst for more information.
Simon Glassd570dec2017-06-18 22:08:58 -0600573 """
Simon Glass55526782020-12-28 20:35:02 -0700574 structs = self._struct_data
Simon Glass1f730c82017-06-18 22:08:59 -0600575 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900576 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600577
578 # Output the struct definition
579 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600580 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600581 for pname in sorted(structs[name]):
582 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600583 info = self.get_phandle_argc(prop, structs[name])
584 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600585 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600586 struct_name = 'struct phandle_%d_arg' % info.max_args
587 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600588 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600589 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600590 else:
591 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600592 self.out('\t%s%s' % (tab_to(2, ptype),
593 conv_name_to_c(prop.name)))
594 if isinstance(prop.value, list):
595 self.out('[%d]' % len(prop.value))
596 self.out(';\n')
597 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600598
Simon Glass9d98b6e2020-12-23 08:11:20 -0700599 def _output_list(self, node, prop):
600 """Output the C code for a devicetree property that holds a list
Simon Glassd570dec2017-06-18 22:08:58 -0600601
602 Args:
Simon Glass9d98b6e2020-12-23 08:11:20 -0700603 node (fdt.Node): Node to output
604 prop (fdt.Prop): Prop to output
Simon Glassd570dec2017-06-18 22:08:58 -0600605 """
Simon Glass9d98b6e2020-12-23 08:11:20 -0700606 self.buf('{')
607 vals = []
608 # For phandles, output a reference to the platform data
609 # of the target node.
610 info = self.get_phandle_argc(prop, node.name)
611 if info:
612 # Process the list as pairs of (phandle, id)
613 pos = 0
614 for args in info.args:
615 phandle_cell = prop.value[pos]
616 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
617 target_node = self._fdt.phandle_to_node[phandle]
618 arg_values = []
619 for i in range(args):
620 arg_values.append(
621 str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
622 pos += 1 + args
623 vals.append('\t{%d, {%s}}' % (target_node.idx,
624 ', '.join(arg_values)))
625 for val in vals:
626 self.buf('\n\t\t%s,' % val)
627 else:
628 for val in prop.value:
629 vals.append(get_value(prop.type, val))
Simon Glassbc9e2682020-10-03 09:25:18 -0600630
Simon Glass9d98b6e2020-12-23 08:11:20 -0700631 # Put 8 values per line to avoid very long lines.
632 for i in range(0, len(vals), 8):
633 if i:
634 self.buf(',\n\t\t')
635 self.buf(', '.join(vals[i:i + 8]))
636 self.buf('}')
Simon Glassbc9e2682020-10-03 09:25:18 -0600637
Simon Glass62a95372021-02-03 06:00:59 -0700638 def _declare_device(self, node):
Simon Glass9fdd0c32020-12-23 08:11:21 -0700639 """Add a device declaration to the output
640
Simon Glass1d8364a2020-12-28 20:34:54 -0700641 This declares a U_BOOT_DRVINFO() for the device being processed
Simon Glass9fdd0c32020-12-23 08:11:21 -0700642
643 Args:
Simon Glass62a95372021-02-03 06:00:59 -0700644 node: Node to process
Simon Glass9fdd0c32020-12-23 08:11:21 -0700645 """
Simon Glass62a95372021-02-03 06:00:59 -0700646 self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
647 self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
Simon Glasse2119082021-02-03 06:01:19 -0700648 self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
Simon Glass62a95372021-02-03 06:00:59 -0700649 self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
650 (VAL_PREFIX, node.var_name))
Simon Glass9fdd0c32020-12-23 08:11:21 -0700651 idx = -1
Simon Glass62a95372021-02-03 06:00:59 -0700652 if node.parent and node.parent in self._valid_nodes:
653 idx = node.parent.idx
Simon Glass9fdd0c32020-12-23 08:11:21 -0700654 self.buf('\t.parent_idx\t= %d,\n' % idx)
655 self.buf('};\n')
656 self.buf('\n')
657
Simon Glassc7b4b832021-02-03 06:01:20 -0700658 def prep_priv(self, struc, name, suffix, section='.priv_data'):
659 if not struc:
660 return None
661 var_name = '_%s%s' % (name, suffix)
662 hdr = self._scan._structs.get(struc)
663 if hdr:
664 self.buf('#include <%s>\n' % hdr.fname)
665 else:
666 print('Warning: Cannot find header file for struct %s' % struc)
667 attr = '__attribute__ ((section ("%s")))' % section
668 return var_name, struc, attr
669
670 def alloc_priv(self, info, name, extra, suffix='_priv'):
671 result = self.prep_priv(info, name, suffix)
672 if not result:
673 return None
674 var_name, struc, section = result
675 self.buf('u8 %s_%s[sizeof(struct %s)]\n\t%s;\n' %
676 (var_name, extra, struc.strip(), section))
677 return '%s_%s' % (var_name, extra)
678
Simon Glassfea2f252021-02-03 06:01:21 -0700679 def alloc_plat(self, info, name, extra, node):
680 result = self.prep_priv(info, name, '_plat')
681 if not result:
682 return None
683 var_name, struc, section = result
684 self.buf('struct %s %s\n\t%s_%s = {\n' %
685 (struc.strip(), section, var_name, extra))
686 self.buf('\t.dtplat = {\n')
687 for pname in sorted(node.props):
688 self._output_prop(node, node.props[pname], 2)
689 self.buf('\t},\n')
690 self.buf('};\n')
691 return '&%s_%s' % (var_name, extra)
692
693 def _declare_device_inst(self, node, parent_driver):
694 """Add a device instance declaration to the output
695
696 This declares a DM_DEVICE_INST() for the device being processed
697
698 Args:
699 node: Node to output
700 """
701 driver = node.driver
702 uclass = node.uclass
703 self.buf('\n')
704 num_lines = len(self._lines)
705 plat_name = self.alloc_plat(driver.plat, driver.name, node.var_name,
706 node)
707 priv_name = self.alloc_priv(driver.priv, driver.name, node.var_name)
708 parent_plat_name = None
709 parent_priv_name = None
710 if parent_driver:
711 # TODO: deal with uclass providing these values
712 parent_plat_name = self.alloc_priv(
713 parent_driver.child_plat, driver.name, node.var_name,
714 '_parent_plat')
715 parent_priv_name = self.alloc_priv(
716 parent_driver.child_priv, driver.name, node.var_name,
717 '_parent_priv')
718 uclass_plat_name = self.alloc_priv(
719 uclass.per_dev_plat, driver.name + '_uc', node.var_name, 'plat')
720 uclass_priv_name = self.alloc_priv(uclass.per_dev_priv,
721 driver.name + '_uc', node.var_name)
722 for hdr in driver.headers:
723 self.buf('#include %s\n' % hdr)
724
725 # Add a blank line if we emitted any stuff above, for readability
726 if num_lines != len(self._lines):
727 self.buf('\n')
728
729 self.buf('DM_DEVICE_INST(%s) = {\n' % node.var_name)
730 self.buf('\t.driver\t\t= DM_DRIVER_REF(%s),\n' % node.struct_name)
731 self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
732 if plat_name:
733 self.buf('\t.plat_\t\t= %s,\n' % plat_name)
734 else:
735 self.buf('\t.plat_\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
736 if parent_plat_name:
737 self.buf('\t.parent_plat_\t= %s,\n' % parent_plat_name)
738 if uclass_plat_name:
739 self.buf('\t.uclass_plat_\t= %s,\n' % uclass_plat_name)
740 driver_date = None
741
742 if node != self._fdt.GetRoot():
743 compat_list = node.props['compatible'].value
744 if not isinstance(compat_list, list):
745 compat_list = [compat_list]
746 for compat in compat_list:
747 driver_data = driver.compat.get(compat)
748 if driver_data:
749 self.buf('\t.driver_data\t= %s,\n' % driver_data)
750 break
751
752 if node.parent and node.parent.parent:
Simon Glass9ebd5512021-06-27 17:51:10 -0600753 if node.parent not in self._valid_nodes:
754 # This might indicate that the parent node is not in the
755 # SPL/TPL devicetree but the child is. For example if we are
756 # dealing with of-platdata in TPL, the parent has a
Simon Glass9dbf90e2023-02-13 08:56:37 -0700757 # bootph-pre-sram tag but the child has bootph-all. In
Simon Glass9ebd5512021-06-27 17:51:10 -0600758 # this case the child node exists in TPL but the parent does
759 # not.
760 raise ValueError("Node '%s' requires parent node '%s' but it is not in the valid list" %
761 (node.path, node.parent.path))
Simon Glassfea2f252021-02-03 06:01:21 -0700762 self.buf('\t.parent\t\t= DM_DEVICE_REF(%s),\n' %
763 node.parent.var_name)
764 if priv_name:
765 self.buf('\t.priv_\t\t= %s,\n' % priv_name)
766 self.buf('\t.uclass\t\t= DM_UCLASS_REF(%s),\n' % uclass.name)
767
768 if uclass_priv_name:
769 self.buf('\t.uclass_priv_ = %s,\n' % uclass_priv_name)
770 if parent_priv_name:
771 self.buf('\t.parent_priv_\t= %s,\n' % parent_priv_name)
772 self.list_node('uclass_node', uclass.node_refs, node.uclass_seq)
773 self.list_head('child_head', 'sibling_node', node.child_devs, node.var_name)
774 if node.parent in self._valid_nodes:
775 self.list_node('sibling_node', node.parent.child_refs,
776 node.parent_seq)
777 # flags is left as 0
778
779 self.buf('\t.seq_ = %d,\n' % node.seq)
780
781 self.buf('};\n')
782 self.buf('\n')
783 return parent_plat_name
784
785 def _output_prop(self, node, prop, tabs=1):
Simon Glass9829eea2020-12-23 08:11:22 -0700786 """Output a line containing the value of a struct member
787
788 Args:
789 node (Node): Node being output
790 prop (Prop): Prop object to output
791 """
792 if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
793 return
794 member_name = conv_name_to_c(prop.name)
Simon Glassfea2f252021-02-03 06:01:21 -0700795 self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
Simon Glass9829eea2020-12-23 08:11:22 -0700796
797 # Special handling for lists
798 if isinstance(prop.value, list):
799 self._output_list(node, prop)
800 else:
801 self.buf(get_value(prop.type, prop.value))
802 self.buf(',\n')
803
Simon Glass62a95372021-02-03 06:00:59 -0700804 def _output_values(self, node):
Simon Glass9829eea2020-12-23 08:11:22 -0700805 """Output the definition of a device's struct values
806
807 Args:
Simon Glass62a95372021-02-03 06:00:59 -0700808 node (Node): Node to output
Simon Glass9829eea2020-12-23 08:11:22 -0700809 """
810 self.buf('static struct %s%s %s%s = {\n' %
Simon Glass62a95372021-02-03 06:00:59 -0700811 (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
Simon Glass9829eea2020-12-23 08:11:22 -0700812 for pname in sorted(node.props):
813 self._output_prop(node, node.props[pname])
814 self.buf('};\n')
Simon Glassc7b4b832021-02-03 06:01:20 -0700815
816 def list_head(self, head_member, node_member, node_refs, var_name):
817 self.buf('\t.%s\t= {\n' % head_member)
818 if node_refs:
819 last = node_refs[-1].dev_ref
820 first = node_refs[0].dev_ref
821 member = node_member
822 else:
823 last = 'DM_DEVICE_REF(%s)' % var_name
824 first = last
825 member = head_member
826 self.buf('\t\t.prev = &%s->%s,\n' % (last, member))
827 self.buf('\t\t.next = &%s->%s,\n' % (first, member))
828 self.buf('\t},\n')
829
830 def list_node(self, member, node_refs, seq):
831 self.buf('\t.%s\t= {\n' % member)
832 self.buf('\t\t.prev = %s,\n' % node_refs[seq - 1])
833 self.buf('\t\t.next = %s,\n' % node_refs[seq + 1])
834 self.buf('\t},\n')
835
836 def generate_uclasses(self):
Simon Glassc7b4b832021-02-03 06:01:20 -0700837 self.out('\n')
Simon Glassc7b4b832021-02-03 06:01:20 -0700838 self.out('#include <dm.h>\n')
839 self.out('#include <dt-structs.h>\n')
840 self.out('\n')
841 self.buf('/*\n')
Simon Glassfea2f252021-02-03 06:01:21 -0700842 self.buf(
843 " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
Simon Glassc7b4b832021-02-03 06:01:20 -0700844 uclass_list = self._valid_uclasses
Simon Glassfea2f252021-02-03 06:01:21 -0700845 for seq, uclass in enumerate(uclass_list):
846 self.buf(' * %3d: %s\n' % (seq, uclass.name))
847 self.buf(' *\n')
848 self.buf(' * Sequence numbers allocated in each uclass:\n')
Simon Glassc7b4b832021-02-03 06:01:20 -0700849 for uclass in uclass_list:
850 if uclass.alias_num_to_node:
851 self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
852 for seq, node in uclass.alias_num_to_node.items():
853 self.buf(' * %d: %s\n' % (seq, node.path))
854 self.buf(' */\n')
855
856 uclass_node = {}
857 for seq, uclass in enumerate(uclass_list):
858 uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
859 uclass.name)
860 uclass_node[-1] = '&uclass_head'
861 uclass_node[len(uclass_list)] = '&uclass_head'
862 self.buf('\n')
863 self.buf('struct list_head %s = {\n' % 'uclass_head')
864 self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
865 self.buf('\t.next = %s,\n' % uclass_node[0])
866 self.buf('};\n')
867 self.buf('\n')
868
869 for seq, uclass in enumerate(uclass_list):
870 uc_drv = self._scan._uclass.get(uclass.uclass_id)
871
872 priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
873
874 self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
875 if priv_name:
876 self.buf('\t.priv_\t\t= %s,\n' % priv_name)
877 self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
878 self.list_node('sibling_node', uclass_node, seq)
879 self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
880 self.buf('};\n')
881 self.buf('\n')
882 self.out(''.join(self.get_buf()))
Simon Glass9829eea2020-12-23 08:11:22 -0700883
Simon Glassbe88d2f2021-02-03 06:01:07 -0700884 def read_aliases(self):
885 """Read the aliases and attach the information to self._alias
886
887 Raises:
888 ValueError: The alias path is not found
889 """
890 alias_node = self._fdt.GetNode('/aliases')
891 if not alias_node:
892 return
893 re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
894 for prop in alias_node.props.values():
895 m_alias = re_num.match(prop.name)
896 if not m_alias:
897 raise ValueError("Cannot decode alias '%s'" % prop.name)
898 name, num = m_alias.groups()
899 node = self._fdt.GetNode(prop.value)
900 result = self._scan.add_uclass_alias(name, num, node)
901 if result is None:
902 raise ValueError("Alias '%s' path '%s' not found" %
903 (prop.name, prop.value))
904 elif result is False:
905 print("Could not find uclass for alias '%s'" % prop.name)
906
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700907 def generate_decl(self):
908 nodes_to_output = list(self._valid_nodes)
909
910 self.buf('#include <dm/device-internal.h>\n')
911 self.buf('#include <dm/uclass-internal.h>\n')
912 self.buf('\n')
913 self.buf(
914 '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
915 for node in nodes_to_output:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300916 self.buf('extern U_BOOT_DRIVER(%s);\n' % node.struct_name);
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700917 self.buf('\n')
918
919 if self._instantiate:
920 self.buf(
921 '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
922 for node in nodes_to_output:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300923 self.buf('extern DM_DEVICE_INST(%s);\n' % node.var_name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700924 self.buf('\n')
925
926 uclass_list = self._valid_uclasses
927
928 self.buf(
929 '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
930 for uclass in uclass_list:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300931 self.buf('extern UCLASS_DRIVER(%s);\n' % uclass.name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700932
933 if self._instantiate:
934 self.buf('\n')
935 self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
936 for uclass in uclass_list:
Simon Glassed5e6ae2021-03-15 17:25:11 +1300937 self.buf('extern DM_UCLASS_INST(%s);\n' % uclass.name)
Simon Glass3fa3bbb2021-02-03 06:01:14 -0700938 self.out(''.join(self.get_buf()))
939
Simon Glass80d782c42021-02-03 06:01:10 -0700940 def assign_seqs(self):
Simon Glassdf56e0b2021-02-03 06:01:09 -0700941 """Assign a sequence number to each node"""
942 for node in self._valid_nodes_unsorted:
Simon Glass80d782c42021-02-03 06:01:10 -0700943 seq = self._scan.assign_seq(node)
944 if seq is not None:
945 node.seq = seq
Simon Glassdf56e0b2021-02-03 06:01:09 -0700946
Simon Glass047a4802021-02-03 06:01:00 -0700947 def process_nodes(self, need_drivers):
948 nodes_to_output = list(self._valid_nodes)
949
Simon Glasseb3c2492021-02-03 06:01:01 -0700950 # Figure out which drivers we actually use
951 self._scan.mark_used(nodes_to_output)
952
Simon Glass047a4802021-02-03 06:01:00 -0700953 for node in nodes_to_output:
954 node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
955 driver = self._scan.get_driver(node.struct_name)
956 if not driver:
957 if not need_drivers:
958 continue
959 raise ValueError("Cannot parse/find driver for '%s'" %
960 node.struct_name)
961 node.driver = driver
Simon Glass80d782c42021-02-03 06:01:10 -0700962 uclass = self._scan._uclass.get(driver.uclass_id)
963 if not uclass:
964 raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
965 (driver.uclass_id, node.struct_name))
966 node.uclass = uclass
967 node.uclass_seq = len(node.uclass.devs)
968 node.uclass.devs.append(node)
969 uclass.node_refs[node.uclass_seq] = \
970 '&%s->uclass_node' % node.dev_ref
971
Simon Glass047a4802021-02-03 06:01:00 -0700972 parent_driver = None
973 if node.parent in self._valid_nodes:
974 parent_driver = self._scan.get_driver(node.parent.struct_name)
975 if not parent_driver:
976 if not need_drivers:
977 continue
978 raise ValueError(
979 "Cannot parse/find parent driver '%s' for '%s'" %
980 (node.parent.struct_name, node.struct_name))
981 node.parent_seq = len(node.parent.child_devs)
982 node.parent.child_devs.append(node)
983 node.parent.child_refs[node.parent_seq] = \
984 '&%s->sibling_node' % node.dev_ref
985 node.parent_driver = parent_driver
986
987 for node in nodes_to_output:
988 ref = '&%s->child_head' % node.dev_ref
989 node.child_refs[-1] = ref
990 node.child_refs[len(node.child_devs)] = ref
991
Simon Glass80d782c42021-02-03 06:01:10 -0700992 uclass_set = set()
993 for driver in self._scan._drivers.values():
994 if driver.used and driver.uclass:
995 uclass_set.add(driver.uclass)
996 self._valid_uclasses = sorted(list(uclass_set),
997 key=lambda uc: uc.uclass_id)
998
999 for seq, uclass in enumerate(uclass_set):
1000 ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
1001 uclass.node_refs[-1] = ref
1002 uclass.node_refs[len(uclass.devs)] = ref
1003
Simon Glassbe749002021-02-03 06:01:15 -07001004 def output_node_plat(self, node):
Simon Glass9d98b6e2020-12-23 08:11:20 -07001005 """Output the C code for a node
Simon Glassbc9e2682020-10-03 09:25:18 -06001006
Simon Glass9d98b6e2020-12-23 08:11:20 -07001007 Args:
1008 node (fdt.Node): node to output
1009 """
Simon Glassbe749002021-02-03 06:01:15 -07001010 driver = node.driver
1011 parent_driver = node.parent_driver
1012
1013 line1 = 'Node %s index %d' % (node.path, node.idx)
1014 if driver:
1015 self.buf('/*\n')
1016 self.buf(' * %s\n' % line1)
1017 self.buf(' * driver %s parent %s\n' % (driver.name,
1018 parent_driver.name if parent_driver else 'None'))
1019 self.buf(' */\n')
1020 else:
1021 self.buf('/* %s */\n' % line1)
Simon Glassd570dec2017-06-18 22:08:58 -06001022
Simon Glass62a95372021-02-03 06:00:59 -07001023 self._output_values(node)
1024 self._declare_device(node)
Simon Glassd570dec2017-06-18 22:08:58 -06001025
Simon Glass1f730c82017-06-18 22:08:59 -06001026 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -06001027
Simon Glassfea2f252021-02-03 06:01:21 -07001028 def output_node_instance(self, node):
1029 """Output the C code for a node
1030
1031 Args:
1032 node (fdt.Node): node to output
1033 """
1034 parent_driver = node.parent_driver
1035
1036 self.buf('/*\n')
1037 self.buf(' * Node %s index %d\n' % (node.path, node.idx))
1038 self.buf(' * driver %s parent %s\n' % (node.driver.name,
1039 parent_driver.name if parent_driver else 'None'))
1040 self.buf('*/\n')
1041
1042 if not node.driver.plat:
1043 self._output_values(node)
1044 self._declare_device_inst(node, parent_driver)
1045
1046 self.out(''.join(self.get_buf()))
1047
Simon Glass55526782020-12-28 20:35:02 -07001048 def generate_plat(self):
Simon Glassd570dec2017-06-18 22:08:58 -06001049 """Generate device defintions for the platform data
1050
1051 This writes out C platform data initialisation data and
Simon Glass1d8364a2020-12-28 20:34:54 -07001052 U_BOOT_DRVINFO() declarations for each valid node. Where a node has
Simon Glassd570dec2017-06-18 22:08:58 -06001053 multiple compatible strings, a #define is used to make them equivalent.
1054
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +01001055 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glassd570dec2017-06-18 22:08:58 -06001056 information.
1057 """
Simon Glass1d8364a2020-12-28 20:34:54 -07001058 self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
Simon Glassbeddd7a2020-12-28 20:35:01 -07001059 self.out('#define DT_PLAT_C\n')
Simon Glass4c73d7b2020-10-03 11:31:41 -06001060 self.out('\n')
Simon Glass1f730c82017-06-18 22:08:59 -06001061 self.out('#include <dm.h>\n')
1062 self.out('#include <dt-structs.h>\n')
1063 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -06001064
Simon Glasse2119082021-02-03 06:01:19 -07001065 if self._valid_nodes:
1066 self.out('/*\n')
1067 self.out(
1068 " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
1069 self.out(' *\n')
1070 self.out(' * idx %-20s %-s\n' % ('driver_info', 'driver'))
1071 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1072 for node in self._valid_nodes:
1073 self.out(' * %3d: %-20s %-s\n' %
1074 (node.idx, node.var_name, node.struct_name))
1075 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1076 self.out(' */\n')
1077 self.out('\n')
1078
1079 for node in self._valid_nodes:
1080 self.output_node_plat(node)
Simon Glass3fa797a2017-06-18 22:09:03 -06001081
Walter Lozanodc5b4372020-06-25 01:10:13 -03001082 self.out(''.join(self.get_buf()))
Simon Glass3fa797a2017-06-18 22:09:03 -06001083
Simon Glassfea2f252021-02-03 06:01:21 -07001084 def generate_device(self):
1085 """Generate device instances
1086
1087 This writes out DM_DEVICE_INST() records for each device in the
1088 build.
1089
1090 See the documentation in doc/driver-model/of-plat.rst for more
1091 information.
1092 """
Simon Glassfea2f252021-02-03 06:01:21 -07001093 self.out('#include <dm.h>\n')
1094 self.out('#include <dt-structs.h>\n')
1095 self.out('\n')
1096
1097 if self._valid_nodes:
1098 self.out('/*\n')
1099 self.out(
1100 " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
1101 self.out(' *\n')
1102 self.out(' * idx %-20s %-s\n' % ('udevice', 'driver'))
1103 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1104 for node in self._valid_nodes:
1105 self.out(' * %3d: %-20s %-s\n' %
1106 (node.idx, node.var_name, node.struct_name))
1107 self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
1108 self.out(' */\n')
1109 self.out('\n')
1110
1111 for node in self._valid_nodes:
1112 self.output_node_instance(node)
1113
1114 self.out(''.join(self.get_buf()))
1115
Simon Glassc3a310a82020-12-28 20:34:51 -07001116
1117# Types of output file we understand
1118# key: Command used to generate this file
1119# value: OutputFile for this command
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001120OUTPUT_FILES_COMMON = {
Simon Glass3fa3bbb2021-02-03 06:01:14 -07001121 'decl':
1122 OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
1123 'Declares externs for all device/uclass instances'),
Simon Glass6b208842020-12-28 20:35:00 -07001124 'struct':
1125 OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
Simon Glass55526782020-12-28 20:35:02 -07001126 DtbPlatdata.generate_structs,
Simon Glass6b208842020-12-28 20:35:00 -07001127 'Defines the structs used to hold devicetree data'),
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001128 }
1129
1130# File generated without instantiate
1131OUTPUT_FILES_NOINST = {
Simon Glass6b208842020-12-28 20:35:00 -07001132 'platdata':
Simon Glass55526782020-12-28 20:35:02 -07001133 OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
Simon Glass6b208842020-12-28 20:35:00 -07001134 'Declares the U_BOOT_DRIVER() records and platform data'),
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001135 }
1136
1137# File generated with instantiate
1138OUTPUT_FILES_INST = {
Simon Glassfea2f252021-02-03 06:01:21 -07001139 'device':
1140 OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
1141 'Declares the DM_DEVICE_INST() records'),
Simon Glassc7b4b832021-02-03 06:01:20 -07001142 'uclass':
1143 OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
1144 'Declares the uclass instances (struct uclass)'),
Simon Glassc3a310a82020-12-28 20:34:51 -07001145 }
1146
Simon Glass6a65d8a2020-12-28 20:34:50 -07001147
Simon Glassf303ee72021-02-03 06:01:02 -07001148def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
Simon Glass3809ad92021-02-03 06:01:12 -07001149 instantiate, warning_disabled=False, drivers_additional=None,
1150 basedir=None, scan=None):
Simon Glass3fa797a2017-06-18 22:09:03 -06001151 """Run all the steps of the dtoc tool
1152
1153 Args:
Simon Glass94ee3bd2020-11-08 20:36:21 -07001154 args (list): List of non-option arguments provided to the problem
1155 dtb_file (str): Filename of dtb file to process
1156 include_disabled (bool): True to include disabled nodes
Simon Glass6ca0c7a2020-12-28 20:34:48 -07001157 output (str): Name of output file (None for stdout)
Simon Glass6a65d8a2020-12-28 20:34:50 -07001158 output_dirs (tuple of str):
1159 Directory to put C output files
1160 Directory to put H output files
Simon Glassf303ee72021-02-03 06:01:02 -07001161 phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
1162 or 'tpl'. None if not known
Simon Glass3809ad92021-02-03 06:01:12 -07001163 instantiate: Instantiate devices so they don't need to be bound at
1164 run-time
Simon Glass93daa012020-12-03 16:55:16 -07001165 warning_disabled (bool): True to avoid showing warnings about missing
1166 drivers
Simon Glass27511232020-12-23 08:11:19 -07001167 drivers_additional (list): List of additional drivers to use during
Simon Glass93daa012020-12-03 16:55:16 -07001168 scanning
Simon Glass4f2059b2020-12-28 20:35:03 -07001169 basedir (str): Base directory of U-Boot source code. Defaults to the
1170 grandparent of this file's directory
Simon Glass768ff0a2021-02-03 06:00:51 -07001171 scan (src_src.Scanner): Scanner from a previous run. This can help speed
1172 up tests. Use None for normal operation
1173
Simon Glassbe88d2f2021-02-03 06:01:07 -07001174 Returns:
1175 DtbPlatdata object
1176
Simon Glass94ee3bd2020-11-08 20:36:21 -07001177 Raises:
1178 ValueError: if args has no command, or an unknown command
Simon Glass3fa797a2017-06-18 22:09:03 -06001179 """
1180 if not args:
Simon Glassc3a310a82020-12-28 20:34:51 -07001181 raise ValueError('Please specify a command: struct, platdata, all')
1182 if output and output_dirs and any(output_dirs):
1183 raise ValueError('Must specify either output or output_dirs, not both')
Simon Glass3fa797a2017-06-18 22:09:03 -06001184
Simon Glass768ff0a2021-02-03 06:00:51 -07001185 if not scan:
Simon Glass695077d2021-03-26 16:17:25 +13001186 scan = src_scan.Scanner(basedir, drivers_additional, phase)
Simon Glass768ff0a2021-02-03 06:00:51 -07001187 scan.scan_drivers()
Simon Glass047a4802021-02-03 06:01:00 -07001188 do_process = True
1189 else:
1190 do_process = False
Simon Glass3809ad92021-02-03 06:01:12 -07001191 plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
Simon Glass3fa797a2017-06-18 22:09:03 -06001192 plat.scan_dtb()
Simon Glass3809ad92021-02-03 06:01:12 -07001193 plat.scan_tree(add_root=instantiate)
Simon Glass44479782021-02-03 06:00:58 -07001194 plat.prepare_nodes()
Simon Glass1b1fe412017-08-29 14:15:50 -06001195 plat.scan_reg_sizes()
Simon Glassc3a310a82020-12-28 20:34:51 -07001196 plat.setup_output_dirs(output_dirs)
Simon Glass55526782020-12-28 20:35:02 -07001197 plat.scan_structs()
Simon Glass3fa797a2017-06-18 22:09:03 -06001198 plat.scan_phandles()
Simon Glass3809ad92021-02-03 06:01:12 -07001199 plat.process_nodes(instantiate)
Simon Glassbe88d2f2021-02-03 06:01:07 -07001200 plat.read_aliases()
Simon Glass80d782c42021-02-03 06:01:10 -07001201 plat.assign_seqs()
Simon Glass3fa797a2017-06-18 22:09:03 -06001202
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001203 # Figure out what output files we plan to generate
Simon Glass705b84b2021-04-27 08:19:48 +12001204 output_files = dict(OUTPUT_FILES_COMMON)
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001205 if instantiate:
1206 output_files.update(OUTPUT_FILES_INST)
1207 else:
1208 output_files.update(OUTPUT_FILES_NOINST)
1209
Simon Glass4e8e8462020-12-28 20:34:52 -07001210 cmds = args[0].split(',')
1211 if 'all' in cmds:
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001212 cmds = sorted(output_files.keys())
Simon Glass4e8e8462020-12-28 20:34:52 -07001213 for cmd in cmds:
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001214 outfile = output_files.get(cmd)
Simon Glassc3a310a82020-12-28 20:34:51 -07001215 if not outfile:
1216 raise ValueError("Unknown command '%s': (use: %s)" %
Simon Glassdb2b9ca2021-03-25 06:40:51 +13001217 (cmd, ', '.join(sorted(output_files.keys()))))
Simon Glassc3a310a82020-12-28 20:34:51 -07001218 plat.setup_output(outfile.ftype,
1219 outfile.fname if output_dirs else output)
Simon Glass6b208842020-12-28 20:35:00 -07001220 plat.out_header(outfile)
Simon Glass55526782020-12-28 20:35:02 -07001221 outfile.method(plat)
Simon Glassc3a310a82020-12-28 20:34:51 -07001222 plat.finish_output()
Simon Glass695077d2021-03-26 16:17:25 +13001223
1224 if not warning_disabled:
1225 scan.show_warnings()
Simon Glassbe88d2f2021-02-03 06:01:07 -07001226 return plat