Merge https://source.denx.de/u-boot/custodians/u-boot-usb
[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         if parent and not parent.props:
444             raise ValueError("Parent node '%s' has no properties - do you need u-boot,dm-spl or similar?" %
445                              parent.path)
446         num_addr, num_size = 2, 2
447         if parent:
448             addr_prop = parent.props.get('#address-cells')
449             size_prop = parent.props.get('#size-cells')
450             if addr_prop:
451                 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
452             if size_prop:
453                 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
454         return num_addr, num_size
455
456     def scan_reg_sizes(self):
457         """Scan for 64-bit 'reg' properties and update the values
458
459         This finds 'reg' properties with 64-bit data and converts the value to
460         an array of 64-values. This allows it to be output in a way that the
461         C code can read.
462         """
463         for node in self._valid_nodes:
464             reg = node.props.get('reg')
465             if not reg:
466                 continue
467             num_addr, num_size = self.get_num_cells(node)
468             total = num_addr + num_size
469
470             if reg.type != fdt.Type.INT:
471                 raise ValueError("Node '%s' reg property is not an int" %
472                                  node.name)
473             if not isinstance(reg.value, list):
474                 reg.value = [reg.value]
475             if len(reg.value) % total:
476                 raise ValueError(
477                     "Node '%s' (parent '%s') reg property has %d cells "
478                     'which is not a multiple of na + ns = %d + %d)' %
479                     (node.name, node.parent.name, len(reg.value), num_addr,
480                      num_size))
481             reg.num_addr = num_addr
482             reg.num_size = num_size
483             if num_addr > 1 or num_size > 1:
484                 reg.type = fdt.Type.INT64
485                 i = 0
486                 new_value = []
487                 val = reg.value
488                 while i < len(val):
489                     addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
490                     i += num_addr
491                     size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
492                     i += num_size
493                     new_value += [addr, size]
494                 reg.value = new_value
495
496     def scan_structs(self):
497         """Scan the device tree building up the C structures we will use.
498
499         Build a dict keyed by C struct name containing a dict of Prop
500         object for each struct field (keyed by property name). Where the
501         same struct appears multiple times, try to use the 'widest'
502         property, i.e. the one with a type which can express all others.
503
504         Once the widest property is determined, all other properties are
505         updated to match that width.
506
507         The results are written to self._struct_data
508         """
509         structs = self._struct_data
510         for node in self._valid_nodes:
511             fields = {}
512
513             # Get a list of all the valid properties in this node.
514             for name, prop in node.props.items():
515                 if name not in PROP_IGNORE_LIST and name[0] != '#':
516                     fields[name] = copy.deepcopy(prop)
517
518             # If we've seen this struct_name before, update the existing struct
519             if node.struct_name in structs:
520                 struct = structs[node.struct_name]
521                 for name, prop in fields.items():
522                     oldprop = struct.get(name)
523                     if oldprop:
524                         oldprop.Widen(prop)
525                     else:
526                         struct[name] = prop
527
528             # Otherwise store this as a new struct.
529             else:
530                 structs[node.struct_name] = fields
531
532         for node in self._valid_nodes:
533             struct = structs[node.struct_name]
534             for name, prop in node.props.items():
535                 if name not in PROP_IGNORE_LIST and name[0] != '#':
536                     prop.Widen(struct[name])
537
538     def scan_phandles(self):
539         """Figure out what phandles each node uses
540
541         We need to be careful when outputing nodes that use phandles since
542         they must come after the declaration of the phandles in the C file.
543         Otherwise we get a compiler error since the phandle struct is not yet
544         declared.
545
546         This function adds to each node a list of phandle nodes that the node
547         depends on. This allows us to output things in the right order.
548         """
549         for node in self._valid_nodes:
550             node.phandles = set()
551             for pname, prop in node.props.items():
552                 if pname in PROP_IGNORE_LIST or pname[0] == '#':
553                     continue
554                 info = self.get_phandle_argc(prop, node.name)
555                 if info:
556                     # Process the list as pairs of (phandle, id)
557                     pos = 0
558                     for args in info.args:
559                         phandle_cell = prop.value[pos]
560                         phandle = fdt_util.fdt32_to_cpu(phandle_cell)
561                         target_node = self._fdt.phandle_to_node[phandle]
562                         node.phandles.add(target_node)
563                         pos += 1 + args
564
565
566     def generate_structs(self):
567         """Generate struct defintions for the platform data
568
569         This writes out the body of a header file consisting of structure
570         definitions for node in self._valid_nodes. See the documentation in
571         doc/driver-model/of-plat.rst for more information.
572         """
573         structs = self._struct_data
574         self.out('#include <stdbool.h>\n')
575         self.out('#include <linux/libfdt.h>\n')
576
577         # Output the struct definition
578         for name in sorted(structs):
579             self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
580             for pname in sorted(structs[name]):
581                 prop = structs[name][pname]
582                 info = self.get_phandle_argc(prop, structs[name])
583                 if info:
584                     # For phandles, include a reference to the target
585                     struct_name = 'struct phandle_%d_arg' % info.max_args
586                     self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
587                                              conv_name_to_c(prop.name),
588                                              len(info.args)))
589                 else:
590                     ptype = TYPE_NAMES[prop.type]
591                     self.out('\t%s%s' % (tab_to(2, ptype),
592                                          conv_name_to_c(prop.name)))
593                     if isinstance(prop.value, list):
594                         self.out('[%d]' % len(prop.value))
595                 self.out(';\n')
596             self.out('};\n')
597
598     def _output_list(self, node, prop):
599         """Output the C code for a devicetree property that holds a list
600
601         Args:
602             node (fdt.Node): Node to output
603             prop (fdt.Prop): Prop to output
604         """
605         self.buf('{')
606         vals = []
607         # For phandles, output a reference to the platform data
608         # of the target node.
609         info = self.get_phandle_argc(prop, node.name)
610         if info:
611             # Process the list as pairs of (phandle, id)
612             pos = 0
613             for args in info.args:
614                 phandle_cell = prop.value[pos]
615                 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
616                 target_node = self._fdt.phandle_to_node[phandle]
617                 arg_values = []
618                 for i in range(args):
619                     arg_values.append(
620                         str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
621                 pos += 1 + args
622                 vals.append('\t{%d, {%s}}' % (target_node.idx,
623                                               ', '.join(arg_values)))
624             for val in vals:
625                 self.buf('\n\t\t%s,' % val)
626         else:
627             for val in prop.value:
628                 vals.append(get_value(prop.type, val))
629
630             # Put 8 values per line to avoid very long lines.
631             for i in range(0, len(vals), 8):
632                 if i:
633                     self.buf(',\n\t\t')
634                 self.buf(', '.join(vals[i:i + 8]))
635         self.buf('}')
636
637     def _declare_device(self, node):
638         """Add a device declaration to the output
639
640         This declares a U_BOOT_DRVINFO() for the device being processed
641
642         Args:
643             node: Node to process
644         """
645         self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
646         self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
647         self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
648         self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
649                  (VAL_PREFIX, node.var_name))
650         idx = -1
651         if node.parent and node.parent in self._valid_nodes:
652             idx = node.parent.idx
653         self.buf('\t.parent_idx\t= %d,\n' % idx)
654         self.buf('};\n')
655         self.buf('\n')
656
657     def prep_priv(self, struc, name, suffix, section='.priv_data'):
658         if not struc:
659             return None
660         var_name = '_%s%s' % (name, suffix)
661         hdr = self._scan._structs.get(struc)
662         if hdr:
663             self.buf('#include <%s>\n' % hdr.fname)
664         else:
665             print('Warning: Cannot find header file for struct %s' % struc)
666         attr = '__attribute__ ((section ("%s")))' % section
667         return var_name, struc, attr
668
669     def alloc_priv(self, info, name, extra, suffix='_priv'):
670         result = self.prep_priv(info, name, suffix)
671         if not result:
672             return None
673         var_name, struc, section = result
674         self.buf('u8 %s_%s[sizeof(struct %s)]\n\t%s;\n' %
675                  (var_name, extra, struc.strip(), section))
676         return '%s_%s' % (var_name, extra)
677
678     def alloc_plat(self, info, name, extra, node):
679         result = self.prep_priv(info, name, '_plat')
680         if not result:
681             return None
682         var_name, struc, section = result
683         self.buf('struct %s %s\n\t%s_%s = {\n' %
684                  (struc.strip(), section, var_name, extra))
685         self.buf('\t.dtplat = {\n')
686         for pname in sorted(node.props):
687             self._output_prop(node, node.props[pname], 2)
688         self.buf('\t},\n')
689         self.buf('};\n')
690         return '&%s_%s' % (var_name, extra)
691
692     def _declare_device_inst(self, node, parent_driver):
693         """Add a device instance declaration to the output
694
695         This declares a DM_DEVICE_INST() for the device being processed
696
697         Args:
698             node: Node to output
699         """
700         driver = node.driver
701         uclass = node.uclass
702         self.buf('\n')
703         num_lines = len(self._lines)
704         plat_name = self.alloc_plat(driver.plat, driver.name, node.var_name,
705                                     node)
706         priv_name = self.alloc_priv(driver.priv, driver.name, node.var_name)
707         parent_plat_name = None
708         parent_priv_name = None
709         if parent_driver:
710             # TODO: deal with uclass providing these values
711             parent_plat_name = self.alloc_priv(
712                 parent_driver.child_plat, driver.name, node.var_name,
713                 '_parent_plat')
714             parent_priv_name = self.alloc_priv(
715                 parent_driver.child_priv, driver.name, node.var_name,
716                 '_parent_priv')
717         uclass_plat_name = self.alloc_priv(
718             uclass.per_dev_plat, driver.name + '_uc', node.var_name, 'plat')
719         uclass_priv_name = self.alloc_priv(uclass.per_dev_priv,
720                                            driver.name + '_uc', node.var_name)
721         for hdr in driver.headers:
722             self.buf('#include %s\n' % hdr)
723
724         # Add a blank line if we emitted any stuff above, for readability
725         if num_lines != len(self._lines):
726             self.buf('\n')
727
728         self.buf('DM_DEVICE_INST(%s) = {\n' % node.var_name)
729         self.buf('\t.driver\t\t= DM_DRIVER_REF(%s),\n' % node.struct_name)
730         self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
731         if plat_name:
732             self.buf('\t.plat_\t\t= %s,\n' % plat_name)
733         else:
734             self.buf('\t.plat_\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
735         if parent_plat_name:
736             self.buf('\t.parent_plat_\t= %s,\n' % parent_plat_name)
737         if uclass_plat_name:
738             self.buf('\t.uclass_plat_\t= %s,\n' % uclass_plat_name)
739         driver_date = None
740
741         if node != self._fdt.GetRoot():
742             compat_list = node.props['compatible'].value
743             if not isinstance(compat_list, list):
744                 compat_list = [compat_list]
745             for compat in compat_list:
746                 driver_data = driver.compat.get(compat)
747                 if driver_data:
748                     self.buf('\t.driver_data\t= %s,\n' % driver_data)
749                     break
750
751         if node.parent and node.parent.parent:
752             self.buf('\t.parent\t\t= DM_DEVICE_REF(%s),\n' %
753                      node.parent.var_name)
754         if priv_name:
755             self.buf('\t.priv_\t\t= %s,\n' % priv_name)
756         self.buf('\t.uclass\t\t= DM_UCLASS_REF(%s),\n' % uclass.name)
757
758         if uclass_priv_name:
759             self.buf('\t.uclass_priv_ = %s,\n' % uclass_priv_name)
760         if parent_priv_name:
761             self.buf('\t.parent_priv_\t= %s,\n' % parent_priv_name)
762         self.list_node('uclass_node', uclass.node_refs, node.uclass_seq)
763         self.list_head('child_head', 'sibling_node', node.child_devs, node.var_name)
764         if node.parent in self._valid_nodes:
765             self.list_node('sibling_node', node.parent.child_refs,
766                            node.parent_seq)
767         # flags is left as 0
768
769         self.buf('\t.seq_ = %d,\n' % node.seq)
770
771         self.buf('};\n')
772         self.buf('\n')
773         return parent_plat_name
774
775     def _output_prop(self, node, prop, tabs=1):
776         """Output a line containing the value of a struct member
777
778         Args:
779             node (Node): Node being output
780             prop (Prop): Prop object to output
781         """
782         if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
783             return
784         member_name = conv_name_to_c(prop.name)
785         self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
786
787         # Special handling for lists
788         if isinstance(prop.value, list):
789             self._output_list(node, prop)
790         else:
791             self.buf(get_value(prop.type, prop.value))
792         self.buf(',\n')
793
794     def _output_values(self, node):
795         """Output the definition of a device's struct values
796
797         Args:
798             node (Node): Node to output
799         """
800         self.buf('static struct %s%s %s%s = {\n' %
801                  (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
802         for pname in sorted(node.props):
803             self._output_prop(node, node.props[pname])
804         self.buf('};\n')
805
806     def list_head(self, head_member, node_member, node_refs, var_name):
807         self.buf('\t.%s\t= {\n' % head_member)
808         if node_refs:
809             last = node_refs[-1].dev_ref
810             first = node_refs[0].dev_ref
811             member = node_member
812         else:
813             last = 'DM_DEVICE_REF(%s)' % var_name
814             first = last
815             member = head_member
816         self.buf('\t\t.prev = &%s->%s,\n' % (last, member))
817         self.buf('\t\t.next = &%s->%s,\n' % (first, member))
818         self.buf('\t},\n')
819
820     def list_node(self, member, node_refs, seq):
821         self.buf('\t.%s\t= {\n' % member)
822         self.buf('\t\t.prev = %s,\n' % node_refs[seq - 1])
823         self.buf('\t\t.next = %s,\n' % node_refs[seq + 1])
824         self.buf('\t},\n')
825
826     def generate_uclasses(self):
827         if not self.check_instantiate(True):
828             return
829         self.out('\n')
830         self.out('#include <common.h>\n')
831         self.out('#include <dm.h>\n')
832         self.out('#include <dt-structs.h>\n')
833         self.out('\n')
834         self.buf('/*\n')
835         self.buf(
836             " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
837         uclass_list = self._valid_uclasses
838         for seq, uclass in enumerate(uclass_list):
839             self.buf(' * %3d: %s\n' % (seq, uclass.name))
840         self.buf(' *\n')
841         self.buf(' * Sequence numbers allocated in each uclass:\n')
842         for uclass in uclass_list:
843             if uclass.alias_num_to_node:
844                 self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
845                 for seq, node in uclass.alias_num_to_node.items():
846                     self.buf(' *    %d: %s\n' % (seq, node.path))
847         self.buf(' */\n')
848
849         uclass_node = {}
850         for seq, uclass in enumerate(uclass_list):
851             uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
852                                 uclass.name)
853         uclass_node[-1] = '&uclass_head'
854         uclass_node[len(uclass_list)] = '&uclass_head'
855         self.buf('\n')
856         self.buf('struct list_head %s = {\n' % 'uclass_head')
857         self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
858         self.buf('\t.next = %s,\n' % uclass_node[0])
859         self.buf('};\n')
860         self.buf('\n')
861
862         for seq, uclass in enumerate(uclass_list):
863             uc_drv = self._scan._uclass.get(uclass.uclass_id)
864
865             priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
866
867             self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
868             if priv_name:
869                 self.buf('\t.priv_\t\t= %s,\n' % priv_name)
870             self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
871             self.list_node('sibling_node', uclass_node, seq)
872             self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
873             self.buf('};\n')
874             self.buf('\n')
875         self.out(''.join(self.get_buf()))
876
877     def read_aliases(self):
878         """Read the aliases and attach the information to self._alias
879
880         Raises:
881             ValueError: The alias path is not found
882         """
883         alias_node = self._fdt.GetNode('/aliases')
884         if not alias_node:
885             return
886         re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
887         for prop in alias_node.props.values():
888             m_alias = re_num.match(prop.name)
889             if not m_alias:
890                 raise ValueError("Cannot decode alias '%s'" % prop.name)
891             name, num = m_alias.groups()
892             node = self._fdt.GetNode(prop.value)
893             result = self._scan.add_uclass_alias(name, num, node)
894             if result is None:
895                 raise ValueError("Alias '%s' path '%s' not found" %
896                                  (prop.name, prop.value))
897             elif result is False:
898                 print("Could not find uclass for alias '%s'" % prop.name)
899
900     def generate_decl(self):
901         nodes_to_output = list(self._valid_nodes)
902
903         self.buf('#include <dm/device-internal.h>\n')
904         self.buf('#include <dm/uclass-internal.h>\n')
905         self.buf('\n')
906         self.buf(
907             '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
908         for node in nodes_to_output:
909             self.buf('extern U_BOOT_DRIVER(%s);\n' % node.struct_name);
910         self.buf('\n')
911
912         if self._instantiate:
913             self.buf(
914                 '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
915             for node in nodes_to_output:
916                 self.buf('extern DM_DEVICE_INST(%s);\n' % node.var_name)
917             self.buf('\n')
918
919         uclass_list = self._valid_uclasses
920
921         self.buf(
922             '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
923         for uclass in uclass_list:
924             self.buf('extern UCLASS_DRIVER(%s);\n' % uclass.name)
925
926         if self._instantiate:
927             self.buf('\n')
928             self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
929             for uclass in uclass_list:
930                 self.buf('extern DM_UCLASS_INST(%s);\n' % uclass.name)
931         self.out(''.join(self.get_buf()))
932
933     def assign_seqs(self):
934         """Assign a sequence number to each node"""
935         for node in self._valid_nodes_unsorted:
936             seq = self._scan.assign_seq(node)
937             if seq is not None:
938                 node.seq = seq
939
940     def process_nodes(self, need_drivers):
941         nodes_to_output = list(self._valid_nodes)
942
943         # Figure out which drivers we actually use
944         self._scan.mark_used(nodes_to_output)
945
946         for node in nodes_to_output:
947             node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
948             driver = self._scan.get_driver(node.struct_name)
949             if not driver:
950                 if not need_drivers:
951                     continue
952                 raise ValueError("Cannot parse/find driver for '%s'" %
953                                  node.struct_name)
954             node.driver = driver
955             uclass = self._scan._uclass.get(driver.uclass_id)
956             if not uclass:
957                 raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
958                                 (driver.uclass_id, node.struct_name))
959             node.uclass = uclass
960             node.uclass_seq = len(node.uclass.devs)
961             node.uclass.devs.append(node)
962             uclass.node_refs[node.uclass_seq] = \
963                 '&%s->uclass_node' % node.dev_ref
964
965             parent_driver = None
966             if node.parent in self._valid_nodes:
967                 parent_driver = self._scan.get_driver(node.parent.struct_name)
968                 if not parent_driver:
969                     if not need_drivers:
970                         continue
971                     raise ValueError(
972                         "Cannot parse/find parent driver '%s' for '%s'" %
973                         (node.parent.struct_name, node.struct_name))
974                 node.parent_seq = len(node.parent.child_devs)
975                 node.parent.child_devs.append(node)
976                 node.parent.child_refs[node.parent_seq] = \
977                     '&%s->sibling_node' % node.dev_ref
978                 node.parent_driver = parent_driver
979
980         for node in nodes_to_output:
981             ref = '&%s->child_head' % node.dev_ref
982             node.child_refs[-1] = ref
983             node.child_refs[len(node.child_devs)] = ref
984
985         uclass_set = set()
986         for driver in self._scan._drivers.values():
987             if driver.used and driver.uclass:
988                 uclass_set.add(driver.uclass)
989         self._valid_uclasses = sorted(list(uclass_set),
990                                       key=lambda uc: uc.uclass_id)
991
992         for seq, uclass in enumerate(uclass_set):
993             ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
994             uclass.node_refs[-1] = ref
995             uclass.node_refs[len(uclass.devs)] = ref
996
997     def output_node_plat(self, node):
998         """Output the C code for a node
999
1000         Args:
1001             node (fdt.Node): node to output
1002         """
1003         driver = node.driver
1004         parent_driver = node.parent_driver
1005
1006         line1 = 'Node %s index %d' % (node.path, node.idx)
1007         if driver:
1008             self.buf('/*\n')
1009             self.buf(' * %s\n' % line1)
1010             self.buf(' * driver %s parent %s\n' % (driver.name,
1011                 parent_driver.name if parent_driver else 'None'))
1012             self.buf(' */\n')
1013         else:
1014             self.buf('/* %s */\n' % line1)
1015
1016         self._output_values(node)
1017         self._declare_device(node)
1018
1019         self.out(''.join(self.get_buf()))
1020
1021     def output_node_instance(self, node):
1022         """Output the C code for a node
1023
1024         Args:
1025             node (fdt.Node): node to output
1026         """
1027         parent_driver = node.parent_driver
1028
1029         self.buf('/*\n')
1030         self.buf(' * Node %s index %d\n' % (node.path, node.idx))
1031         self.buf(' * driver %s parent %s\n' % (node.driver.name,
1032                  parent_driver.name if parent_driver else 'None'))
1033         self.buf('*/\n')
1034
1035         if not node.driver.plat:
1036             self._output_values(node)
1037         self._declare_device_inst(node, parent_driver)
1038
1039         self.out(''.join(self.get_buf()))
1040
1041     def check_instantiate(self, require):
1042         """Check if self._instantiate is set to the required value
1043
1044         If not, this outputs a message into the current file
1045
1046         Args:
1047             require: True to require --instantiate, False to require that it not
1048                 be enabled
1049         """
1050         if require != self._instantiate:
1051             self.out(
1052                 '/* This file is not used: --instantiate was %senabled */\n' %
1053                 ('not ' if require else ''))
1054             return False
1055         return True
1056
1057     def generate_plat(self):
1058         """Generate device defintions for the platform data
1059
1060         This writes out C platform data initialisation data and
1061         U_BOOT_DRVINFO() declarations for each valid node. Where a node has
1062         multiple compatible strings, a #define is used to make them equivalent.
1063
1064         See the documentation in doc/driver-model/of-plat.rst for more
1065         information.
1066         """
1067         if not self.check_instantiate(False):
1068             return
1069         self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
1070         self.out('#define DT_PLAT_C\n')
1071         self.out('\n')
1072         self.out('#include <common.h>\n')
1073         self.out('#include <dm.h>\n')
1074         self.out('#include <dt-structs.h>\n')
1075         self.out('\n')
1076
1077         if self._valid_nodes:
1078             self.out('/*\n')
1079             self.out(
1080                 " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
1081             self.out(' *\n')
1082             self.out(' * idx  %-20s %-s\n' % ('driver_info', 'driver'))
1083             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1084             for node in self._valid_nodes:
1085                 self.out(' * %3d: %-20s %-s\n' %
1086                         (node.idx, node.var_name, node.struct_name))
1087             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1088             self.out(' */\n')
1089             self.out('\n')
1090
1091             for node in self._valid_nodes:
1092                 self.output_node_plat(node)
1093
1094         self.out(''.join(self.get_buf()))
1095
1096     def generate_device(self):
1097         """Generate device instances
1098
1099         This writes out DM_DEVICE_INST() records for each device in the
1100         build.
1101
1102         See the documentation in doc/driver-model/of-plat.rst for more
1103         information.
1104         """
1105         if not self.check_instantiate(True):
1106             return
1107         self.out('#include <common.h>\n')
1108         self.out('#include <dm.h>\n')
1109         self.out('#include <dt-structs.h>\n')
1110         self.out('\n')
1111
1112         if self._valid_nodes:
1113             self.out('/*\n')
1114             self.out(
1115                 " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
1116             self.out(' *\n')
1117             self.out(' * idx  %-20s %-s\n' % ('udevice', 'driver'))
1118             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1119             for node in self._valid_nodes:
1120                 self.out(' * %3d: %-20s %-s\n' %
1121                         (node.idx, node.var_name, node.struct_name))
1122             self.out(' * ---  %-20s %-s\n' % ('-' * 20, '-' * 20))
1123             self.out(' */\n')
1124             self.out('\n')
1125
1126             for node in self._valid_nodes:
1127                 self.output_node_instance(node)
1128
1129         self.out(''.join(self.get_buf()))
1130
1131
1132 # Types of output file we understand
1133 # key: Command used to generate this file
1134 # value: OutputFile for this command
1135 OUTPUT_FILES_COMMON = {
1136     'decl':
1137         OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
1138                    'Declares externs for all device/uclass instances'),
1139     'struct':
1140         OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
1141                    DtbPlatdata.generate_structs,
1142                    'Defines the structs used to hold devicetree data'),
1143     }
1144
1145 # File generated without instantiate
1146 OUTPUT_FILES_NOINST = {
1147     'platdata':
1148         OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
1149                    'Declares the U_BOOT_DRIVER() records and platform data'),
1150     }
1151
1152 # File generated with instantiate
1153 OUTPUT_FILES_INST = {
1154     'device':
1155         OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
1156                    'Declares the DM_DEVICE_INST() records'),
1157     'uclass':
1158         OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
1159                    'Declares the uclass instances (struct uclass)'),
1160     }
1161
1162
1163 def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
1164               instantiate, warning_disabled=False, drivers_additional=None,
1165               basedir=None, scan=None):
1166     """Run all the steps of the dtoc tool
1167
1168     Args:
1169         args (list): List of non-option arguments provided to the problem
1170         dtb_file (str): Filename of dtb file to process
1171         include_disabled (bool): True to include disabled nodes
1172         output (str): Name of output file (None for stdout)
1173         output_dirs (tuple of str):
1174             Directory to put C output files
1175             Directory to put H output files
1176         phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
1177              or 'tpl'. None if not known
1178         instantiate: Instantiate devices so they don't need to be bound at
1179             run-time
1180         warning_disabled (bool): True to avoid showing warnings about missing
1181             drivers
1182         drivers_additional (list): List of additional drivers to use during
1183             scanning
1184         basedir (str): Base directory of U-Boot source code. Defaults to the
1185             grandparent of this file's directory
1186         scan (src_src.Scanner): Scanner from a previous run. This can help speed
1187             up tests. Use None for normal operation
1188
1189     Returns:
1190         DtbPlatdata object
1191
1192     Raises:
1193         ValueError: if args has no command, or an unknown command
1194     """
1195     if not args:
1196         raise ValueError('Please specify a command: struct, platdata, all')
1197     if output and output_dirs and any(output_dirs):
1198         raise ValueError('Must specify either output or output_dirs, not both')
1199
1200     if not scan:
1201         scan = src_scan.Scanner(basedir, drivers_additional, phase)
1202         scan.scan_drivers()
1203         do_process = True
1204     else:
1205         do_process = False
1206     plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
1207     plat.scan_dtb()
1208     plat.scan_tree(add_root=instantiate)
1209     plat.prepare_nodes()
1210     plat.scan_reg_sizes()
1211     plat.setup_output_dirs(output_dirs)
1212     plat.scan_structs()
1213     plat.scan_phandles()
1214     plat.process_nodes(instantiate)
1215     plat.read_aliases()
1216     plat.assign_seqs()
1217
1218     # Figure out what output files we plan to generate
1219     output_files = OUTPUT_FILES_COMMON
1220     if instantiate:
1221         output_files.update(OUTPUT_FILES_INST)
1222     else:
1223         output_files.update(OUTPUT_FILES_NOINST)
1224
1225     cmds = args[0].split(',')
1226     if 'all' in cmds:
1227         cmds = sorted(output_files.keys())
1228     for cmd in cmds:
1229         outfile = output_files.get(cmd)
1230         if not outfile:
1231             raise ValueError("Unknown command '%s': (use: %s)" %
1232                              (cmd, ', '.join(sorted(output_files.keys()))))
1233         plat.setup_output(outfile.ftype,
1234                           outfile.fname if output_dirs else output)
1235         plat.out_header(outfile)
1236         outfile.method(plat)
1237     plat.finish_output()
1238
1239     if not warning_disabled:
1240         scan.show_warnings()
1241     return plat