blob: 90a9e1a626912f6230d4e6c4016bcb1cadb10319 [file] [log] [blame]
Simon Glassd570dec2017-06-18 22:08:58 -06001#!/usr/bin/python
Tom Rini10e47792018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glassd570dec2017-06-18 22:08:58 -06003#
4# Copyright (C) 2017 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
Simon Glassd570dec2017-06-18 22:08:58 -06007
Simon Glass1f730c82017-06-18 22:08:59 -06008"""Device tree to platform data class
9
10This supports converting device tree data to C structures definitions and
11static data.
12"""
13
Simon Glassec3b5e42017-08-29 14:15:55 -060014import collections
Simon Glassd570dec2017-06-18 22:08:58 -060015import copy
Simon Glass1f730c82017-06-18 22:08:59 -060016import sys
Simon Glassd570dec2017-06-18 22:08:58 -060017
18import fdt
19import fdt_util
Simon Glass534eda92019-05-17 22:00:43 -060020import tools
Simon Glassd570dec2017-06-18 22:08:58 -060021
22# When we see these properties we ignore them - i.e. do not create a structure member
23PROP_IGNORE_LIST = [
24 '#address-cells',
25 '#gpio-cells',
26 '#size-cells',
27 'compatible',
28 'linux,phandle',
29 "status",
30 'phandle',
31 'u-boot,dm-pre-reloc',
32 'u-boot,dm-tpl',
33 'u-boot,dm-spl',
34]
35
36# C type declarations for the tyues we support
37TYPE_NAMES = {
38 fdt.TYPE_INT: 'fdt32_t',
39 fdt.TYPE_BYTE: 'unsigned char',
40 fdt.TYPE_STRING: 'const char *',
41 fdt.TYPE_BOOL: 'bool',
Simon Glassfc3ae9c2017-08-29 14:15:48 -060042 fdt.TYPE_INT64: 'fdt64_t',
Simon Glass1f730c82017-06-18 22:08:59 -060043}
Simon Glassd570dec2017-06-18 22:08:58 -060044
45STRUCT_PREFIX = 'dtd_'
46VAL_PREFIX = 'dtv_'
47
Simon Glassec3b5e42017-08-29 14:15:55 -060048# This holds information about a property which includes phandles.
49#
50# max_args: integer: Maximum number or arguments that any phandle uses (int).
51# args: Number of args for each phandle in the property. The total number of
52# phandles is len(args). This is a list of integers.
53PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
54
55
Simon Glass1f730c82017-06-18 22:08:59 -060056def conv_name_to_c(name):
Simon Glassd570dec2017-06-18 22:08:58 -060057 """Convert a device-tree name to a C identifier
58
Simon Glass2e0bf3f2017-06-18 22:09:04 -060059 This uses multiple replace() calls instead of re.sub() since it is faster
60 (400ms for 1m calls versus 1000ms for the 're' version).
61
Simon Glassd570dec2017-06-18 22:08:58 -060062 Args:
63 name: Name to convert
64 Return:
65 String containing the C version of this name
66 """
Simon Glass1f730c82017-06-18 22:08:59 -060067 new = name.replace('@', '_at_')
68 new = new.replace('-', '_')
69 new = new.replace(',', '_')
70 new = new.replace('.', '_')
Simon Glass1f730c82017-06-18 22:08:59 -060071 return new
Simon Glassd570dec2017-06-18 22:08:58 -060072
Simon Glass1f730c82017-06-18 22:08:59 -060073def tab_to(num_tabs, line):
74 """Append tabs to a line of text to reach a tab stop.
Simon Glassd570dec2017-06-18 22:08:58 -060075
Simon Glass1f730c82017-06-18 22:08:59 -060076 Args:
77 num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
78 line: Line of text to append to
79
80 Returns:
81 line with the correct number of tabs appeneded. If the line already
82 extends past that tab stop then a single space is appended.
83 """
84 if len(line) >= num_tabs * 8:
85 return line + ' '
86 return line + '\t' * (num_tabs - len(line) // 8)
87
Simon Glass7a2add12017-06-18 22:09:02 -060088def get_value(ftype, value):
89 """Get a value as a C expression
90
91 For integers this returns a byte-swapped (little-endian) hex string
92 For bytes this returns a hex string, e.g. 0x12
93 For strings this returns a literal string enclosed in quotes
94 For booleans this return 'true'
95
96 Args:
97 type: Data type (fdt_util)
98 value: Data value, as a string of bytes
99 """
100 if ftype == fdt.TYPE_INT:
101 return '%#x' % fdt_util.fdt32_to_cpu(value)
102 elif ftype == fdt.TYPE_BYTE:
Simon Glass534eda92019-05-17 22:00:43 -0600103 return '%#x' % tools.ToByte(value[0])
Simon Glass7a2add12017-06-18 22:09:02 -0600104 elif ftype == fdt.TYPE_STRING:
105 return '"%s"' % value
106 elif ftype == fdt.TYPE_BOOL:
107 return 'true'
Simon Glassfc3ae9c2017-08-29 14:15:48 -0600108 elif ftype == fdt.TYPE_INT64:
109 return '%#x' % value
Simon Glass7a2add12017-06-18 22:09:02 -0600110
111def get_compat_name(node):
112 """Get a node's first compatible string as a C identifier
113
114 Args:
115 node: Node object to check
116 Return:
117 Tuple:
118 C identifier for the first compatible string
119 List of C identifiers for all the other compatible strings
120 (possibly empty)
121 """
122 compat = node.props['compatible'].value
123 aliases = []
124 if isinstance(compat, list):
125 compat, aliases = compat[0], compat[1:]
126 return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases]
127
Simon Glass7a2add12017-06-18 22:09:02 -0600128
Simon Glass1f730c82017-06-18 22:08:59 -0600129class DtbPlatdata(object):
Simon Glassd570dec2017-06-18 22:08:58 -0600130 """Provide a means to convert device tree binary data to platform data
131
132 The output of this process is C structures which can be used in space-
133 constrained encvironments where the ~3KB code overhead of device tree
134 code is not affordable.
135
136 Properties:
Simon Glass1f730c82017-06-18 22:08:59 -0600137 _fdt: Fdt object, referencing the device tree
Simon Glassd570dec2017-06-18 22:08:58 -0600138 _dtb_fname: Filename of the input device tree binary file
139 _valid_nodes: A list of Node object with compatible strings
Simon Glasseab3f622017-06-18 22:09:01 -0600140 _include_disabled: true to include nodes marked status = "disabled"
Simon Glassd570dec2017-06-18 22:08:58 -0600141 _outfile: The current output file (sys.stdout or a real file)
142 _lines: Stashed list of output lines for outputting in the future
Simon Glassd570dec2017-06-18 22:08:58 -0600143 """
Simon Glasseab3f622017-06-18 22:09:01 -0600144 def __init__(self, dtb_fname, include_disabled):
Simon Glass1f730c82017-06-18 22:08:59 -0600145 self._fdt = None
Simon Glassd570dec2017-06-18 22:08:58 -0600146 self._dtb_fname = dtb_fname
147 self._valid_nodes = None
Simon Glasseab3f622017-06-18 22:09:01 -0600148 self._include_disabled = include_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600149 self._outfile = None
150 self._lines = []
151 self._aliases = {}
152
Simon Glass1f730c82017-06-18 22:08:59 -0600153 def setup_output(self, fname):
Simon Glassd570dec2017-06-18 22:08:58 -0600154 """Set up the output destination
155
Simon Glass1f730c82017-06-18 22:08:59 -0600156 Once this is done, future calls to self.out() will output to this
Simon Glassd570dec2017-06-18 22:08:58 -0600157 file.
158
159 Args:
160 fname: Filename to send output to, or '-' for stdout
161 """
162 if fname == '-':
163 self._outfile = sys.stdout
164 else:
165 self._outfile = open(fname, 'w')
166
Simon Glass1f730c82017-06-18 22:08:59 -0600167 def out(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600168 """Output a string to the output file
169
170 Args:
Simon Glass1f730c82017-06-18 22:08:59 -0600171 line: String to output
Simon Glassd570dec2017-06-18 22:08:58 -0600172 """
Simon Glass1f730c82017-06-18 22:08:59 -0600173 self._outfile.write(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600174
Simon Glass1f730c82017-06-18 22:08:59 -0600175 def buf(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600176 """Buffer up a string to send later
177
178 Args:
Simon Glass1f730c82017-06-18 22:08:59 -0600179 line: String to add to our 'buffer' list
Simon Glassd570dec2017-06-18 22:08:58 -0600180 """
Simon Glass1f730c82017-06-18 22:08:59 -0600181 self._lines.append(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600182
Simon Glass1f730c82017-06-18 22:08:59 -0600183 def get_buf(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600184 """Get the contents of the output buffer, and clear it
185
186 Returns:
187 The output buffer, which is then cleared for future use
188 """
189 lines = self._lines
190 self._lines = []
191 return lines
192
Simon Glass68d32c72017-08-29 14:16:01 -0600193 def out_header(self):
194 """Output a message indicating that this is an auto-generated file"""
195 self.out('''/*
196 * DO NOT MODIFY
197 *
198 * This file was generated by dtoc from a .dtb (device tree binary) file.
199 */
200
201''')
202
Simon Glassec3b5e42017-08-29 14:15:55 -0600203 def get_phandle_argc(self, prop, node_name):
204 """Check if a node contains phandles
Simon Glassce5621d2017-08-29 14:15:54 -0600205
Simon Glassec3b5e42017-08-29 14:15:55 -0600206 We have no reliable way of detecting whether a node uses a phandle
207 or not. As an interim measure, use a list of known property names.
208
209 Args:
210 prop: Prop object to check
211 Return:
212 Number of argument cells is this is a phandle, else None
213 """
214 if prop.name in ['clocks']:
Simon Glass609e2b12018-07-06 10:27:31 -0600215 if not isinstance(prop.value, list):
216 prop.value = [prop.value]
Simon Glassec3b5e42017-08-29 14:15:55 -0600217 val = prop.value
Simon Glassec3b5e42017-08-29 14:15:55 -0600218 i = 0
Simon Glassce5621d2017-08-29 14:15:54 -0600219
Simon Glassec3b5e42017-08-29 14:15:55 -0600220 max_args = 0
221 args = []
222 while i < len(val):
223 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass609e2b12018-07-06 10:27:31 -0600224 # If we get to the end of the list, stop. This can happen
225 # since some nodes have more phandles in the list than others,
226 # but we allocate enough space for the largest list. So those
227 # nodes with shorter lists end up with zeroes at the end.
228 if not phandle:
229 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600230 target = self._fdt.phandle_to_node.get(phandle)
231 if not target:
232 raise ValueError("Cannot parse '%s' in node '%s'" %
233 (prop.name, node_name))
234 prop_name = '#clock-cells'
235 cells = target.props.get(prop_name)
236 if not cells:
237 raise ValueError("Node '%s' has no '%s' property" %
238 (target.name, prop_name))
239 num_args = fdt_util.fdt32_to_cpu(cells.value)
240 max_args = max(max_args, num_args)
241 args.append(num_args)
242 i += 1 + num_args
243 return PhandleInfo(max_args, args)
244 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600245
Simon Glass1f730c82017-06-18 22:08:59 -0600246 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200247 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600248
Simon Glass1f730c82017-06-18 22:08:59 -0600249 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600250 device tree root node, and progress from there.
251 """
Simon Glass1f730c82017-06-18 22:08:59 -0600252 self._fdt = fdt.FdtScan(self._dtb_fname)
253
254 def scan_node(self, root):
255 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600256
Simon Glass17ffd622017-08-29 14:15:53 -0600257 This adds each node to self._valid_nodes.
Simon Glass1f730c82017-06-18 22:08:59 -0600258
259 Args:
260 root: Root node for scan
261 """
Simon Glassd570dec2017-06-18 22:08:58 -0600262 for node in root.subnodes:
263 if 'compatible' in node.props:
264 status = node.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600265 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600266 status.value != 'disabled'):
Simon Glassd570dec2017-06-18 22:08:58 -0600267 self._valid_nodes.append(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600268
269 # recurse to handle any subnodes
Simon Glass1f730c82017-06-18 22:08:59 -0600270 self.scan_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600271
Simon Glass1f730c82017-06-18 22:08:59 -0600272 def scan_tree(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600273 """Scan the device tree for useful information
274
275 This fills in the following properties:
Simon Glassd570dec2017-06-18 22:08:58 -0600276 _valid_nodes: A list of nodes we wish to consider include in the
277 platform data
278 """
Simon Glassd570dec2017-06-18 22:08:58 -0600279 self._valid_nodes = []
Simon Glass1f730c82017-06-18 22:08:59 -0600280 return self.scan_node(self._fdt.GetRoot())
Simon Glassd570dec2017-06-18 22:08:58 -0600281
Simon Glass1b1fe412017-08-29 14:15:50 -0600282 @staticmethod
283 def get_num_cells(node):
284 """Get the number of cells in addresses and sizes for this node
285
286 Args:
287 node: Node to check
288
289 Returns:
290 Tuple:
291 Number of address cells for this node
292 Number of size cells for this node
293 """
294 parent = node.parent
295 na, ns = 2, 2
296 if parent:
297 na_prop = parent.props.get('#address-cells')
298 ns_prop = parent.props.get('#size-cells')
299 if na_prop:
300 na = fdt_util.fdt32_to_cpu(na_prop.value)
301 if ns_prop:
302 ns = fdt_util.fdt32_to_cpu(ns_prop.value)
303 return na, ns
304
305 def scan_reg_sizes(self):
306 """Scan for 64-bit 'reg' properties and update the values
307
308 This finds 'reg' properties with 64-bit data and converts the value to
309 an array of 64-values. This allows it to be output in a way that the
310 C code can read.
311 """
312 for node in self._valid_nodes:
313 reg = node.props.get('reg')
314 if not reg:
315 continue
316 na, ns = self.get_num_cells(node)
317 total = na + ns
318
319 if reg.type != fdt.TYPE_INT:
Simon Glassc38fee042018-07-06 10:27:32 -0600320 raise ValueError("Node '%s' reg property is not an int" %
321 node.name)
Simon Glass1b1fe412017-08-29 14:15:50 -0600322 if len(reg.value) % total:
323 raise ValueError("Node '%s' reg property has %d cells "
324 'which is not a multiple of na + ns = %d + %d)' %
325 (node.name, len(reg.value), na, ns))
326 reg.na = na
327 reg.ns = ns
328 if na != 1 or ns != 1:
329 reg.type = fdt.TYPE_INT64
330 i = 0
331 new_value = []
332 val = reg.value
333 if not isinstance(val, list):
334 val = [val]
335 while i < len(val):
336 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
337 i += na
338 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
339 i += ns
340 new_value += [addr, size]
341 reg.value = new_value
342
Simon Glass1f730c82017-06-18 22:08:59 -0600343 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600344 """Scan the device tree building up the C structures we will use.
345
346 Build a dict keyed by C struct name containing a dict of Prop
347 object for each struct field (keyed by property name). Where the
348 same struct appears multiple times, try to use the 'widest'
349 property, i.e. the one with a type which can express all others.
350
351 Once the widest property is determined, all other properties are
352 updated to match that width.
353 """
354 structs = {}
355 for node in self._valid_nodes:
Simon Glass7a2add12017-06-18 22:09:02 -0600356 node_name, _ = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600357 fields = {}
358
359 # Get a list of all the valid properties in this node.
360 for name, prop in node.props.items():
361 if name not in PROP_IGNORE_LIST and name[0] != '#':
362 fields[name] = copy.deepcopy(prop)
363
364 # If we've seen this node_name before, update the existing struct.
365 if node_name in structs:
366 struct = structs[node_name]
367 for name, prop in fields.items():
368 oldprop = struct.get(name)
369 if oldprop:
370 oldprop.Widen(prop)
371 else:
372 struct[name] = prop
373
374 # Otherwise store this as a new struct.
375 else:
376 structs[node_name] = fields
377
378 upto = 0
379 for node in self._valid_nodes:
Simon Glass7a2add12017-06-18 22:09:02 -0600380 node_name, _ = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600381 struct = structs[node_name]
382 for name, prop in node.props.items():
383 if name not in PROP_IGNORE_LIST and name[0] != '#':
384 prop.Widen(struct[name])
385 upto += 1
386
Simon Glass7a2add12017-06-18 22:09:02 -0600387 struct_name, aliases = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600388 for alias in aliases:
389 self._aliases[alias] = struct_name
390
391 return structs
392
Simon Glass1f730c82017-06-18 22:08:59 -0600393 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600394 """Figure out what phandles each node uses
395
396 We need to be careful when outputing nodes that use phandles since
397 they must come after the declaration of the phandles in the C file.
398 Otherwise we get a compiler error since the phandle struct is not yet
399 declared.
400
401 This function adds to each node a list of phandle nodes that the node
402 depends on. This allows us to output things in the right order.
403 """
404 for node in self._valid_nodes:
405 node.phandles = set()
406 for pname, prop in node.props.items():
407 if pname in PROP_IGNORE_LIST or pname[0] == '#':
408 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600409 info = self.get_phandle_argc(prop, node.name)
410 if info:
Simon Glassec3b5e42017-08-29 14:15:55 -0600411 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600412 pos = 0
413 for args in info.args:
414 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600415 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
416 target_node = self._fdt.phandle_to_node[phandle]
417 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600418 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600419
420
Simon Glass1f730c82017-06-18 22:08:59 -0600421 def generate_structs(self, structs):
Simon Glassd570dec2017-06-18 22:08:58 -0600422 """Generate struct defintions for the platform data
423
424 This writes out the body of a header file consisting of structure
425 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100426 doc/driver-model/of-plat.rst for more information.
Simon Glassd570dec2017-06-18 22:08:58 -0600427 """
Simon Glass68d32c72017-08-29 14:16:01 -0600428 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600429 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900430 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600431
432 # Output the struct definition
433 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600434 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600435 for pname in sorted(structs[name]):
436 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600437 info = self.get_phandle_argc(prop, structs[name])
438 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600439 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600440 struct_name = 'struct phandle_%d_arg' % info.max_args
441 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600442 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600443 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600444 else:
445 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600446 self.out('\t%s%s' % (tab_to(2, ptype),
447 conv_name_to_c(prop.name)))
448 if isinstance(prop.value, list):
449 self.out('[%d]' % len(prop.value))
450 self.out(';\n')
451 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600452
Simon Glass61b88e52019-05-17 22:00:31 -0600453 for alias, struct_name in self._aliases.items():
Heiko Schocher701c4012019-04-16 13:31:58 +0200454 if alias not in sorted(structs):
455 self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
456 STRUCT_PREFIX, struct_name))
Simon Glassd570dec2017-06-18 22:08:58 -0600457
Simon Glass1f730c82017-06-18 22:08:59 -0600458 def output_node(self, node):
Simon Glassd570dec2017-06-18 22:08:58 -0600459 """Output the C code for a node
460
461 Args:
462 node: node to output
463 """
Simon Glass7a2add12017-06-18 22:09:02 -0600464 struct_name, _ = get_compat_name(node)
Simon Glass1f730c82017-06-18 22:08:59 -0600465 var_name = conv_name_to_c(node.name)
Simon Goldschmidt6d99b852019-01-07 20:29:26 +0100466 self.buf('static const struct %s%s %s%s = {\n' %
Simon Glass1f730c82017-06-18 22:08:59 -0600467 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
Simon Glassc82de562019-05-17 22:00:32 -0600468 for pname in sorted(node.props):
469 prop = node.props[pname]
Simon Glassd570dec2017-06-18 22:08:58 -0600470 if pname in PROP_IGNORE_LIST or pname[0] == '#':
471 continue
Simon Glass1f730c82017-06-18 22:08:59 -0600472 member_name = conv_name_to_c(prop.name)
473 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
Simon Glassd570dec2017-06-18 22:08:58 -0600474
475 # Special handling for lists
Simon Glass1f730c82017-06-18 22:08:59 -0600476 if isinstance(prop.value, list):
477 self.buf('{')
Simon Glassd570dec2017-06-18 22:08:58 -0600478 vals = []
479 # For phandles, output a reference to the platform data
480 # of the target node.
Simon Glassec3b5e42017-08-29 14:15:55 -0600481 info = self.get_phandle_argc(prop, node.name)
482 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600483 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600484 pos = 0
485 for args in info.args:
486 phandle_cell = prop.value[pos]
Simon Glassd570dec2017-06-18 22:08:58 -0600487 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
Simon Glass17ffd622017-08-29 14:15:53 -0600488 target_node = self._fdt.phandle_to_node[phandle]
Simon Glass1f730c82017-06-18 22:08:59 -0600489 name = conv_name_to_c(target_node.name)
Simon Glass3deeb472017-08-29 14:15:59 -0600490 arg_values = []
491 for i in range(args):
492 arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
493 pos += 1 + args
494 vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
495 ', '.join(arg_values)))
Simon Glassd0cd0752017-08-29 14:15:57 -0600496 for val in vals:
497 self.buf('\n\t\t%s,' % val)
Simon Glassd570dec2017-06-18 22:08:58 -0600498 else:
499 for val in prop.value:
Simon Glass7a2add12017-06-18 22:09:02 -0600500 vals.append(get_value(prop.type, val))
Simon Glass131e0b02017-08-29 14:15:49 -0600501
Simon Glassd0cd0752017-08-29 14:15:57 -0600502 # Put 8 values per line to avoid very long lines.
Simon Glass61b88e52019-05-17 22:00:31 -0600503 for i in range(0, len(vals), 8):
Simon Glassd0cd0752017-08-29 14:15:57 -0600504 if i:
505 self.buf(',\n\t\t')
506 self.buf(', '.join(vals[i:i + 8]))
Simon Glass1f730c82017-06-18 22:08:59 -0600507 self.buf('}')
Simon Glassd570dec2017-06-18 22:08:58 -0600508 else:
Simon Glass7a2add12017-06-18 22:09:02 -0600509 self.buf(get_value(prop.type, prop.value))
Simon Glass1f730c82017-06-18 22:08:59 -0600510 self.buf(',\n')
511 self.buf('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600512
513 # Add a device declaration
Simon Glass1f730c82017-06-18 22:08:59 -0600514 self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
515 self.buf('\t.name\t\t= "%s",\n' % struct_name)
516 self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
517 self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
518 self.buf('};\n')
519 self.buf('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600520
Simon Glass1f730c82017-06-18 22:08:59 -0600521 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -0600522
Simon Glass1f730c82017-06-18 22:08:59 -0600523 def generate_tables(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600524 """Generate device defintions for the platform data
525
526 This writes out C platform data initialisation data and
527 U_BOOT_DEVICE() declarations for each valid node. Where a node has
528 multiple compatible strings, a #define is used to make them equivalent.
529
Heinrich Schuchardtc79f03c2020-02-25 21:35:39 +0100530 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glassd570dec2017-06-18 22:08:58 -0600531 information.
532 """
Simon Glass68d32c72017-08-29 14:16:01 -0600533 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600534 self.out('#include <common.h>\n')
535 self.out('#include <dm.h>\n')
536 self.out('#include <dt-structs.h>\n')
537 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600538 nodes_to_output = list(self._valid_nodes)
539
540 # Keep outputing nodes until there is none left
541 while nodes_to_output:
542 node = nodes_to_output[0]
543 # Output all the node's dependencies first
544 for req_node in node.phandles:
545 if req_node in nodes_to_output:
Simon Glass1f730c82017-06-18 22:08:59 -0600546 self.output_node(req_node)
Simon Glassd570dec2017-06-18 22:08:58 -0600547 nodes_to_output.remove(req_node)
Simon Glass1f730c82017-06-18 22:08:59 -0600548 self.output_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600549 nodes_to_output.remove(node)
Simon Glass3fa797a2017-06-18 22:09:03 -0600550
551
552def run_steps(args, dtb_file, include_disabled, output):
553 """Run all the steps of the dtoc tool
554
555 Args:
556 args: List of non-option arguments provided to the problem
557 dtb_file: Filename of dtb file to process
558 include_disabled: True to include disabled nodes
559 output: Name of output file
560 """
561 if not args:
562 raise ValueError('Please specify a command: struct, platdata')
563
564 plat = DtbPlatdata(dtb_file, include_disabled)
565 plat.scan_dtb()
566 plat.scan_tree()
Simon Glass1b1fe412017-08-29 14:15:50 -0600567 plat.scan_reg_sizes()
Simon Glass3fa797a2017-06-18 22:09:03 -0600568 plat.setup_output(output)
569 structs = plat.scan_structs()
570 plat.scan_phandles()
571
572 for cmd in args[0].split(','):
573 if cmd == 'struct':
574 plat.generate_structs(structs)
575 elif cmd == 'platdata':
576 plat.generate_tables()
577 else:
578 raise ValueError("Unknown command '%s': (use: struct, platdata)" %
579 cmd)