dtoc: Show driver warnings once at the end
[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     'u-boot,dm-pre-reloc',
39     'u-boot,dm-tpl',
40     'u-boot,dm-spl',
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     'gpios': '#gpio-cells',
66     'sandbox,emul': '#emul-cells',
67     }
68
69 class Ftype(IntEnum):
70     SOURCE, HEADER = range(2)
71
72
73 # This holds information about each type of output file dtoc can create
74 # type: Type of file (Ftype)
75 # fname: Filename excluding directory, e.g. 'dt-plat.c'
76 # hdr_comment: Comment explaining the purpose of the file
77 OutputFile = collections.namedtuple('OutputFile',
78                                     ['ftype', 'fname', 'method', 'hdr_comment'])
79
80 # This holds information about a property which includes phandles.
81 #
82 # max_args: integer: Maximum number or arguments that any phandle uses (int).
83 # args: Number of args for each phandle in the property. The total number of
84 #     phandles is len(args). This is a list of integers.
85 PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
86
87 # Holds a single phandle link, allowing a C struct value to be assigned to point
88 # to a device
89 #
90 # var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
91 # dev_name: Name of device to assign to (e.g. 'clock')
92 PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
93
94
95 def tab_to(num_tabs, line):
96     """Append tabs to a line of text to reach a tab stop.
97
98     Args:
99         num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
100         line (str): Line of text to append to
101
102     Returns:
103         str: line with the correct number of tabs appeneded. If the line already
104         extends past that tab stop then a single space is appended.
105     """
106     if len(line) >= num_tabs * 8:
107         return line + ' '
108     return line + '\t' * (num_tabs - len(line) // 8)
109
110 def get_value(ftype, value):
111     """Get a value as a C expression
112
113     For integers this returns a byte-swapped (little-endian) hex string
114     For bytes this returns a hex string, e.g. 0x12
115     For strings this returns a literal string enclosed in quotes
116     For booleans this return 'true'
117
118     Args:
119         ftype (fdt.Type): Data type (fdt_util)
120         value (bytes): Data value, as a string of bytes
121
122     Returns:
123         str: String representation of the value
124     """
125     if ftype == fdt.Type.INT:
126         val = '%#x' % fdt_util.fdt32_to_cpu(value)
127     elif ftype == fdt.Type.BYTE:
128         char = value[0]
129         val = '%#x' % (ord(char) if isinstance(char, str) else char)
130     elif ftype == fdt.Type.STRING:
131         # Handle evil ACPI backslashes by adding another backslash before them.
132         # So "\\_SB.GPO0" in the device tree effectively stays like that in C
133         val = '"%s"' % value.replace('\\', '\\\\')
134     elif ftype == fdt.Type.BOOL:
135         val = 'true'
136     else:  # ftype == fdt.Type.INT64:
137         val = '%#x' % value
138     return val
139
140
141 class DtbPlatdata():
142     """Provide a means to convert device tree binary data to platform data
143
144     The output of this process is C structures which can be used in space-
145     constrained encvironments where the ~3KB code overhead of device tree
146     code is not affordable.
147
148     Properties:
149         _scan: Scan object, for scanning and reporting on useful information
150             from the U-Boot source code
151         _fdt: Fdt object, referencing the device tree
152         _dtb_fname: Filename of the input device tree binary file
153         _valid_nodes_unsorted: A list of Node object with compatible strings,
154             ordered by devicetree node order
155         _valid_nodes: A list of Node object with compatible strings, ordered by
156             conv_name_to_c(node.name)
157         _include_disabled: true to include nodes marked status = "disabled"
158         _outfile: The current output file (sys.stdout or a real file)
159         _lines: Stashed list of output lines for outputting in the future
160         _dirname: Directory to hold output files, or None for none (all files
161             go to stdout)
162         _struct_data (dict): OrderedDict of dtplat structures to output
163             key (str): Node name, as a C identifier
164                     value: dict containing structure fields:
165                         key (str): Field name
166                         value: Prop object with field information
167         _basedir (str): Base directory of source tree
168         _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
169             the selected devices (see _valid_node), in alphabetical order
170         _instantiate: Instantiate devices so they don't need to be bound at
171             run-time
172     """
173     def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
174         self._scan = scan
175         self._fdt = None
176         self._dtb_fname = dtb_fname
177         self._valid_nodes = None
178         self._valid_nodes_unsorted = None
179         self._include_disabled = include_disabled
180         self._outfile = None
181         self._lines = []
182         self._dirnames = [None] * len(Ftype)
183         self._struct_data = collections.OrderedDict()
184         self._basedir = None
185         self._valid_uclasses = None
186         self._instantiate = instantiate
187
188     def setup_output_dirs(self, output_dirs):
189         """Set up the output directories
190
191         This should be done before setup_output() is called
192
193         Args:
194             output_dirs (tuple of str):
195                 Directory to use for C output files.
196                     Use None to write files relative current directory
197                 Directory to use for H output files.
198                     Defaults to the C output dir
199         """
200         def process_dir(ftype, dirname):
201             if dirname:
202                 os.makedirs(dirname, exist_ok=True)
203                 self._dirnames[ftype] = dirname
204
205         if output_dirs:
206             c_dirname = output_dirs[0]
207             h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
208             process_dir(Ftype.SOURCE, c_dirname)
209             process_dir(Ftype.HEADER, h_dirname)
210
211     def setup_output(self, ftype, fname):
212         """Set up the output destination
213
214         Once this is done, future calls to self.out() will output to this
215         file. The file used is as follows:
216
217         self._dirnames[ftype] is None: output to fname, or stdout if None
218         self._dirnames[ftype] is not None: output to fname in that directory
219
220         Calling this function multiple times will close the old file and open
221         the new one. If they are the same file, nothing happens and output will
222         continue to the same file.
223
224         Args:
225             ftype (str): Type of file to create ('c' or 'h')
226             fname (str): Filename to send output to. If there is a directory in
227                 self._dirnames for this file type, it will be put in that
228                 directory
229         """
230         dirname = self._dirnames[ftype]
231         if dirname:
232             pathname = os.path.join(dirname, fname)
233             if self._outfile:
234                 self._outfile.close()
235             self._outfile = open(pathname, 'w')
236         elif fname:
237             if not self._outfile:
238                 self._outfile = open(fname, 'w')
239         else:
240             self._outfile = sys.stdout
241
242     def finish_output(self):
243         """Finish outputing to a file
244
245         This closes the output file, if one is in use
246         """
247         if self._outfile != sys.stdout:
248             self._outfile.close()
249             self._outfile = None
250
251     def out(self, line):
252         """Output a string to the output file
253
254         Args:
255             line (str): String to output
256         """
257         self._outfile.write(line)
258
259     def buf(self, line):
260         """Buffer up a string to send later
261
262         Args:
263             line (str): String to add to our 'buffer' list
264         """
265         self._lines.append(line)
266
267     def get_buf(self):
268         """Get the contents of the output buffer, and clear it
269
270         Returns:
271             list(str): The output buffer, which is then cleared for future use
272         """
273         lines = self._lines
274         self._lines = []
275         return lines
276
277     def out_header(self, outfile):
278         """Output a message indicating that this is an auto-generated file
279
280         Args:
281             outfile: OutputFile describing the file being generated
282         """
283         self.out('''/*
284  * DO NOT MODIFY
285  *
286  * %s.
287  * This was generated by dtoc from a .dtb (device tree binary) file.
288  */
289
290 ''' % outfile.hdr_comment)
291
292     def get_phandle_argc(self, prop, node_name):
293         """Check if a node contains phandles
294
295         We have no reliable way of detecting whether a node uses a phandle
296         or not. As an interim measure, use a list of known property names.
297
298         Args:
299             prop (fdt.Prop): Prop object to check
300             node_name (str): Node name, only used for raising an error
301         Returns:
302             int or None: Number of argument cells is this is a phandle,
303                 else None
304         Raises:
305             ValueError: if the phandle cannot be parsed or the required property
306                 is not present
307         """
308         cells_prop = None
309         for name, cprop in PHANDLE_PROPS.items():
310             if prop.name.endswith(name):
311                 cells_prop = cprop
312         if cells_prop:
313             if not isinstance(prop.value, list):
314                 prop.value = [prop.value]
315             val = prop.value
316             i = 0
317
318             max_args = 0
319             args = []
320             while i < len(val):
321                 phandle = fdt_util.fdt32_to_cpu(val[i])
322                 # If we get to the end of the list, stop. This can happen
323                 # since some nodes have more phandles in the list than others,
324                 # but we allocate enough space for the largest list. So those
325                 # nodes with shorter lists end up with zeroes at the end.
326                 if not phandle:
327                     break
328                 target = self._fdt.phandle_to_node.get(phandle)
329                 if not target:
330                     raise ValueError("Cannot parse '%s' in node '%s'" %
331                                      (prop.name, node_name))
332                 cells = target.props.get(cells_prop)
333                 if not cells:
334                     raise ValueError("Node '%s' has no cells property" %
335                                      target.name)
336                 num_args = fdt_util.fdt32_to_cpu(cells.value)
337                 max_args = max(max_args, num_args)
338                 args.append(num_args)
339                 i += 1 + num_args
340             return PhandleInfo(max_args, args)
341         return None
342
343     def scan_dtb(self):
344         """Scan the device tree to obtain a tree of nodes and properties
345
346         Once this is done, self._fdt.GetRoot() can be called to obtain the
347         device tree root node, and progress from there.
348         """
349         self._fdt = fdt.FdtScan(self._dtb_fname)
350
351     def scan_node(self, node, valid_nodes):
352         """Scan a node and subnodes to build a tree of node and phandle info
353
354         This adds each subnode to self._valid_nodes if it is enabled and has a
355         compatible string.
356
357         Args:
358             node (Node): Node for scan for subnodes
359             valid_nodes (list of Node): List of Node objects to add to
360         """
361         for subnode in node.subnodes:
362             if 'compatible' in subnode.props:
363                 status = subnode.props.get('status')
364                 if (not self._include_disabled and not status or
365                         status.value != 'disabled'):
366                     valid_nodes.append(subnode)
367
368             # recurse to handle any subnodes
369             self.scan_node(subnode, valid_nodes)
370
371     def scan_tree(self, add_root):
372         """Scan the device tree for useful information
373
374         This fills in the following properties:
375             _valid_nodes_unsorted: A list of nodes we wish to consider include
376                 in the platform data (in devicetree node order)
377             _valid_nodes: Sorted version of _valid_nodes_unsorted
378
379         Args:
380             add_root: True to add the root node also (which wouldn't normally
381                 be added as it may not have a compatible string)
382         """
383         root = self._fdt.GetRoot()
384         valid_nodes = []
385         if add_root:
386             valid_nodes.append(root)
387         self.scan_node(root, valid_nodes)
388         self._valid_nodes_unsorted = valid_nodes
389         self._valid_nodes = sorted(valid_nodes,
390                                    key=lambda x: conv_name_to_c(x.name))
391
392     def prepare_nodes(self):
393         """Add extra properties to the nodes we are using
394
395         The following properties are added for use by dtoc:
396             idx: Index number of this node (0=first, etc.)
397             struct_name: Name of the struct dtd used by this node
398             var_name: C name for this node
399             child_devs: List of child devices for this node, each a None
400             child_refs: Dict of references for each child:
401                 key: Position in child list (-1=head, 0=first, 1=second, ...
402                                              n-1=last, n=head)
403             seq: Sequence number of the device (unique within its uclass), or
404                 -1 not not known yet
405             dev_ref: Reference to this device, e.g. 'DM_DEVICE_REF(serial)'
406             driver: Driver record for this node, or None if not known
407             uclass: Uclass record for this node, or None if not known
408             uclass_seq: Position of this device within the uclass list (0=first,
409                 n-1=last)
410             parent_seq: Position of this device within it siblings (0=first,
411                 n-1=last)
412             parent_driver: Driver record of the node's parent, or None if none.
413                 We don't use node.parent.driver since node.parent may not be in
414                 the list of valid nodes
415         """
416         for idx, node in enumerate(self._valid_nodes):
417             node.idx = idx
418             node.struct_name, _ = self._scan.get_normalized_compat_name(node)
419             node.var_name = conv_name_to_c(node.name)
420             node.child_devs = []
421             node.child_refs = {}
422             node.seq = -1
423             node.dev_ref = None
424             node.driver = None
425             node.uclass = None
426             node.uclass_seq = None
427             node.parent_seq = None
428             node.parent_driver = None
429
430     @staticmethod
431     def get_num_cells(node):
432         """Get the number of cells in addresses and sizes for this node
433
434         Args:
435             node (fdt.None): Node to check
436
437         Returns:
438             Tuple:
439                 Number of address cells for this node
440                 Number of size cells for this node
441         """
442         parent = node.parent
443         num_addr, num_size = 2, 2
444         if parent:
445             addr_prop = parent.props.get('#address-cells')
446             size_prop = parent.props.get('#size-cells')
447             if addr_prop:
448                 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
449             if size_prop:
450                 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
451         return num_addr, num_size
452
453     def scan_reg_sizes(self):
454         """Scan for 64-bit 'reg' properties and update the values
455
456         This finds 'reg' properties with 64-bit data and converts the value to
457         an array of 64-values. This allows it to be output in a way that the
458         C code can read.
459         """
460         for node in self._valid_nodes:
461             reg = node.props.get('reg')
462             if not reg:
463                 continue
464             num_addr, num_size = self.get_num_cells(node)
465             total = num_addr + num_size
466
467             if reg.type != fdt.Type.INT:
468                 raise ValueError("Node '%s' reg property is not an int" %
469                                  node.name)
470             if len(reg.value) % total:
471                 raise ValueError(
472                     "Node '%s' reg property has %d cells "
473                     'which is not a multiple of na + ns = %d + %d)' %
474                     (node.name, len(reg.value), num_addr, num_size))
475             reg.num_addr = num_addr
476             reg.num_size = num_size
477             if num_addr != 1 or num_size != 1:
478                 reg.type = fdt.Type.INT64
479                 i = 0
480                 new_value = []
481                 val = reg.value
482                 if not isinstance(val, list):
483                     val = [val]
484                 while i < len(val):
485                     addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
486                     i += num_addr
487                     size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
488                     i += num_size
489                     new_value += [addr, size]
490                 reg.value = new_value
491
492     def scan_structs(self):
493         """Scan the device tree building up the C structures we will use.
494
495         Build a dict keyed by C struct name containing a dict of Prop
496         object for each struct field (keyed by property name). Where the
497         same struct appears multiple times, try to use the 'widest'
498         property, i.e. the one with a type which can express all others.
499
500         Once the widest property is determined, all other properties are
501         updated to match that width.
502
503         The results are written to self._struct_data
504         """
505         structs = self._struct_data
506         for node in self._valid_nodes:
507             fields = {}
508
509             # Get a list of all the valid properties in this node.
510             for name, prop in node.props.items():
511                 if name not in PROP_IGNORE_LIST and name[0] != '#':
512                     fields[name] = copy.deepcopy(prop)
513
514             # If we've seen this struct_name before, update the existing struct
515             if node.struct_name in structs:
516                 struct = structs[node.struct_name]
517                 for name, prop in fields.items():
518                     oldprop = struct.get(name)
519                     if oldprop:
520                         oldprop.Widen(prop)
521                     else:
522                         struct[name] = prop
523
524             # Otherwise store this as a new struct.
525             else:
526                 structs[node.struct_name] = fields
527
528         for node in self._valid_nodes:
529             struct = structs[node.struct_name]
530             for name, prop in node.props.items():
531                 if name not in PROP_IGNORE_LIST and name[0] != '#':
532                     prop.Widen(struct[name])
533
534     def scan_phandles(self):
535         """Figure out what phandles each node uses
536
537         We need to be careful when outputing nodes that use phandles since
538         they must come after the declaration of the phandles in the C file.
539         Otherwise we get a compiler error since the phandle struct is not yet
540         declared.
541
542         This function adds to each node a list of phandle nodes that the node
543         depends on. This allows us to output things in the right order.
544         """
545         for node in self._valid_nodes:
546             node.phandles = set()
547             for pname, prop in node.props.items():
548                 if pname in PROP_IGNORE_LIST or pname[0] == '#':
549                     continue
550                 info = self.get_phandle_argc(prop, node.name)
551                 if info:
552                     # Process the list as pairs of (phandle, id)
553                     pos = 0
554                     for args in info.args:
555                         phandle_cell = prop.value[pos]
556                         phandle = fdt_util.fdt32_to_cpu(phandle_cell)
557                         target_node = self._fdt.phandle_to_node[phandle]
558                         node.phandles.add(target_node)
559                         pos += 1 + args
560
561
562     def generate_structs(self):
563         """Generate struct defintions for the platform data
564
565         This writes out the body of a header file consisting of structure
566         definitions for node in self._valid_nodes. See the documentation in
567         doc/driver-model/of-plat.rst for more information.
568         """
569         structs = self._struct_data
570         self.out('#include <stdbool.h>\n')
571         self.out('#include <linux/libfdt.h>\n')
572
573         # Output the struct definition
574         for name in sorted(structs):
575             self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
576             for pname in sorted(structs[name]):
577                 prop = structs[name][pname]
578                 info = self.get_phandle_argc(prop, structs[name])
579                 if info:
580                     # For phandles, include a reference to the target
581                     struct_name = 'struct phandle_%d_arg' % info.max_args
582                     self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
583                                              conv_name_to_c(prop.name),
584                                              len(info.args)))
585                 else:
586                     ptype = TYPE_NAMES[prop.type]
587                     self.out('\t%s%s' % (tab_to(2, ptype),
588                                          conv_name_to_c(prop.name)))
589                     if isinstance(prop.value, list):
590                         self.out('[%d]' % len(prop.value))
591                 self.out(';\n')
592             self.out('};\n')
593
594     def _output_list(self, node, prop):
595         """Output the C code for a devicetree property that holds a list
596
597         Args:
598             node (fdt.Node): Node to output
599             prop (fdt.Prop): Prop to output
600         """
601         self.buf('{')
602         vals = []
603         # For phandles, output a reference to the platform data
604         # of the target node.
605         info = self.get_phandle_argc(prop, node.name)
606         if info:
607             # Process the list as pairs of (phandle, id)
608             pos = 0
609             for args in info.args:
610                 phandle_cell = prop.value[pos]
611                 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
612                 target_node = self._fdt.phandle_to_node[phandle]
613                 arg_values = []
614                 for i in range(args):
615                     arg_values.append(
616                         str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
617                 pos += 1 + args
618                 vals.append('\t{%d, {%s}}' % (target_node.idx,
619                                               ', '.join(arg_values)))
620             for val in vals:
621                 self.buf('\n\t\t%s,' % val)
622         else:
623             for val in prop.value:
624                 vals.append(get_value(prop.type, val))
625
626             # Put 8 values per line to avoid very long lines.
627             for i in range(0, len(vals), 8):
628                 if i:
629                     self.buf(',\n\t\t')
630                 self.buf(', '.join(vals[i:i + 8]))
631         self.buf('}')
632
633     def _declare_device(self, node):
634         """Add a device declaration to the output
635
636         This declares a U_BOOT_DRVINFO() for the device being processed
637
638         Args:
639             node: Node to process
640         """
641         self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
642         self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
643         self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
644         self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
645                  (VAL_PREFIX, node.var_name))
646         idx = -1
647         if node.parent and node.parent in self._valid_nodes:
648             idx = node.parent.idx
649         self.buf('\t.parent_idx\t= %d,\n' % idx)
650         self.buf('};\n')
651         self.buf('\n')
652
653     def prep_priv(self, struc, name, suffix, section='.priv_data'):
654         if not struc:
655             return None
656         var_name = '_%s%s' % (name, suffix)
657         hdr = self._scan._structs.get(struc)
658         if hdr:
659             self.buf('#include <%s>\n' % hdr.fname)
660         else:
661             print('Warning: Cannot find header file for struct %s' % struc)
662         attr = '__attribute__ ((section ("%s")))' % section
663         return var_name, struc, attr
664
665     def alloc_priv(self, info, name, extra, suffix='_priv'):
666         result = self.prep_priv(info, name, suffix)
667         if not result:
668             return None
669         var_name, struc, section = result
670         self.buf('u8 %s_%s[sizeof(struct %s)]\n\t%s;\n' %
671                  (var_name, extra, struc.strip(), section))
672         return '%s_%s' % (var_name, extra)
673
674     def alloc_plat(self, info, name, extra, node):
675         result = self.prep_priv(info, name, '_plat')
676         if not result:
677             return None
678         var_name, struc, section = result
679         self.buf('struct %s %s\n\t%s_%s = {\n' %
680                  (struc.strip(), section, var_name, extra))
681         self.buf('\t.dtplat = {\n')
682         for pname in sorted(node.props):
683             self._output_prop(node, node.props[pname], 2)
684         self.buf('\t},\n')
685         self.buf('};\n')
686         return '&%s_%s' % (var_name, extra)
687
688     def _declare_device_inst(self, node, parent_driver):
689         """Add a device instance declaration to the output
690
691         This declares a DM_DEVICE_INST() for the device being processed
692
693         Args:
694             node: Node to output
695         """
696         driver = node.driver
697         uclass = node.uclass
698         self.buf('\n')
699         num_lines = len(self._lines)
700         plat_name = self.alloc_plat(driver.plat, driver.name, node.var_name,
701                                     node)
702         priv_name = self.alloc_priv(driver.priv, driver.name, node.var_name)
703         parent_plat_name = None
704         parent_priv_name = None
705         if parent_driver:
706             # TODO: deal with uclass providing these values
707             parent_plat_name = self.alloc_priv(
708                 parent_driver.child_plat, driver.name, node.var_name,
709                 '_parent_plat')
710             parent_priv_name = self.alloc_priv(
711                 parent_driver.child_priv, driver.name, node.var_name,
712                 '_parent_priv')
713         uclass_plat_name = self.alloc_priv(
714             uclass.per_dev_plat, driver.name + '_uc', node.var_name, 'plat')
715         uclass_priv_name = self.alloc_priv(uclass.per_dev_priv,
716                                            driver.name + '_uc', node.var_name)
717         for hdr in driver.headers:
718             self.buf('#include %s\n' % hdr)
719
720         # Add a blank line if we emitted any stuff above, for readability
721         if num_lines != len(self._lines):
722             self.buf('\n')
723
724         self.buf('DM_DEVICE_INST(%s) = {\n' % node.var_name)
725         self.buf('\t.driver\t\t= DM_DRIVER_REF(%s),\n' % node.struct_name)
726         self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
727         if plat_name:
728             self.buf('\t.plat_\t\t= %s,\n' % plat_name)
729         else:
730             self.buf('\t.plat_\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
731         if parent_plat_name:
732             self.buf('\t.parent_plat_\t= %s,\n' % parent_plat_name)
733         if uclass_plat_name:
734             self.buf('\t.uclass_plat_\t= %s,\n' % uclass_plat_name)
735         driver_date = None
736
737         if node != self._fdt.GetRoot():
738             compat_list = node.props['compatible'].value
739             if not isinstance(compat_list, list):
740                 compat_list = [compat_list]
741             for compat in compat_list:
742                 driver_data = driver.compat.get(compat)
743                 if driver_data:
744                     self.buf('\t.driver_data\t= %s,\n' % driver_data)
745                     break
746
747         if node.parent and node.parent.parent:
748             self.buf('\t.parent\t\t= DM_DEVICE_REF(%s),\n' %
749                      node.parent.var_name)
750         if priv_name:
751             self.buf('\t.priv_\t\t= %s,\n' % priv_name)
752         self.buf('\t.uclass\t\t= DM_UCLASS_REF(%s),\n' % uclass.name)
753
754         if uclass_priv_name:
755             self.buf('\t.uclass_priv_ = %s,\n' % uclass_priv_name)
756         if parent_priv_name:
757             self.buf('\t.parent_priv_\t= %s,\n' % parent_priv_name)
758         self.list_node('uclass_node', uclass.node_refs, node.uclass_seq)
759         self.list_head('child_head', 'sibling_node', node.child_devs, node.var_name)
760         if node.parent in self._valid_nodes:
761             self.list_node('sibling_node', node.parent.child_refs,
762                            node.parent_seq)
763         # flags is left as 0
764
765         self.buf('\t.seq_ = %d,\n' % node.seq)
766
767         self.buf('};\n')
768         self.buf('\n')
769         return parent_plat_name
770
771     def _output_prop(self, node, prop, tabs=1):
772         """Output a line containing the value of a struct member
773
774         Args:
775             node (Node): Node being output
776             prop (Prop): Prop object to output
777         """
778         if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
779             return
780         member_name = conv_name_to_c(prop.name)
781         self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
782
783         # Special handling for lists
784         if isinstance(prop.value, list):
785             self._output_list(node, prop)
786         else:
787             self.buf(get_value(prop.type, prop.value))
788         self.buf(',\n')
789
790     def _output_values(self, node):
791         """Output the definition of a device's struct values
792
793         Args:
794             node (Node): Node to output
795         """
796         self.buf('static struct %s%s %s%s = {\n' %
797                  (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
798         for pname in sorted(node.props):
799             self._output_prop(node, node.props[pname])
800         self.buf('};\n')
801
802     def list_head(self, head_member, node_member, node_refs, var_name):
803         self.buf('\t.%s\t= {\n' % head_member)
804         if node_refs:
805             last = node_refs[-1].dev_ref
806             first = node_refs[0].dev_ref
807             member = node_member
808         else:
809             last = 'DM_DEVICE_REF(%s)' % var_name
810             first = last
811             member = head_member
812         self.buf('\t\t.prev = &%s->%s,\n' % (last, member))
813         self.buf('\t\t.next = &%s->%s,\n' % (first, member))
814         self.buf('\t},\n')
815
816     def list_node(self, member, node_refs, seq):
817         self.buf('\t.%s\t= {\n' % member)
818         self.buf('\t\t.prev = %s,\n' % node_refs[seq - 1])
819         self.buf('\t\t.next = %s,\n' % node_refs[seq + 1])
820         self.buf('\t},\n')
821
822     def generate_uclasses(self):
823         if not self.check_instantiate(True):
824             return
825         self.out('\n')
826         self.out('#include <common.h>\n')
827         self.out('#include <dm.h>\n')
828         self.out('#include <dt-structs.h>\n')
829         self.out('\n')
830         self.buf('/*\n')
831         self.buf(
832             " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
833         uclass_list = self._valid_uclasses
834         for seq, uclass in enumerate(uclass_list):
835             self.buf(' * %3d: %s\n' % (seq, uclass.name))
836         self.buf(' *\n')
837         self.buf(' * Sequence numbers allocated in each uclass:\n')
838         for uclass in uclass_list:
839             if uclass.alias_num_to_node:
840                 self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
841                 for seq, node in uclass.alias_num_to_node.items():
842                     self.buf(' *    %d: %s\n' % (seq, node.path))
843         self.buf(' */\n')
844
845         uclass_node = {}
846         for seq, uclass in enumerate(uclass_list):
847             uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
848                                 uclass.name)
849         uclass_node[-1] = '&uclass_head'
850         uclass_node[len(uclass_list)] = '&uclass_head'
851         self.buf('\n')
852         self.buf('struct list_head %s = {\n' % 'uclass_head')
853         self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
854         self.buf('\t.next = %s,\n' % uclass_node[0])
855         self.buf('};\n')
856         self.buf('\n')
857
858         for seq, uclass in enumerate(uclass_list):
859             uc_drv = self._scan._uclass.get(uclass.uclass_id)
860
861             priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
862
863             self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
864             if priv_name:
865                 self.buf('\t.priv_\t\t= %s,\n' % priv_name)
866             self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
867             self.list_node('sibling_node', uclass_node, seq)
868             self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
869             self.buf('};\n')
870             self.buf('\n')
871         self.out(''.join(self.get_buf()))
872
873     def read_aliases(self):
874         """Read the aliases and attach the information to self._alias
875
876         Raises:
877             ValueError: The alias path is not found
878         """
879         alias_node = self._fdt.GetNode('/aliases')
880         if not alias_node:
881             return
882         re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
883         for prop in alias_node.props.values():
884             m_alias = re_num.match(prop.name)
885             if not m_alias:
886                 raise ValueError("Cannot decode alias '%s'" % prop.name)
887             name, num = m_alias.groups()
888             node = self._fdt.GetNode(prop.value)
889             result = self._scan.add_uclass_alias(name, num, node)
890             if result is None:
891                 raise ValueError("Alias '%s' path '%s' not found" %
892                                  (prop.name, prop.value))
893             elif result is False:
894                 print("Could not find uclass for alias '%s'" % prop.name)
895
896     def generate_decl(self):
897         nodes_to_output = list(self._valid_nodes)
898
899         self.buf('#include <dm/device-internal.h>\n')
900         self.buf('#include <dm/uclass-internal.h>\n')
901         self.buf('\n')
902         self.buf(
903             '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
904         for node in nodes_to_output:
905             self.buf('extern U_BOOT_DRIVER(%s);\n' % node.struct_name);
906         self.buf('\n')
907
908         if self._instantiate:
909             self.buf(
910                 '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
911             for node in nodes_to_output:
912                 self.buf('extern DM_DEVICE_INST(%s);\n' % node.var_name)
913             self.buf('\n')
914
915         uclass_list = self._valid_uclasses
916
917         self.buf(
918             '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
919         for uclass in uclass_list:
920             self.buf('extern UCLASS_DRIVER(%s);\n' % uclass.name)
921
922         if self._instantiate:
923             self.buf('\n')
924             self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
925             for uclass in uclass_list:
926                 self.buf('extern DM_UCLASS_INST(%s);\n' % uclass.name)
927         self.out(''.join(self.get_buf()))
928
929     def assign_seqs(self):
930         """Assign a sequence number to each node"""
931         for node in self._valid_nodes_unsorted:
932             seq = self._scan.assign_seq(node)
933             if seq is not None:
934                 node.seq = seq
935
936     def process_nodes(self, need_drivers):
937         nodes_to_output = list(self._valid_nodes)
938
939         # Figure out which drivers we actually use
940         self._scan.mark_used(nodes_to_output)
941
942         for node in nodes_to_output:
943             node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
944             driver = self._scan.get_driver(node.struct_name)
945             if not driver:
946                 if not need_drivers:
947                     continue
948                 raise ValueError("Cannot parse/find driver for '%s'" %
949                                  node.struct_name)
950             node.driver = driver
951             uclass = self._scan._uclass.get(driver.uclass_id)
952             if not uclass:
953                 raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
954                                 (driver.uclass_id, node.struct_name))
955             node.uclass = uclass
956             node.uclass_seq = len(node.uclass.devs)
957             node.uclass.devs.append(node)
958             uclass.node_refs[node.uclass_seq] = \
959                 '&%s->uclass_node' % node.dev_ref
960
961             parent_driver = None
962             if node.parent in self._valid_nodes:
963                 parent_driver = self._scan.get_driver(node.parent.struct_name)
964                 if not parent_driver:
965                     if not need_drivers:
966                         continue
967                     raise ValueError(
968                         "Cannot parse/find parent driver '%s' for '%s'" %
969                         (node.parent.struct_name, node.struct_name))
970                 node.parent_seq = len(node.parent.child_devs)
971                 node.parent.child_devs.append(node)
972                 node.parent.child_refs[node.parent_seq] = \
973                     '&%s->sibling_node' % node.dev_ref
974                 node.parent_driver = parent_driver
975
976         for node in nodes_to_output:
977             ref = '&%s->child_head' % node.dev_ref
978             node.child_refs[-1] = ref
979             node.child_refs[len(node.child_devs)] = ref
980
981         uclass_set = set()
982         for driver in self._scan._drivers.values():
983             if driver.used and driver.uclass:
984                 uclass_set.add(driver.uclass)
985         self._valid_uclasses = sorted(list(uclass_set),
986                                       key=lambda uc: uc.uclass_id)
987
988         for seq, uclass in enumerate(uclass_set):
989             ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
990             uclass.node_refs[-1] = ref
991             uclass.node_refs[len(uclass.devs)] = ref
992
993     def output_node_plat(self, node):
994         """Output the C code for a node
995
996         Args:
997             node (fdt.Node): node to output
998         """
999         driver = node.driver
1000         parent_driver = node.parent_driver
1001
1002         line1 = 'Node %s index %d' % (node.path, node.idx)
1003         if driver:
1004             self.buf('/*\n')
1005             self.buf(' * %s\n' % line1)
1006             self.buf(' * driver %s parent %s\n' % (driver.name,
1007                 parent_driver.name if parent_driver else 'None'))
1008             self.buf(' */\n')
1009         else:
1010             self.buf('/* %s */\n' % line1)
1011
1012         self._output_values(node)
1013         self._declare_device(node)
1014
1015         self.out(''.join(self.get_buf()))
1016
1017     def output_node_instance(self, node):
1018         """Output the C code for a node
1019
1020         Args:
1021             node (fdt.Node): node to output
1022         """
1023         parent_driver = node.parent_driver
1024
1025         self.buf('/*\n')
1026         self.buf(' * Node %s index %d\n' % (node.path, node.idx))
1027         self.buf(' * driver %s parent %s\n' % (node.driver.name,
1028                  parent_driver.name if parent_driver else 'None'))
1029         self.buf('*/\n')
1030
1031         if not node.driver.plat:
1032             self._output_values(node)
1033         self._declare_device_inst(node, parent_driver)
1034
1035         self.out(''.join(self.get_buf()))
1036
1037     def check_instantiate(self, require):
1038         """Check if self._instantiate is set to the required value
1039
1040         If not, this outputs a message into the current file
1041
1042         Args:
1043             require: True to require --instantiate, False to require that it not
1044                 be enabled
1045         """
1046         if require != self._instantiate:
1047             self.out(
1048                 '/* This file is not used: --instantiate was %senabled */\n' %
1049                 ('not ' if require else ''))
1050             return False
1051         return True
1052
1053     def generate_plat(self):
1054         """Generate device defintions for the platform data
1055
1056         This writes out C platform data initialisation data and
1057         U_BOOT_DRVINFO() declarations for each valid node. Where a node has
1058         multiple compatible strings, a #define is used to make them equivalent.
1059
1060         See the documentation in doc/driver-model/of-plat.rst for more
1061         information.
1062         """
1063         if not self.check_instantiate(False):
1064             return
1065         self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
1066         self.out('#define DT_PLAT_C\n')
1067         self.out('\n')
1068         self.out('#include <common.h>\n')
1069         self.out('#include <dm.h>\n')
1070         self.out('#include <dt-structs.h>\n')
1071         self.out('\n')
1072
1073         if self._valid_nodes:
1074             self.out('/*\n')
1075             self.out(
1076                 " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
1077             self.out(' *\n')
1078             self.out(' * idx  %-20s %-s\n' % ('driver_info', 'driver'))
1079             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1080             for node in self._valid_nodes:
1081                 self.out(' * %3d: %-20s %-s\n' %
1082                         (node.idx, node.var_name, node.struct_name))
1083             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1084             self.out(' */\n')
1085             self.out('\n')
1086
1087             for node in self._valid_nodes:
1088                 self.output_node_plat(node)
1089
1090         self.out(''.join(self.get_buf()))
1091
1092     def generate_device(self):
1093         """Generate device instances
1094
1095         This writes out DM_DEVICE_INST() records for each device in the
1096         build.
1097
1098         See the documentation in doc/driver-model/of-plat.rst for more
1099         information.
1100         """
1101         if not self.check_instantiate(True):
1102             return
1103         self.out('#include <common.h>\n')
1104         self.out('#include <dm.h>\n')
1105         self.out('#include <dt-structs.h>\n')
1106         self.out('\n')
1107
1108         if self._valid_nodes:
1109             self.out('/*\n')
1110             self.out(
1111                 " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
1112             self.out(' *\n')
1113             self.out(' * idx  %-20s %-s\n' % ('udevice', 'driver'))
1114             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1115             for node in self._valid_nodes:
1116                 self.out(' * %3d: %-20s %-s\n' %
1117                         (node.idx, node.var_name, node.struct_name))
1118             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1119             self.out(' */\n')
1120             self.out('\n')
1121
1122             for node in self._valid_nodes:
1123                 self.output_node_instance(node)
1124
1125         self.out(''.join(self.get_buf()))
1126
1127
1128 # Types of output file we understand
1129 # key: Command used to generate this file
1130 # value: OutputFile for this command
1131 OUTPUT_FILES_COMMON = {
1132     'decl':
1133         OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
1134                    'Declares externs for all device/uclass instances'),
1135     'struct':
1136         OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
1137                    DtbPlatdata.generate_structs,
1138                    'Defines the structs used to hold devicetree data'),
1139     }
1140
1141 # File generated without instantiate
1142 OUTPUT_FILES_NOINST = {
1143     'platdata':
1144         OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
1145                    'Declares the U_BOOT_DRIVER() records and platform data'),
1146     }
1147
1148 # File generated with instantiate
1149 OUTPUT_FILES_INST = {
1150     'device':
1151         OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
1152                    'Declares the DM_DEVICE_INST() records'),
1153     'uclass':
1154         OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
1155                    'Declares the uclass instances (struct uclass)'),
1156     }
1157
1158
1159 def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
1160               instantiate, warning_disabled=False, drivers_additional=None,
1161               basedir=None, scan=None):
1162     """Run all the steps of the dtoc tool
1163
1164     Args:
1165         args (list): List of non-option arguments provided to the problem
1166         dtb_file (str): Filename of dtb file to process
1167         include_disabled (bool): True to include disabled nodes
1168         output (str): Name of output file (None for stdout)
1169         output_dirs (tuple of str):
1170             Directory to put C output files
1171             Directory to put H output files
1172         phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
1173              or 'tpl'. None if not known
1174         instantiate: Instantiate devices so they don't need to be bound at
1175             run-time
1176         warning_disabled (bool): True to avoid showing warnings about missing
1177             drivers
1178         drivers_additional (list): List of additional drivers to use during
1179             scanning
1180         basedir (str): Base directory of U-Boot source code. Defaults to the
1181             grandparent of this file's directory
1182         scan (src_src.Scanner): Scanner from a previous run. This can help speed
1183             up tests. Use None for normal operation
1184
1185     Returns:
1186         DtbPlatdata object
1187
1188     Raises:
1189         ValueError: if args has no command, or an unknown command
1190     """
1191     if not args:
1192         raise ValueError('Please specify a command: struct, platdata, all')
1193     if output and output_dirs and any(output_dirs):
1194         raise ValueError('Must specify either output or output_dirs, not both')
1195
1196     if not scan:
1197         scan = src_scan.Scanner(basedir, drivers_additional, phase)
1198         scan.scan_drivers()
1199         do_process = True
1200     else:
1201         do_process = False
1202     plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
1203     plat.scan_dtb()
1204     plat.scan_tree(add_root=instantiate)
1205     plat.prepare_nodes()
1206     plat.scan_reg_sizes()
1207     plat.setup_output_dirs(output_dirs)
1208     plat.scan_structs()
1209     plat.scan_phandles()
1210     plat.process_nodes(instantiate)
1211     plat.read_aliases()
1212     plat.assign_seqs()
1213
1214     # Figure out what output files we plan to generate
1215     output_files = OUTPUT_FILES_COMMON
1216     if instantiate:
1217         output_files.update(OUTPUT_FILES_INST)
1218     else:
1219         output_files.update(OUTPUT_FILES_NOINST)
1220
1221     cmds = args[0].split(',')
1222     if 'all' in cmds:
1223         cmds = sorted(output_files.keys())
1224     for cmd in cmds:
1225         outfile = output_files.get(cmd)
1226         if not outfile:
1227             raise ValueError("Unknown command '%s': (use: %s)" %
1228                              (cmd, ', '.join(sorted(output_files.keys()))))
1229         plat.setup_output(outfile.ftype,
1230                           outfile.fname if output_dirs else output)
1231         plat.out_header(outfile)
1232         outfile.method(plat)
1233     plat.finish_output()
1234
1235     if not warning_disabled:
1236         scan.show_warnings()
1237     return plat