]> Git Repo - u-boot.git/blame - tools/dtoc/dtb_platdata.py
dtoc: Tidy up more Python style in dtb_platdata
[u-boot.git] / tools / dtoc / dtb_platdata.py
CommitLineData
7581c01a 1#!/usr/bin/python
83d290c5 2# SPDX-License-Identifier: GPL-2.0+
7581c01a
SG
3#
4# Copyright (C) 2017 Google, Inc
5# Written by Simon Glass <[email protected]>
6#
7581c01a 7
2be282ca
SG
8"""Device tree to platform data class
9
10This supports converting device tree data to C structures definitions and
11static data.
9b330382
SG
12
13See doc/driver-model/of-plat.rst for more informaiton
2be282ca
SG
14"""
15
8fed2eb2 16import collections
7581c01a 17import copy
dac8228d
WL
18import os
19import re
2be282ca 20import sys
7581c01a 21
bf776679
SG
22from dtoc import fdt
23from dtoc import fdt_util
7581c01a 24
9b330382
SG
25# When we see these properties we ignore them - i.e. do not create a structure
26# member
7581c01a
SG
27PROP_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
5ea9dccf 40# C type declarations for the types we support
7581c01a 41TYPE_NAMES = {
5ea9dccf
SG
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',
2be282ca 47}
7581c01a
SG
48
49STRUCT_PREFIX = 'dtd_'
50VAL_PREFIX = 'dtv_'
51
8fed2eb2
SG
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.
57PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
58
97136eb5
SG
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')
64PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
65
8fed2eb2 66
2be282ca 67def conv_name_to_c(name):
7581c01a
SG
68 """Convert a device-tree name to a C identifier
69
30107b08
SG
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
7581c01a 73 Args:
9b330382 74 name (str): Name to convert
7581c01a 75 Return:
9b330382 76 str: String containing the C version of this name
7581c01a 77 """
2be282ca
SG
78 new = name.replace('@', '_at_')
79 new = new.replace('-', '_')
80 new = new.replace(',', '_')
81 new = new.replace('.', '_')
2be282ca
SG
82 return new
83
84def tab_to(num_tabs, line):
85 """Append tabs to a line of text to reach a tab stop.
86
87 Args:
9b330382
SG
88 num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
89 line (str): Line of text to append to
2be282ca
SG
90
91 Returns:
9b330382 92 str: line with the correct number of tabs appeneded. If the line already
2be282ca
SG
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
56e0bbe0
SG
99def 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:
9b330382
SG
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
56e0bbe0 113 """
5ea9dccf 114 if ftype == fdt.Type.INT:
56e0bbe0 115 return '%#x' % fdt_util.fdt32_to_cpu(value)
5ea9dccf 116 elif ftype == fdt.Type.BYTE:
78128d52
SG
117 char = value[0]
118 return '%#x' % (ord(char) if isinstance(char, str) else char)
5ea9dccf 119 elif ftype == fdt.Type.STRING:
f02d0eb3
SG
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('\\', '\\\\')
5ea9dccf 123 elif ftype == fdt.Type.BOOL:
56e0bbe0 124 return 'true'
9b330382 125 else: # ftype == fdt.Type.INT64:
fbdfd228 126 return '%#x' % value
56e0bbe0
SG
127
128def get_compat_name(node):
dcb3ed64 129 """Get the node's list of compatible string as a C identifiers
56e0bbe0
SG
130
131 Args:
9b330382 132 node (fdt.Node): Node object to check
56e0bbe0 133 Return:
dcb3ed64 134 List of C identifiers for all the compatible strings
56e0bbe0
SG
135 """
136 compat = node.props['compatible'].value
dcb3ed64
WL
137 if not isinstance(compat, list):
138 compat = [compat]
139 return [conv_name_to_c(c) for c in compat]
56e0bbe0 140
56e0bbe0 141
2be282ca 142class DtbPlatdata(object):
7581c01a
SG
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:
2be282ca 150 _fdt: Fdt object, referencing the device tree
7581c01a 151 _dtb_fname: Filename of the input device tree binary file
1b27273e
SG
152 _valid_nodes: A list of Node object with compatible strings. The list
153 is ordered by conv_name_to_c(node.name)
e36024b0 154 _include_disabled: true to include nodes marked status = "disabled"
7581c01a 155 _outfile: The current output file (sys.stdout or a real file)
361e7335 156 _warning_disabled: true to disable warnings about driver names not found
7581c01a 157 _lines: Stashed list of output lines for outputting in the future
dac8228d
WL
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)
6c74d1b8 163 _drivers_additional: List of additional drivers to use during scanning
7581c01a 164 """
6c74d1b8 165 def __init__(self, dtb_fname, include_disabled, warning_disabled,
78128d52 166 drivers_additional=None):
2be282ca 167 self._fdt = None
7581c01a
SG
168 self._dtb_fname = dtb_fname
169 self._valid_nodes = None
e36024b0 170 self._include_disabled = include_disabled
7581c01a 171 self._outfile = None
361e7335 172 self._warning_disabled = warning_disabled
7581c01a 173 self._lines = []
dac8228d
WL
174 self._drivers = []
175 self._driver_aliases = {}
78128d52 176 self._drivers_additional = drivers_additional or []
dac8228d
WL
177
178 def get_normalized_compat_name(self, node):
179 """Get a node's normalized compat name
180
dcb3ed64 181 Returns a valid driver name by retrieving node's list of compatible
dac8228d
WL
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 """
dcb3ed64
WL
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:]
7581c01a 213
2be282ca 214 def setup_output(self, fname):
7581c01a
SG
215 """Set up the output destination
216
2be282ca 217 Once this is done, future calls to self.out() will output to this
7581c01a
SG
218 file.
219
220 Args:
9b330382 221 fname (str): Filename to send output to, or '-' for stdout
7581c01a
SG
222 """
223 if fname == '-':
224 self._outfile = sys.stdout
225 else:
226 self._outfile = open(fname, 'w')
227
2be282ca 228 def out(self, line):
7581c01a
SG
229 """Output a string to the output file
230
231 Args:
9b330382 232 line (str): String to output
7581c01a 233 """
2be282ca 234 self._outfile.write(line)
7581c01a 235
2be282ca 236 def buf(self, line):
7581c01a
SG
237 """Buffer up a string to send later
238
239 Args:
9b330382 240 line (str): String to add to our 'buffer' list
7581c01a 241 """
2be282ca 242 self._lines.append(line)
7581c01a 243
2be282ca 244 def get_buf(self):
7581c01a
SG
245 """Get the contents of the output buffer, and clear it
246
247 Returns:
9b330382 248 list(str): The output buffer, which is then cleared for future use
7581c01a
SG
249 """
250 lines = self._lines
251 self._lines = []
252 return lines
253
d503114c
SG
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
8fed2eb2
SG
264 def get_phandle_argc(self, prop, node_name):
265 """Check if a node contains phandles
2925c26b 266
8fed2eb2
SG
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.
2925c26b 269
8fed2eb2 270 Args:
9b330382
SG
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
8fed2eb2 279 """
ad34017c 280 if prop.name in ['clocks', 'cd-gpios']:
760b7170
SG
281 if not isinstance(prop.value, list):
282 prop.value = [prop.value]
8fed2eb2 283 val = prop.value
8fed2eb2
SG
284 i = 0
285
286 max_args = 0
287 args = []
288 while i < len(val):
289 phandle = fdt_util.fdt32_to_cpu(val[i])
760b7170
SG
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
8fed2eb2
SG
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))
ad34017c
WL
300 cells = None
301 for prop_name in ['#clock-cells', '#gpio-cells']:
302 cells = target.props.get(prop_name)
303 if cells:
304 break
8fed2eb2 305 if not cells:
ad34017c 306 raise ValueError("Node '%s' has no cells property" %
9b330382 307 (target.name))
8fed2eb2
SG
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
2925c26b 314
78128d52 315 def scan_driver(self, fname):
dac8228d
WL
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
78128d52 321 fname: Driver filename to scan
dac8228d 322 """
78128d52 323 with open(fname, encoding='utf-8') as inf:
dac8228d 324 try:
78128d52 325 buff = inf.read()
dac8228d
WL
326 except UnicodeDecodeError:
327 # This seems to happen on older Python versions
78128d52 328 print("Skipping file '%s' due to unicode error" % fname)
dac8228d
WL
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)
78128d52
SG
340 driver_aliases = re.findall(
341 'U_BOOT_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
342 buff)
dac8228d
WL
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 = './'
78128d52
SG
358 for (dirpath, _, filenames) in os.walk(basedir):
359 for fname in filenames:
360 if not fname.endswith('.c'):
dac8228d 361 continue
78128d52 362 self.scan_driver(dirpath + '/' + fname)
dac8228d 363
78128d52
SG
364 for fname in self._drivers_additional:
365 if not isinstance(fname, str) or len(fname) == 0:
6c74d1b8 366 continue
78128d52
SG
367 if fname[0] == '/':
368 self.scan_driver(fname)
6c74d1b8 369 else:
78128d52 370 self.scan_driver(basedir + '/' + fname)
6c74d1b8 371
2be282ca 372 def scan_dtb(self):
f1a7ba1d 373 """Scan the device tree to obtain a tree of nodes and properties
7581c01a 374
2be282ca 375 Once this is done, self._fdt.GetRoot() can be called to obtain the
7581c01a
SG
376 device tree root node, and progress from there.
377 """
2be282ca
SG
378 self._fdt = fdt.FdtScan(self._dtb_fname)
379
1b27273e 380 def scan_node(self, root, valid_nodes):
2be282ca
SG
381 """Scan a node and subnodes to build a tree of node and phandle info
382
72ab7c5e 383 This adds each node to self._valid_nodes.
7581c01a 384
2be282ca
SG
385 Args:
386 root: Root node for scan
1b27273e 387 valid_nodes: List of Node objects to add to
2be282ca 388 """
7581c01a
SG
389 for node in root.subnodes:
390 if 'compatible' in node.props:
391 status = node.props.get('status')
e36024b0 392 if (not self._include_disabled and not status or
2be282ca 393 status.value != 'disabled'):
1b27273e 394 valid_nodes.append(node)
7581c01a
SG
395
396 # recurse to handle any subnodes
1b27273e 397 self.scan_node(node, valid_nodes)
7581c01a 398
2be282ca 399 def scan_tree(self):
7581c01a
SG
400 """Scan the device tree for useful information
401
402 This fills in the following properties:
7581c01a
SG
403 _valid_nodes: A list of nodes we wish to consider include in the
404 platform data
405 """
1b27273e
SG
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
7581c01a 412
c20ee0ed
SG
413 @staticmethod
414 def get_num_cells(node):
415 """Get the number of cells in addresses and sizes for this node
416
417 Args:
9b330382 418 node (fdt.None): Node to check
c20ee0ed
SG
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
78128d52 426 num_addr, num_size = 2, 2
c20ee0ed 427 if parent:
78128d52
SG
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
c20ee0ed
SG
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
78128d52
SG
447 num_addr, num_size = self.get_num_cells(node)
448 total = num_addr + num_size
c20ee0ed 449
5ea9dccf 450 if reg.type != fdt.Type.INT:
dfe5f5b9
SG
451 raise ValueError("Node '%s' reg property is not an int" %
452 node.name)
c20ee0ed 453 if len(reg.value) % total:
9b330382
SG
454 raise ValueError(
455 "Node '%s' reg property has %d cells "
456 'which is not a multiple of na + ns = %d + %d)' %
78128d52
SG
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:
5ea9dccf 461 reg.type = fdt.Type.INT64
c20ee0ed
SG
462 i = 0
463 new_value = []
464 val = reg.value
465 if not isinstance(val, list):
466 val = [val]
467 while i < len(val):
78128d52
SG
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
c20ee0ed
SG
472 new_value += [addr, size]
473 reg.value = new_value
474
2be282ca 475 def scan_structs(self):
7581c01a
SG
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.
e4fb5faa
SG
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
7581c01a 492 """
1b27273e 493 structs = collections.OrderedDict()
7581c01a 494 for node in self._valid_nodes:
dac8228d 495 node_name, _ = self.get_normalized_compat_name(node)
7581c01a
SG
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
7581c01a 517 for node in self._valid_nodes:
dac8228d 518 node_name, _ = self.get_normalized_compat_name(node)
7581c01a
SG
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])
7581c01a 523
7581c01a
SG
524 return structs
525
2be282ca 526 def scan_phandles(self):
7581c01a
SG
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
8fed2eb2
SG
542 info = self.get_phandle_argc(prop, node.name)
543 if info:
8fed2eb2 544 # Process the list as pairs of (phandle, id)
634eba4b
SG
545 pos = 0
546 for args in info.args:
547 phandle_cell = prop.value[pos]
8fed2eb2
SG
548 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
549 target_node = self._fdt.phandle_to_node[phandle]
550 node.phandles.add(target_node)
634eba4b 551 pos += 1 + args
7581c01a
SG
552
553
2be282ca 554 def generate_structs(self, structs):
7581c01a
SG
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
2799a69e 559 doc/driver-model/of-plat.rst for more information.
e4fb5faa
SG
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
7581c01a 568 """
d503114c 569 self.out_header()
2be282ca 570 self.out('#include <stdbool.h>\n')
b08c8c48 571 self.out('#include <linux/libfdt.h>\n')
7581c01a
SG
572
573 # Output the struct definition
574 for name in sorted(structs):
2be282ca 575 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
7581c01a
SG
576 for pname in sorted(structs[name]):
577 prop = structs[name][pname]
8fed2eb2
SG
578 info = self.get_phandle_argc(prop, structs[name])
579 if info:
7581c01a 580 # For phandles, include a reference to the target
0d15463c
SG
581 struct_name = 'struct phandle_%d_arg' % info.max_args
582 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
2be282ca 583 conv_name_to_c(prop.name),
634eba4b 584 len(info.args)))
7581c01a
SG
585 else:
586 ptype = TYPE_NAMES[prop.type]
2be282ca
SG
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')
7581c01a 593
2be282ca 594 def output_node(self, node):
7581c01a
SG
595 """Output the C code for a node
596
597 Args:
9b330382 598 node (fdt.Node): node to output
7581c01a 599 """
26e408fe
SG
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
26e408fe
SG
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]
26e408fe
SG
619 arg_values = []
620 for i in range(args):
8a38abfc
SG
621 arg_values.append(
622 str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
26e408fe 623 pos += 1 + args
8a38abfc
SG
624 vals.append('\t{%d, {%s}}' % (target_node.idx,
625 ', '.join(arg_values)))
26e408fe
SG
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
dac8228d 639 struct_name, _ = self.get_normalized_compat_name(node)
2be282ca 640 var_name = conv_name_to_c(node.name)
1b27273e 641 self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
51f1263d 642 self.buf('static struct %s%s %s%s = {\n' %
2be282ca 643 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
1953ce75
SG
644 for pname in sorted(node.props):
645 prop = node.props[pname]
7581c01a
SG
646 if pname in PROP_IGNORE_LIST or pname[0] == '#':
647 continue
2be282ca
SG
648 member_name = conv_name_to_c(prop.name)
649 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
7581c01a
SG
650
651 # Special handling for lists
2be282ca 652 if isinstance(prop.value, list):
26e408fe 653 _output_list(node, prop)
7581c01a 654 else:
56e0bbe0 655 self.buf(get_value(prop.type, prop.value))
2be282ca
SG
656 self.buf(',\n')
657 self.buf('};\n')
7581c01a
SG
658
659 # Add a device declaration
2be282ca
SG
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))
e41651ff
SG
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)
2be282ca
SG
668 self.buf('};\n')
669 self.buf('\n')
7581c01a 670
2be282ca 671 self.out(''.join(self.get_buf()))
7581c01a 672
2be282ca 673 def generate_tables(self):
7581c01a
SG
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
2799a69e 680 See the documentation in doc/driver-model/of-plat.rst for more
7581c01a
SG
681 information.
682 """
d503114c 683 self.out_header()
cb43ac18
SG
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')
2be282ca
SG
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')
7581c01a
SG
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:
2be282ca 699 self.output_node(req_node)
7581c01a 700 nodes_to_output.remove(req_node)
2be282ca 701 self.output_node(node)
7581c01a 702 nodes_to_output.remove(node)
fa0ea5b0 703
51f1263d
WL
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')
51f1263d
WL
708 self.buf('}\n')
709
710 self.out(''.join(self.get_buf()))
fa0ea5b0 711
6c74d1b8 712def run_steps(args, dtb_file, include_disabled, output, warning_disabled=False,
78128d52 713 drivers_additional=None):
fa0ea5b0
SG
714 """Run all the steps of the dtoc tool
715
716 Args:
9b330382
SG
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
78128d52
SG
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
9b330382
SG
725 Raises:
726 ValueError: if args has no command, or an unknown command
fa0ea5b0
SG
727 """
728 if not args:
729 raise ValueError('Please specify a command: struct, platdata')
730
78128d52
SG
731 plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled,
732 drivers_additional)
dac8228d 733 plat.scan_drivers()
fa0ea5b0
SG
734 plat.scan_dtb()
735 plat.scan_tree()
c20ee0ed 736 plat.scan_reg_sizes()
fa0ea5b0
SG
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.261391 seconds and 4 git commands to generate.