Prepare v2023.10
[platform/kernel/u-boot.git] / tools / dtoc / dtb_platdata.py
1 #!/usr/bin/python
2 # SPDX-License-Identifier: GPL-2.0+
3 #
4 # Copyright (C) 2017 Google, Inc
5 # Written by Simon Glass <sjg@chromium.org>
6 #
7
8 """Device tree to platform data class
9
10 This supports converting device tree data to C structures definitions and
11 static data.
12
13 See doc/driver-model/of-plat.rst for more informaiton
14 """
15
16 import collections
17 import copy
18 from enum import IntEnum
19 import os
20 import re
21 import sys
22
23 from dtoc import fdt
24 from dtoc import fdt_util
25 from dtoc import src_scan
26 from dtoc.src_scan import conv_name_to_c
27
28 # When we see these properties we ignore them - i.e. do not create a structure
29 # member
30 PROP_IGNORE_LIST = [
31     '#address-cells',
32     '#gpio-cells',
33     '#size-cells',
34     'compatible',
35     'linux,phandle',
36     "status",
37     'phandle',
38     'bootph-all',
39     'bootph-pre-sram',
40     'bootph-pre-ram',
41 ]
42
43 # C type declarations for the types we support
44 TYPE_NAMES = {
45     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',
50 }
51
52 STRUCT_PREFIX = 'dtd_'
53 VAL_PREFIX = 'dtv_'
54
55 # 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.
63 PHANDLE_PROPS = {
64     'clocks': '#clock-cells',
65     'interrupts-extended': '#interrupt-cells',
66     'gpios': '#gpio-cells',
67     'sandbox,emul': '#emul-cells',
68     }
69
70 class Ftype(IntEnum):
71     SOURCE, HEADER = range(2)
72
73
74 # This holds information about each type of output file dtoc can create
75 # ftype: Type of file (Ftype)
76 # fname: Filename excluding directory, e.g. 'dt-plat.c'
77 # hdr_comment: Comment explaining the purpose of the file
78 OutputFile = collections.namedtuple('OutputFile',
79                                     ['ftype', 'fname', 'method', 'hdr_comment'])
80
81 # 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.
86 PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
87
88 # 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')
93 PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
94
95
96 def tab_to(num_tabs, line):
97     """Append tabs to a line of text to reach a tab stop.
98
99     Args:
100         num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
101         line (str): Line of text to append to
102
103     Returns:
104         str: line with the correct number of tabs appeneded. If the line already
105         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
111 def 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:
120         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
125     """
126     if ftype == fdt.Type.INT:
127         val = '%#x' % fdt_util.fdt32_to_cpu(value)
128     elif ftype == fdt.Type.BYTE:
129         char = value[0]
130         val = '%#x' % (ord(char) if isinstance(char, str) else char)
131     elif ftype == fdt.Type.STRING:
132         # Handle evil ACPI backslashes by adding another backslash before them.
133         # So "\\_SB.GPO0" in the device tree effectively stays like that in C
134         val = '"%s"' % value.replace('\\', '\\\\')
135     elif ftype == fdt.Type.BOOL:
136         val = 'true'
137     else:  # ftype == fdt.Type.INT64:
138         val = '%#x' % value
139     return val
140
141
142 class DtbPlatdata():
143     """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:
150         _scan: Scan object, for scanning and reporting on useful information
151             from the U-Boot source code
152         _fdt: Fdt object, referencing the device tree
153         _dtb_fname: Filename of the input device tree binary file
154         _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)
158         _include_disabled: true to include nodes marked status = "disabled"
159         _outfile: The current output file (sys.stdout or a real file)
160         _lines: Stashed list of output lines for outputting in the future
161         _dirname: Directory to hold output files, or None for none (all files
162             go to stdout)
163         _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
168         _basedir (str): Base directory of source tree
169         _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
170             the selected devices (see _valid_node), in alphabetical order
171         _instantiate: Instantiate devices so they don't need to be bound at
172             run-time
173     """
174     def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
175         self._scan = scan
176         self._fdt = None
177         self._dtb_fname = dtb_fname
178         self._valid_nodes = None
179         self._valid_nodes_unsorted = None
180         self._include_disabled = include_disabled
181         self._outfile = None
182         self._lines = []
183         self._dirnames = [None] * len(Ftype)
184         self._struct_data = collections.OrderedDict()
185         self._basedir = None
186         self._valid_uclasses = None
187         self._instantiate = instantiate
188
189     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):
213         """Set up the output destination
214
215         Once this is done, future calls to self.out() will output to this
216         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.
224
225         Args:
226             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
230         """
231         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')
240         else:
241             self._outfile = sys.stdout
242
243     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()
250             self._outfile = None
251
252     def out(self, line):
253         """Output a string to the output file
254
255         Args:
256             line (str): String to output
257         """
258         self._outfile.write(line)
259
260     def buf(self, line):
261         """Buffer up a string to send later
262
263         Args:
264             line (str): String to add to our 'buffer' list
265         """
266         self._lines.append(line)
267
268     def get_buf(self):
269         """Get the contents of the output buffer, and clear it
270
271         Returns:
272             list(str): The output buffer, which is then cleared for future use
273         """
274         lines = self._lines
275         self._lines = []
276         return lines
277
278     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         """
284         self.out('''/*
285  * DO NOT MODIFY
286  *
287  * %s.
288  * This was generated by dtoc from a .dtb (device tree binary) file.
289  */
290
291 ''' % outfile.hdr_comment)
292
293     def get_phandle_argc(self, prop, node_name):
294         """Check if a node contains phandles
295
296         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:
300             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
308         """
309         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:
314             if not isinstance(prop.value, list):
315                 prop.value = [prop.value]
316             val = prop.value
317             i = 0
318
319             max_args = 0
320             args = []
321             while i < len(val):
322                 phandle = fdt_util.fdt32_to_cpu(val[i])
323                 # 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
329                 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))
333                 cells = target.props.get(cells_prop)
334                 if not cells:
335                     raise ValueError("Node '%s' has no cells property" %
336                                      target.name)
337                 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
343
344     def scan_dtb(self):
345         """Scan the device tree to obtain a tree of nodes and properties
346
347         Once this is done, self._fdt.GetRoot() can be called to obtain the
348         device tree root node, and progress from there.
349         """
350         self._fdt = fdt.FdtScan(self._dtb_fname)
351
352     def scan_node(self, node, valid_nodes):
353         """Scan a node and subnodes to build a tree of node and phandle info
354
355         This adds each subnode to self._valid_nodes if it is enabled and has a
356         compatible string.
357
358         Args:
359             node (Node): Node for scan for subnodes
360             valid_nodes (list of Node): List of Node objects to add to
361         """
362         for subnode in node.subnodes:
363             if 'compatible' in subnode.props:
364                 status = subnode.props.get('status')
365                 if (not self._include_disabled and not status or
366                         status.value != 'disabled'):
367                     valid_nodes.append(subnode)
368
369             # recurse to handle any subnodes
370             self.scan_node(subnode, valid_nodes)
371
372     def scan_tree(self, add_root):
373         """Scan the device tree for useful information
374
375         This fills in the following properties:
376             _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
379
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)
383         """
384         root = self._fdt.GetRoot()
385         valid_nodes = []
386         if add_root:
387             valid_nodes.append(root)
388         self.scan_node(root, valid_nodes)
389         self._valid_nodes_unsorted = valid_nodes
390         self._valid_nodes = sorted(valid_nodes,
391                                    key=lambda x: conv_name_to_c(x.name))
392
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         """
417         for idx, node in enumerate(self._valid_nodes):
418             node.idx = idx
419             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
430
431     @staticmethod
432     def get_num_cells(node):
433         """Get the number of cells in addresses and sizes for this node
434
435         Args:
436             node (fdt.None): Node to check
437
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
444         if parent and not parent.props:
445             raise ValueError("Parent node '%s' has no properties - do you need bootph-pre-ram or similar?" %
446                              parent.path)
447         num_addr, num_size = 2, 2
448         if parent:
449             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
456
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
468             num_addr, num_size = self.get_num_cells(node)
469             total = num_addr + num_size
470
471             if reg.type != fdt.Type.INT:
472                 raise ValueError("Node '%s' reg property is not an int" %
473                                  node.name)
474             if not isinstance(reg.value, list):
475                 reg.value = [reg.value]
476             if len(reg.value) % total:
477                 raise ValueError(
478                     "Node '%s' (parent '%s') reg property has %d cells "
479                     'which is not a multiple of na + ns = %d + %d)' %
480                     (node.name, node.parent.name, len(reg.value), num_addr,
481                      num_size))
482             reg.num_addr = num_addr
483             reg.num_size = num_size
484             if num_addr > 1 or num_size > 1:
485                 reg.type = fdt.Type.INT64
486                 i = 0
487                 new_value = []
488                 val = reg.value
489                 while i < len(val):
490                     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
494                     new_value += [addr, size]
495                 reg.value = new_value
496
497     def scan_structs(self):
498         """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.
507
508         The results are written to self._struct_data
509         """
510         structs = self._struct_data
511         for node in self._valid_nodes:
512             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
519             # 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]
522                 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:
531                 structs[node.struct_name] = fields
532
533         for node in self._valid_nodes:
534             struct = structs[node.struct_name]
535             for name, prop in node.props.items():
536                 if name not in PROP_IGNORE_LIST and name[0] != '#':
537                     prop.Widen(struct[name])
538
539     def scan_phandles(self):
540         """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
555                 info = self.get_phandle_argc(prop, node.name)
556                 if info:
557                     # Process the list as pairs of (phandle, id)
558                     pos = 0
559                     for args in info.args:
560                         phandle_cell = prop.value[pos]
561                         phandle = fdt_util.fdt32_to_cpu(phandle_cell)
562                         target_node = self._fdt.phandle_to_node[phandle]
563                         node.phandles.add(target_node)
564                         pos += 1 + args
565
566
567     def generate_structs(self):
568         """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
572         doc/driver-model/of-plat.rst for more information.
573         """
574         structs = self._struct_data
575         self.out('#include <stdbool.h>\n')
576         self.out('#include <linux/libfdt.h>\n')
577
578         # Output the struct definition
579         for name in sorted(structs):
580             self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
581             for pname in sorted(structs[name]):
582                 prop = structs[name][pname]
583                 info = self.get_phandle_argc(prop, structs[name])
584                 if info:
585                     # For phandles, include a reference to the target
586                     struct_name = 'struct phandle_%d_arg' % info.max_args
587                     self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
588                                              conv_name_to_c(prop.name),
589                                              len(info.args)))
590                 else:
591                     ptype = TYPE_NAMES[prop.type]
592                     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')
598
599     def _output_list(self, node, prop):
600         """Output the C code for a devicetree property that holds a list
601
602         Args:
603             node (fdt.Node): Node to output
604             prop (fdt.Prop): Prop to output
605         """
606         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))
630
631             # 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('}')
637
638     def _declare_device(self, node):
639         """Add a device declaration to the output
640
641         This declares a U_BOOT_DRVINFO() for the device being processed
642
643         Args:
644             node: Node to process
645         """
646         self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
647         self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
648         self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
649         self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
650                  (VAL_PREFIX, node.var_name))
651         idx = -1
652         if node.parent and node.parent in self._valid_nodes:
653             idx = node.parent.idx
654         self.buf('\t.parent_idx\t= %d,\n' % idx)
655         self.buf('};\n')
656         self.buf('\n')
657
658     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
679     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:
753             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
757                 # bootph-pre-sram tag but the child has bootph-all. In
758                 # 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))
762             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):
786         """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)
795         self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
796
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
804     def _output_values(self, node):
805         """Output the definition of a device's struct values
806
807         Args:
808             node (Node): Node to output
809         """
810         self.buf('static struct %s%s %s%s = {\n' %
811                  (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
812         for pname in sorted(node.props):
813             self._output_prop(node, node.props[pname])
814         self.buf('};\n')
815
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):
837         self.out('\n')
838         self.out('#include <common.h>\n')
839         self.out('#include <dm.h>\n')
840         self.out('#include <dt-structs.h>\n')
841         self.out('\n')
842         self.buf('/*\n')
843         self.buf(
844             " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
845         uclass_list = self._valid_uclasses
846         for seq, uclass in enumerate(uclass_list):
847             self.buf(' * %3d: %s\n' % (seq, uclass.name))
848         self.buf(' *\n')
849         self.buf(' * Sequence numbers allocated in each uclass:\n')
850         for uclass in uclass_list:
851             if uclass.alias_num_to_node:
852                 self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
853                 for seq, node in uclass.alias_num_to_node.items():
854                     self.buf(' *    %d: %s\n' % (seq, node.path))
855         self.buf(' */\n')
856
857         uclass_node = {}
858         for seq, uclass in enumerate(uclass_list):
859             uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
860                                 uclass.name)
861         uclass_node[-1] = '&uclass_head'
862         uclass_node[len(uclass_list)] = '&uclass_head'
863         self.buf('\n')
864         self.buf('struct list_head %s = {\n' % 'uclass_head')
865         self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
866         self.buf('\t.next = %s,\n' % uclass_node[0])
867         self.buf('};\n')
868         self.buf('\n')
869
870         for seq, uclass in enumerate(uclass_list):
871             uc_drv = self._scan._uclass.get(uclass.uclass_id)
872
873             priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
874
875             self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
876             if priv_name:
877                 self.buf('\t.priv_\t\t= %s,\n' % priv_name)
878             self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
879             self.list_node('sibling_node', uclass_node, seq)
880             self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
881             self.buf('};\n')
882             self.buf('\n')
883         self.out(''.join(self.get_buf()))
884
885     def read_aliases(self):
886         """Read the aliases and attach the information to self._alias
887
888         Raises:
889             ValueError: The alias path is not found
890         """
891         alias_node = self._fdt.GetNode('/aliases')
892         if not alias_node:
893             return
894         re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
895         for prop in alias_node.props.values():
896             m_alias = re_num.match(prop.name)
897             if not m_alias:
898                 raise ValueError("Cannot decode alias '%s'" % prop.name)
899             name, num = m_alias.groups()
900             node = self._fdt.GetNode(prop.value)
901             result = self._scan.add_uclass_alias(name, num, node)
902             if result is None:
903                 raise ValueError("Alias '%s' path '%s' not found" %
904                                  (prop.name, prop.value))
905             elif result is False:
906                 print("Could not find uclass for alias '%s'" % prop.name)
907
908     def generate_decl(self):
909         nodes_to_output = list(self._valid_nodes)
910
911         self.buf('#include <dm/device-internal.h>\n')
912         self.buf('#include <dm/uclass-internal.h>\n')
913         self.buf('\n')
914         self.buf(
915             '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
916         for node in nodes_to_output:
917             self.buf('extern U_BOOT_DRIVER(%s);\n' % node.struct_name);
918         self.buf('\n')
919
920         if self._instantiate:
921             self.buf(
922                 '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
923             for node in nodes_to_output:
924                 self.buf('extern DM_DEVICE_INST(%s);\n' % node.var_name)
925             self.buf('\n')
926
927         uclass_list = self._valid_uclasses
928
929         self.buf(
930             '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
931         for uclass in uclass_list:
932             self.buf('extern UCLASS_DRIVER(%s);\n' % uclass.name)
933
934         if self._instantiate:
935             self.buf('\n')
936             self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
937             for uclass in uclass_list:
938                 self.buf('extern DM_UCLASS_INST(%s);\n' % uclass.name)
939         self.out(''.join(self.get_buf()))
940
941     def assign_seqs(self):
942         """Assign a sequence number to each node"""
943         for node in self._valid_nodes_unsorted:
944             seq = self._scan.assign_seq(node)
945             if seq is not None:
946                 node.seq = seq
947
948     def process_nodes(self, need_drivers):
949         nodes_to_output = list(self._valid_nodes)
950
951         # Figure out which drivers we actually use
952         self._scan.mark_used(nodes_to_output)
953
954         for node in nodes_to_output:
955             node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
956             driver = self._scan.get_driver(node.struct_name)
957             if not driver:
958                 if not need_drivers:
959                     continue
960                 raise ValueError("Cannot parse/find driver for '%s'" %
961                                  node.struct_name)
962             node.driver = driver
963             uclass = self._scan._uclass.get(driver.uclass_id)
964             if not uclass:
965                 raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
966                                 (driver.uclass_id, node.struct_name))
967             node.uclass = uclass
968             node.uclass_seq = len(node.uclass.devs)
969             node.uclass.devs.append(node)
970             uclass.node_refs[node.uclass_seq] = \
971                 '&%s->uclass_node' % node.dev_ref
972
973             parent_driver = None
974             if node.parent in self._valid_nodes:
975                 parent_driver = self._scan.get_driver(node.parent.struct_name)
976                 if not parent_driver:
977                     if not need_drivers:
978                         continue
979                     raise ValueError(
980                         "Cannot parse/find parent driver '%s' for '%s'" %
981                         (node.parent.struct_name, node.struct_name))
982                 node.parent_seq = len(node.parent.child_devs)
983                 node.parent.child_devs.append(node)
984                 node.parent.child_refs[node.parent_seq] = \
985                     '&%s->sibling_node' % node.dev_ref
986                 node.parent_driver = parent_driver
987
988         for node in nodes_to_output:
989             ref = '&%s->child_head' % node.dev_ref
990             node.child_refs[-1] = ref
991             node.child_refs[len(node.child_devs)] = ref
992
993         uclass_set = set()
994         for driver in self._scan._drivers.values():
995             if driver.used and driver.uclass:
996                 uclass_set.add(driver.uclass)
997         self._valid_uclasses = sorted(list(uclass_set),
998                                       key=lambda uc: uc.uclass_id)
999
1000         for seq, uclass in enumerate(uclass_set):
1001             ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
1002             uclass.node_refs[-1] = ref
1003             uclass.node_refs[len(uclass.devs)] = ref
1004
1005     def output_node_plat(self, node):
1006         """Output the C code for a node
1007
1008         Args:
1009             node (fdt.Node): node to output
1010         """
1011         driver = node.driver
1012         parent_driver = node.parent_driver
1013
1014         line1 = 'Node %s index %d' % (node.path, node.idx)
1015         if driver:
1016             self.buf('/*\n')
1017             self.buf(' * %s\n' % line1)
1018             self.buf(' * driver %s parent %s\n' % (driver.name,
1019                 parent_driver.name if parent_driver else 'None'))
1020             self.buf(' */\n')
1021         else:
1022             self.buf('/* %s */\n' % line1)
1023
1024         self._output_values(node)
1025         self._declare_device(node)
1026
1027         self.out(''.join(self.get_buf()))
1028
1029     def output_node_instance(self, node):
1030         """Output the C code for a node
1031
1032         Args:
1033             node (fdt.Node): node to output
1034         """
1035         parent_driver = node.parent_driver
1036
1037         self.buf('/*\n')
1038         self.buf(' * Node %s index %d\n' % (node.path, node.idx))
1039         self.buf(' * driver %s parent %s\n' % (node.driver.name,
1040                  parent_driver.name if parent_driver else 'None'))
1041         self.buf('*/\n')
1042
1043         if not node.driver.plat:
1044             self._output_values(node)
1045         self._declare_device_inst(node, parent_driver)
1046
1047         self.out(''.join(self.get_buf()))
1048
1049     def generate_plat(self):
1050         """Generate device defintions for the platform data
1051
1052         This writes out C platform data initialisation data and
1053         U_BOOT_DRVINFO() declarations for each valid node. Where a node has
1054         multiple compatible strings, a #define is used to make them equivalent.
1055
1056         See the documentation in doc/driver-model/of-plat.rst for more
1057         information.
1058         """
1059         self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
1060         self.out('#define DT_PLAT_C\n')
1061         self.out('\n')
1062         self.out('#include <common.h>\n')
1063         self.out('#include <dm.h>\n')
1064         self.out('#include <dt-structs.h>\n')
1065         self.out('\n')
1066
1067         if self._valid_nodes:
1068             self.out('/*\n')
1069             self.out(
1070                 " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
1071             self.out(' *\n')
1072             self.out(' * idx  %-20s %-s\n' % ('driver_info', 'driver'))
1073             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1074             for node in self._valid_nodes:
1075                 self.out(' * %3d: %-20s %-s\n' %
1076                         (node.idx, node.var_name, node.struct_name))
1077             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1078             self.out(' */\n')
1079             self.out('\n')
1080
1081             for node in self._valid_nodes:
1082                 self.output_node_plat(node)
1083
1084         self.out(''.join(self.get_buf()))
1085
1086     def generate_device(self):
1087         """Generate device instances
1088
1089         This writes out DM_DEVICE_INST() records for each device in the
1090         build.
1091
1092         See the documentation in doc/driver-model/of-plat.rst for more
1093         information.
1094         """
1095         self.out('#include <common.h>\n')
1096         self.out('#include <dm.h>\n')
1097         self.out('#include <dt-structs.h>\n')
1098         self.out('\n')
1099
1100         if self._valid_nodes:
1101             self.out('/*\n')
1102             self.out(
1103                 " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
1104             self.out(' *\n')
1105             self.out(' * idx  %-20s %-s\n' % ('udevice', 'driver'))
1106             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1107             for node in self._valid_nodes:
1108                 self.out(' * %3d: %-20s %-s\n' %
1109                         (node.idx, node.var_name, node.struct_name))
1110             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1111             self.out(' */\n')
1112             self.out('\n')
1113
1114             for node in self._valid_nodes:
1115                 self.output_node_instance(node)
1116
1117         self.out(''.join(self.get_buf()))
1118
1119
1120 # Types of output file we understand
1121 # key: Command used to generate this file
1122 # value: OutputFile for this command
1123 OUTPUT_FILES_COMMON = {
1124     'decl':
1125         OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
1126                    'Declares externs for all device/uclass instances'),
1127     'struct':
1128         OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
1129                    DtbPlatdata.generate_structs,
1130                    'Defines the structs used to hold devicetree data'),
1131     }
1132
1133 # File generated without instantiate
1134 OUTPUT_FILES_NOINST = {
1135     'platdata':
1136         OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
1137                    'Declares the U_BOOT_DRIVER() records and platform data'),
1138     }
1139
1140 # File generated with instantiate
1141 OUTPUT_FILES_INST = {
1142     'device':
1143         OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
1144                    'Declares the DM_DEVICE_INST() records'),
1145     'uclass':
1146         OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
1147                    'Declares the uclass instances (struct uclass)'),
1148     }
1149
1150
1151 def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
1152               instantiate, warning_disabled=False, drivers_additional=None,
1153               basedir=None, scan=None):
1154     """Run all the steps of the dtoc tool
1155
1156     Args:
1157         args (list): List of non-option arguments provided to the problem
1158         dtb_file (str): Filename of dtb file to process
1159         include_disabled (bool): True to include disabled nodes
1160         output (str): Name of output file (None for stdout)
1161         output_dirs (tuple of str):
1162             Directory to put C output files
1163             Directory to put H output files
1164         phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
1165              or 'tpl'. None if not known
1166         instantiate: Instantiate devices so they don't need to be bound at
1167             run-time
1168         warning_disabled (bool): True to avoid showing warnings about missing
1169             drivers
1170         drivers_additional (list): List of additional drivers to use during
1171             scanning
1172         basedir (str): Base directory of U-Boot source code. Defaults to the
1173             grandparent of this file's directory
1174         scan (src_src.Scanner): Scanner from a previous run. This can help speed
1175             up tests. Use None for normal operation
1176
1177     Returns:
1178         DtbPlatdata object
1179
1180     Raises:
1181         ValueError: if args has no command, or an unknown command
1182     """
1183     if not args:
1184         raise ValueError('Please specify a command: struct, platdata, all')
1185     if output and output_dirs and any(output_dirs):
1186         raise ValueError('Must specify either output or output_dirs, not both')
1187
1188     if not scan:
1189         scan = src_scan.Scanner(basedir, drivers_additional, phase)
1190         scan.scan_drivers()
1191         do_process = True
1192     else:
1193         do_process = False
1194     plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
1195     plat.scan_dtb()
1196     plat.scan_tree(add_root=instantiate)
1197     plat.prepare_nodes()
1198     plat.scan_reg_sizes()
1199     plat.setup_output_dirs(output_dirs)
1200     plat.scan_structs()
1201     plat.scan_phandles()
1202     plat.process_nodes(instantiate)
1203     plat.read_aliases()
1204     plat.assign_seqs()
1205
1206     # Figure out what output files we plan to generate
1207     output_files = dict(OUTPUT_FILES_COMMON)
1208     if instantiate:
1209         output_files.update(OUTPUT_FILES_INST)
1210     else:
1211         output_files.update(OUTPUT_FILES_NOINST)
1212
1213     cmds = args[0].split(',')
1214     if 'all' in cmds:
1215         cmds = sorted(output_files.keys())
1216     for cmd in cmds:
1217         outfile = output_files.get(cmd)
1218         if not outfile:
1219             raise ValueError("Unknown command '%s': (use: %s)" %
1220                              (cmd, ', '.join(sorted(output_files.keys()))))
1221         plat.setup_output(outfile.ftype,
1222                           outfile.fname if output_dirs else output)
1223         plat.out_header(outfile)
1224         outfile.method(plat)
1225     plat.finish_output()
1226
1227     if not warning_disabled:
1228         scan.show_warnings()
1229     return plat