]> Git Repo - u-boot.git/blob - tools/dtoc/dtb_platdata.py
dtoc: Tidy up more Python style in dtb_platdata
[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 <[email protected]>
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 import os
19 import re
20 import sys
21
22 from dtoc import fdt
23 from dtoc import fdt_util
24
25 # When we see these properties we ignore them - i.e. do not create a structure
26 # member
27 PROP_IGNORE_LIST = [
28     '#address-cells',
29     '#gpio-cells',
30     '#size-cells',
31     'compatible',
32     'linux,phandle',
33     "status",
34     'phandle',
35     'u-boot,dm-pre-reloc',
36     'u-boot,dm-tpl',
37     'u-boot,dm-spl',
38 ]
39
40 # C type declarations for the types we support
41 TYPE_NAMES = {
42     fdt.Type.INT: 'fdt32_t',
43     fdt.Type.BYTE: 'unsigned char',
44     fdt.Type.STRING: 'const char *',
45     fdt.Type.BOOL: 'bool',
46     fdt.Type.INT64: 'fdt64_t',
47 }
48
49 STRUCT_PREFIX = 'dtd_'
50 VAL_PREFIX = 'dtv_'
51
52 # This holds information about a property which includes phandles.
53 #
54 # max_args: integer: Maximum number or arguments that any phandle uses (int).
55 # args: Number of args for each phandle in the property. The total number of
56 #     phandles is len(args). This is a list of integers.
57 PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
58
59 # Holds a single phandle link, allowing a C struct value to be assigned to point
60 # to a device
61 #
62 # var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
63 # dev_name: Name of device to assign to (e.g. 'clock')
64 PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
65
66
67 def conv_name_to_c(name):
68     """Convert a device-tree name to a C identifier
69
70     This uses multiple replace() calls instead of re.sub() since it is faster
71     (400ms for 1m calls versus 1000ms for the 're' version).
72
73     Args:
74         name (str): Name to convert
75     Return:
76         str: String containing the C version of this name
77     """
78     new = name.replace('@', '_at_')
79     new = new.replace('-', '_')
80     new = new.replace(',', '_')
81     new = new.replace('.', '_')
82     return new
83
84 def tab_to(num_tabs, line):
85     """Append tabs to a line of text to reach a tab stop.
86
87     Args:
88         num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
89         line (str): Line of text to append to
90
91     Returns:
92         str: line with the correct number of tabs appeneded. If the line already
93         extends past that tab stop then a single space is appended.
94     """
95     if len(line) >= num_tabs * 8:
96         return line + ' '
97     return line + '\t' * (num_tabs - len(line) // 8)
98
99 def get_value(ftype, value):
100     """Get a value as a C expression
101
102     For integers this returns a byte-swapped (little-endian) hex string
103     For bytes this returns a hex string, e.g. 0x12
104     For strings this returns a literal string enclosed in quotes
105     For booleans this return 'true'
106
107     Args:
108         ftype (fdt.Type): Data type (fdt_util)
109         value (bytes): Data value, as a string of bytes
110
111     Returns:
112         str: String representation of the value
113     """
114     if ftype == fdt.Type.INT:
115         return '%#x' % fdt_util.fdt32_to_cpu(value)
116     elif ftype == fdt.Type.BYTE:
117         char = value[0]
118         return '%#x' % (ord(char) if isinstance(char, str) else char)
119     elif ftype == fdt.Type.STRING:
120         # Handle evil ACPI backslashes by adding another backslash before them.
121         # So "\\_SB.GPO0" in the device tree effectively stays like that in C
122         return '"%s"' % value.replace('\\', '\\\\')
123     elif ftype == fdt.Type.BOOL:
124         return 'true'
125     else:  # ftype == fdt.Type.INT64:
126         return '%#x' % value
127
128 def get_compat_name(node):
129     """Get the node's list of compatible string as a C identifiers
130
131     Args:
132         node (fdt.Node): Node object to check
133     Return:
134         List of C identifiers for all the compatible strings
135     """
136     compat = node.props['compatible'].value
137     if not isinstance(compat, list):
138         compat = [compat]
139     return [conv_name_to_c(c) for c in compat]
140
141
142 class DtbPlatdata(object):
143     """Provide a means to convert device tree binary data to platform data
144
145     The output of this process is C structures which can be used in space-
146     constrained encvironments where the ~3KB code overhead of device tree
147     code is not affordable.
148
149     Properties:
150         _fdt: Fdt object, referencing the device tree
151         _dtb_fname: Filename of the input device tree binary file
152         _valid_nodes: A list of Node object with compatible strings. The list
153             is ordered by conv_name_to_c(node.name)
154         _include_disabled: true to include nodes marked status = "disabled"
155         _outfile: The current output file (sys.stdout or a real file)
156         _warning_disabled: true to disable warnings about driver names not found
157         _lines: Stashed list of output lines for outputting in the future
158         _drivers: List of valid driver names found in drivers/
159         _driver_aliases: Dict that holds aliases for driver names
160             key: Driver alias declared with
161                 U_BOOT_DRIVER_ALIAS(driver_alias, driver_name)
162             value: Driver name declared with U_BOOT_DRIVER(driver_name)
163         _drivers_additional: List of additional drivers to use during scanning
164     """
165     def __init__(self, dtb_fname, include_disabled, warning_disabled,
166                  drivers_additional=None):
167         self._fdt = None
168         self._dtb_fname = dtb_fname
169         self._valid_nodes = None
170         self._include_disabled = include_disabled
171         self._outfile = None
172         self._warning_disabled = warning_disabled
173         self._lines = []
174         self._drivers = []
175         self._driver_aliases = {}
176         self._drivers_additional = drivers_additional or []
177
178     def get_normalized_compat_name(self, node):
179         """Get a node's normalized compat name
180
181         Returns a valid driver name by retrieving node's list of compatible
182         string as a C identifier and performing a check against _drivers
183         and a lookup in driver_aliases printing a warning in case of failure.
184
185         Args:
186             node: Node object to check
187         Return:
188             Tuple:
189                 Driver name associated with the first compatible string
190                 List of C identifiers for all the other compatible strings
191                     (possibly empty)
192                 In case of no match found, the return will be the same as
193                 get_compat_name()
194         """
195         compat_list_c = get_compat_name(node)
196
197         for compat_c in compat_list_c:
198             if not compat_c in self._drivers:
199                 compat_c = self._driver_aliases.get(compat_c)
200                 if not compat_c:
201                     continue
202
203             aliases_c = compat_list_c
204             if compat_c in aliases_c:
205                 aliases_c.remove(compat_c)
206             return compat_c, aliases_c
207
208         if not self._warning_disabled:
209             print('WARNING: the driver %s was not found in the driver list'
210                   % (compat_list_c[0]))
211
212         return compat_list_c[0], compat_list_c[1:]
213
214     def setup_output(self, fname):
215         """Set up the output destination
216
217         Once this is done, future calls to self.out() will output to this
218         file.
219
220         Args:
221             fname (str): Filename to send output to, or '-' for stdout
222         """
223         if fname == '-':
224             self._outfile = sys.stdout
225         else:
226             self._outfile = open(fname, 'w')
227
228     def out(self, line):
229         """Output a string to the output file
230
231         Args:
232             line (str): String to output
233         """
234         self._outfile.write(line)
235
236     def buf(self, line):
237         """Buffer up a string to send later
238
239         Args:
240             line (str): String to add to our 'buffer' list
241         """
242         self._lines.append(line)
243
244     def get_buf(self):
245         """Get the contents of the output buffer, and clear it
246
247         Returns:
248             list(str): The output buffer, which is then cleared for future use
249         """
250         lines = self._lines
251         self._lines = []
252         return lines
253
254     def out_header(self):
255         """Output a message indicating that this is an auto-generated file"""
256         self.out('''/*
257  * DO NOT MODIFY
258  *
259  * This file was generated by dtoc from a .dtb (device tree binary) file.
260  */
261
262 ''')
263
264     def get_phandle_argc(self, prop, node_name):
265         """Check if a node contains phandles
266
267         We have no reliable way of detecting whether a node uses a phandle
268         or not. As an interim measure, use a list of known property names.
269
270         Args:
271             prop (fdt.Prop): Prop object to check
272             node_name (str): Node name, only used for raising an error
273         Returns:
274             int or None: Number of argument cells is this is a phandle,
275                 else None
276         Raises:
277             ValueError: if the phandle cannot be parsed or the required property
278                 is not present
279         """
280         if prop.name in ['clocks', 'cd-gpios']:
281             if not isinstance(prop.value, list):
282                 prop.value = [prop.value]
283             val = prop.value
284             i = 0
285
286             max_args = 0
287             args = []
288             while i < len(val):
289                 phandle = fdt_util.fdt32_to_cpu(val[i])
290                 # If we get to the end of the list, stop. This can happen
291                 # since some nodes have more phandles in the list than others,
292                 # but we allocate enough space for the largest list. So those
293                 # nodes with shorter lists end up with zeroes at the end.
294                 if not phandle:
295                     break
296                 target = self._fdt.phandle_to_node.get(phandle)
297                 if not target:
298                     raise ValueError("Cannot parse '%s' in node '%s'" %
299                                      (prop.name, node_name))
300                 cells = None
301                 for prop_name in ['#clock-cells', '#gpio-cells']:
302                     cells = target.props.get(prop_name)
303                     if cells:
304                         break
305                 if not cells:
306                     raise ValueError("Node '%s' has no cells property" %
307                                      (target.name))
308                 num_args = fdt_util.fdt32_to_cpu(cells.value)
309                 max_args = max(max_args, num_args)
310                 args.append(num_args)
311                 i += 1 + num_args
312             return PhandleInfo(max_args, args)
313         return None
314
315     def scan_driver(self, fname):
316         """Scan a driver file to build a list of driver names and aliases
317
318         This procedure will populate self._drivers and self._driver_aliases
319
320         Args
321             fname: Driver filename to scan
322         """
323         with open(fname, encoding='utf-8') as inf:
324             try:
325                 buff = inf.read()
326             except UnicodeDecodeError:
327                 # This seems to happen on older Python versions
328                 print("Skipping file '%s' due to unicode error" % fname)
329                 return
330
331             # The following re will search for driver names declared as
332             # U_BOOT_DRIVER(driver_name)
333             drivers = re.findall('U_BOOT_DRIVER\((.*)\)', buff)
334
335             for driver in drivers:
336                 self._drivers.append(driver)
337
338             # The following re will search for driver aliases declared as
339             # U_BOOT_DRIVER_ALIAS(alias, driver_name)
340             driver_aliases = re.findall(
341                 'U_BOOT_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
342                 buff)
343
344             for alias in driver_aliases: # pragma: no cover
345                 if len(alias) != 2:
346                     continue
347                 self._driver_aliases[alias[1]] = alias[0]
348
349     def scan_drivers(self):
350         """Scan the driver folders to build a list of driver names and aliases
351
352         This procedure will populate self._drivers and self._driver_aliases
353
354         """
355         basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
356         if basedir == '':
357             basedir = './'
358         for (dirpath, _, filenames) in os.walk(basedir):
359             for fname in filenames:
360                 if not fname.endswith('.c'):
361                     continue
362                 self.scan_driver(dirpath + '/' + fname)
363
364         for fname in self._drivers_additional:
365             if not isinstance(fname, str) or len(fname) == 0:
366                 continue
367             if fname[0] == '/':
368                 self.scan_driver(fname)
369             else:
370                 self.scan_driver(basedir + '/' + fname)
371
372     def scan_dtb(self):
373         """Scan the device tree to obtain a tree of nodes and properties
374
375         Once this is done, self._fdt.GetRoot() can be called to obtain the
376         device tree root node, and progress from there.
377         """
378         self._fdt = fdt.FdtScan(self._dtb_fname)
379
380     def scan_node(self, root, valid_nodes):
381         """Scan a node and subnodes to build a tree of node and phandle info
382
383         This adds each node to self._valid_nodes.
384
385         Args:
386             root: Root node for scan
387             valid_nodes: List of Node objects to add to
388         """
389         for node in root.subnodes:
390             if 'compatible' in node.props:
391                 status = node.props.get('status')
392                 if (not self._include_disabled and not status or
393                         status.value != 'disabled'):
394                     valid_nodes.append(node)
395
396             # recurse to handle any subnodes
397             self.scan_node(node, valid_nodes)
398
399     def scan_tree(self):
400         """Scan the device tree for useful information
401
402         This fills in the following properties:
403             _valid_nodes: A list of nodes we wish to consider include in the
404                 platform data
405         """
406         valid_nodes = []
407         self.scan_node(self._fdt.GetRoot(), valid_nodes)
408         self._valid_nodes = sorted(valid_nodes,
409                                    key=lambda x: conv_name_to_c(x.name))
410         for idx, node in enumerate(self._valid_nodes):
411             node.idx = idx
412
413     @staticmethod
414     def get_num_cells(node):
415         """Get the number of cells in addresses and sizes for this node
416
417         Args:
418             node (fdt.None): Node to check
419
420         Returns:
421             Tuple:
422                 Number of address cells for this node
423                 Number of size cells for this node
424         """
425         parent = node.parent
426         num_addr, num_size = 2, 2
427         if parent:
428             addr_prop = parent.props.get('#address-cells')
429             size_prop = parent.props.get('#size-cells')
430             if addr_prop:
431                 num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
432             if size_prop:
433                 num_size = fdt_util.fdt32_to_cpu(size_prop.value)
434         return num_addr, num_size
435
436     def scan_reg_sizes(self):
437         """Scan for 64-bit 'reg' properties and update the values
438
439         This finds 'reg' properties with 64-bit data and converts the value to
440         an array of 64-values. This allows it to be output in a way that the
441         C code can read.
442         """
443         for node in self._valid_nodes:
444             reg = node.props.get('reg')
445             if not reg:
446                 continue
447             num_addr, num_size = self.get_num_cells(node)
448             total = num_addr + num_size
449
450             if reg.type != fdt.Type.INT:
451                 raise ValueError("Node '%s' reg property is not an int" %
452                                  node.name)
453             if len(reg.value) % total:
454                 raise ValueError(
455                     "Node '%s' reg property has %d cells "
456                     'which is not a multiple of na + ns = %d + %d)' %
457                     (node.name, len(reg.value), num_addr, num_size))
458             reg.num_addr = num_addr
459             reg.num_size = num_size
460             if num_addr != 1 or num_size != 1:
461                 reg.type = fdt.Type.INT64
462                 i = 0
463                 new_value = []
464                 val = reg.value
465                 if not isinstance(val, list):
466                     val = [val]
467                 while i < len(val):
468                     addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
469                     i += num_addr
470                     size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
471                     i += num_size
472                     new_value += [addr, size]
473                 reg.value = new_value
474
475     def scan_structs(self):
476         """Scan the device tree building up the C structures we will use.
477
478         Build a dict keyed by C struct name containing a dict of Prop
479         object for each struct field (keyed by property name). Where the
480         same struct appears multiple times, try to use the 'widest'
481         property, i.e. the one with a type which can express all others.
482
483         Once the widest property is determined, all other properties are
484         updated to match that width.
485
486         Returns:
487             dict containing structures:
488                 key (str): Node name, as a C identifier
489                 value: dict containing structure fields:
490                     key (str): Field name
491                     value: Prop object with field information
492         """
493         structs = collections.OrderedDict()
494         for node in self._valid_nodes:
495             node_name, _ = self.get_normalized_compat_name(node)
496             fields = {}
497
498             # Get a list of all the valid properties in this node.
499             for name, prop in node.props.items():
500                 if name not in PROP_IGNORE_LIST and name[0] != '#':
501                     fields[name] = copy.deepcopy(prop)
502
503             # If we've seen this node_name before, update the existing struct.
504             if node_name in structs:
505                 struct = structs[node_name]
506                 for name, prop in fields.items():
507                     oldprop = struct.get(name)
508                     if oldprop:
509                         oldprop.Widen(prop)
510                     else:
511                         struct[name] = prop
512
513             # Otherwise store this as a new struct.
514             else:
515                 structs[node_name] = fields
516
517         for node in self._valid_nodes:
518             node_name, _ = self.get_normalized_compat_name(node)
519             struct = structs[node_name]
520             for name, prop in node.props.items():
521                 if name not in PROP_IGNORE_LIST and name[0] != '#':
522                     prop.Widen(struct[name])
523
524         return structs
525
526     def scan_phandles(self):
527         """Figure out what phandles each node uses
528
529         We need to be careful when outputing nodes that use phandles since
530         they must come after the declaration of the phandles in the C file.
531         Otherwise we get a compiler error since the phandle struct is not yet
532         declared.
533
534         This function adds to each node a list of phandle nodes that the node
535         depends on. This allows us to output things in the right order.
536         """
537         for node in self._valid_nodes:
538             node.phandles = set()
539             for pname, prop in node.props.items():
540                 if pname in PROP_IGNORE_LIST or pname[0] == '#':
541                     continue
542                 info = self.get_phandle_argc(prop, node.name)
543                 if info:
544                     # Process the list as pairs of (phandle, id)
545                     pos = 0
546                     for args in info.args:
547                         phandle_cell = prop.value[pos]
548                         phandle = fdt_util.fdt32_to_cpu(phandle_cell)
549                         target_node = self._fdt.phandle_to_node[phandle]
550                         node.phandles.add(target_node)
551                         pos += 1 + args
552
553
554     def generate_structs(self, structs):
555         """Generate struct defintions for the platform data
556
557         This writes out the body of a header file consisting of structure
558         definitions for node in self._valid_nodes. See the documentation in
559         doc/driver-model/of-plat.rst for more information.
560
561         Args:
562             structs: dict containing structures:
563                 key (str): Node name, as a C identifier
564                 value: dict containing structure fields:
565                     key (str): Field name
566                     value: Prop object with field information
567
568         """
569         self.out_header()
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_node(self, node):
595         """Output the C code for a node
596
597         Args:
598             node (fdt.Node): node to output
599         """
600         def _output_list(node, prop):
601             """Output the C code for a devicetree property that holds a list
602
603             Args:
604                 node (fdt.Node): Node to output
605                 prop (fdt.Prop): Prop to output
606             """
607             self.buf('{')
608             vals = []
609             # For phandles, output a reference to the platform data
610             # of the target node.
611             info = self.get_phandle_argc(prop, node.name)
612             if info:
613                 # Process the list as pairs of (phandle, id)
614                 pos = 0
615                 for args in info.args:
616                     phandle_cell = prop.value[pos]
617                     phandle = fdt_util.fdt32_to_cpu(phandle_cell)
618                     target_node = self._fdt.phandle_to_node[phandle]
619                     arg_values = []
620                     for i in range(args):
621                         arg_values.append(
622                             str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
623                     pos += 1 + args
624                     vals.append('\t{%d, {%s}}' % (target_node.idx,
625                                                   ', '.join(arg_values)))
626                 for val in vals:
627                     self.buf('\n\t\t%s,' % val)
628             else:
629                 for val in prop.value:
630                     vals.append(get_value(prop.type, val))
631
632                 # Put 8 values per line to avoid very long lines.
633                 for i in range(0, len(vals), 8):
634                     if i:
635                         self.buf(',\n\t\t')
636                     self.buf(', '.join(vals[i:i + 8]))
637             self.buf('}')
638
639         struct_name, _ = self.get_normalized_compat_name(node)
640         var_name = conv_name_to_c(node.name)
641         self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
642         self.buf('static struct %s%s %s%s = {\n' %
643                  (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
644         for pname in sorted(node.props):
645             prop = node.props[pname]
646             if pname in PROP_IGNORE_LIST or pname[0] == '#':
647                 continue
648             member_name = conv_name_to_c(prop.name)
649             self.buf('\t%s= ' % tab_to(3, '.' + member_name))
650
651             # Special handling for lists
652             if isinstance(prop.value, list):
653                 _output_list(node, prop)
654             else:
655                 self.buf(get_value(prop.type, prop.value))
656             self.buf(',\n')
657         self.buf('};\n')
658
659         # Add a device declaration
660         self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
661         self.buf('\t.name\t\t= "%s",\n' % struct_name)
662         self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
663         self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
664         idx = -1
665         if node.parent and node.parent in self._valid_nodes:
666             idx = node.parent.idx
667         self.buf('\t.parent_idx\t= %d,\n' % idx)
668         self.buf('};\n')
669         self.buf('\n')
670
671         self.out(''.join(self.get_buf()))
672
673     def generate_tables(self):
674         """Generate device defintions for the platform data
675
676         This writes out C platform data initialisation data and
677         U_BOOT_DEVICE() declarations for each valid node. Where a node has
678         multiple compatible strings, a #define is used to make them equivalent.
679
680         See the documentation in doc/driver-model/of-plat.rst for more
681         information.
682         """
683         self.out_header()
684         self.out('/* Allow use of U_BOOT_DEVICE() in this file */\n')
685         self.out('#define DT_PLATDATA_C\n')
686         self.out('\n')
687         self.out('#include <common.h>\n')
688         self.out('#include <dm.h>\n')
689         self.out('#include <dt-structs.h>\n')
690         self.out('\n')
691         nodes_to_output = list(self._valid_nodes)
692
693         # Keep outputing nodes until there is none left
694         while nodes_to_output:
695             node = nodes_to_output[0]
696             # Output all the node's dependencies first
697             for req_node in node.phandles:
698                 if req_node in nodes_to_output:
699                     self.output_node(req_node)
700                     nodes_to_output.remove(req_node)
701             self.output_node(node)
702             nodes_to_output.remove(node)
703
704         # Define dm_populate_phandle_data() which will add the linking between
705         # nodes using DM_GET_DEVICE
706         # dtv_dmc_at_xxx.clocks[0].node = DM_GET_DEVICE(clock_controller_at_xxx)
707         self.buf('void dm_populate_phandle_data(void) {\n')
708         self.buf('}\n')
709
710         self.out(''.join(self.get_buf()))
711
712 def run_steps(args, dtb_file, include_disabled, output, warning_disabled=False,
713               drivers_additional=None):
714     """Run all the steps of the dtoc tool
715
716     Args:
717         args (list): List of non-option arguments provided to the problem
718         dtb_file (str): Filename of dtb file to process
719         include_disabled (bool): True to include disabled nodes
720         output (str): Name of output file
721         warning_disabled (bool): True to avoid showing warnings about missing
722             drivers
723        _drivers_additional (list): List of additional drivers to use during
724             scanning
725     Raises:
726         ValueError: if args has no command, or an unknown command
727     """
728     if not args:
729         raise ValueError('Please specify a command: struct, platdata')
730
731     plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled,
732                        drivers_additional)
733     plat.scan_drivers()
734     plat.scan_dtb()
735     plat.scan_tree()
736     plat.scan_reg_sizes()
737     plat.setup_output(output)
738     structs = plat.scan_structs()
739     plat.scan_phandles()
740
741     for cmd in args[0].split(','):
742         if cmd == 'struct':
743             plat.generate_structs(structs)
744         elif cmd == 'platdata':
745             plat.generate_tables()
746         else:
747             raise ValueError("Unknown command '%s': (use: struct, platdata)" %
748                              cmd)
This page took 0.071569 seconds and 4 git commands to generate.